public void Decompiler_handles_strings_with_newlines(string newline, string escapedNewline) { var template = @"{ ""$schema"": ""https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#"", ""contentVersion"": ""1.0.0.0"", ""parameters"": {}, ""variables"": { ""multilineString"": ""multi line string"" }, ""resources"": [], ""outputs"": {} }"; // replace newlines with the style passed in template = string.Join(newline, Regex.Split(template, "\r?\n")); var fileUri = new Uri("file:///path/to/main.json"); var fileResolver = new InMemoryFileResolver(new Dictionary <Uri, string> { [fileUri] = template, });; var(entryPointUri, filesToSave) = TemplateDecompiler.DecompileFileWithModules(TestResourceTypeProvider.Create(), fileResolver, fileUri); // this behavior is actaully controlled by newtonsoft's deserializer, but we should assert it anyway to avoid regressions. filesToSave[entryPointUri].Should().Contain($"var multilineString = 'multi{escapedNewline} line{escapedNewline} string'"); }
public void Decompiler_handles_banned_function_replacement(string expression, string type, string expectedValue) { var template = @"{ ""$schema"": ""https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#"", ""contentVersion"": ""1.0.0.0"", ""parameters"": {}, ""variables"": { ""a"": true, ""b"": false, ""c"": true }, ""resources"": [], ""outputs"": { ""calculated"": { ""type"": """ + type + @""", ""value"": ""[" + expression + @"]"" } } }"; var fileUri = new Uri("file:///path/to/main.json"); var fileResolver = new InMemoryFileResolver(new Dictionary <Uri, string> { [fileUri] = template, }); var(entryPointUri, filesToSave) = TemplateDecompiler.DecompileFileWithModules(TestResourceTypeProvider.Create(), fileResolver, fileUri); filesToSave[entryPointUri].Should().Contain($"output calculated {type} = ({expectedValue})"); }
public int Decompile(ILogger logger, DecompileArguments arguments) { logger.LogWarning( "WARNING: Decompilation is a best-effort process, as there is no guaranteed mapping from ARM JSON to Bicep.\n" + "You may need to fix warnings and errors in the generated bicep file(s), or decompilation may fail entirely if an accurate conversion is not possible.\n" + "If you would like to report any issues or inaccurate conversions, please see https://github.com/Azure/bicep/issues."); var diagnosticLogger = new BicepDiagnosticLogger(logger); var jsonPath = PathHelper.ResolvePath(arguments.InputFile); try { var(bicepUri, filesToSave) = TemplateDecompiler.DecompileFileWithModules(resourceTypeProvider, new FileResolver(), PathHelper.FilePathToFileUrl(jsonPath)); foreach (var(fileUri, bicepOutput) in filesToSave) { File.WriteAllText(fileUri.LocalPath, bicepOutput); } var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), new Workspace(), bicepUri); var compilation = new Compilation(resourceTypeProvider, syntaxTreeGrouping); return(LogDiagnosticsAndCheckSuccess(diagnosticLogger, compilation) ? 0 : 1); } catch (Exception exception) { this.errorWriter.WriteLine($"{jsonPath}: Decompilation failed with fatal error \"{exception.Message}\""); return(1); } }
public void Decompiler_raises_errors_for_unsupported_features(string resourcePath, string expectedMessage) { Action onDecompile = () => { var fileResolver = ReadResourceFile(resourcePath); TemplateDecompiler.DecompileFileWithModules(TestTypeHelper.CreateEmptyProvider(), fileResolver, new Uri($"file:///{resourcePath}")); }; onDecompile.Should().Throw <ConversionFailedException>().WithMessage(expectedMessage); }
public (Uri, ImmutableDictionary <Uri, string>) Decompile(string inputPath, string outputPath) { inputPath = PathHelper.ResolvePath(inputPath); Uri inputUri = PathHelper.FilePathToFileUrl(inputPath); Uri outputUri = PathHelper.FilePathToFileUrl(outputPath); var decompilation = TemplateDecompiler.DecompileFileWithModules(invocationContext.ResourceTypeProvider, new FileResolver(), inputUri, outputUri); foreach (var(fileUri, bicepOutput) in decompilation.filesToSave) { workspace.UpsertSyntaxTrees(SyntaxTree.Create(fileUri, bicepOutput).AsEnumerable()); } _ = Compile(decompilation.entrypointUri.AbsolutePath); // to verify success we recompile and check for syntax errors. return(decompilation); }
public async Task <(Uri, ImmutableDictionary <Uri, string>)> DecompileAsync(string inputPath, string outputPath) { inputPath = PathHelper.ResolvePath(inputPath); Uri inputUri = PathHelper.FilePathToFileUrl(inputPath); Uri outputUri = PathHelper.FilePathToFileUrl(outputPath); var decompilation = decompiler.DecompileFileWithModules(inputUri, outputUri); foreach (var(fileUri, bicepOutput) in decompilation.filesToSave) { workspace.UpsertSourceFile(SourceFileFactory.CreateBicepFile(fileUri, bicepOutput)); } // to verify success we recompile and check for syntax errors. await CompileAsync(decompilation.entrypointUri.AbsolutePath, skipRestore : true); return(decompilation); }
public DecompileResult Decompile(string jsonContent) { var jsonUri = new Uri("inmemory:///main.json"); var fileResolver = new InMemoryFileResolver(new Dictionary <Uri, string> { [jsonUri] = jsonContent, }); try { var(entrypointUri, filesToSave) = TemplateDecompiler.DecompileFileWithModules(resourceTypeProvider, fileResolver, jsonUri); return(new DecompileResult(filesToSave[entrypointUri], null)); } catch (Exception exception) { return(new DecompileResult(null, exception.Message)); } }
public void Decompiler_generates_expected_bicep_files_with_diagnostics(ExampleData example) { // save all the files in the containing directory to disk so that we can test module resolution var parentStream = Path.GetDirectoryName(example.BicepStreamName) !.Replace('\\', '/'); var outputDirectory = FileHelper.SaveEmbeddedResourcesWithPathPrefix(TestContext, typeof(DecompilationTests).Assembly, parentStream); var bicepFileName = Path.Combine(outputDirectory, Path.GetFileName(example.BicepStreamName)); var jsonFileName = Path.Combine(outputDirectory, Path.GetFileName(example.JsonStreamName)); var typeProvider = AzResourceTypeProvider.CreateWithAzTypes(); var(bicepUri, filesToSave) = TemplateDecompiler.DecompileFileWithModules(typeProvider, new FileResolver(), PathHelper.FilePathToFileUrl(jsonFileName)); var syntaxTrees = filesToSave.Select(kvp => SyntaxTree.Create(kvp.Key, kvp.Value)); var workspace = new Workspace(); workspace.UpsertSyntaxTrees(syntaxTrees); var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), workspace, bicepUri); var compilation = new Compilation(typeProvider, syntaxTreeGrouping); var diagnosticsBySyntaxTree = compilation.GetAllDiagnosticsBySyntaxTree(); using (new AssertionScope()) { foreach (var syntaxTree in syntaxTreeGrouping.SyntaxTrees) { var exampleExists = File.Exists(syntaxTree.FileUri.LocalPath); exampleExists.Should().BeTrue($"Generated example \"{syntaxTree.FileUri.LocalPath}\" should be checked in"); var diagnostics = diagnosticsBySyntaxTree[syntaxTree]; var bicepOutput = filesToSave[syntaxTree.FileUri]; var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(bicepOutput, Environment.NewLine, diagnostics, diag => OutputHelper.GetDiagLoggingString(bicepOutput, outputDirectory, diag)); File.WriteAllText(syntaxTree.FileUri.LocalPath + ".actual", sourceTextWithDiags); sourceTextWithDiags.Should().EqualWithLineByLineDiffOutput( TestContext, exampleExists ? File.ReadAllText(syntaxTree.FileUri.LocalPath) : "", expectedLocation: Path.Combine("src", "Bicep.Decompiler.IntegrationTests", parentStream, Path.GetRelativePath(outputDirectory, syntaxTree.FileUri.LocalPath)), actualLocation: syntaxTree.FileUri.LocalPath + ".actual"); } } }
public DecompileResult Decompile(string jsonContent) { var jsonUri = new Uri("inmemory:///main.json"); var fileResolver = new InMemoryFileResolver(new Dictionary <Uri, string> { [jsonUri] = jsonContent, }); try { var bicepUri = PathHelper.ChangeToBicepExtension(jsonUri); var decompiler = new TemplateDecompiler(namespaceProvider, fileResolver, new EmptyModuleRegistryProvider(), new ConfigurationManager(new IOFileSystem())); var(entrypointUri, filesToSave) = decompiler.DecompileFileWithModules(jsonUri, bicepUri); return(new DecompileResult(filesToSave[entrypointUri], null)); } catch (Exception exception) { return(new DecompileResult(null, exception.Message)); } }
private bool DecompileSingleFile(IDiagnosticLogger logger, string filePath) { try { var(bicepUri, filesToSave) = TemplateDecompiler.DecompileFileWithModules(resourceTypeProvider, new FileResolver(), PathHelper.FilePathToFileUrl(filePath)); foreach (var(fileUri, bicepOutput) in filesToSave) { File.WriteAllText(fileUri.LocalPath, bicepOutput); } var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), new Workspace(), bicepUri); var compilation = new Compilation(resourceTypeProvider, syntaxTreeGrouping); return(LogDiagnosticsAndCheckSuccess(logger, compilation)); } catch (Exception exception) { this.errorWriter.WriteLine($"{filePath}: Decompilation failed with fatal error \"{exception.Message}\""); return(false); } }
private int DecompileToFile(IDiagnosticLogger logger, string jsonPath, string outputPath) { try { var(_, filesToSave) = TemplateDecompiler.DecompileFileWithModules(resourceTypeProvider, new FileResolver(), PathHelper.FilePathToFileUrl(jsonPath)); foreach (var(_, bicepOutput) in filesToSave) { File.WriteAllText(outputPath, bicepOutput); } var outputPathToCheck = Path.GetFullPath(outputPath); var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), new Workspace(), PathHelper.FilePathToFileUrl(outputPathToCheck)); var compilation = new Compilation(resourceTypeProvider, syntaxTreeGrouping); return(LogDiagnosticsAndCheckSuccess(logger, compilation) ? 0 : 1); } catch (Exception exception) { this.errorWriter.WriteLine($"{jsonPath}: Decompilation failed with fatal error \"{exception.Message}\""); return(1); } }