Пример #1
0
        private int DecompileToStdout(IDiagnosticLogger logger, string jsonPath)
        {
            var tempOutputPath = Path.ChangeExtension(Path.GetTempFileName(), "bicep");

            try
            {
                var(_, filesToSave) = TemplateDecompiler.DecompileFileWithModules(resourceTypeProvider, new FileResolver(), PathHelper.FilePathToFileUrl(jsonPath));
                foreach (var(_, bicepOutput) in filesToSave)
                {
                    this.outputWriter.Write(bicepOutput);
                    File.WriteAllText(tempOutputPath, bicepOutput);
                }

                var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), new Workspace(), PathHelper.FilePathToFileUrl(tempOutputPath));
                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);
            } finally
            {
                if (File.Exists(tempOutputPath))
                {
                    File.Delete(tempOutputPath);
                }
            }
        }
Пример #2
0
        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(TestTypeHelper.CreateEmptyProvider(), fileResolver, fileUri);

            filesToSave[entryPointUri].Should().Contain($"output calculated {type} = ({expectedValue})");
        }
Пример #3
0
        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);
            }
        }
Пример #4
0
        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(TestTypeHelper.CreateEmptyProvider(), fileResolver, fileUri);

            // this behavior is actually 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'");
        }
Пример #5
0
        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);
        }
Пример #6
0
 public CompilationService(
     IDiagnosticLogger diagnosticLogger,
     IFileResolver fileResolver,
     InvocationContext invocationContext,
     IModuleDispatcher moduleDispatcher,
     IConfigurationManager configurationManager,
     TemplateDecompiler decompiler)
 {
     this.diagnosticLogger     = diagnosticLogger;
     this.fileResolver         = fileResolver;
     this.moduleDispatcher     = moduleDispatcher;
     this.configurationManager = configurationManager;
     this.invocationContext    = invocationContext;
     this.workspace            = new Workspace();
     this.decompiler           = decompiler;
 }
Пример #7
0
        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);
        }
Пример #8
0
        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));
            }
        }
Пример #9
0
        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");
                }
            }
        }
Пример #10
0
        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));
            }
        }
Пример #11
0
        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);
            }
        }
Пример #12
0
        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);
            }
        }