using System; using System.Collections.Generic; using System.Linq; using Semmle.BuildAnalyser; using Semmle.Util.Logging; namespace Semmle.Extraction.CSharp.Standalone { /// /// One independent run of the extractor. /// class Extraction { public Extraction(string directory) { this.directory = directory; } public readonly string directory; public readonly List Sources = new List(); }; /// /// Searches for source/references and creates separate extractions. /// class Analysis { readonly ILogger logger; public Analysis(ILogger logger) { this.logger = logger; } // The extraction configuration for the entire project. Extraction projectExtraction; public IEnumerable References { get; private set; } /// /// The extraction configuration. /// public Extraction Extraction => projectExtraction; /// /// Creates an extraction for the current directory /// and adds it to the list of all extractions. /// /// The directory of the extraction. /// The extraction. void CreateExtraction(string dir) { projectExtraction = new Extraction(dir); } BuildAnalysis buildAnalysis; /// /// Analyse projects/solution and resolves references. /// /// The build analysis options. public void AnalyseProjects(Options options) { CreateExtraction(options.SrcDir); var progressMonitor = new ProgressMonitor(logger); buildAnalysis = new BuildAnalysis(options, progressMonitor); References = buildAnalysis.ReferenceFiles; projectExtraction.Sources.AddRange(options.SolutionFile == null ? buildAnalysis.AllSourceFiles : buildAnalysis.ProjectSourceFiles); } /// /// Delete any Nuget assemblies. /// public void Cleanup() { buildAnalysis.Cleanup(); } }; public class Program { static int Main(string[] args) { var options = Options.Create(args); var output = new ConsoleLogger(options.Verbosity); var a = new Analysis(output); if (options.Help) { options.ShowHelp(System.Console.Out); return 0; } if (options.Errors) return 1; output.Log(Severity.Info, "Running C# standalone extractor"); a.AnalyseProjects(options); int sourceFiles = a.Extraction.Sources.Count(); if (sourceFiles == 0) { output.Log(Severity.Error, "No source files found"); return 1; } if (!options.SkipExtraction) { output.Log(Severity.Info, ""); output.Log(Severity.Info, "Extracting..."); Extractor.ExtractStandalone( a.Extraction.Sources, a.References, new ExtractionProgress(output), new FileLogger(options.Verbosity, Extractor.GetCSharpLogPath()), options); output.Log(Severity.Info, "Extraction complete"); } a.Cleanup(); return 0; } class ExtractionProgress : IProgressMonitor { public ExtractionProgress(ILogger output) { logger = output; } readonly ILogger logger; public void Analysed(int item, int total, string source, string output, TimeSpan time, AnalysisAction action) { logger.Log(Severity.Info, "[{0}/{1}] {2} ({3})", item, total, source, action == AnalysisAction.Extracted ? time.ToString() : action == AnalysisAction.Excluded ? "excluded" : "up to date"); } public void MissingType(string type) { logger.Log(Severity.Debug, "Missing type {0}", type); } public void MissingNamespace(string @namespace) { logger.Log(Severity.Info, "Missing namespace {0}", @namespace); } public void MissingSummary(int missingTypes, int missingNamespaces) { logger.Log(Severity.Info, "Failed to resolve {0} types and {1} namespaces", missingTypes, missingNamespaces); } } } }