mirror of
https://github.com/github/codeql.git
synced 2026-05-05 13:45:19 +02:00
C#: Recognize .proj files in autobuilder
When determining the target of `msbuild` or `dotnet build`, first look for `.proj` files, then `.sln` files, and finally `.csproj`/`.vcxproj` files. In all three cases, choose the project/solution file closest to the root.
This commit is contained in:
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Construction;
|
||||
using System.Xml;
|
||||
|
||||
namespace Semmle.Extraction.Tests
|
||||
{
|
||||
@@ -129,12 +130,24 @@ namespace Semmle.Extraction.Tests
|
||||
|
||||
string IBuildActions.PathCombine(params string[] parts)
|
||||
{
|
||||
return string.Join('\\', parts);
|
||||
return string.Join('\\', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
||||
}
|
||||
|
||||
string IBuildActions.GetFullPath(string path) => path;
|
||||
|
||||
string IBuildActions.GetDirectoryName(string path) => System.IO.Path.GetDirectoryName(path);
|
||||
|
||||
void IBuildActions.WriteAllText(string filename, string contents)
|
||||
{
|
||||
}
|
||||
|
||||
public IDictionary<string, XmlDocument> LoadXml = new Dictionary<string, XmlDocument>();
|
||||
XmlDocument IBuildActions.LoadXml(string filename)
|
||||
{
|
||||
if (LoadXml.TryGetValue(filename, out var xml))
|
||||
return xml;
|
||||
throw new ArgumentException("Missing LoadXml " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -142,23 +155,21 @@ namespace Semmle.Extraction.Tests
|
||||
/// </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 string FullPath { get; set; }
|
||||
|
||||
public Version ToolsVersion => new Version("14.0");
|
||||
|
||||
public IEnumerable<IProjectOrSolution> IncludedProjects => throw new NotImplementedException();
|
||||
|
||||
public TestSolution(string path)
|
||||
{
|
||||
Path = path;
|
||||
FullPath = path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,11 +329,11 @@ namespace Semmle.Extraction.Tests
|
||||
}
|
||||
|
||||
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")
|
||||
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";
|
||||
@@ -354,16 +365,26 @@ namespace Semmle.Extraction.Tests
|
||||
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 dotnet clean test.csproj"] = 0;
|
||||
Actions.RunProcess["cmd.exe /C dotnet restore test.csproj"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false test.csproj"] = 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["test.csproj"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs";
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs\ntest.csproj";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
var xml = new XmlDocument();
|
||||
xml.LoadXml(@"<Project Sdk=""Microsoft.NET.Sdk"">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>");
|
||||
Actions.LoadXml["test.csproj"] = xml;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true);
|
||||
TestAutobuilderScript(autobuilder, 0, 6);
|
||||
@@ -373,16 +394,26 @@ namespace Semmle.Extraction.Tests
|
||||
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["dotnet clean test.csproj"] = 0;
|
||||
Actions.RunProcess["dotnet restore test.csproj"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false test.csproj"] = 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.FileExists["test.csproj"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs";
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
var xml = new XmlDocument();
|
||||
xml.LoadXml(@"<Project Sdk=""Microsoft.NET.Sdk"">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>");
|
||||
Actions.LoadXml["test.csproj"] = xml;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 0, 6);
|
||||
@@ -391,10 +422,6 @@ namespace Semmle.Extraction.Tests
|
||||
[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;
|
||||
@@ -402,7 +429,7 @@ namespace Semmle.Extraction.Tests
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 1, 4);
|
||||
TestAutobuilderScript(autobuilder, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -438,7 +465,7 @@ namespace Semmle.Extraction.Tests
|
||||
|
||||
var autobuilder = CreateAutoBuilder("cpp", true);
|
||||
var solution = new TestSolution(@"C:\Project\test.sln");
|
||||
autobuilder.SolutionsToBuild.Add(solution);
|
||||
autobuilder.ProjectsOrSolutionsToBuild.Add(solution);
|
||||
TestAutobuilderScript(autobuilder, 0, 2);
|
||||
}
|
||||
|
||||
@@ -495,7 +522,7 @@ namespace Semmle.Extraction.Tests
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildless:"true");
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true");
|
||||
TestAutobuilderScript(autobuilder, 0, 3);
|
||||
}
|
||||
|
||||
@@ -550,7 +577,7 @@ namespace Semmle.Extraction.Tests
|
||||
Assert.Equal(commandsRun, EndCallbackReturn.Count);
|
||||
|
||||
var action = Actions.RunProcess.GetEnumerator();
|
||||
for(int cmd=0; cmd<commandsRun; ++cmd)
|
||||
for (int cmd = 0; cmd < commandsRun; ++cmd)
|
||||
{
|
||||
Assert.True(action.MoveNext());
|
||||
|
||||
@@ -573,7 +600,7 @@ namespace Semmle.Extraction.Tests
|
||||
|
||||
SkipVsWhere();
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildCommand:"./build.sh --skip-tests");
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildCommand: "./build.sh --skip-tests");
|
||||
TestAutobuilderScript(autobuilder, 0, 3);
|
||||
}
|
||||
|
||||
@@ -584,7 +611,6 @@ namespace Semmle.Extraction.Tests
|
||||
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";
|
||||
@@ -593,7 +619,7 @@ namespace Semmle.Extraction.Tests
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 0, 5);
|
||||
TestAutobuilderScript(autobuilder, 0, 4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -604,14 +630,13 @@ namespace Semmle.Extraction.Tests
|
||||
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);
|
||||
TestAutobuilderScript(autobuilder, 1, 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -622,14 +647,13 @@ namespace Semmle.Extraction.Tests
|
||||
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);
|
||||
TestAutobuilderScript(autobuilder, 1, 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -639,7 +663,6 @@ namespace Semmle.Extraction.Tests
|
||||
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;
|
||||
@@ -647,7 +670,7 @@ namespace Semmle.Extraction.Tests
|
||||
Actions.FileExists["csharp.log"] = true;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true);
|
||||
TestAutobuilderScript(autobuilder, 0, 4);
|
||||
TestAutobuilderScript(autobuilder, 0, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -657,15 +680,14 @@ namespace Semmle.Extraction.Tests
|
||||
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);
|
||||
var autobuilder = CreateAutoBuilder("csharp", true, ignoreErrors: "true");
|
||||
TestAutobuilderScript(autobuilder, 1, 1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -707,12 +729,12 @@ namespace Semmle.Extraction.Tests
|
||||
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 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);
|
||||
autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution1);
|
||||
autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution2);
|
||||
|
||||
TestAutobuilderScript(autobuilder, 0, 6);
|
||||
}
|
||||
@@ -737,8 +759,8 @@ namespace Semmle.Extraction.Tests
|
||||
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);
|
||||
autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution1);
|
||||
autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution2);
|
||||
|
||||
TestAutobuilderScript(autobuilder, 1, 2);
|
||||
}
|
||||
@@ -764,11 +786,11 @@ namespace Semmle.Extraction.Tests
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows",
|
||||
msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12",
|
||||
allSolutions: "true", nugetRestore:"false");
|
||||
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);
|
||||
autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution1);
|
||||
autobuilder.ProjectsOrSolutionsToBuild.Add(testSolution2);
|
||||
|
||||
TestAutobuilderScript(autobuilder, 0, 4);
|
||||
}
|
||||
@@ -785,7 +807,7 @@ namespace Semmle.Extraction.Tests
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln", nugetRestore:"false");
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln", nugetRestore: "false");
|
||||
TestAutobuilderScript(autobuilder, 0, 3);
|
||||
}
|
||||
|
||||
@@ -794,18 +816,28 @@ namespace Semmle.Extraction.Tests
|
||||
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["dotnet clean test.csproj"] = 0;
|
||||
Actions.RunProcess["dotnet restore test.csproj"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false --no-restore test.csproj"] = 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.FileExists["test.csproj"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs";
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
var xml = new XmlDocument();
|
||||
xml.LoadXml(@"<Project Sdk=""Microsoft.NET.Sdk"">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, dotnetArguments:"--no-restore"); // nugetRestore=false does not work for now.
|
||||
</Project>");
|
||||
Actions.LoadXml["test.csproj"] = xml;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, dotnetArguments: "--no-restore"); // nugetRestore=false does not work for now.
|
||||
TestAutobuilderScript(autobuilder, 0, 6);
|
||||
}
|
||||
|
||||
@@ -818,19 +850,29 @@ namespace Semmle.Extraction.Tests
|
||||
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:\Project\.dotnet\dotnet clean test.csproj"] = 0;
|
||||
Actions.RunProcess[@"C:\Project\.dotnet\dotnet restore test.csproj"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto C:\Project\.dotnet\dotnet build --no-incremental /p:UseSharedCompilation=false test.csproj"] = 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.FileExists["test.csproj"] = 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.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
var xml = new XmlDocument();
|
||||
xml.LoadXml(@"<Project Sdk=""Microsoft.NET.Sdk"">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion:"2.1.3");
|
||||
</Project>");
|
||||
Actions.LoadXml["test.csproj"] = xml;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3");
|
||||
TestAutobuilderScript(autobuilder, 0, 10);
|
||||
}
|
||||
|
||||
@@ -843,17 +885,27 @@ namespace Semmle.Extraction.Tests
|
||||
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:\Project\.dotnet\dotnet clean test.csproj"] = 0;
|
||||
Actions.RunProcess[@"C:\Project\.dotnet\dotnet restore test.csproj"] = 0;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto C:\Project\.dotnet\dotnet build --no-incremental /p:UseSharedCompilation=false test.csproj"] = 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.FileExists["test.csproj"] = 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.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs\ntest.csproj";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
var xml = new XmlDocument();
|
||||
xml.LoadXml(@"<Project Sdk=""Microsoft.NET.Sdk"">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>");
|
||||
Actions.LoadXml["test.csproj"] = xml;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3");
|
||||
TestAutobuilderScript(autobuilder, 0, 10);
|
||||
@@ -866,20 +918,109 @@ namespace Semmle.Extraction.Tests
|
||||
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:\Project\.dotnet\dotnet clean test.csproj"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet restore test.csproj"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\.dotnet\dotnet build --no-incremental /p:UseSharedCompilation=false test.csproj"] = 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["test.csproj"] = 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.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs\ntest.csproj";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
var xml = new XmlDocument();
|
||||
xml.LoadXml(@"<Project Sdk=""Microsoft.NET.Sdk"">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>");
|
||||
Actions.LoadXml["test.csproj"] = xml;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true, dotnetVersion: "2.1.3");
|
||||
TestAutobuilderScript(autobuilder, 0, 8);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDirsProjWindows()
|
||||
{
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore dirs.proj"] = 1;
|
||||
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 dirs.proj /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[@"a\test.csproj"] = true;
|
||||
Actions.FileExists["dirs.proj"] = 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"] = "a\\test.cs\na\\test.csproj\ndirs.proj";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var csproj = new XmlDocument();
|
||||
csproj.LoadXml(@"<?xml version=""1.0"" encoding=""utf - 8""?>
|
||||
<Project ToolsVersion=""15.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
|
||||
<ItemGroup>
|
||||
<Compile Include=""test.cs"" />
|
||||
</ItemGroup>
|
||||
</Project>");
|
||||
Actions.LoadXml["a\\test.csproj"] = csproj;
|
||||
|
||||
var dirsproj = new XmlDocument();
|
||||
dirsproj.LoadXml(@"<Project DefaultTargets=""Build"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""3.5"">
|
||||
<ItemGroup>
|
||||
<ProjectFiles Include=""a\test.csproj"" />
|
||||
</ItemGroup>
|
||||
</Project>");
|
||||
Actions.LoadXml["dirs.proj"] = dirsproj;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug",
|
||||
vsToolsVersion: "12", allSolutions: "true");
|
||||
TestAutobuilderScript(autobuilder, 0, 4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDirsProjLinux()
|
||||
{
|
||||
Actions.RunProcess[@"mono C:\odasa\tools\csharp\nuget\nuget.exe restore dirs.proj"] = 1;
|
||||
Actions.RunProcess[@"C:\odasa\tools\odasa index --auto msbuild dirs.proj /p:UseSharedCompilation=false /t:rebuild /p:MvcBuildViews=true"] = 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.FileExists["a/test.csproj"] = true;
|
||||
Actions.FileExists["dirs.proj"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "a/test.cs\na/test.csproj\ndirs.proj";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var csproj = new XmlDocument();
|
||||
csproj.LoadXml(@"<?xml version=""1.0"" encoding=""utf - 8""?>
|
||||
<Project ToolsVersion=""15.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
|
||||
<ItemGroup>
|
||||
<Compile Include=""test.cs"" />
|
||||
</ItemGroup>
|
||||
</Project>");
|
||||
Actions.LoadXml["a/test.csproj"] = csproj;
|
||||
|
||||
var dirsproj = new XmlDocument();
|
||||
dirsproj.LoadXml(@"<Project DefaultTargets=""Build"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""3.5"">
|
||||
<ItemGroup>
|
||||
<ProjectFiles Include=""a\test.csproj"" />
|
||||
</ItemGroup>
|
||||
</Project>");
|
||||
Actions.LoadXml["dirs.proj"] = dirsproj;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,26 +29,32 @@ namespace Semmle.Autobuild
|
||||
public class Autobuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Full file paths of files found in the project directory.
|
||||
/// Full file paths of files found in the project directory, as well
|
||||
/// their distance from the project root folder. The list is sorted
|
||||
/// by distance in ascending order.
|
||||
/// </summary>
|
||||
public IEnumerable<string> Paths => pathsLazy.Value;
|
||||
readonly Lazy<IEnumerable<string>> pathsLazy;
|
||||
public IEnumerable<(string, int)> Paths => pathsLazy.Value;
|
||||
readonly Lazy<IEnumerable<(string, int)>> pathsLazy;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of paths matching a set of extensions
|
||||
/// (including the ".").
|
||||
/// (including the "."), as well their distance from the project root folder.
|
||||
/// The list is sorted by distance in ascending order.
|
||||
/// </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)));
|
||||
public IEnumerable<(string, int)> GetExtensions(params string[] extensions) =>
|
||||
Paths.Where(p => extensions.Contains(Path.GetExtension(p.Item1)));
|
||||
|
||||
/// <summary>
|
||||
/// Gets all paths matching a particular filename.
|
||||
/// Gets all paths matching a particular filename, as well
|
||||
/// their distance from the project root folder. The list is sorted
|
||||
/// by distance in ascending order.
|
||||
/// </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);
|
||||
public IEnumerable<(string, int)> GetFilename(string name) =>
|
||||
Paths.Where(p => Path.GetFileName(p.Item1) == name);
|
||||
|
||||
/// <summary>
|
||||
/// Holds if a given path, relative to the root of the source directory
|
||||
@@ -59,30 +65,30 @@ namespace Semmle.Autobuild
|
||||
public bool HasRelativePath(string path) => HasPath(Actions.PathCombine(RootDirectory, path));
|
||||
|
||||
/// <summary>
|
||||
/// List of solution files to build.
|
||||
/// List of project/solution files to build.
|
||||
/// </summary>
|
||||
public IList<ISolution> SolutionsToBuild => solutionsToBuildLazy.Value;
|
||||
readonly Lazy<IList<ISolution>> solutionsToBuildLazy;
|
||||
public IList<IProjectOrSolution> ProjectsOrSolutionsToBuild => projectsOrSolutionsToBuildLazy.Value;
|
||||
readonly Lazy<IList<IProjectOrSolution>> projectsOrSolutionsToBuildLazy;
|
||||
|
||||
/// <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);
|
||||
public bool HasPath(string path) => Paths.Any(p => path == p.Item1);
|
||||
|
||||
void FindFiles(string dir, int depth, IList<string> results)
|
||||
void FindFiles(string dir, int depth, int maxDepth, IList<(string, int)> results)
|
||||
{
|
||||
foreach (var f in Actions.EnumerateFiles(dir))
|
||||
{
|
||||
results.Add(f);
|
||||
results.Add((f, depth));
|
||||
}
|
||||
|
||||
if (depth > 1)
|
||||
if (depth < maxDepth)
|
||||
{
|
||||
foreach (var d in Actions.EnumerateDirectories(dir))
|
||||
{
|
||||
FindFiles(d, depth - 1, results);
|
||||
FindFiles(d, depth + 1, maxDepth, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,46 +119,75 @@ namespace Semmle.Autobuild
|
||||
Actions = actions;
|
||||
Options = options;
|
||||
|
||||
pathsLazy = new Lazy<IEnumerable<string>>(() =>
|
||||
pathsLazy = new Lazy<IEnumerable<(string, int)>>(() =>
|
||||
{
|
||||
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();
|
||||
var files = new List<(string, int)>();
|
||||
FindFiles(options.RootDirectory, 0, options.SearchDepth, files);
|
||||
return files.OrderBy(f => f.Item2).ToArray();
|
||||
});
|
||||
|
||||
solutionsToBuildLazy = new Lazy<IList<ISolution>>(() =>
|
||||
projectsOrSolutionsToBuildLazy = new Lazy<IList<IProjectOrSolution>>(() =>
|
||||
{
|
||||
if (options.Solution.Any())
|
||||
{
|
||||
var ret = new List<ISolution>();
|
||||
var ret = new List<IProjectOrSolution>();
|
||||
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);
|
||||
Log(Severity.Error, $"The specified solution file {solution} was not found");
|
||||
}
|
||||
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).
|
||||
bool FindFiles(string extension, Func<string, ProjectOrSolution> create, out IEnumerable<IProjectOrSolution> files)
|
||||
{
|
||||
var allFiles = GetExtensions(extension).
|
||||
Select(p => (ProjectOrSolution: create(p.Item1), DistanceFromRoot: p.Item2)).
|
||||
Where(p => p.ProjectOrSolution.HasLanguage(this.Options.Language)).
|
||||
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))}");
|
||||
if (allFiles.Length == 0)
|
||||
{
|
||||
files = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.AllSolutions)
|
||||
{
|
||||
files = allFiles.Select(p => p.ProjectOrSolution);
|
||||
return true;
|
||||
}
|
||||
|
||||
var firstIsClosest = allFiles.Length > 1 && allFiles[0].DistanceFromRoot < allFiles[1].DistanceFromRoot;
|
||||
if (allFiles.Length == 1 || firstIsClosest)
|
||||
{
|
||||
files = allFiles.Select(p => p.ProjectOrSolution).Take(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
var candidates = allFiles.
|
||||
Where(f => f.DistanceFromRoot == allFiles[0].DistanceFromRoot).
|
||||
Select(f => f.ProjectOrSolution);
|
||||
Log(Severity.Info, $"Found multiple '{extension}' files, giving up: {string.Join(", ", candidates)}.");
|
||||
files = new IProjectOrSolution[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
return new List<ISolution>(options.AllSolutions ?
|
||||
solutions :
|
||||
solutions.Take(1));
|
||||
// First look for `.proj` files
|
||||
if (FindFiles(".proj", f => new Project(this, f), out var ret1))
|
||||
return ret1.ToList();
|
||||
|
||||
// Then look for `.sln` files
|
||||
if (FindFiles(".sln", f => new Solution(this, f), out var ret2))
|
||||
return ret2.ToList();
|
||||
|
||||
// Finally look for language specific project files, e.g. `.csproj` files
|
||||
if (FindFiles(this.Options.Language.ProjectExtension, f => new Project(this, f), out var ret3))
|
||||
return ret3.ToList();
|
||||
|
||||
return new List<IProjectOrSolution>();
|
||||
});
|
||||
|
||||
SemmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST");
|
||||
|
||||
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
@@ -96,12 +97,27 @@ namespace Semmle.Autobuild
|
||||
/// <returns>The combined path.</returns>
|
||||
string PathCombine(params string[] parts);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path for <paramref name="path"/>, Path.GetFullPath().
|
||||
/// </summary>
|
||||
string GetFullPath(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the directory of <paramref name="path"/>, Path.GetDirectoryName().
|
||||
/// </summary>
|
||||
string GetDirectoryName(string path);
|
||||
|
||||
/// <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>
|
||||
/// Loads the XML document from <paramref name="filename"/>.
|
||||
/// </summary>
|
||||
XmlDocument LoadXml(string filename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -167,10 +183,17 @@ namespace Semmle.Autobuild
|
||||
|
||||
void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents);
|
||||
|
||||
private SystemBuildActions()
|
||||
XmlDocument IBuildActions.LoadXml(string filename)
|
||||
{
|
||||
var ret = new XmlDocument();
|
||||
ret.Load(filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
string IBuildActions.GetFullPath(string path) => Path.GetFullPath(path);
|
||||
|
||||
string IBuildActions.GetDirectoryName(string path) => Path.GetDirectoryName(path);
|
||||
|
||||
public static readonly IBuildActions Instance = new SystemBuildActions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
@@ -32,7 +31,7 @@ namespace Semmle.Autobuild
|
||||
|
||||
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();
|
||||
var scriptPath = builder.Paths.Where(p => scripts.Any(p.Item1.ToLower().EndsWith)).OrderBy(p => p.Item2).Select(p => p.Item1).FirstOrDefault();
|
||||
|
||||
if (scriptPath == null)
|
||||
return BuildScript.Failure;
|
||||
@@ -41,12 +40,12 @@ namespace Semmle.Autobuild
|
||||
chmod.RunCommand("/bin/chmod", $"u+x {scriptPath}");
|
||||
var chmodScript = builder.Actions.IsWindows() ? BuildScript.Success : BuildScript.Try(chmod.Script);
|
||||
|
||||
var path = Path.GetDirectoryName(scriptPath);
|
||||
var dir = builder.Actions.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);
|
||||
var command = new CommandBuilder(builder.Actions, dir, dotNet?.Environment);
|
||||
|
||||
// A specific Visual Studio version may be required
|
||||
var vsTools = MsBuildRule.GetVcVarsBatFile(builder);
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
@@ -15,46 +16,36 @@ namespace Semmle.Autobuild
|
||||
{
|
||||
public BuildScript Analyse(Autobuilder builder)
|
||||
{
|
||||
builder.Log(Severity.Info, "Attempting to build using .NET Core");
|
||||
if (!builder.ProjectsOrSolutionsToBuild.Any())
|
||||
return BuildScript.Failure;
|
||||
|
||||
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);
|
||||
var notDotNetProject = builder.ProjectsOrSolutionsToBuild.
|
||||
SelectMany(p => Enumerators.Singleton(p).Concat(p.IncludedProjects)).
|
||||
OfType<Project>().
|
||||
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;
|
||||
});
|
||||
builder.Log(Severity.Info, "Attempting to build using .NET Core");
|
||||
|
||||
// Attempt dotnet build on each solution
|
||||
return WithDotNet(builder, dotNet =>
|
||||
{
|
||||
var ret = GetInfoCommand(builder.Actions, dotNet);
|
||||
foreach (var solution in builder.SolutionsToBuild)
|
||||
foreach (var projectOrSolution in builder.ProjectsOrSolutionsToBuild)
|
||||
{
|
||||
var cleanCommand = GetCleanCommand(builder.Actions, dotNet);
|
||||
cleanCommand.QuoteArgument(solution.Path);
|
||||
cleanCommand.QuoteArgument(projectOrSolution.FullPath);
|
||||
var clean = cleanCommand.Script;
|
||||
|
||||
var restoreCommand = GetRestoreCommand(builder.Actions, dotNet);
|
||||
restoreCommand.QuoteArgument(solution.Path);
|
||||
restoreCommand.QuoteArgument(projectOrSolution.FullPath);
|
||||
var restore = restoreCommand.Script;
|
||||
|
||||
var buildCommand = GetBuildCommand(builder, dotNet);
|
||||
buildCommand.QuoteArgument(solution.Path);
|
||||
buildCommand.QuoteArgument(projectOrSolution.FullPath);
|
||||
var build = buildCommand.Script;
|
||||
|
||||
ret &= clean & BuildScript.Try(restore) & build;
|
||||
@@ -110,7 +101,7 @@ namespace Semmle.Autobuild
|
||||
// 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)))
|
||||
foreach (var path in builder.Paths.Select(p => p.Item1).Where(p => p.EndsWith("global.json", StringComparison.Ordinal)))
|
||||
{
|
||||
string version;
|
||||
try
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
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)
|
||||
|
||||
@@ -16,19 +16,19 @@ namespace Semmle.Autobuild
|
||||
|
||||
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");
|
||||
if (!builder.ProjectsOrSolutionsToBuild.Any())
|
||||
return BuildScript.Failure;
|
||||
}
|
||||
|
||||
builder.Log(Severity.Info, "Attempting to build using MSBuild");
|
||||
|
||||
var vsTools = GetVcVarsBatFile(builder);
|
||||
|
||||
if (vsTools == null && builder.SolutionsToBuild.Any())
|
||||
if (vsTools == null && builder.ProjectsOrSolutionsToBuild.Any())
|
||||
{
|
||||
vsTools = BuildTools.FindCompatibleVcVars(builder.Actions, builder.SolutionsToBuild.First());
|
||||
var firstSolution = builder.ProjectsOrSolutionsToBuild.OfType<ISolution>().FirstOrDefault();
|
||||
vsTools = firstSolution != null
|
||||
? BuildTools.FindCompatibleVcVars(builder.Actions, firstSolution)
|
||||
: BuildTools.VcVarsAllBatFiles(builder.Actions).OrderByDescending(b => b.ToolsVersion).FirstOrDefault();
|
||||
}
|
||||
|
||||
if (vsTools == null && builder.Actions.IsWindows())
|
||||
@@ -40,36 +40,42 @@ namespace Semmle.Autobuild
|
||||
|
||||
var ret = BuildScript.Success;
|
||||
|
||||
foreach (var solution in builder.SolutionsToBuild)
|
||||
foreach (var projectOrSolution in builder.ProjectsOrSolutionsToBuild)
|
||||
{
|
||||
if (builder.Options.NugetRestore)
|
||||
{
|
||||
var nugetCommand = new CommandBuilder(builder.Actions).
|
||||
RunCommand(nuget).
|
||||
Argument("restore").
|
||||
QuoteArgument(solution.Path);
|
||||
QuoteArgument(projectOrSolution.FullPath);
|
||||
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.QuoteArgument(projectOrSolution.FullPath);
|
||||
|
||||
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;
|
||||
string target = builder.Options.MsBuildTarget != null
|
||||
? builder.Options.MsBuildTarget
|
||||
: "rebuild";
|
||||
string platform = builder.Options.MsBuildPlatform != null
|
||||
? builder.Options.MsBuildPlatform
|
||||
: projectOrSolution is ISolution s1 ? s1.DefaultPlatformName : null;
|
||||
string configuration = builder.Options.MsBuildConfiguration != null
|
||||
? builder.Options.MsBuildConfiguration
|
||||
: projectOrSolution is ISolution s2 ? s2.DefaultConfigurationName : null;
|
||||
|
||||
command.Argument("/t:" + target);
|
||||
command.Argument(string.Format("/p:Platform=\"{0}\"", platform));
|
||||
command.Argument(string.Format("/p:Configuration=\"{0}\"", configuration));
|
||||
if (platform != null)
|
||||
command.Argument(string.Format("/p:Platform=\"{0}\"", platform));
|
||||
if (configuration != null)
|
||||
command.Argument(string.Format("/p:Configuration=\"{0}\"", configuration));
|
||||
command.Argument("/p:MvcBuildViews=true");
|
||||
|
||||
command.Argument(builder.Options.MsBuildArguments);
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Representation of a .csproj (C#) or .vcxproj (C++) file.
|
||||
/// Representation of a .proj file, a .csproj file (C#), or a .vcxproj file (C++).
|
||||
/// C# project files come in 2 flavours, .Net core and msbuild, but they
|
||||
/// have the same file extension.
|
||||
/// </summary>
|
||||
public class Project
|
||||
public class Project : ProjectOrSolution
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds if this project is for .Net core.
|
||||
@@ -21,18 +23,28 @@ namespace Semmle.Autobuild
|
||||
|
||||
public Version ToolsVersion { get; private set; }
|
||||
|
||||
readonly string filename;
|
||||
readonly List<Project> includedProjects = new List<Project>();
|
||||
public override IEnumerable<IProjectOrSolution> IncludedProjects =>
|
||||
includedProjects.Concat(includedProjects.SelectMany(s => s.IncludedProjects));
|
||||
|
||||
public Project(Autobuilder builder, string filename)
|
||||
public Project(Autobuilder builder, string path) : base(builder, path)
|
||||
{
|
||||
this.filename = filename;
|
||||
ToolsVersion = new Version();
|
||||
|
||||
if (!File.Exists(filename))
|
||||
if (!builder.Actions.FileExists(FullPath))
|
||||
return;
|
||||
|
||||
var projFile = new XmlDocument();
|
||||
projFile.Load(filename);
|
||||
XmlDocument projFile;
|
||||
try
|
||||
{
|
||||
projFile = builder.Actions.LoadXml(FullPath);
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
builder.Log(Severity.Info, $"Skipping project file {path} as it is not a valid XML document.");
|
||||
return;
|
||||
}
|
||||
|
||||
var root = projFile.DocumentElement;
|
||||
|
||||
if (root.Name == "Project")
|
||||
@@ -40,30 +52,35 @@ namespace Semmle.Autobuild
|
||||
if (root.HasAttribute("Sdk"))
|
||||
{
|
||||
DotNetProject = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
var toolsVersion = root.GetAttribute("ToolsVersion");
|
||||
if (!string.IsNullOrEmpty(toolsVersion))
|
||||
{
|
||||
var toolsVersion = root.GetAttribute("ToolsVersion");
|
||||
if (string.IsNullOrEmpty(toolsVersion))
|
||||
try
|
||||
{
|
||||
builder.Log(Severity.Warning, "Project {0} is missing a tools version", filename);
|
||||
ToolsVersion = new Version(toolsVersion);
|
||||
ValidToolsVersion = true;
|
||||
}
|
||||
else
|
||||
catch // Generic catch clause - Version constructor throws about 5 different exceptions.
|
||||
{
|
||||
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);
|
||||
}
|
||||
builder.Log(Severity.Warning, "Project {0} has invalid tools version {1}", path, toolsVersion);
|
||||
}
|
||||
}
|
||||
|
||||
// The documentation on `.proj` files is very limited, but it appears that both
|
||||
// `<ProjectFile Include="X"/>` and `<ProjectFiles Include="X"/>` is valid
|
||||
var mgr = new XmlNamespaceManager(projFile.NameTable);
|
||||
mgr.AddNamespace("msbuild", "http://schemas.microsoft.com/developer/msbuild/2003");
|
||||
var projectFileIncludes = root.SelectNodes("//msbuild:Project/msbuild:ItemGroup/msbuild:ProjectFile/@Include", mgr).OfType<XmlNode>();
|
||||
var projectFilesIncludes = root.SelectNodes("//msbuild:Project/msbuild:ItemGroup/msbuild:ProjectFiles/@Include", mgr).OfType<XmlNode>();
|
||||
foreach (var include in projectFileIncludes.Concat(projectFilesIncludes))
|
||||
{
|
||||
var includePath = builder.Actions.IsWindows() ? include.Value : include.Value.Replace("\\", "/");
|
||||
includedProjects.Add(new Project(builder, builder.Actions.PathCombine(builder.Actions.GetDirectoryName(this.FullPath), includePath)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => filename;
|
||||
}
|
||||
}
|
||||
|
||||
47
csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs
Normal file
47
csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// A file that can be the target in an invocation of `msbuild` or `dotnet build`.
|
||||
/// Either a solution file or a project file (`.proj`, `.csproj`, or `.vcxproj`).
|
||||
/// </summary>
|
||||
public interface IProjectOrSolution
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the full path of this file.
|
||||
/// </summary>
|
||||
string FullPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of other projects included by this file.
|
||||
/// </summary>
|
||||
IEnumerable<IProjectOrSolution> IncludedProjects { get; }
|
||||
}
|
||||
|
||||
public abstract class ProjectOrSolution : IProjectOrSolution
|
||||
{
|
||||
public string FullPath { get; private set; }
|
||||
|
||||
protected ProjectOrSolution(Autobuilder builder, string path)
|
||||
{
|
||||
FullPath = builder.Actions.GetFullPath(path);
|
||||
}
|
||||
|
||||
public abstract IEnumerable<IProjectOrSolution> IncludedProjects { get; }
|
||||
|
||||
public override string ToString() => FullPath;
|
||||
}
|
||||
|
||||
public static class IProjectOrSolutionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds if this file includes a project with code from language <paramref name="l"/>.
|
||||
/// </summary>
|
||||
public static bool HasLanguage(this IProjectOrSolution p, Language l) =>
|
||||
l.ProjectFileHasThisLanguage(p.FullPath) ||
|
||||
p.IncludedProjects.Any(p0 => l.ProjectFileHasThisLanguage(p0.FullPath));
|
||||
}
|
||||
}
|
||||
@@ -10,15 +10,8 @@ namespace Semmle.Autobuild
|
||||
/// <summary>
|
||||
/// A solution file, extension .sln.
|
||||
/// </summary>
|
||||
public interface ISolution
|
||||
public interface ISolution : IProjectOrSolution
|
||||
{
|
||||
/// <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>
|
||||
@@ -34,16 +27,6 @@ namespace Semmle.Autobuild
|
||||
/// </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
|
||||
@@ -56,11 +39,12 @@ namespace Semmle.Autobuild
|
||||
/// <summary>
|
||||
/// A solution file on the filesystem, read using Microsoft.Build.
|
||||
/// </summary>
|
||||
class Solution : ISolution
|
||||
class Solution : ProjectOrSolution, ISolution
|
||||
{
|
||||
readonly SolutionFile solution;
|
||||
|
||||
public IEnumerable<Project> Projects { get; private set; }
|
||||
readonly IEnumerable<Project> includedProjects;
|
||||
public override IEnumerable<IProjectOrSolution> IncludedProjects => includedProjects;
|
||||
|
||||
public IEnumerable<SolutionConfigurationInSolution> Configurations =>
|
||||
solution == null ? Enumerable.Empty<SolutionConfigurationInSolution>() : solution.SolutionConfigurations;
|
||||
@@ -71,18 +55,16 @@ namespace Semmle.Autobuild
|
||||
public string DefaultPlatformName =>
|
||||
solution == null ? "" : solution.GetDefaultPlatformName();
|
||||
|
||||
public Solution(Autobuilder builder, string path)
|
||||
public Solution(Autobuilder builder, string path) : base(builder, path)
|
||||
{
|
||||
Path = System.IO.Path.GetFullPath(path);
|
||||
try
|
||||
{
|
||||
solution = SolutionFile.Parse(Path);
|
||||
solution = SolutionFile.Parse(FullPath);
|
||||
|
||||
Projects =
|
||||
includedProjects =
|
||||
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 => builder.Actions.GetFullPath(FileUtils.ConvertToNative(p.AbsolutePath))).
|
||||
Select(p => new Project(builder, p)).
|
||||
ToArray();
|
||||
}
|
||||
@@ -90,17 +72,11 @@ namespace Semmle.Autobuild
|
||||
{
|
||||
// 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];
|
||||
includedProjects = new[] { new Project(builder, path) };
|
||||
}
|
||||
}
|
||||
|
||||
public string Path { get; private set; }
|
||||
|
||||
public int ProjectCount => Projects.Count();
|
||||
|
||||
IEnumerable<Version> ToolsVersions => Projects.Where(p => p.ValidToolsVersion).Select(p => p.ToolsVersion);
|
||||
IEnumerable<Version> ToolsVersions => includedProjects.Where(p => p.ValidToolsVersion).Select(p => p.ToolsVersion);
|
||||
|
||||
public Version ToolsVersion => ToolsVersions.Any() ? ToolsVersions.Max() : new Version();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user