mirror of
https://github.com/github/codeql.git
synced 2026-04-26 09:15:12 +02:00
C#: Move autobuilder into separate folder
This commit is contained in:
885
csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs
Normal file
885
csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs
Normal file
@@ -0,0 +1,885 @@
|
||||
using Xunit;
|
||||
using Semmle.Autobuild;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Construction;
|
||||
|
||||
namespace Semmle.Extraction.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test class to script Autobuilder scenarios.
|
||||
/// For most methods, it uses two fields:
|
||||
/// - an IList to capture the the arguments passed to it
|
||||
/// - an IDictionary of possible return values.
|
||||
/// </summary>
|
||||
class TestActions : IBuildActions
|
||||
{
|
||||
/// <summary>
|
||||
/// List of strings passed to FileDelete.
|
||||
/// </summary>
|
||||
public IList<string> FileDeleteIn = new List<string>();
|
||||
|
||||
void IBuildActions.FileDelete(string file)
|
||||
{
|
||||
FileDeleteIn.Add(file);
|
||||
}
|
||||
|
||||
public IList<string> FileExistsIn = new List<string>();
|
||||
public IDictionary<string, bool> FileExists = new Dictionary<string, bool>();
|
||||
|
||||
bool IBuildActions.FileExists(string file)
|
||||
{
|
||||
FileExistsIn.Add(file);
|
||||
if (FileExists.TryGetValue(file, out var ret))
|
||||
return ret;
|
||||
if (FileExists.TryGetValue(System.IO.Path.GetFileName(file), out ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing FileExists " + file);
|
||||
}
|
||||
|
||||
public IList<string> RunProcessIn = new List<string>();
|
||||
public IDictionary<string, int> RunProcess = new Dictionary<string, int>();
|
||||
public IDictionary<string, string> RunProcessOut = new Dictionary<string, string>();
|
||||
public IDictionary<string, string> RunProcessWorkingDirectory = new Dictionary<string, string>();
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary<string, string> env, out IList<string> stdOut)
|
||||
{
|
||||
var pattern = cmd + " " + args;
|
||||
RunProcessIn.Add(pattern);
|
||||
if (RunProcessOut.TryGetValue(pattern, out var str))
|
||||
stdOut = str.Split("\n");
|
||||
else
|
||||
throw new ArgumentException("Missing RunProcessOut " + pattern);
|
||||
RunProcessWorkingDirectory.TryGetValue(pattern, out var wd);
|
||||
if (wd != workingDirectory)
|
||||
throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern);
|
||||
if (RunProcess.TryGetValue(pattern, out var ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing RunProcess " + pattern);
|
||||
}
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary<string, string> env)
|
||||
{
|
||||
var pattern = cmd + " " + args;
|
||||
RunProcessIn.Add(pattern);
|
||||
RunProcessWorkingDirectory.TryGetValue(pattern, out var wd);
|
||||
if (wd != workingDirectory)
|
||||
throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern);
|
||||
if (RunProcess.TryGetValue(pattern, out var ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing RunProcess " + pattern);
|
||||
}
|
||||
|
||||
public IList<string> DirectoryDeleteIn = new List<string>();
|
||||
|
||||
void IBuildActions.DirectoryDelete(string dir, bool recursive)
|
||||
{
|
||||
DirectoryDeleteIn.Add(dir);
|
||||
}
|
||||
|
||||
public IDictionary<string, bool> DirectoryExists = new Dictionary<string, bool>();
|
||||
public IList<string> DirectoryExistsIn = new List<string>();
|
||||
|
||||
bool IBuildActions.DirectoryExists(string dir)
|
||||
{
|
||||
DirectoryExistsIn.Add(dir);
|
||||
if (DirectoryExists.TryGetValue(dir, out var ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing DirectoryExists " + dir);
|
||||
}
|
||||
|
||||
public IDictionary<string, string> GetEnvironmentVariable = new Dictionary<string, string>();
|
||||
|
||||
string IBuildActions.GetEnvironmentVariable(string name)
|
||||
{
|
||||
if (GetEnvironmentVariable.TryGetValue(name, out var ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing GetEnvironmentVariable " + name);
|
||||
}
|
||||
|
||||
public string GetCurrentDirectory;
|
||||
|
||||
string IBuildActions.GetCurrentDirectory()
|
||||
{
|
||||
return GetCurrentDirectory;
|
||||
}
|
||||
|
||||
public IDictionary<string, string> EnumerateFiles = new Dictionary<string, string>();
|
||||
|
||||
IEnumerable<string> IBuildActions.EnumerateFiles(string dir)
|
||||
{
|
||||
if (EnumerateFiles.TryGetValue(dir, out var str))
|
||||
return str.Split("\n");
|
||||
throw new ArgumentException("Missing EnumerateFiles " + dir);
|
||||
}
|
||||
|
||||
public IDictionary<string, string> EnumerateDirectories = new Dictionary<string, string>();
|
||||
|
||||
IEnumerable<string> IBuildActions.EnumerateDirectories(string dir)
|
||||
{
|
||||
if (EnumerateDirectories.TryGetValue(dir, out var str))
|
||||
return string.IsNullOrEmpty(str) ? Enumerable.Empty<string>() : str.Split("\n");
|
||||
throw new ArgumentException("Missing EnumerateDirectories " + dir);
|
||||
}
|
||||
|
||||
public bool IsWindows;
|
||||
|
||||
bool IBuildActions.IsWindows() => IsWindows;
|
||||
|
||||
string IBuildActions.PathCombine(params string[] parts)
|
||||
{
|
||||
return string.Join('\\', parts);
|
||||
}
|
||||
|
||||
void IBuildActions.WriteAllText(string filename, string contents)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A fake solution to build.
|
||||
/// </summary>
|
||||
class TestSolution : ISolution
|
||||
{
|
||||
public IEnumerable<Project> Projects => throw new NotImplementedException();
|
||||
|
||||
public IEnumerable<SolutionConfigurationInSolution> Configurations => throw new NotImplementedException();
|
||||
|
||||
public string DefaultConfigurationName => "Release";
|
||||
|
||||
public string DefaultPlatformName => "x86";
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public int ProjectCount => throw new NotImplementedException();
|
||||
|
||||
public Version ToolsVersion => new Version("14.0");
|
||||
|
||||
public TestSolution(string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
}
|
||||
|
||||
public class BuildScriptTests
|
||||
{
|
||||
TestActions Actions = new TestActions();
|
||||
|
||||
// Records the arguments passed to StartCallback.
|
||||
IList<string> StartCallbackIn = new List<string>();
|
||||
|
||||
void StartCallback(string s)
|
||||
{
|
||||
StartCallbackIn.Add(s);
|
||||
}
|
||||
|
||||
// Records the arguments passed to EndCallback
|
||||
IList<string> EndCallbackIn = new List<string>();
|
||||
IList<int> EndCallbackReturn = new List<int>();
|
||||
|
||||
void EndCallback(int ret, string s)
|
||||
{
|
||||
EndCallbackReturn.Add(ret);
|
||||
EndCallbackIn.Add(s);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestBuildCommand()
|
||||
{
|
||||
var cmd = BuildScript.Create("abc", "def ghi", null, null);
|
||||
|
||||
Actions.RunProcess["abc def ghi"] = 1;
|
||||
cmd.Run(Actions, StartCallback, EndCallback);
|
||||
Assert.Equal("abc def ghi", Actions.RunProcessIn[0]);
|
||||
Assert.Equal("abc def ghi", StartCallbackIn[0]);
|
||||
Assert.Equal("", EndCallbackIn[0]);
|
||||
Assert.Equal(1, EndCallbackReturn[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestAnd1()
|
||||
{
|
||||
var cmd = BuildScript.Create("abc", "def ghi", null, null) & BuildScript.Create("odasa", null, null, null);
|
||||
|
||||
Actions.RunProcess["abc def ghi"] = 1;
|
||||
cmd.Run(Actions, StartCallback, EndCallback);
|
||||
|
||||
Assert.Equal("abc def ghi", Actions.RunProcessIn[0]);
|
||||
Assert.Equal("abc def ghi", StartCallbackIn[0]);
|
||||
Assert.Equal("", EndCallbackIn[0]);
|
||||
Assert.Equal(1, EndCallbackReturn[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestAnd2()
|
||||
{
|
||||
var cmd = BuildScript.Create("odasa", null, null, null) & BuildScript.Create("abc", "def ghi", null, null);
|
||||
|
||||
Actions.RunProcess["abc def ghi"] = 1;
|
||||
Actions.RunProcess["odasa "] = 0;
|
||||
cmd.Run(Actions, StartCallback, EndCallback);
|
||||
|
||||
Assert.Equal("odasa ", Actions.RunProcessIn[0]);
|
||||
Assert.Equal("odasa ", StartCallbackIn[0]);
|
||||
Assert.Equal("", EndCallbackIn[0]);
|
||||
Assert.Equal(0, EndCallbackReturn[0]);
|
||||
|
||||
Assert.Equal("abc def ghi", Actions.RunProcessIn[1]);
|
||||
Assert.Equal("abc def ghi", StartCallbackIn[1]);
|
||||
Assert.Equal("", EndCallbackIn[1]);
|
||||
Assert.Equal(1, EndCallbackReturn[1]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestOr1()
|
||||
{
|
||||
var cmd = BuildScript.Create("odasa", null, null, null) | BuildScript.Create("abc", "def ghi", null, null);
|
||||
|
||||
Actions.RunProcess["abc def ghi"] = 1;
|
||||
Actions.RunProcess["odasa "] = 0;
|
||||
cmd.Run(Actions, StartCallback, EndCallback);
|
||||
|
||||
Assert.Equal("odasa ", Actions.RunProcessIn[0]);
|
||||
Assert.Equal("odasa ", StartCallbackIn[0]);
|
||||
Assert.Equal("", EndCallbackIn[0]);
|
||||
Assert.Equal(0, EndCallbackReturn[0]);
|
||||
Assert.Equal(1, EndCallbackReturn.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestOr2()
|
||||
{
|
||||
var cmd = BuildScript.Create("abc", "def ghi", null, null) | BuildScript.Create("odasa", null, null, null);
|
||||
|
||||
Actions.RunProcess["abc def ghi"] = 1;
|
||||
Actions.RunProcess["odasa "] = 0;
|
||||
cmd.Run(Actions, StartCallback, EndCallback);
|
||||
|
||||
Assert.Equal("abc def ghi", Actions.RunProcessIn[0]);
|
||||
Assert.Equal("abc def ghi", StartCallbackIn[0]);
|
||||
Assert.Equal("", EndCallbackIn[0]);
|
||||
Assert.Equal(1, EndCallbackReturn[0]);
|
||||
|
||||
Assert.Equal("odasa ", Actions.RunProcessIn[1]);
|
||||
Assert.Equal("odasa ", StartCallbackIn[1]);
|
||||
Assert.Equal("", EndCallbackIn[1]);
|
||||
Assert.Equal(0, EndCallbackReturn[1]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestSuccess()
|
||||
{
|
||||
Assert.Equal(0, BuildScript.Success.Run(Actions, StartCallback, EndCallback));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestFailure()
|
||||
{
|
||||
Assert.NotEqual(0, BuildScript.Failure.Run(Actions, StartCallback, EndCallback));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDeleteDirectorySuccess()
|
||||
{
|
||||
Actions.DirectoryExists["trap"] = true;
|
||||
Assert.Equal(0, BuildScript.DeleteDirectory("trap").Run(Actions, StartCallback, EndCallback));
|
||||
Assert.Equal("trap", Actions.DirectoryDeleteIn[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDeleteDirectoryFailure()
|
||||
{
|
||||
Actions.DirectoryExists["trap"] = false;
|
||||
Assert.NotEqual(0, BuildScript.DeleteDirectory("trap").Run(Actions, StartCallback, EndCallback));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDeleteFileSuccess()
|
||||
{
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Assert.Equal(0, BuildScript.DeleteFile("csharp.log").Run(Actions, StartCallback, EndCallback));
|
||||
Assert.Equal("csharp.log", Actions.FileExistsIn[0]);
|
||||
Assert.Equal("csharp.log", Actions.FileDeleteIn[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDeleteFileFailure()
|
||||
{
|
||||
Actions.FileExists["csharp.log"] = false;
|
||||
Assert.NotEqual(0, BuildScript.DeleteFile("csharp.log").Run(Actions, StartCallback, EndCallback));
|
||||
Assert.Equal("csharp.log", Actions.FileExistsIn[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestTry()
|
||||
{
|
||||
Assert.Equal(0, BuildScript.Try(BuildScript.Failure).Run(Actions, StartCallback, EndCallback));
|
||||
}
|
||||
|
||||
Autobuilder CreateAutoBuilder(string lgtmLanguage, bool isWindows,
|
||||
string buildless=null, string solution=null, string buildCommand=null, string ignoreErrors=null,
|
||||
string msBuildArguments=null, string msBuildPlatform=null, string msBuildConfiguration=null, string msBuildTarget=null,
|
||||
string dotnetArguments=null, string dotnetVersion=null, string vsToolsVersion=null,
|
||||
string nugetRestore=null, string allSolutions=null,
|
||||
string cwd=@"C:\Project")
|
||||
{
|
||||
Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";
|
||||
Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java";
|
||||
Actions.GetEnvironmentVariable["LGTM_PROJECT_LANGUAGE"] = lgtmLanguage;
|
||||
Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools";
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_PLATFORM"] = msBuildPlatform;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_CONFIGURATION"] = msBuildConfiguration;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_TARGET"] = msBuildTarget;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_ARGUMENTS"] = dotnetArguments;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_VERSION"] = dotnetVersion;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_BUILD_COMMAND"] = buildCommand;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_SOLUTION"] = solution;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_IGNORE_ERRORS"] = ignoreErrors;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_BUILDLESS"] = buildless;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_ALL_SOLUTIONS"] = allSolutions;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_NUGET_RESTORE"] = nugetRestore;
|
||||
Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = isWindows ? @"C:\Program Files (x86)" : null;
|
||||
Actions.GetCurrentDirectory = cwd;
|
||||
Actions.IsWindows = isWindows;
|
||||
|
||||
var options = new AutobuildOptions();
|
||||
options.ReadEnvironment(Actions);
|
||||
return new Autobuilder(Actions, options);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDefaultCSharpAutoBuilder()
|
||||
{
|
||||
Actions.RunProcess["cmd.exe /C dotnet --info"] = 0;
|
||||
Actions.RunProcess["cmd.exe /C dotnet clean"] = 0;
|
||||
Actions.RunProcess["cmd.exe /C dotnet restore"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true);
|
||||
TestAutobuilderScript(autobuilder, 0, 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLinuxCSharpAutoBuilder()
|
||||
{
|
||||
Actions.RunProcess["dotnet --info"] = 0;
|
||||
Actions.RunProcess["dotnet clean"] = 0;
|
||||
Actions.RunProcess["dotnet restore"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 0, 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLinuxCSharpAutoBuilderExtractorFailed()
|
||||
{
|
||||
Actions.RunProcess["dotnet --info"] = 0;
|
||||
Actions.RunProcess["dotnet clean"] = 0;
|
||||
Actions.RunProcess["dotnet restore"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false"] = 0;
|
||||
Actions.FileExists["csharp.log"] = false;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 1, 4);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void TestDefaultCppAutobuilder()
|
||||
{
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("cpp", true);
|
||||
var script = autobuilder.GetBuildScript();
|
||||
|
||||
// Fails due to no solutions present.
|
||||
Assert.NotEqual(0, script.Run(Actions, StartCallback, EndCallback));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestCppAutobuilderSuccess()
|
||||
{
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1;
|
||||
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0;
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0;
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "";
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("cpp", true);
|
||||
var solution = new TestSolution(@"C:\Project\test.sln");
|
||||
autobuilder.SolutionsToBuild.Add(solution);
|
||||
TestAutobuilderScript(autobuilder, 0, 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestVsWhereSucceeded()
|
||||
{
|
||||
Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)";
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true;
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 0;
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "C:\\VS1\nC:\\VS2";
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "10.0\n11.0";
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0;
|
||||
|
||||
var candidates = BuildTools.GetCandidateVcVarsFiles(Actions).ToArray();
|
||||
Assert.Equal("C:\\VS1\\VC\\vcvarsall.bat", candidates[0].Path);
|
||||
Assert.Equal(10, candidates[0].ToolsVersion);
|
||||
Assert.Equal("C:\\VS2\\VC\\vcvarsall.bat", candidates[1].Path);
|
||||
Assert.Equal(11, candidates[1].ToolsVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestVsWhereNotExist()
|
||||
{
|
||||
Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)";
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false;
|
||||
|
||||
var candidates = BuildTools.GetCandidateVcVarsFiles(Actions).ToArray();
|
||||
Assert.Equal(4, candidates.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestVcVarsAllBatFiles()
|
||||
{
|
||||
Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)";
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = false;
|
||||
|
||||
var vcvarsfiles = BuildTools.VcVarsAllBatFiles(Actions).ToArray();
|
||||
Assert.Equal(2, vcvarsfiles.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLinuxBuildlessExtractionSuccess()
|
||||
{
|
||||
Actions.RunProcess[@"C:\odasa\tools\csharp\Semmle.Extraction.CSharp.Standalone --references:."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildless:"true");
|
||||
TestAutobuilderScript(autobuilder, 0, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLinuxBuildlessExtractionFailed()
|
||||
{
|
||||
Actions.RunProcess[@"C:\odasa\tools\csharp\Semmle.Extraction.CSharp.Standalone --references:."] = 10;
|
||||
Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true");
|
||||
TestAutobuilderScript(autobuilder, 10, 1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLinuxBuildlessExtractionSolution()
|
||||
{
|
||||
Actions.RunProcess[@"C:\odasa\tools\csharp\Semmle.Extraction.CSharp.Standalone foo.sln --references:."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln");
|
||||
TestAutobuilderScript(autobuilder, 0, 3);
|
||||
}
|
||||
|
||||
void SkipVsWhere()
|
||||
{
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = false;
|
||||
}
|
||||
|
||||
void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun)
|
||||
{
|
||||
Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(Actions, StartCallback, EndCallback));
|
||||
|
||||
// Check expected commands actually ran
|
||||
Assert.Equal(commandsRun, StartCallbackIn.Count);
|
||||
Assert.Equal(commandsRun, EndCallbackIn.Count);
|
||||
Assert.Equal(commandsRun, EndCallbackReturn.Count);
|
||||
|
||||
var action = Actions.RunProcess.GetEnumerator();
|
||||
for(int cmd=0; cmd<commandsRun; ++cmd)
|
||||
{
|
||||
Assert.True(action.MoveNext());
|
||||
|
||||
Assert.Equal(action.Current.Key, StartCallbackIn[cmd]);
|
||||
Assert.Equal(action.Current.Value, EndCallbackReturn[cmd]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLinuxBuildCommand()
|
||||
{
|
||||
Actions.RunProcess["C:\\odasa\\tools\\odasa index --auto \"./build.sh --skip-tests\""] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
SkipVsWhere();
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildCommand:"./build.sh --skip-tests");
|
||||
TestAutobuilderScript(autobuilder, 0, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLinuxBuildSh()
|
||||
{
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild/build.sh";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.RunProcess["dotnet --info"] = 1;
|
||||
Actions.RunProcess["/bin/chmod u+x build/build.sh"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto build/build.sh"] = 0;
|
||||
Actions.RunProcessWorkingDirectory[@"C:\odasa\tools\odasa index --auto build/build.sh"] = "build";
|
||||
Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 0, 5);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLinuxBuildShCSharpLogMissing()
|
||||
{
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.sh";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
|
||||
Actions.RunProcess["dotnet --info"] = 1;
|
||||
Actions.RunProcess["/bin/chmod u+x build.sh"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto build.sh"] = 0;
|
||||
Actions.RunProcessWorkingDirectory[@"C:\odasa\tools\odasa index --auto build.sh"] = "";
|
||||
Actions.FileExists["csharp.log"] = false;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 1, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLinuxBuildShFailed()
|
||||
{
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.sh";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
|
||||
Actions.RunProcess["dotnet --info"] = 1;
|
||||
Actions.RunProcess["/bin/chmod u+x build.sh"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto build.sh"] = 5;
|
||||
Actions.RunProcessWorkingDirectory[@"C:\odasa\tools\odasa index --auto build.sh"] = "";
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 1, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestWindowsBuildBat()
|
||||
{
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.bat";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.RunProcess["cmd.exe /C dotnet --info"] = 1;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto build.bat"] = 0;
|
||||
Actions.RunProcessWorkingDirectory[@"cmd.exe /C C:\odasa\tools\odasa index --auto build.bat"] = "";
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true);
|
||||
TestAutobuilderScript(autobuilder, 0, 4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestWindowsBuildBatIgnoreErrors()
|
||||
{
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbuild.bat";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.RunProcess["cmd.exe /C dotnet --info"] = 1;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto build.bat"] = 1;
|
||||
Actions.RunProcessWorkingDirectory[@"cmd.exe /C C:\odasa\tools\odasa index --auto build.bat"] = "";
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true, ignoreErrors:"true");
|
||||
TestAutobuilderScript(autobuilder, 1, 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestWindowsCmdIgnoreErrors()
|
||||
{
|
||||
Actions.RunProcess["cmd.exe /C C:\\odasa\\tools\\odasa index --auto ^\"build.cmd --skip-tests^\""] = 3;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
SkipVsWhere();
|
||||
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true, buildCommand: "build.cmd --skip-tests", ignoreErrors: "true");
|
||||
TestAutobuilderScript(autobuilder, 3, 1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestWindowCSharpMsBuild()
|
||||
{
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test1.sln"] = 0;
|
||||
Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test2.sln"] = 0;
|
||||
Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true;
|
||||
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments:"/P:Fu=Bar", msBuildTarget:"Windows", msBuildPlatform:"x86", msBuildConfiguration:"Debug",
|
||||
vsToolsVersion:"12", allSolutions:"true");
|
||||
var testSolution1 = new TestSolution(@"C:\Project\test1.sln");
|
||||
var testSolution2 = new TestSolution(@"C:\Project\test2.sln");
|
||||
autobuilder.SolutionsToBuild.Add(testSolution1);
|
||||
autobuilder.SolutionsToBuild.Add(testSolution2);
|
||||
|
||||
TestAutobuilderScript(autobuilder, 0, 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestWindowCSharpMsBuildFailed()
|
||||
{
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test1.sln"] = 0;
|
||||
Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 1;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug",
|
||||
vsToolsVersion: "12", allSolutions: "true");
|
||||
var testSolution1 = new TestSolution(@"C:\Project\test1.sln");
|
||||
var testSolution2 = new TestSolution(@"C:\Project\test2.sln");
|
||||
autobuilder.SolutionsToBuild.Add(testSolution1);
|
||||
autobuilder.SolutionsToBuild.Add(testSolution2);
|
||||
|
||||
TestAutobuilderScript(autobuilder, 1, 2);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void TestSkipNugetMsBuild()
|
||||
{
|
||||
Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows",
|
||||
msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12",
|
||||
allSolutions: "true", nugetRestore:"false");
|
||||
var testSolution1 = new TestSolution(@"C:\Project\test1.sln");
|
||||
var testSolution2 = new TestSolution(@"C:\Project\test2.sln");
|
||||
autobuilder.SolutionsToBuild.Add(testSolution1);
|
||||
autobuilder.SolutionsToBuild.Add(testSolution2);
|
||||
|
||||
TestAutobuilderScript(autobuilder, 0, 4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestSkipNugetBuildless()
|
||||
{
|
||||
Actions.RunProcess[@"C:\odasa\tools\csharp\Semmle.Extraction.CSharp.Standalone foo.sln --references:. --skip-nuget"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln", nugetRestore:"false");
|
||||
TestAutobuilderScript(autobuilder, 0, 3);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void TestSkipNugetDotnet()
|
||||
{
|
||||
Actions.RunProcess["dotnet --info"] = 0;
|
||||
Actions.RunProcess["dotnet clean"] = 0;
|
||||
Actions.RunProcess["dotnet restore"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false --no-restore"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, dotnetArguments:"--no-restore"); // nugetRestore=false does not work for now.
|
||||
TestAutobuilderScript(autobuilder, 0, 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDotnetVersionNotInstalled()
|
||||
{
|
||||
Actions.RunProcess["dotnet --list-sdks"] = 0;
|
||||
Actions.RunProcessOut["dotnet --list-sdks"] = "2.1.2 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]";
|
||||
Actions.RunProcess[@"curl -sO https://dot.net/v1/dotnet-install.sh"] = 0;
|
||||
Actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0;
|
||||
Actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir C:\Project\.dotnet"] = 0;
|
||||
Actions.RunProcess[@"C:\Project\.dotnet\dotnet --info"] = 0;
|
||||
Actions.RunProcess[@"C:\Project\.dotnet\dotnet clean"] = 0;
|
||||
Actions.RunProcess[@"C:\Project\.dotnet\dotnet restore"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto C:\Project\.dotnet\dotnet build --no-incremental /p:UseSharedCompilation=false"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.GetEnvironmentVariable["PATH"] = "/bin:/usr/bin";
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion:"2.1.3");
|
||||
TestAutobuilderScript(autobuilder, 0, 10);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDotnetVersionAlreadyInstalled()
|
||||
{
|
||||
Actions.RunProcess["dotnet --list-sdks"] = 0;
|
||||
Actions.RunProcessOut["dotnet --list-sdks"] = "2.1.3 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]";
|
||||
Actions.RunProcess[@"curl -sO https://dot.net/v1/dotnet-install.sh"] = 0;
|
||||
Actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0;
|
||||
Actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir C:\Project\.dotnet"] = 0;
|
||||
Actions.RunProcess[@"C:\Project\.dotnet\dotnet --info"] = 0;
|
||||
Actions.RunProcess[@"C:\Project\.dotnet\dotnet clean"] = 0;
|
||||
Actions.RunProcess[@"C:\Project\.dotnet\dotnet restore"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto C:\Project\.dotnet\dotnet build --no-incremental /p:UseSharedCompilation=false"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.GetEnvironmentVariable["PATH"] = "/bin:/usr/bin";
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3");
|
||||
TestAutobuilderScript(autobuilder, 0, 10);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDotnetVersionWindows()
|
||||
{
|
||||
Actions.RunProcess["cmd.exe /C dotnet --list-sdks"] = 0;
|
||||
Actions.RunProcessOut["cmd.exe /C dotnet --list-sdks"] = "2.1.3 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]";
|
||||
Actions.RunProcess[@"cmd.exe /C powershell -NoProfile -ExecutionPolicy unrestricted -file C:\Project\install-dotnet.ps1 -Version 2.1.3 -InstallDir C:\Project\.dotnet"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet --info"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet clean"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet restore"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\.dotnet\dotnet build --no-incremental /p:UseSharedCompilation=false"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0;
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.GetEnvironmentVariable["PATH"] = "/bin:/usr/bin";
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true, dotnetVersion: "2.1.3");
|
||||
TestAutobuilderScript(autobuilder, 0, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Semmle.Autobuild.Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Semmle.Extraction.Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Autobuild\Semmle.Autobuild.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
20
csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs
Normal file
20
csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// ASP extraction.
|
||||
/// </summary>
|
||||
class AspBuildRule : IBuildRule
|
||||
{
|
||||
public BuildScript Analyse(Autobuilder builder)
|
||||
{
|
||||
var command = new CommandBuilder(builder.Actions).
|
||||
RunCommand(builder.Actions.PathCombine(builder.SemmleJavaHome, "bin", "java")).
|
||||
Argument("-jar").
|
||||
QuoteArgument(builder.Actions.PathCombine(builder.SemmleDist, "tools", "extractor-asp.jar")).
|
||||
Argument(".");
|
||||
return command.Script;
|
||||
}
|
||||
}
|
||||
}
|
||||
103
csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs
Normal file
103
csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Encapsulates build options.
|
||||
/// </summary>
|
||||
public class AutobuildOptions
|
||||
{
|
||||
public readonly int SearchDepth = 3;
|
||||
public string RootDirectory = null;
|
||||
static readonly string prefix = "LGTM_INDEX_";
|
||||
|
||||
public string VsToolsVersion;
|
||||
public string MsBuildArguments;
|
||||
public string MsBuildPlatform;
|
||||
public string MsBuildConfiguration;
|
||||
public string MsBuildTarget;
|
||||
public string DotNetArguments;
|
||||
public string DotNetVersion;
|
||||
public string BuildCommand;
|
||||
public string[] Solution;
|
||||
|
||||
public bool IgnoreErrors;
|
||||
public bool Buildless;
|
||||
public bool AllSolutions;
|
||||
public bool NugetRestore;
|
||||
|
||||
public Language Language;
|
||||
|
||||
/// <summary>
|
||||
/// Reads options from environment variables.
|
||||
/// Throws ArgumentOutOfRangeException for invalid arguments.
|
||||
/// </summary>
|
||||
public void ReadEnvironment(IBuildActions actions)
|
||||
{
|
||||
RootDirectory = actions.GetCurrentDirectory();
|
||||
VsToolsVersion = actions.GetEnvironmentVariable(prefix + "VSTOOLS_VERSION");
|
||||
MsBuildArguments = actions.GetEnvironmentVariable(prefix + "MSBUILD_ARGUMENTS");
|
||||
MsBuildPlatform = actions.GetEnvironmentVariable(prefix + "MSBUILD_PLATFORM");
|
||||
MsBuildConfiguration = actions.GetEnvironmentVariable(prefix + "MSBUILD_CONFIGURATION");
|
||||
MsBuildTarget = actions.GetEnvironmentVariable(prefix + "MSBUILD_TARGET");
|
||||
DotNetArguments = actions.GetEnvironmentVariable(prefix + "DOTNET_ARGUMENTS");
|
||||
DotNetVersion = actions.GetEnvironmentVariable(prefix + "DOTNET_VERSION");
|
||||
BuildCommand = actions.GetEnvironmentVariable(prefix + "BUILD_COMMAND");
|
||||
Solution = actions.GetEnvironmentVariable(prefix + "SOLUTION").AsList(new string[0]);
|
||||
|
||||
IgnoreErrors = actions.GetEnvironmentVariable(prefix + "IGNORE_ERRORS").AsBool("ignore_errors", false);
|
||||
Buildless = actions.GetEnvironmentVariable(prefix + "BUILDLESS").AsBool("buildless", false);
|
||||
AllSolutions = actions.GetEnvironmentVariable(prefix + "ALL_SOLUTIONS").AsBool("all_solutions", false);
|
||||
NugetRestore = actions.GetEnvironmentVariable(prefix + "NUGET_RESTORE").AsBool("nuget_restore", true);
|
||||
|
||||
Language = actions.GetEnvironmentVariable("LGTM_PROJECT_LANGUAGE").AsLanguage();
|
||||
}
|
||||
}
|
||||
|
||||
public static class OptionsExtensions
|
||||
{
|
||||
public static bool AsBool(this string value, string param, bool defaultValue)
|
||||
{
|
||||
if (value == null) return defaultValue;
|
||||
switch (value.ToLower())
|
||||
{
|
||||
case "on":
|
||||
case "yes":
|
||||
case "true":
|
||||
case "enabled":
|
||||
return true;
|
||||
case "off":
|
||||
case "no":
|
||||
case "false":
|
||||
case "disabled":
|
||||
return false;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(param, value, "The Boolean value is invalid.");
|
||||
}
|
||||
}
|
||||
|
||||
public static Language AsLanguage(this string key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case null:
|
||||
throw new ArgumentException("Environment variable required: LGTM_PROJECT_LANGUAGE");
|
||||
case "csharp":
|
||||
return Language.CSharp;
|
||||
case "cpp":
|
||||
return Language.Cpp;
|
||||
default:
|
||||
throw new ArgumentException("Language key not understood: '" + key + "'");
|
||||
}
|
||||
}
|
||||
|
||||
public static string[] AsList(this string value, string[] defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
return defaultValue;
|
||||
|
||||
return value.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
352
csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs
Normal file
352
csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs
Normal file
@@ -0,0 +1,352 @@
|
||||
using Semmle.Extraction.CSharp;
|
||||
using Semmle.Util.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// A build rule analyses the files in "builder" and outputs a build script.
|
||||
/// </summary>
|
||||
interface IBuildRule
|
||||
{
|
||||
/// <summary>
|
||||
/// Analyse the files and produce a build script.
|
||||
/// </summary>
|
||||
/// <param name="builder">The files and options relating to the build.</param>
|
||||
BuildScript Analyse(Autobuilder builder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main application logic, containing all data
|
||||
/// gathered from the project and filesystem.
|
||||
///
|
||||
/// The overall design is intended to be extensible so that in theory,
|
||||
/// it should be possible to add new build rules without touching this code.
|
||||
/// </summary>
|
||||
public class Autobuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Full file paths of files found in the project directory.
|
||||
/// </summary>
|
||||
public IEnumerable<string> Paths => pathsLazy.Value;
|
||||
readonly Lazy<IEnumerable<string>> pathsLazy;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of paths matching a set of extensions
|
||||
/// (including the ".").
|
||||
/// </summary>
|
||||
/// <param name="extensions">The extensions to find.</param>
|
||||
/// <returns>The files matching the extension.</returns>
|
||||
public IEnumerable<string> GetExtensions(params string[] extensions) =>
|
||||
Paths.Where(p => extensions.Contains(Path.GetExtension(p)));
|
||||
|
||||
/// <summary>
|
||||
/// Gets all paths matching a particular filename.
|
||||
/// </summary>
|
||||
/// <param name="name">The filename to find.</param>
|
||||
/// <returns>Possibly empty sequence of paths with the given filename.</returns>
|
||||
public IEnumerable<string> GetFilename(string name) => Paths.Where(p => Path.GetFileName(p) == name);
|
||||
|
||||
/// <summary>
|
||||
/// Holds if a given path, relative to the root of the source directory
|
||||
/// was found.
|
||||
/// </summary>
|
||||
/// <param name="path">The relative path.</param>
|
||||
/// <returns>True iff the path was found.</returns>
|
||||
public bool HasRelativePath(string path) => HasPath(Actions.PathCombine(RootDirectory, path));
|
||||
|
||||
/// <summary>
|
||||
/// List of solution files to build.
|
||||
/// </summary>
|
||||
public IList<ISolution> SolutionsToBuild => solutionsToBuildLazy.Value;
|
||||
readonly Lazy<IList<ISolution>> solutionsToBuildLazy;
|
||||
|
||||
/// <summary>
|
||||
/// Holds if a given path was found.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the file.</param>
|
||||
/// <returns>True iff the path was found.</returns>
|
||||
public bool HasPath(string path) => Paths.Any(p => path == p);
|
||||
|
||||
void FindFiles(string dir, int depth, IList<string> results)
|
||||
{
|
||||
foreach (var f in Actions.EnumerateFiles(dir))
|
||||
{
|
||||
results.Add(f);
|
||||
}
|
||||
|
||||
if (depth > 1)
|
||||
{
|
||||
foreach (var d in Actions.EnumerateDirectories(dir))
|
||||
{
|
||||
FindFiles(d, depth - 1, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The root of the source directory.
|
||||
/// </summary>
|
||||
string RootDirectory => Options.RootDirectory;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the supplied build configuration.
|
||||
/// </summary>
|
||||
public AutobuildOptions Options { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of build actions used during the autobuilder.
|
||||
/// Could be real system operations, or a stub for testing.
|
||||
/// </summary>
|
||||
public IBuildActions Actions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Find all the relevant files and picks the best
|
||||
/// solution file and tools.
|
||||
/// </summary>
|
||||
/// <param name="options">The command line options.</param>
|
||||
public Autobuilder(IBuildActions actions, AutobuildOptions options)
|
||||
{
|
||||
Actions = actions;
|
||||
Options = options;
|
||||
|
||||
pathsLazy = new Lazy<IEnumerable<string>>(() =>
|
||||
{
|
||||
var files = new List<string>();
|
||||
FindFiles(options.RootDirectory, options.SearchDepth, files);
|
||||
return files.
|
||||
OrderBy(s => s.Count(c => c == Path.DirectorySeparatorChar)).
|
||||
ThenBy(s => Path.GetFileName(s).Length).
|
||||
ToArray();
|
||||
});
|
||||
|
||||
solutionsToBuildLazy = new Lazy<IList<ISolution>>(() =>
|
||||
{
|
||||
if (options.Solution.Any())
|
||||
{
|
||||
var ret = new List<ISolution>();
|
||||
foreach (var solution in options.Solution)
|
||||
{
|
||||
if (actions.FileExists(solution))
|
||||
ret.Add(new Solution(this, solution));
|
||||
else
|
||||
Log(Severity.Error, "The specified solution file {0} was not found", solution);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
var solutions = GetExtensions(".sln").
|
||||
Select(s => new Solution(this, s)).
|
||||
Where(s => s.ProjectCount > 0).
|
||||
OrderByDescending(s => s.ProjectCount).
|
||||
ThenBy(s => s.Path.Length).
|
||||
ToArray();
|
||||
|
||||
foreach (var sln in solutions)
|
||||
{
|
||||
Log(Severity.Info, $"Found {sln.Path} with {sln.ProjectCount} {this.Options.Language} projects, version {sln.ToolsVersion}, config {string.Join(" ", sln.Configurations.Select(c => c.FullName))}");
|
||||
}
|
||||
|
||||
return new List<ISolution>(options.AllSolutions ?
|
||||
solutions :
|
||||
solutions.Take(1));
|
||||
});
|
||||
|
||||
SemmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST");
|
||||
|
||||
SemmleJavaHome = Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME");
|
||||
|
||||
SemmlePlatformTools = Actions.GetEnvironmentVariable("SEMMLE_PLATFORM_TOOLS");
|
||||
|
||||
if (SemmleDist == null)
|
||||
Log(Severity.Error, "The environment variable SEMMLE_DIST has not been set.");
|
||||
}
|
||||
|
||||
readonly ILogger logger = new ConsoleLogger(Verbosity.Info);
|
||||
|
||||
/// <summary>
|
||||
/// Log a given build event to the console.
|
||||
/// </summary>
|
||||
/// <param name="format">The format string.</param>
|
||||
/// <param name="args">Inserts to the format string.</param>
|
||||
public void Log(Severity severity, string format, params object[] args)
|
||||
{
|
||||
logger.Log(severity, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to build this project.
|
||||
/// </summary>
|
||||
/// <returns>The exit code, 0 for success and non-zero for failures.</returns>
|
||||
public int AttemptBuild()
|
||||
{
|
||||
Log(Severity.Info, $"Working directory: {Options.RootDirectory}");
|
||||
|
||||
var script = GetBuildScript();
|
||||
if (Options.IgnoreErrors)
|
||||
script |= BuildScript.Success;
|
||||
|
||||
void startCallback(string s) => Log(Severity.Info, $"\nRunning {s}");
|
||||
void exitCallback(int ret, string msg) => Log(Severity.Info, $"Exit code {ret}{(string.IsNullOrEmpty(msg) ? "" : $": {msg}")}");
|
||||
return script.Run(Actions, startCallback, exitCallback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the build script to use for this project.
|
||||
/// </summary>
|
||||
public BuildScript GetBuildScript()
|
||||
{
|
||||
var isCSharp = Options.Language == Language.CSharp;
|
||||
return isCSharp ? GetCSharpBuildScript() : GetCppBuildScript();
|
||||
}
|
||||
|
||||
BuildScript GetCSharpBuildScript()
|
||||
{
|
||||
/// <summary>
|
||||
/// A script that checks that the C# extractor has been executed.
|
||||
/// </summary>
|
||||
BuildScript CheckExtractorRun(bool warnOnFailure) =>
|
||||
BuildScript.Create(actions =>
|
||||
{
|
||||
if (actions.FileExists(Extractor.GetCSharpLogPath()))
|
||||
return 0;
|
||||
|
||||
if (warnOnFailure)
|
||||
Log(Severity.Error, "No C# code detected during build.");
|
||||
|
||||
return 1;
|
||||
});
|
||||
|
||||
var attempt = BuildScript.Failure;
|
||||
switch (GetCSharpBuildStrategy())
|
||||
{
|
||||
case CSharpBuildStrategy.CustomBuildCommand:
|
||||
attempt = new BuildCommandRule().Analyse(this) & CheckExtractorRun(true);
|
||||
break;
|
||||
case CSharpBuildStrategy.Buildless:
|
||||
// No need to check that the extractor has been executed in buildless mode
|
||||
attempt = new StandaloneBuildRule().Analyse(this);
|
||||
break;
|
||||
case CSharpBuildStrategy.MSBuild:
|
||||
attempt = new MsBuildRule().Analyse(this) & CheckExtractorRun(true);
|
||||
break;
|
||||
case CSharpBuildStrategy.DotNet:
|
||||
attempt = new DotNetRule().Analyse(this) & CheckExtractorRun(true);
|
||||
break;
|
||||
case CSharpBuildStrategy.Auto:
|
||||
var cleanTrapFolder =
|
||||
BuildScript.DeleteDirectory(Actions.GetEnvironmentVariable("TRAP_FOLDER"));
|
||||
var cleanSourceArchive =
|
||||
BuildScript.DeleteDirectory(Actions.GetEnvironmentVariable("SOURCE_ARCHIVE"));
|
||||
var cleanExtractorLog =
|
||||
BuildScript.DeleteFile(Extractor.GetCSharpLogPath());
|
||||
var attemptExtractorCleanup =
|
||||
BuildScript.Try(cleanTrapFolder) &
|
||||
BuildScript.Try(cleanSourceArchive) &
|
||||
BuildScript.Try(cleanExtractorLog);
|
||||
|
||||
/// <summary>
|
||||
/// Execute script `s` and check that the C# extractor has been executed.
|
||||
/// If either fails, attempt to cleanup any artifacts produced by the extractor,
|
||||
/// and exit with code 1, in order to proceed to the next attempt.
|
||||
/// </summary>
|
||||
BuildScript IntermediateAttempt(BuildScript s) =>
|
||||
(s & CheckExtractorRun(false)) |
|
||||
(attemptExtractorCleanup & BuildScript.Failure);
|
||||
|
||||
attempt =
|
||||
// First try .NET Core
|
||||
IntermediateAttempt(new DotNetRule().Analyse(this)) |
|
||||
// Then MSBuild
|
||||
(() => IntermediateAttempt(new MsBuildRule().Analyse(this))) |
|
||||
// And finally look for a script that might be a build script
|
||||
(() => new BuildCommandAutoRule().Analyse(this) & CheckExtractorRun(true)) |
|
||||
// All attempts failed: print message
|
||||
AutobuildFailure();
|
||||
break;
|
||||
}
|
||||
|
||||
return
|
||||
attempt &
|
||||
(() => new AspBuildRule().Analyse(this)) &
|
||||
(() => new XmlBuildRule().Analyse(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the build strategy that the autobuilder should apply, based on the
|
||||
/// options in the `lgtm.yml` file.
|
||||
/// </summary>
|
||||
CSharpBuildStrategy GetCSharpBuildStrategy()
|
||||
{
|
||||
if (Options.BuildCommand != null)
|
||||
return CSharpBuildStrategy.CustomBuildCommand;
|
||||
|
||||
if (Options.Buildless)
|
||||
return CSharpBuildStrategy.Buildless;
|
||||
|
||||
if (Options.MsBuildArguments != null
|
||||
|| Options.MsBuildConfiguration != null
|
||||
|| Options.MsBuildPlatform != null
|
||||
|| Options.MsBuildTarget != null)
|
||||
return CSharpBuildStrategy.MSBuild;
|
||||
|
||||
if (Options.DotNetArguments != null || Options.DotNetVersion != null)
|
||||
return CSharpBuildStrategy.DotNet;
|
||||
|
||||
return CSharpBuildStrategy.Auto;
|
||||
}
|
||||
|
||||
enum CSharpBuildStrategy
|
||||
{
|
||||
CustomBuildCommand,
|
||||
Buildless,
|
||||
MSBuild,
|
||||
DotNet,
|
||||
Auto
|
||||
}
|
||||
|
||||
BuildScript GetCppBuildScript()
|
||||
{
|
||||
if (Options.BuildCommand != null)
|
||||
return new BuildCommandRule().Analyse(this);
|
||||
|
||||
return
|
||||
// First try MSBuild
|
||||
new MsBuildRule().Analyse(this) |
|
||||
// Then look for a script that might be a build script
|
||||
(() => new BuildCommandAutoRule().Analyse(this)) |
|
||||
// All attempts failed: print message
|
||||
AutobuildFailure();
|
||||
}
|
||||
|
||||
BuildScript AutobuildFailure() =>
|
||||
BuildScript.Create(actions =>
|
||||
{
|
||||
Log(Severity.Error, "Could not auto-detect a suitable build method");
|
||||
return 1;
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Value of SEMMLE_DIST environment variable.
|
||||
/// </summary>
|
||||
public string SemmleDist { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of SEMMLE_JAVA_HOME environment variable.
|
||||
/// </summary>
|
||||
public string SemmleJavaHome { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of SEMMLE_PLATFORM_TOOLS environment variable.
|
||||
/// </summary>
|
||||
public string SemmlePlatformTools { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The absolute path of the odasa executable.
|
||||
/// </summary>
|
||||
public string Odasa => SemmleDist == null ? null : Actions.PathCombine(SemmleDist, "tools", "odasa");
|
||||
}
|
||||
}
|
||||
176
csharp/autobuilder/Semmle.Autobuild/BuildActions.cs
Normal file
176
csharp/autobuilder/Semmle.Autobuild/BuildActions.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using Semmle.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper around system calls so that the build scripts can be unit-tested.
|
||||
/// </summary>
|
||||
public interface IBuildActions
|
||||
{
|
||||
/// <summary>
|
||||
/// Runs a process and captures its output.
|
||||
/// </summary>
|
||||
/// <param name="exe">The exe to run.</param>
|
||||
/// <param name="args">The other command line arguments.</param>
|
||||
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
|
||||
/// <param name="env">Additional environment variables.</param>
|
||||
/// <param name="stdOut">The lines of stdout.</param>
|
||||
/// <returns>The process exit code.</returns>
|
||||
int RunProcess(string exe, string args, string workingDirectory, IDictionary<string, string> env, out IList<string> stdOut);
|
||||
|
||||
/// <summary>
|
||||
/// Runs a process but does not capture its output.
|
||||
/// </summary>
|
||||
/// <param name="exe">The exe to run.</param>
|
||||
/// <param name="args">The other command line arguments.</param>
|
||||
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
|
||||
/// <param name="env">Additional environment variables.</param>
|
||||
/// <returns>The process exit code.</returns>
|
||||
int RunProcess(string exe, string args, string workingDirectory, IDictionary<string, string> env);
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether a file exists, File.Exists().
|
||||
/// </summary>
|
||||
/// <param name="file">The filename.</param>
|
||||
/// <returns>True iff the file exists.</returns>
|
||||
bool FileExists(string file);
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether a directory exists, Directory.Exists().
|
||||
/// </summary>
|
||||
/// <param name="dir">The directory name.</param>
|
||||
/// <returns>True iff the directory exists.</returns>
|
||||
bool DirectoryExists(string dir);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a file, File.Delete().
|
||||
/// </summary>
|
||||
/// <param name="file">The filename.</param>
|
||||
void FileDelete(string file);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a directory, Directory.Delete().
|
||||
/// </summary>
|
||||
void DirectoryDelete(string dir, bool recursive);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an environment variable, Environment.GetEnvironmentVariable().
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the variable.</param>
|
||||
/// <returns>The string value, or null if the variable is not defined.</returns>
|
||||
string GetEnvironmentVariable(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current directory, Directory.GetCurrentDirectory().
|
||||
/// </summary>
|
||||
/// <returns>The current directory.</returns>
|
||||
string GetCurrentDirectory();
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates files in a directory, Directory.EnumerateFiles().
|
||||
/// </summary>
|
||||
/// <param name="dir">The directory to enumerate.</param>
|
||||
/// <returns>A list of filenames, or an empty list.</returns>
|
||||
IEnumerable<string> EnumerateFiles(string dir);
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the directories in a directory, Directory.EnumerateDirectories().
|
||||
/// </summary>
|
||||
/// <param name="dir">The directory to enumerate.</param>
|
||||
/// <returns>List of subdirectories, or empty list.</returns>
|
||||
IEnumerable<string> EnumerateDirectories(string dir);
|
||||
|
||||
/// <summary>
|
||||
/// True if we are running on Windows.
|
||||
/// </summary>
|
||||
bool IsWindows();
|
||||
|
||||
/// <summary>
|
||||
/// Combine path segments, Path.Combine().
|
||||
/// </summary>
|
||||
/// <param name="parts">The parts of the path.</param>
|
||||
/// <returns>The combined path.</returns>
|
||||
string PathCombine(params string[] parts);
|
||||
|
||||
/// <summary>
|
||||
/// Writes contents to file, File.WriteAllText().
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
/// <param name="contents">The text.</param>
|
||||
void WriteAllText(string filename, string contents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An implementation of IBuildActions that actually performs the requested operations.
|
||||
/// </summary>
|
||||
class SystemBuildActions : IBuildActions
|
||||
{
|
||||
void IBuildActions.FileDelete(string file) => File.Delete(file);
|
||||
|
||||
bool IBuildActions.FileExists(string file) => File.Exists(file);
|
||||
|
||||
ProcessStartInfo GetProcessStartInfo(string exe, string arguments, string workingDirectory, IDictionary<string, string> environment, bool redirectStandardOutput)
|
||||
{
|
||||
var pi = new ProcessStartInfo(exe, arguments)
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = redirectStandardOutput
|
||||
};
|
||||
if (workingDirectory != null)
|
||||
pi.WorkingDirectory = workingDirectory;
|
||||
|
||||
// Environment variables can only be used when not redirecting stdout
|
||||
if (!redirectStandardOutput)
|
||||
{
|
||||
pi.Environment["UseSharedCompilation"] = "false";
|
||||
if (environment != null)
|
||||
environment.ForEach(kvp => pi.Environment[kvp.Key] = kvp.Value);
|
||||
}
|
||||
return pi;
|
||||
}
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary<string, string> environment)
|
||||
{
|
||||
var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, false);
|
||||
using (var p = Process.Start(pi))
|
||||
{
|
||||
p.WaitForExit();
|
||||
return p.ExitCode;
|
||||
}
|
||||
}
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary<string, string> environment, out IList<string> stdOut)
|
||||
{
|
||||
var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, true);
|
||||
return pi.ReadOutput(out stdOut);
|
||||
}
|
||||
|
||||
void IBuildActions.DirectoryDelete(string dir, bool recursive) => Directory.Delete(dir, recursive);
|
||||
|
||||
bool IBuildActions.DirectoryExists(string dir) => Directory.Exists(dir);
|
||||
|
||||
string IBuildActions.GetEnvironmentVariable(string name) => Environment.GetEnvironmentVariable(name);
|
||||
|
||||
string IBuildActions.GetCurrentDirectory() => Directory.GetCurrentDirectory();
|
||||
|
||||
IEnumerable<string> IBuildActions.EnumerateFiles(string dir) => Directory.EnumerateFiles(dir);
|
||||
|
||||
IEnumerable<string> IBuildActions.EnumerateDirectories(string dir) => Directory.EnumerateDirectories(dir);
|
||||
|
||||
bool IBuildActions.IsWindows() => Win32.IsWindows();
|
||||
|
||||
string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts);
|
||||
|
||||
void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents);
|
||||
|
||||
private SystemBuildActions()
|
||||
{
|
||||
}
|
||||
|
||||
public static readonly IBuildActions Instance = new SystemBuildActions();
|
||||
}
|
||||
}
|
||||
61
csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs
Normal file
61
csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Auto-detection of build scripts.
|
||||
/// </summary>
|
||||
class BuildCommandAutoRule : IBuildRule
|
||||
{
|
||||
readonly IEnumerable<string> winExtensions = new List<string> {
|
||||
".bat",
|
||||
".cmd",
|
||||
".exe"
|
||||
};
|
||||
|
||||
readonly IEnumerable<string> linuxExtensions = new List<string> {
|
||||
"",
|
||||
".sh"
|
||||
};
|
||||
|
||||
readonly IEnumerable<string> buildScripts = new List<string> {
|
||||
"build"
|
||||
};
|
||||
|
||||
public BuildScript Analyse(Autobuilder builder)
|
||||
{
|
||||
builder.Log(Severity.Info, "Attempting to locate build script");
|
||||
|
||||
var extensions = builder.Actions.IsWindows() ? winExtensions : linuxExtensions;
|
||||
var scripts = buildScripts.SelectMany(s => extensions.Select(e => s + e));
|
||||
var scriptPath = builder.Paths.Where(p => scripts.Any(p.ToLower().EndsWith)).OrderBy(p => p.Length).FirstOrDefault();
|
||||
|
||||
if (scriptPath == null)
|
||||
return BuildScript.Failure;
|
||||
|
||||
var chmod = new CommandBuilder(builder.Actions);
|
||||
chmod.RunCommand("/bin/chmod", $"u+x {scriptPath}");
|
||||
var chmodScript = builder.Actions.IsWindows() ? BuildScript.Success : BuildScript.Try(chmod.Script);
|
||||
|
||||
var path = Path.GetDirectoryName(scriptPath);
|
||||
|
||||
// A specific .NET Core version may be required
|
||||
return chmodScript & DotNetRule.WithDotNet(builder, dotNet =>
|
||||
{
|
||||
var command = new CommandBuilder(builder.Actions, path, dotNet?.Environment);
|
||||
|
||||
// A specific Visual Studio version may be required
|
||||
var vsTools = MsBuildRule.GetVcVarsBatFile(builder);
|
||||
if (vsTools != null)
|
||||
command.CallBatFile(vsTools.Path);
|
||||
|
||||
command.IndexCommand(builder.Odasa, scriptPath);
|
||||
return command.Script;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
28
csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs
Normal file
28
csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Execute the build_command rule.
|
||||
/// </summary>
|
||||
class BuildCommandRule : IBuildRule
|
||||
{
|
||||
public BuildScript Analyse(Autobuilder builder)
|
||||
{
|
||||
if (builder.Options.BuildCommand == null)
|
||||
return BuildScript.Failure;
|
||||
|
||||
// Custom build commands may require a specific .NET Core version
|
||||
return DotNetRule.WithDotNet(builder, dotNet =>
|
||||
{
|
||||
var command = new CommandBuilder(builder.Actions, null, dotNet?.Environment);
|
||||
|
||||
// Custom build commands may require a specific Visual Studio version
|
||||
var vsTools = MsBuildRule.GetVcVarsBatFile(builder);
|
||||
if (vsTools != null)
|
||||
command.CallBatFile(vsTools.Path);
|
||||
command.IndexCommand(builder.Odasa, builder.Options.BuildCommand);
|
||||
|
||||
return command.Script;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
274
csharp/autobuilder/Semmle.Autobuild/BuildScript.cs
Normal file
274
csharp/autobuilder/Semmle.Autobuild/BuildScript.cs
Normal file
@@ -0,0 +1,274 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// A build script.
|
||||
/// </summary>
|
||||
public abstract class BuildScript
|
||||
{
|
||||
/// <summary>
|
||||
/// Run this build script.
|
||||
/// </summary>
|
||||
/// <param name="actions">
|
||||
/// The interface used to implement the build actions.
|
||||
/// </param>
|
||||
/// <param name="startCallback">
|
||||
/// A call back that is called every time a new process is started. The
|
||||
/// argument to the call back is a textual representation of the process.
|
||||
/// </param>
|
||||
/// <param name="exitCallBack">
|
||||
/// A call back that is called every time a new process exits. The first
|
||||
/// argument to the call back is the exit code, and the second argument is
|
||||
/// an exit message.
|
||||
/// </param>
|
||||
/// <returns>The exit code from this build script.</returns>
|
||||
public abstract int Run(IBuildActions actions, Action<string> startCallback, Action<int, string> exitCallBack);
|
||||
|
||||
/// <summary>
|
||||
/// Run this build command.
|
||||
/// </summary>
|
||||
/// <param name="actions">
|
||||
/// The interface used to implement the build actions.
|
||||
/// </param>
|
||||
/// <param name="startCallback">
|
||||
/// A call back that is called every time a new process is started. The
|
||||
/// argument to the call back is a textual representation of the process.
|
||||
/// </param>
|
||||
/// <param name="exitCallBack">
|
||||
/// A call back that is called every time a new process exits. The first
|
||||
/// argument to the call back is the exit code, and the second argument is
|
||||
/// an exit message.
|
||||
/// </param>
|
||||
/// <param name="stdout">Contents of standard out.</param>
|
||||
/// <returns>The exit code from this build script.</returns>
|
||||
public abstract int Run(IBuildActions actions, Action<string> startCallback, Action<int, string> exitCallBack, out IList<string> stdout);
|
||||
|
||||
class BuildCommand : BuildScript
|
||||
{
|
||||
readonly string exe, arguments, workingDirectory;
|
||||
readonly IDictionary<string, string> environment;
|
||||
|
||||
/// <summary>
|
||||
/// Create a simple build command.
|
||||
/// </summary>
|
||||
/// <param name="exe">The executable to run.</param>
|
||||
/// <param name="argumentsOpt">The arguments to the executable, or null.</param>
|
||||
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
|
||||
/// <param name="environment">Additional environment variables.</param>
|
||||
public BuildCommand(string exe, string argumentsOpt, string workingDirectory = null, IDictionary<string, string> environment = null)
|
||||
{
|
||||
this.exe = exe;
|
||||
this.arguments = argumentsOpt ?? "";
|
||||
this.workingDirectory = workingDirectory;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
public override string ToString() => exe + " " + arguments;
|
||||
|
||||
public override int Run(IBuildActions actions, Action<string> startCallback, Action<int, string> exitCallBack)
|
||||
{
|
||||
startCallback(this.ToString());
|
||||
var ret = 1;
|
||||
var retMessage = "";
|
||||
try
|
||||
{
|
||||
ret = actions.RunProcess(exe, arguments, workingDirectory, environment);
|
||||
}
|
||||
catch (Exception ex)
|
||||
when (ex is System.ComponentModel.Win32Exception || ex is FileNotFoundException)
|
||||
{
|
||||
retMessage = ex.Message;
|
||||
}
|
||||
|
||||
exitCallBack(ret, retMessage);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override int Run(IBuildActions actions, Action<string> startCallback, Action<int, string> exitCallBack, out IList<string> stdout)
|
||||
{
|
||||
startCallback(this.ToString());
|
||||
var ret = 1;
|
||||
var retMessage = "";
|
||||
try
|
||||
{
|
||||
ret = actions.RunProcess(exe, arguments, workingDirectory, environment, out stdout);
|
||||
}
|
||||
catch (Exception ex)
|
||||
when (ex is System.ComponentModel.Win32Exception || ex is FileNotFoundException)
|
||||
{
|
||||
retMessage = ex.Message;
|
||||
stdout = new string[0];
|
||||
}
|
||||
exitCallBack(ret, retMessage);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ReturnBuildCommand : BuildScript
|
||||
{
|
||||
readonly Func<IBuildActions, int> func;
|
||||
public ReturnBuildCommand(Func<IBuildActions, int> func)
|
||||
{
|
||||
this.func = func;
|
||||
}
|
||||
|
||||
public override int Run(IBuildActions actions, Action<string> startCallback, Action<int, string> exitCallBack) => func(actions);
|
||||
|
||||
public override int Run(IBuildActions actions, Action<string> startCallback, Action<int, string> exitCallBack, out IList<string> stdout)
|
||||
{
|
||||
stdout = new string[0];
|
||||
return func(actions);
|
||||
}
|
||||
}
|
||||
|
||||
class BindBuildScript : BuildScript
|
||||
{
|
||||
readonly BuildScript s1;
|
||||
readonly Func<IList<string>, int, BuildScript> s2a;
|
||||
readonly Func<int, BuildScript> s2b;
|
||||
public BindBuildScript(BuildScript s1, Func<IList<string>, int, BuildScript> s2)
|
||||
{
|
||||
this.s1 = s1;
|
||||
this.s2a = s2;
|
||||
}
|
||||
|
||||
public BindBuildScript(BuildScript s1, Func<int, BuildScript> s2)
|
||||
{
|
||||
this.s1 = s1;
|
||||
this.s2b = s2;
|
||||
}
|
||||
|
||||
public override int Run(IBuildActions actions, Action<string> startCallback, Action<int, string> exitCallBack)
|
||||
{
|
||||
int ret1;
|
||||
if (s2a != null)
|
||||
{
|
||||
ret1 = s1.Run(actions, startCallback, exitCallBack, out var stdout1);
|
||||
return s2a(stdout1, ret1).Run(actions, startCallback, exitCallBack);
|
||||
}
|
||||
|
||||
ret1 = s1.Run(actions, startCallback, exitCallBack);
|
||||
return s2b(ret1).Run(actions, startCallback, exitCallBack);
|
||||
}
|
||||
|
||||
public override int Run(IBuildActions actions, Action<string> startCallback, Action<int, string> exitCallBack, out IList<string> stdout)
|
||||
{
|
||||
var ret1 = s1.Run(actions, startCallback, exitCallBack, out var stdout1);
|
||||
var ret2 = (s2a != null ? s2a(stdout1, ret1) : s2b(ret1)).Run(actions, startCallback, exitCallBack, out var stdout2);
|
||||
var @out = new List<string>();
|
||||
@out.AddRange(stdout1);
|
||||
@out.AddRange(stdout2);
|
||||
stdout = @out;
|
||||
return ret2;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a simple build script that runs the specified exe.
|
||||
/// </summary>
|
||||
/// <param name="argumentsOpt">The arguments to the executable, or null.</param>
|
||||
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
|
||||
/// <param name="environment">Additional environment variables.</param>
|
||||
public static BuildScript Create(string exe, string argumentsOpt, string workingDirectory, IDictionary<string, string> environment) =>
|
||||
new BuildCommand(exe, argumentsOpt, workingDirectory, environment);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a simple build script that runs the specified function.
|
||||
/// </summary>
|
||||
public static BuildScript Create(Func<IBuildActions, int> func) =>
|
||||
new ReturnBuildCommand(func);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a build script that runs <paramref name="s1"/>, followed by running the script
|
||||
/// produced by <paramref name="s2"/> on the exit code from <paramref name="s1"/>.
|
||||
/// </summary>
|
||||
public static BuildScript Bind(BuildScript s1, Func<int, BuildScript> s2) =>
|
||||
new BindBuildScript(s1, s2);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a build script that runs <paramref name="s1"/>, followed by running the script
|
||||
/// produced by <paramref name="s2"/> on the exit code and standard output from
|
||||
/// <paramref name="s1"/>.
|
||||
/// </summary>
|
||||
public static BuildScript Bind(BuildScript s1, Func<IList<string>, int, BuildScript> s2) =>
|
||||
new BindBuildScript(s1, s2);
|
||||
|
||||
const int SuccessCode = 0;
|
||||
/// <summary>
|
||||
/// The empty build script that always returns exit code 0.
|
||||
/// </summary>
|
||||
public static readonly BuildScript Success = Create(actions => SuccessCode);
|
||||
|
||||
const int FailureCode = 1;
|
||||
/// <summary>
|
||||
/// The empty build script that always returns exit code 1.
|
||||
/// </summary>
|
||||
public static readonly BuildScript Failure = Create(actions => FailureCode);
|
||||
|
||||
static bool Succeeded(int i) => i == SuccessCode;
|
||||
|
||||
public static BuildScript operator &(BuildScript s1, BuildScript s2) =>
|
||||
new BindBuildScript(s1, ret1 => Succeeded(ret1) ? s2 : Create(actions => ret1));
|
||||
|
||||
public static BuildScript operator &(BuildScript s1, Func<BuildScript> s2) =>
|
||||
new BindBuildScript(s1, ret1 => Succeeded(ret1) ? s2() : Create(actions => ret1));
|
||||
|
||||
public static BuildScript operator |(BuildScript s1, BuildScript s2) =>
|
||||
new BindBuildScript(s1, ret1 => Succeeded(ret1) ? Success : s2);
|
||||
|
||||
public static BuildScript operator |(BuildScript s1, Func<BuildScript> s2) =>
|
||||
new BindBuildScript(s1, ret1 => Succeeded(ret1) ? Success : s2());
|
||||
|
||||
/// <summary>
|
||||
/// Creates a build script that attempts to run the build script <paramref name="s"/>,
|
||||
/// always returning a successful exit code.
|
||||
/// </summary>
|
||||
public static BuildScript Try(BuildScript s) => s | Success;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a build script that deletes the given directory.
|
||||
/// </summary>
|
||||
public static BuildScript DeleteDirectory(string dir) =>
|
||||
Create(actions =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(dir) || !actions.DirectoryExists(dir))
|
||||
return FailureCode;
|
||||
|
||||
try
|
||||
{
|
||||
actions.DirectoryDelete(dir, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return FailureCode;
|
||||
}
|
||||
return SuccessCode;
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Creates a build script that deletes the given file.
|
||||
/// </summary>
|
||||
public static BuildScript DeleteFile(string file) =>
|
||||
Create(actions =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(file) || !actions.FileExists(file))
|
||||
return FailureCode;
|
||||
|
||||
try
|
||||
{
|
||||
actions.FileDelete(file);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return FailureCode;
|
||||
}
|
||||
return SuccessCode;
|
||||
});
|
||||
}
|
||||
}
|
||||
99
csharp/autobuilder/Semmle.Autobuild/BuildTools.cs
Normal file
99
csharp/autobuilder/Semmle.Autobuild/BuildTools.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// A BAT file used to initialise the appropriate
|
||||
/// Visual Studio version/platform.
|
||||
/// </summary>
|
||||
public class VcVarsBatFile
|
||||
{
|
||||
public readonly int ToolsVersion;
|
||||
public readonly string Path;
|
||||
public readonly string[] Platform;
|
||||
|
||||
public VcVarsBatFile(string path, int version, params string[] platform)
|
||||
{
|
||||
Path = path;
|
||||
ToolsVersion = version;
|
||||
Platform = platform;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Collection of available Visual Studio build tools.
|
||||
/// </summary>
|
||||
public static class BuildTools
|
||||
{
|
||||
public static IEnumerable<VcVarsBatFile> GetCandidateVcVarsFiles(IBuildActions actions)
|
||||
{
|
||||
var programFilesx86 = actions.GetEnvironmentVariable("ProgramFiles(x86)");
|
||||
if (programFilesx86 == null)
|
||||
yield break;
|
||||
|
||||
// Attempt to use vswhere to find installations of Visual Studio
|
||||
string vswhere = actions.PathCombine(programFilesx86, "Microsoft Visual Studio", "Installer", "vswhere.exe");
|
||||
|
||||
if (actions.FileExists(vswhere))
|
||||
{
|
||||
int exitCode1 = actions.RunProcess(vswhere, "-prerelease -legacy -property installationPath", null, null, out var installationList);
|
||||
int exitCode2 = actions.RunProcess(vswhere, "-prerelease -legacy -property installationVersion", null, null, out var versionList);
|
||||
|
||||
if (exitCode1 == 0 && exitCode2 == 0 && versionList.Count == installationList.Count)
|
||||
{
|
||||
// vswhere ran successfully and produced the expected output
|
||||
foreach (var vsInstallation in versionList.Zip(installationList, (v, i) => (Version: v, InstallationPath: i)))
|
||||
{
|
||||
var dot = vsInstallation.Version.IndexOf('.');
|
||||
var majorVersionString = dot == -1 ? vsInstallation.Version : vsInstallation.Version.Substring(0, dot);
|
||||
if (int.TryParse(majorVersionString, out int majorVersion))
|
||||
{
|
||||
if (majorVersion < 15)
|
||||
{
|
||||
yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion, "x86");
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion, "x86");
|
||||
yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion, "x64");
|
||||
}
|
||||
}
|
||||
// else: Skip installation without a version
|
||||
}
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
// vswhere not installed or didn't run correctly - return legacy Visual Studio versions
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14, "x86");
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12, "x86");
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11, "x86");
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10, "x86");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates all available tools.
|
||||
/// </summary>
|
||||
public static IEnumerable<VcVarsBatFile> VcVarsAllBatFiles(IBuildActions actions) =>
|
||||
GetCandidateVcVarsFiles(actions).Where(v => actions.FileExists(v.Path));
|
||||
|
||||
/// <summary>
|
||||
/// Finds a VcVars file that provides a compatible environment for the given solution.
|
||||
/// </summary>
|
||||
/// <param name="sln">The solution file.</param>
|
||||
/// <returns>A compatible file, or throws an exception.</returns>
|
||||
public static VcVarsBatFile FindCompatibleVcVars(IBuildActions actions, ISolution sln) =>
|
||||
FindCompatibleVcVars(actions, sln.ToolsVersion.Major);
|
||||
|
||||
/// <summary>
|
||||
/// Finds a VcVars that provides a compatible environment for the given tools version.
|
||||
/// </summary>
|
||||
/// <param name="targetVersion">The tools version.</param>
|
||||
/// <returns>A compatible file, or null.</returns>
|
||||
public static VcVarsBatFile FindCompatibleVcVars(IBuildActions actions, int targetVersion) =>
|
||||
targetVersion < 10 ?
|
||||
VcVarsAllBatFiles(actions).OrderByDescending(b => b.ToolsVersion).FirstOrDefault() :
|
||||
VcVarsAllBatFiles(actions).Where(b => b.ToolsVersion >= targetVersion).OrderBy(b => b.ToolsVersion).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
195
csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs
Normal file
195
csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility to construct a build command.
|
||||
/// </summary>
|
||||
class CommandBuilder
|
||||
{
|
||||
enum EscapeMode { Process, Cmd };
|
||||
|
||||
readonly StringBuilder arguments;
|
||||
bool firstCommand;
|
||||
string executable;
|
||||
readonly EscapeMode escapingMode;
|
||||
readonly string workingDirectory;
|
||||
readonly IDictionary<string, string> environment;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:Semmle.Autobuild.CommandBuilder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
|
||||
/// <param name="environment">Additional environment variables.</param>
|
||||
public CommandBuilder(IBuildActions actions, string workingDirectory = null, IDictionary<string, string> environment = null)
|
||||
{
|
||||
arguments = new StringBuilder();
|
||||
if (actions.IsWindows())
|
||||
{
|
||||
executable = "cmd.exe";
|
||||
arguments.Append("/C");
|
||||
escapingMode = EscapeMode.Cmd;
|
||||
}
|
||||
else
|
||||
{
|
||||
escapingMode = EscapeMode.Process;
|
||||
}
|
||||
|
||||
firstCommand = true;
|
||||
this.workingDirectory = workingDirectory;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
void OdasaIndex(string odasa)
|
||||
{
|
||||
RunCommand(odasa, "index --auto");
|
||||
}
|
||||
|
||||
public CommandBuilder CallBatFile(string batFile, string argumentsOpt = null)
|
||||
{
|
||||
NextCommand();
|
||||
arguments.Append(" CALL");
|
||||
QuoteArgument(batFile);
|
||||
Argument(argumentsOpt);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform odasa index on a given command or BAT file.
|
||||
/// </summary>
|
||||
/// <param name="odasa">The odasa executable.</param>
|
||||
/// <param name="command">The command to run.</param>
|
||||
/// <param name="argumentsOpt">Additional arguments.</param>
|
||||
/// <returns>this for chaining calls.</returns>
|
||||
public CommandBuilder IndexCommand(string odasa, string command, string argumentsOpt = null)
|
||||
{
|
||||
OdasaIndex(odasa);
|
||||
QuoteArgument(command);
|
||||
Argument(argumentsOpt);
|
||||
return this;
|
||||
}
|
||||
|
||||
static readonly char[] specialChars = { ' ', '\t', '\n', '\v', '\"' };
|
||||
static readonly char[] cmdMetacharacter = { '(', ')', '%', '!', '^', '\"', '<', '>', '&', '|' };
|
||||
|
||||
/// <summary>
|
||||
/// Appends the given argument to the command line.
|
||||
/// </summary>
|
||||
/// <param name="argument">The argument to append.</param>
|
||||
/// <param name="force">Whether to always quote the argument.</param>
|
||||
/// <param name="cmd">Whether to escape for cmd.exe</param>
|
||||
///
|
||||
/// <remarks>
|
||||
/// This implementation is copied from
|
||||
/// https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
|
||||
/// </remarks>
|
||||
void ArgvQuote(string argument, bool force)
|
||||
{
|
||||
bool cmd = escapingMode == EscapeMode.Cmd;
|
||||
if (!force &&
|
||||
!string.IsNullOrEmpty(argument) &&
|
||||
argument.IndexOfAny(specialChars) == -1)
|
||||
{
|
||||
arguments.Append(argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cmd) arguments.Append('^');
|
||||
arguments.Append('\"');
|
||||
for (int it = 0; ; ++it)
|
||||
{
|
||||
var numBackslashes = 0;
|
||||
while (it != argument.Length && argument[it] == '\\')
|
||||
{
|
||||
++it;
|
||||
++numBackslashes;
|
||||
}
|
||||
|
||||
if (it == argument.Length)
|
||||
{
|
||||
arguments.Append('\\', numBackslashes * 2);
|
||||
break;
|
||||
}
|
||||
else if (argument[it] == '\"')
|
||||
{
|
||||
arguments.Append('\\', numBackslashes * 2 + 1);
|
||||
if (cmd) arguments.Append('^');
|
||||
arguments.Append(arguments[it]);
|
||||
}
|
||||
else
|
||||
{
|
||||
arguments.Append('\\', numBackslashes);
|
||||
if (cmd && cmdMetacharacter.Any(c => c == argument[it]))
|
||||
arguments.Append('^');
|
||||
|
||||
arguments.Append(argument[it]);
|
||||
}
|
||||
}
|
||||
if (cmd) arguments.Append('^');
|
||||
arguments.Append('\"');
|
||||
}
|
||||
}
|
||||
|
||||
public CommandBuilder QuoteArgument(string argumentsOpt)
|
||||
{
|
||||
if (argumentsOpt != null)
|
||||
{
|
||||
NextArgument();
|
||||
ArgvQuote(argumentsOpt, false);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void NextArgument()
|
||||
{
|
||||
if (arguments.Length > 0)
|
||||
arguments.Append(' ');
|
||||
}
|
||||
|
||||
public CommandBuilder Argument(string argumentsOpt)
|
||||
{
|
||||
if (argumentsOpt != null)
|
||||
{
|
||||
NextArgument();
|
||||
arguments.Append(argumentsOpt);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void NextCommand()
|
||||
{
|
||||
if (firstCommand)
|
||||
firstCommand = false;
|
||||
else
|
||||
arguments.Append(" &&");
|
||||
}
|
||||
|
||||
public CommandBuilder RunCommand(string exe, string argumentsOpt = null)
|
||||
{
|
||||
var (exe0, arg0) =
|
||||
escapingMode == EscapeMode.Process && exe.EndsWith(".exe", System.StringComparison.Ordinal)
|
||||
? ("mono", exe) // Linux
|
||||
: (exe, null);
|
||||
|
||||
NextCommand();
|
||||
if (executable == null)
|
||||
{
|
||||
executable = exe0;
|
||||
}
|
||||
else
|
||||
{
|
||||
QuoteArgument(exe0);
|
||||
}
|
||||
Argument(arg0);
|
||||
Argument(argumentsOpt);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a build script that contains just this command.
|
||||
/// </summary>
|
||||
public BuildScript Script => BuildScript.Create(executable, arguments.ToString(), workingDirectory, environment);
|
||||
}
|
||||
}
|
||||
268
csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs
Normal file
268
csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs
Normal file
@@ -0,0 +1,268 @@
|
||||
using System;
|
||||
using Semmle.Util.Logging;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// A build rule where the build command is of the form "dotnet build".
|
||||
/// Currently unused because the tracer does not work with dotnet.
|
||||
/// </summary>
|
||||
class DotNetRule : IBuildRule
|
||||
{
|
||||
public BuildScript Analyse(Autobuilder builder)
|
||||
{
|
||||
builder.Log(Severity.Info, "Attempting to build using .NET Core");
|
||||
|
||||
var projects = builder.SolutionsToBuild.Any()
|
||||
? builder.SolutionsToBuild.SelectMany(s => s.Projects).ToArray()
|
||||
: builder.GetExtensions(Language.CSharp.ProjectExtension).Select(p => new Project(builder, p)).ToArray();
|
||||
|
||||
var notDotNetProject = projects.FirstOrDefault(p => !p.DotNetProject);
|
||||
if (notDotNetProject != null)
|
||||
{
|
||||
builder.Log(Severity.Info, "Not using .NET Core because of incompatible project {0}", notDotNetProject);
|
||||
return BuildScript.Failure;
|
||||
}
|
||||
|
||||
if (!builder.SolutionsToBuild.Any())
|
||||
// Attempt dotnet build in root folder
|
||||
return WithDotNet(builder, dotNet =>
|
||||
{
|
||||
var info = GetInfoCommand(builder.Actions, dotNet);
|
||||
var clean = GetCleanCommand(builder.Actions, dotNet).Script;
|
||||
var restore = GetRestoreCommand(builder.Actions, dotNet).Script;
|
||||
var build = GetBuildCommand(builder, dotNet).Script;
|
||||
return info & clean & BuildScript.Try(restore) & build;
|
||||
});
|
||||
|
||||
// Attempt dotnet build on each solution
|
||||
return WithDotNet(builder, dotNet =>
|
||||
{
|
||||
var ret = GetInfoCommand(builder.Actions, dotNet);
|
||||
foreach (var solution in builder.SolutionsToBuild)
|
||||
{
|
||||
var cleanCommand = GetCleanCommand(builder.Actions, dotNet);
|
||||
cleanCommand.QuoteArgument(solution.Path);
|
||||
var clean = cleanCommand.Script;
|
||||
|
||||
var restoreCommand = GetRestoreCommand(builder.Actions, dotNet);
|
||||
restoreCommand.QuoteArgument(solution.Path);
|
||||
var restore = restoreCommand.Script;
|
||||
|
||||
var buildCommand = GetBuildCommand(builder, dotNet);
|
||||
buildCommand.QuoteArgument(solution.Path);
|
||||
var build = buildCommand.Script;
|
||||
|
||||
ret &= clean & BuildScript.Try(restore) & build;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a script that attempts to download relevant version(s) of the
|
||||
/// .NET Core SDK, followed by running the script generated by <paramref name="f"/>.
|
||||
///
|
||||
/// The first element <code>DotNetPath</code> of the argument to <paramref name="f"/>
|
||||
/// is the path where .NET Core was installed, and the second element <code>Environment</code>
|
||||
/// is any additional required environment variables. The tuple argument is <code>null</code>
|
||||
/// when the installation failed.
|
||||
/// </summary>
|
||||
public static BuildScript WithDotNet(Autobuilder builder, Func<(string DotNetPath, IDictionary<string, string> Environment)?, BuildScript> f)
|
||||
{
|
||||
var installDir = builder.Actions.PathCombine(builder.Options.RootDirectory, ".dotnet");
|
||||
var installScript = DownloadDotNet(builder, installDir);
|
||||
return BuildScript.Bind(installScript, installed =>
|
||||
{
|
||||
if (installed == 0)
|
||||
{
|
||||
// The installation succeeded, so use the newly installed .NET Core
|
||||
var path = builder.Actions.GetEnvironmentVariable("PATH");
|
||||
var delim = builder.Actions.IsWindows() ? ";" : ":";
|
||||
var env = new Dictionary<string, string>{
|
||||
{ "DOTNET_MULTILEVEL_LOOKUP", "false" }, // prevent look up of other .NET Core SDKs
|
||||
{ "DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "true" },
|
||||
{ "PATH", installDir + delim + path }
|
||||
};
|
||||
return f((installDir, env));
|
||||
}
|
||||
|
||||
return f(null);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a script for downloading relevant versions of the
|
||||
/// .NET Core SDK. The SDK(s) will be installed at <code>installDir</code>
|
||||
/// (provided that the script succeeds).
|
||||
/// </summary>
|
||||
static BuildScript DownloadDotNet(Autobuilder builder, string installDir)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(builder.Options.DotNetVersion))
|
||||
// Specific version supplied in configuration: always use that
|
||||
return DownloadDotNetVersion(builder, installDir, builder.Options.DotNetVersion);
|
||||
|
||||
// Download versions mentioned in `global.json` files
|
||||
// See https://docs.microsoft.com/en-us/dotnet/core/tools/global-json
|
||||
var installScript = BuildScript.Success;
|
||||
var validGlobalJson = false;
|
||||
foreach (var path in builder.Paths.Where(p => p.EndsWith("global.json", StringComparison.Ordinal)))
|
||||
{
|
||||
string version;
|
||||
try
|
||||
{
|
||||
var o = JObject.Parse(File.ReadAllText(path));
|
||||
version = (string)o["sdk"]["version"];
|
||||
}
|
||||
catch
|
||||
{
|
||||
// not a valid global.json file
|
||||
continue;
|
||||
}
|
||||
|
||||
installScript &= DownloadDotNetVersion(builder, installDir, version);
|
||||
validGlobalJson = true;
|
||||
}
|
||||
|
||||
return validGlobalJson ? installScript : BuildScript.Failure;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a script for downloading a specific .NET Core SDK version, if the
|
||||
/// version is not already installed.
|
||||
///
|
||||
/// See https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script.
|
||||
/// </summary>
|
||||
static BuildScript DownloadDotNetVersion(Autobuilder builder, string path, string version)
|
||||
{
|
||||
return BuildScript.Bind(GetInstalledSdksScript(builder.Actions), (sdks, sdksRet) =>
|
||||
{
|
||||
if (sdksRet == 0 && sdks.Count() == 1 && sdks[0].StartsWith(version + " ", StringComparison.Ordinal))
|
||||
// The requested SDK is already installed (and no other SDKs are installed), so
|
||||
// no need to reinstall
|
||||
return BuildScript.Failure;
|
||||
|
||||
builder.Log(Severity.Info, "Attempting to download .NET Core {0}", version);
|
||||
|
||||
if (builder.Actions.IsWindows())
|
||||
{
|
||||
var psScript = @"param([string]$Version, [string]$InstallDir)
|
||||
|
||||
add-type @""
|
||||
using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
public class TrustAllCertsPolicy : ICertificatePolicy
|
||||
{
|
||||
public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
""@
|
||||
$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
|
||||
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
|
||||
$Script = Invoke-WebRequest -useb 'https://dot.net/v1/dotnet-install.ps1'
|
||||
|
||||
$arguments = @{
|
||||
Channel = 'release'
|
||||
Version = $Version
|
||||
InstallDir = $InstallDir
|
||||
}
|
||||
|
||||
$ScriptBlock = [scriptblock]::create("".{$($Script)} $(&{$args} @arguments)"")
|
||||
|
||||
Invoke-Command -ScriptBlock $ScriptBlock";
|
||||
var psScriptFile = builder.Actions.PathCombine(builder.Options.RootDirectory, "install-dotnet.ps1");
|
||||
builder.Actions.WriteAllText(psScriptFile, psScript);
|
||||
|
||||
var install = new CommandBuilder(builder.Actions).
|
||||
RunCommand("powershell").
|
||||
Argument("-NoProfile").
|
||||
Argument("-ExecutionPolicy").
|
||||
Argument("unrestricted").
|
||||
Argument("-file").
|
||||
Argument(psScriptFile).
|
||||
Argument("-Version").
|
||||
Argument(version).
|
||||
Argument("-InstallDir").
|
||||
Argument(path);
|
||||
return install.Script;
|
||||
}
|
||||
else
|
||||
{
|
||||
var curl = new CommandBuilder(builder.Actions).
|
||||
RunCommand("curl").
|
||||
Argument("-sO").
|
||||
Argument("https://dot.net/v1/dotnet-install.sh");
|
||||
|
||||
var chmod = new CommandBuilder(builder.Actions).
|
||||
RunCommand("chmod").
|
||||
Argument("u+x").
|
||||
Argument("dotnet-install.sh");
|
||||
|
||||
var install = new CommandBuilder(builder.Actions).
|
||||
RunCommand("./dotnet-install.sh").
|
||||
Argument("--channel").
|
||||
Argument("release").
|
||||
Argument("--version").
|
||||
Argument(version).
|
||||
Argument("--install-dir").
|
||||
Argument(path);
|
||||
|
||||
return curl.Script & chmod.Script & install.Script;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static BuildScript GetInstalledSdksScript(IBuildActions actions)
|
||||
{
|
||||
var listSdks = new CommandBuilder(actions).
|
||||
RunCommand("dotnet").
|
||||
Argument("--list-sdks");
|
||||
return listSdks.Script;
|
||||
}
|
||||
|
||||
static string DotNetCommand(IBuildActions actions, string dotNetPath) =>
|
||||
dotNetPath != null ? actions.PathCombine(dotNetPath, "dotnet") : "dotnet";
|
||||
|
||||
BuildScript GetInfoCommand(IBuildActions actions, (string DotNetPath, IDictionary<string, string> Environment)? arg)
|
||||
{
|
||||
var info = new CommandBuilder(actions, null, arg?.Environment).
|
||||
RunCommand(DotNetCommand(actions, arg?.DotNetPath)).
|
||||
Argument("--info");
|
||||
return info.Script;
|
||||
}
|
||||
|
||||
CommandBuilder GetCleanCommand(IBuildActions actions, (string DotNetPath, IDictionary<string, string> Environment)? arg)
|
||||
{
|
||||
var clean = new CommandBuilder(actions, null, arg?.Environment).
|
||||
RunCommand(DotNetCommand(actions, arg?.DotNetPath)).
|
||||
Argument("clean");
|
||||
return clean;
|
||||
}
|
||||
|
||||
CommandBuilder GetRestoreCommand(IBuildActions actions, (string DotNetPath, IDictionary<string, string> Environment)? arg)
|
||||
{
|
||||
var restore = new CommandBuilder(actions, null, arg?.Environment).
|
||||
RunCommand(DotNetCommand(actions, arg?.DotNetPath)).
|
||||
Argument("restore");
|
||||
return restore;
|
||||
}
|
||||
|
||||
CommandBuilder GetBuildCommand(Autobuilder builder, (string DotNetPath, IDictionary<string, string> Environment)? arg)
|
||||
{
|
||||
var build = new CommandBuilder(builder.Actions, null, arg?.Environment).
|
||||
IndexCommand(builder.Odasa, DotNetCommand(builder.Actions, arg?.DotNetPath)).
|
||||
Argument("build").
|
||||
Argument("--no-incremental").
|
||||
Argument("/p:UseSharedCompilation=false").
|
||||
Argument(builder.Options.DotNetArguments);
|
||||
return build;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
csharp/autobuilder/Semmle.Autobuild/Language.cs
Normal file
24
csharp/autobuilder/Semmle.Autobuild/Language.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
public sealed class Language
|
||||
{
|
||||
public static readonly Language Cpp = new Language(".vcxproj");
|
||||
public static readonly Language CSharp = new Language(".csproj");
|
||||
|
||||
public bool ProjectFileHasThisLanguage(string path) =>
|
||||
System.IO.Path.GetExtension(path) == ProjectExtension;
|
||||
|
||||
public static bool IsProjectFileForAnySupportedLanguage(string path) =>
|
||||
Cpp.ProjectFileHasThisLanguage(path) || CSharp.ProjectFileHasThisLanguage(path);
|
||||
|
||||
public readonly string ProjectExtension;
|
||||
|
||||
private Language(string extension)
|
||||
{
|
||||
ProjectExtension = extension;
|
||||
}
|
||||
|
||||
public override string ToString() =>
|
||||
ProjectExtension == Cpp.ProjectExtension ? "C/C++" : "C#";
|
||||
}
|
||||
}
|
||||
118
csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs
Normal file
118
csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using Semmle.Util.Logging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// A build rule using msbuild.
|
||||
/// </summary>
|
||||
class MsBuildRule : IBuildRule
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the msbuild command.
|
||||
/// </summary>
|
||||
const string MsBuild = "msbuild";
|
||||
|
||||
public BuildScript Analyse(Autobuilder builder)
|
||||
{
|
||||
builder.Log(Severity.Info, "Attempting to build using MSBuild");
|
||||
|
||||
if (!builder.SolutionsToBuild.Any())
|
||||
{
|
||||
builder.Log(Severity.Info, "Could not find a suitable solution file to build");
|
||||
return BuildScript.Failure;
|
||||
}
|
||||
|
||||
var vsTools = GetVcVarsBatFile(builder);
|
||||
|
||||
if (vsTools == null && builder.SolutionsToBuild.Any())
|
||||
{
|
||||
vsTools = BuildTools.FindCompatibleVcVars(builder.Actions, builder.SolutionsToBuild.First());
|
||||
}
|
||||
|
||||
if (vsTools == null && builder.Actions.IsWindows())
|
||||
{
|
||||
builder.Log(Severity.Warning, "Could not find a suitable version of vcvarsall.bat");
|
||||
}
|
||||
|
||||
var nuget = builder.Actions.PathCombine(builder.SemmlePlatformTools, "csharp", "nuget", "nuget.exe");
|
||||
|
||||
var ret = BuildScript.Success;
|
||||
|
||||
foreach (var solution in builder.SolutionsToBuild)
|
||||
{
|
||||
if (builder.Options.NugetRestore)
|
||||
{
|
||||
var nugetCommand = new CommandBuilder(builder.Actions).
|
||||
RunCommand(nuget).
|
||||
Argument("restore").
|
||||
QuoteArgument(solution.Path);
|
||||
ret &= BuildScript.Try(nugetCommand.Script);
|
||||
}
|
||||
|
||||
var command = new CommandBuilder(builder.Actions);
|
||||
|
||||
if (vsTools != null)
|
||||
{
|
||||
command.CallBatFile(vsTools.Path);
|
||||
}
|
||||
|
||||
command.IndexCommand(builder.Odasa, MsBuild);
|
||||
command.QuoteArgument(solution.Path);
|
||||
|
||||
command.Argument("/p:UseSharedCompilation=false");
|
||||
|
||||
string target = builder.Options.MsBuildTarget != null ? builder.Options.MsBuildTarget : "rebuild";
|
||||
string platform = builder.Options.MsBuildPlatform != null ? builder.Options.MsBuildPlatform : solution.DefaultPlatformName;
|
||||
string configuration = builder.Options.MsBuildConfiguration != null ? builder.Options.MsBuildConfiguration : solution.DefaultConfigurationName;
|
||||
|
||||
command.Argument("/t:" + target);
|
||||
command.Argument(string.Format("/p:Platform=\"{0}\"", platform));
|
||||
command.Argument(string.Format("/p:Configuration=\"{0}\"", configuration));
|
||||
command.Argument("/p:MvcBuildViews=true");
|
||||
|
||||
command.Argument(builder.Options.MsBuildArguments);
|
||||
|
||||
ret &= command.Script;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the BAT file used to initialize the appropriate Visual Studio
|
||||
/// version/platform, as specified by the `vstools_version` property in
|
||||
/// lgtm.yml.
|
||||
///
|
||||
/// Returns <code>null</code> when no version is specified.
|
||||
/// </summary>
|
||||
public static VcVarsBatFile GetVcVarsBatFile(Autobuilder builder)
|
||||
{
|
||||
VcVarsBatFile vsTools = null;
|
||||
|
||||
if (builder.Options.VsToolsVersion != null)
|
||||
{
|
||||
if (int.TryParse(builder.Options.VsToolsVersion, out var msToolsVersion))
|
||||
{
|
||||
foreach (var b in BuildTools.VcVarsAllBatFiles(builder.Actions))
|
||||
{
|
||||
builder.Log(Severity.Info, "Found {0} version {1}", b.Path, b.ToolsVersion);
|
||||
}
|
||||
|
||||
vsTools = BuildTools.FindCompatibleVcVars(builder.Actions, msToolsVersion);
|
||||
if (vsTools == null)
|
||||
builder.Log(Severity.Warning, "Could not find build tools matching version {0}", msToolsVersion);
|
||||
else
|
||||
builder.Log(Severity.Info, "Setting Visual Studio tools to {0}", vsTools.Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Log(Severity.Error, "The format of vstools_version is incorrect. Please specify an integer.");
|
||||
}
|
||||
}
|
||||
|
||||
return vsTools;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
csharp/autobuilder/Semmle.Autobuild/Program.cs
Normal file
28
csharp/autobuilder/Semmle.Autobuild/Program.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static int Main()
|
||||
{
|
||||
var options = new AutobuildOptions();
|
||||
var actions = SystemBuildActions.Instance;
|
||||
|
||||
try
|
||||
{
|
||||
options.ReadEnvironment(actions);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException ex)
|
||||
{
|
||||
Console.WriteLine("The value \"{0}\" for parameter \"{1}\" is invalid", ex.ActualValue, ex.ParamName);
|
||||
}
|
||||
|
||||
var builder = new Autobuilder(actions, options);
|
||||
|
||||
Console.WriteLine($"Semmle autobuilder for {options.Language}");
|
||||
|
||||
return builder.AttemptBuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
69
csharp/autobuilder/Semmle.Autobuild/Project.cs
Normal file
69
csharp/autobuilder/Semmle.Autobuild/Project.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Representation of a .csproj (C#) or .vcxproj (C++) file.
|
||||
/// C# project files come in 2 flavours, .Net core and msbuild, but they
|
||||
/// have the same file extension.
|
||||
/// </summary>
|
||||
public class Project
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds if this project is for .Net core.
|
||||
/// </summary>
|
||||
public bool DotNetProject { get; private set; }
|
||||
|
||||
public bool ValidToolsVersion { get; private set; }
|
||||
|
||||
public Version ToolsVersion { get; private set; }
|
||||
|
||||
readonly string filename;
|
||||
|
||||
public Project(Autobuilder builder, string filename)
|
||||
{
|
||||
this.filename = filename;
|
||||
ToolsVersion = new Version();
|
||||
|
||||
if (!File.Exists(filename))
|
||||
return;
|
||||
|
||||
var projFile = new XmlDocument();
|
||||
projFile.Load(filename);
|
||||
var root = projFile.DocumentElement;
|
||||
|
||||
if (root.Name == "Project")
|
||||
{
|
||||
if (root.HasAttribute("Sdk"))
|
||||
{
|
||||
DotNetProject = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var toolsVersion = root.GetAttribute("ToolsVersion");
|
||||
if (string.IsNullOrEmpty(toolsVersion))
|
||||
{
|
||||
builder.Log(Severity.Warning, "Project {0} is missing a tools version", filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ToolsVersion = new Version(toolsVersion);
|
||||
ValidToolsVersion = true;
|
||||
}
|
||||
catch // Generic catch clause - Version constructor throws about 5 different exceptions.
|
||||
{
|
||||
builder.Log(Severity.Warning, "Project {0} has invalid tools version {1}", filename, toolsVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => filename;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Semmle.Autobuild")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Semmle")]
|
||||
[assembly: AssemblyProduct("Semmle Visual Studio Autobuild")]
|
||||
[assembly: AssemblyCopyright("Copyright © Semmle 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("1d9920ad-7b00-4df1-8b01-9ff5b687828e")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
27
csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj
Normal file
27
csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj
Normal file
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Autobuild</AssemblyName>
|
||||
<RootNamespace>Semmle.Autobuild</RootNamespace>
|
||||
<ApplicationIcon />
|
||||
<OutputType>Exe</OutputType>
|
||||
<StartupObject />
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="15.8.166" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj" />
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
107
csharp/autobuilder/Semmle.Autobuild/Solution.cs
Normal file
107
csharp/autobuilder/Semmle.Autobuild/Solution.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.Build.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// A solution file, extension .sln.
|
||||
/// </summary>
|
||||
public interface ISolution
|
||||
{
|
||||
/// <summary>
|
||||
/// List of C# or C++ projects contained in the solution.
|
||||
/// (There could be other project types as well - these are ignored.)
|
||||
/// </summary>
|
||||
|
||||
IEnumerable<Project> Projects { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Solution configurations.
|
||||
/// </summary>
|
||||
IEnumerable<SolutionConfigurationInSolution> Configurations { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The default configuration name, e.g. "Release"
|
||||
/// </summary>
|
||||
string DefaultConfigurationName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The default platform name, e.g. "x86"
|
||||
/// </summary>
|
||||
string DefaultPlatformName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The path of the solution file.
|
||||
/// </summary>
|
||||
string Path { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of C# or C++ projects.
|
||||
/// </summary>
|
||||
int ProjectCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the "best" tools version for this solution.
|
||||
/// If there are several versions, because the project files
|
||||
/// are inconsistent, then pick the highest/latest version.
|
||||
/// If no tools versions are present, return 0.0.0.0.
|
||||
/// </summary>
|
||||
Version ToolsVersion { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A solution file on the filesystem, read using Microsoft.Build.
|
||||
/// </summary>
|
||||
class Solution : ISolution
|
||||
{
|
||||
readonly SolutionFile solution;
|
||||
|
||||
public IEnumerable<Project> Projects { get; private set; }
|
||||
|
||||
public IEnumerable<SolutionConfigurationInSolution> Configurations =>
|
||||
solution == null ? Enumerable.Empty<SolutionConfigurationInSolution>() : solution.SolutionConfigurations;
|
||||
|
||||
public string DefaultConfigurationName =>
|
||||
solution == null ? "" : solution.GetDefaultConfigurationName();
|
||||
|
||||
public string DefaultPlatformName =>
|
||||
solution == null ? "" : solution.GetDefaultPlatformName();
|
||||
|
||||
public Solution(Autobuilder builder, string path)
|
||||
{
|
||||
Path = System.IO.Path.GetFullPath(path);
|
||||
try
|
||||
{
|
||||
solution = SolutionFile.Parse(Path);
|
||||
|
||||
Projects =
|
||||
solution.ProjectsInOrder.
|
||||
Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat).
|
||||
Select(p => System.IO.Path.GetFullPath(FileUtils.ConvertToNative(p.AbsolutePath))).
|
||||
Where(p => builder.Options.Language.ProjectFileHasThisLanguage(p)).
|
||||
Select(p => new Project(builder, p)).
|
||||
ToArray();
|
||||
}
|
||||
catch (InvalidProjectFileException)
|
||||
{
|
||||
// We allow specifying projects as solutions in lgtm.yml, so model
|
||||
// that scenario as a solution with just that one project
|
||||
Projects = Language.IsProjectFileForAnySupportedLanguage(Path)
|
||||
? new[] { new Project(builder, Path) }
|
||||
: new Project[0];
|
||||
}
|
||||
}
|
||||
|
||||
public string Path { get; private set; }
|
||||
|
||||
public int ProjectCount => Projects.Count();
|
||||
|
||||
IEnumerable<Version> ToolsVersions => Projects.Where(p => p.ValidToolsVersion).Select(p => p.ToolsVersion);
|
||||
|
||||
public Version ToolsVersion => ToolsVersions.Any() ? ToolsVersions.Max() : new Version();
|
||||
}
|
||||
}
|
||||
46
csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs
Normal file
46
csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Build using standalone extraction.
|
||||
/// </summary>
|
||||
class StandaloneBuildRule : IBuildRule
|
||||
{
|
||||
public BuildScript Analyse(Autobuilder builder)
|
||||
{
|
||||
BuildScript GetCommand(string solution)
|
||||
{
|
||||
var standalone = builder.Actions.PathCombine(builder.SemmlePlatformTools, "csharp", "Semmle.Extraction.CSharp.Standalone");
|
||||
var cmd = new CommandBuilder(builder.Actions);
|
||||
cmd.RunCommand(standalone);
|
||||
|
||||
if (solution != null)
|
||||
cmd.QuoteArgument(solution);
|
||||
|
||||
cmd.Argument("--references:.");
|
||||
|
||||
if (!builder.Options.NugetRestore)
|
||||
{
|
||||
cmd.Argument("--skip-nuget");
|
||||
}
|
||||
|
||||
return cmd.Script;
|
||||
}
|
||||
|
||||
if (!builder.Options.Buildless)
|
||||
return BuildScript.Failure;
|
||||
|
||||
var solutions = builder.Options.Solution.Length;
|
||||
|
||||
if (solutions == 0)
|
||||
return GetCommand(null);
|
||||
|
||||
var script = BuildScript.Success;
|
||||
foreach (var solution in builder.Options.Solution)
|
||||
script &= GetCommand(solution);
|
||||
|
||||
return script;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs
Normal file
18
csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// XML extraction.
|
||||
/// </summary>
|
||||
class XmlBuildRule : IBuildRule
|
||||
{
|
||||
public BuildScript Analyse(Autobuilder builder)
|
||||
{
|
||||
var command = new CommandBuilder(builder.Actions).
|
||||
RunCommand(builder.Odasa).
|
||||
Argument("index --xml --extensions config csproj props xml");
|
||||
return command.Script;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user