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);
}
}
}
}