Ejemplo n.º 1
0
        static int HandleCommand(string assembliesPath, string sourcePath, string[]?referencesPaths, bool verbose, bool quiet, bool debug, string?debugPath)
        {
            // If user provided a debug path then assume we should write debug outputs.
            debug |= debugPath is object;
            debugPath ??= Path.Combine(Path.GetTempPath(), $"BuildValidator");
            referencesPaths ??= Array.Empty <string>();

            var options = new Options(assembliesPath, referencesPaths, sourcePath, verbose, quiet, debug, debugPath);

            // TODO: remove the DemoLoggerProvider, update this dependency,
            // and move to the built in logger.
            var loggerFactory = new LoggerFactory(
                new[] { new ConsoleLoggerProvider(new ConsoleLoggerSettings()) },
                new LoggerFilterOptions()
            {
                MinLevel = options.Verbose ? LogLevel.Trace : LogLevel.Information
            });

            if (!options.Quiet)
            {
                loggerFactory.AddProvider(new DemoLoggerProvider());
            }

            var logger = loggerFactory.CreateLogger <Program>();

            try
            {
                var fullDebugPath = Path.GetFullPath(debugPath);
                logger.LogInformation($@"Using debug folder: ""{fullDebugPath}""");
                Directory.Delete(debugPath, recursive: true);
                logger.LogInformation($@"Cleaned debug folder: ""{fullDebugPath}""");
            }
            catch (IOException)
            {
                // no-op
            }

            try
            {
                var sourceResolver    = new LocalSourceResolver(options, loggerFactory);
                var referenceResolver = new LocalReferenceResolver(options, loggerFactory);

                var buildConstructor = new BuildConstructor(referenceResolver, sourceResolver, logger);

                var artifactsDir = new DirectoryInfo(options.AssembliesPath);

                var filesToValidate = artifactsDir.EnumerateFiles("*.exe", SearchOption.AllDirectories)
                                      .Concat(artifactsDir.EnumerateFiles("*.dll", SearchOption.AllDirectories))
                                      .Distinct(FileNameEqualityComparer.Instance);

                var success = ValidateFiles(filesToValidate, buildConstructor, logger, options);
                Console.Out.Flush();
                return(success ? ExitSuccess : ExitFailure);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, ex.Message);
                throw;
            }
        }
Ejemplo n.º 2
0
        private static void ValidateFiles(IEnumerable <FileInfo> files, BuildConstructor buildConstructor, string?thisCompilerVersion)
        {
            var assembliesCompiled = new List <CompilationDiff>();

            foreach (var file in files)
            {
                var compilationDiff = ValidateFile(file, buildConstructor, thisCompilerVersion);

                if (compilationDiff is null)
                {
                    continue;
                }

                assembliesCompiled.Add(compilationDiff);
            }

            var sb = new StringBuilder();

            sb.AppendLine("====================");
            sb.AppendLine("Summary:");
            sb.AppendLine();
            sb.AppendLine("Successful Tests:");

            foreach (var diff in assembliesCompiled.Where(a => a.AreEqual == true))
            {
                sb.AppendLine($"\t{diff.OriginalPath}");
            }

            sb.AppendLine();

            sb.AppendLine("Failed Tests:");
            foreach (var diff in assembliesCompiled.Where(a => a.AreEqual == false))
            {
                sb.AppendLine($"\t{diff.OriginalPath}");
            }

            sb.AppendLine();
            sb.AppendLine("Error Cases:");
            foreach (var diff in assembliesCompiled.Where(a => !a.AreEqual.HasValue))
            {
                sb.AppendLine($"\t{diff.OriginalPath}");
                if (diff.Exception != null)
                {
                    sb.AppendLine($"\tException: {diff.Exception.Message}");
                }
            }
            sb.AppendLine("====================");

            s_logger.LogInformation(sb.ToString());
        }
Ejemplo n.º 3
0
        // TODO: it feels like "logger" and "options" should be instance variables of something
        private static bool ValidateFiles(IEnumerable <FileInfo> originalBinaries, BuildConstructor buildConstructor, ILogger logger, Options options)
        {
            var assembliesCompiled = new List <CompilationDiff>();

            foreach (var file in originalBinaries)
            {
                var compilationDiff = ValidateFile(file, buildConstructor, logger, options);

                if (compilationDiff is null)
                {
                    logger.LogInformation($"Ignoring {file.FullName}");
                    continue;
                }

                assembliesCompiled.Add(compilationDiff);
            }

            bool success = true;

            using var summary = logger.BeginScope("Summary");
            using (logger.BeginScope("Successful rebuilds"))
            {
                foreach (var diff in assembliesCompiled.Where(a => a.AreEqual == true))
                {
                    logger.LogInformation($"\t{diff.OriginalPath}");
                }
            }

            using (logger.BeginScope("Rebuilds with output differences"))
            {
                foreach (var diff in assembliesCompiled.Where(a => a.AreEqual == false))
                {
                    // TODO: can we include the path to any diff artifacts?
                    logger.LogWarning($"\t{diff.OriginalPath}");
                    success = false;
                }
            }

            using (logger.BeginScope("Rebuilds with compilation errors"))
            {
                foreach (var diff in assembliesCompiled.Where(a => a.AreEqual == null))
                {
                    logger.LogError($"{diff.OriginalPath} had {diff.Diagnostics.Length} diagnostics.");
                    success = false;
                }
            }

            return(success);
        }
Ejemplo n.º 4
0
        private static CompilationDiff?ValidateFile(FileInfo file, BuildConstructor buildConstructor, string?thisCompilerVersion)
        {
            if (s_ignorePatterns.Any(r => r.IsMatch(file.FullName)))
            {
                s_logger.LogTrace($"Ignoring {file.FullName}");
                return(null);
            }

            MetadataReaderProvider?pdbReaderProvider = null;

            try
            {
                // Find the embedded pdb
                using var fileStream = file.OpenRead();
                using var peReader   = new PEReader(fileStream);

                var pdbOpened = peReader.TryOpenAssociatedPortablePdb(
                    peImagePath: file.FullName,
                    filePath => File.Exists(filePath) ? File.OpenRead(filePath) : null,
                    out pdbReaderProvider,
                    out var pdbPath);

                if (!pdbOpened || pdbReaderProvider is null)
                {
                    s_logger.LogError($"Could not find pdb for {file.FullName}");
                    return(null);
                }

                s_logger.LogInformation($"Compiling {file.FullName} with pdb {pdbPath ?? "[embedded]"}");

                var reader = pdbReaderProvider.GetMetadataReader();

                // TODO: Check compilation version using the PEReader

                var compilation = buildConstructor.CreateCompilation(reader, file.Name);
                return(CompilationDiff.Create(file, compilation));
            }
            catch (Exception e)
            {
                s_logger.LogError(e, file.FullName);
                return(CompilationDiff.Create(file, e));
            }
            finally
            {
                pdbReaderProvider?.Dispose();
            }
        }
Ejemplo n.º 5
0
        static void Main(string[] args)
        {
            Options options;

            try
            {
                options = Options.Create(args);
            }
            catch (InvalidDataException)
            {
                PrintHelp();
                return;
            }

            var loggerFactory = new LoggerFactory(Enumerable.Empty <ILoggerProvider>(), new LoggerFilterOptions()
            {
                MinLevel = options.Verbose ? LogLevel.Trace : LogLevel.Information
            });

            if (options.ConsoleOutput)
            {
                loggerFactory.AddConsole();
            }

            s_logger = loggerFactory.CreateLogger <Program>();

            var sourceResolver    = new LocalSourceResolver(loggerFactory);
            var referenceResolver = new LocalReferenceResolver(loggerFactory);

            var buildConstructor = new BuildConstructor(referenceResolver, sourceResolver);

            var artifactsDir        = LocalReferenceResolver.GetArtifactsDirectory();
            var thisCompilerVersion = options.IgnoreCompilerVersion
                ? null
                : typeof(Compilation).Assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>()?.InformationalVersion;

            var filesToValidate = artifactsDir.EnumerateFiles("*.exe", SearchOption.AllDirectories)
                                  .Concat(artifactsDir.EnumerateFiles("*.dll", SearchOption.AllDirectories))
                                  .Distinct(FileNameEqualityComparer.Instance);

            ValidateFiles(filesToValidate, buildConstructor, thisCompilerVersion);
        }
Ejemplo n.º 6
0
        private static CompilationDiff?ValidateFile(FileInfo originalBinary, BuildConstructor buildConstructor, ILogger logger, Options options)
        {
            if (s_ignorePatterns.Any(r => r.IsMatch(originalBinary.FullName)))
            {
                logger.LogTrace($"Ignoring {originalBinary.FullName}");
                return(null);
            }

            MetadataReaderProvider?pdbReaderProvider = null;

            try
            {
                // Find the embedded pdb
                using var originalBinaryStream = originalBinary.OpenRead();
                using var originalPeReader     = new PEReader(originalBinaryStream);

                var pdbOpened = originalPeReader.TryOpenAssociatedPortablePdb(
                    peImagePath: originalBinary.FullName,
                    filePath => File.Exists(filePath) ? File.OpenRead(filePath) : null,
                    out pdbReaderProvider,
                    out var pdbPath);

                if (!pdbOpened || pdbReaderProvider is null)
                {
                    logger.LogError($"Could not find pdb for {originalBinary.FullName}");
                    return(null);
                }

                using var _ = logger.BeginScope($"Verifying {originalBinary.FullName} with pdb {pdbPath ?? "[embedded]"}");

                var pdbReader     = pdbReaderProvider.GetMetadataReader();
                var optionsReader = new CompilationOptionsReader(logger, pdbReader, originalPeReader);

                var compilation = buildConstructor.CreateCompilation(
                    optionsReader,
                    Path.GetFileNameWithoutExtension(originalBinary.Name));

                var compilationDiff = CompilationDiff.Create(originalBinary, optionsReader, compilation, getDebugEntryPoint(), logger, options);
                return(compilationDiff);

                IMethodSymbol?getDebugEntryPoint()
                {
                    if (optionsReader.GetMainTypeName() is { } mainTypeName&&
                        optionsReader.GetMainMethodName() is { } mainMethodName)
                    {
                        var typeSymbol = compilation.GetTypeByMetadataName(mainTypeName);
                        if (typeSymbol is object)
                        {
                            var methodSymbols = typeSymbol
                                                .GetMembers(mainMethodName)
                                                .OfType <IMethodSymbol>();
                            return(methodSymbols.FirstOrDefault());
                        }
                    }

                    return(null);
                }
            }
            finally
            {
                pdbReaderProvider?.Dispose();
            }
        }