Add support for requiring Visual Studio's MSBuild from KoreBuild
This commit is contained in:
Родитель
f977d575ec
Коммит
ec1822a2c8
|
@ -1,18 +1,34 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2002
|
||||
VisualStudioVersion = 15.0.27004.2005
|
||||
MinimumVisualStudioVersion = 15.0.26730.03
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A4F4353B-C3D2-40B0-909A-5B48A748EA76}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BF3E9C90-F129-4CE6-8F3B-F96831E4429B}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "files", "files", "{BF3E9C90-F129-4CE6-8F3B-F96831E4429B}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.appveyor.yml = .appveyor.yml
|
||||
.editorconfig = .editorconfig
|
||||
.gitattributes = .gitattributes
|
||||
.gitignore = .gitignore
|
||||
.travis.yml = .travis.yml
|
||||
build.cmd = build.cmd
|
||||
build.ps1 = build.ps1
|
||||
build.sh = build.sh
|
||||
build\common.props = build\common.props
|
||||
CONTRIBUTING.md = CONTRIBUTING.md
|
||||
build\dependencies.props = build\dependencies.props
|
||||
global.json = global.json
|
||||
korebuild.json = korebuild.json
|
||||
LICENSE.txt = LICENSE.txt
|
||||
NuGet.Config = NuGet.Config
|
||||
push.cmd = push.cmd
|
||||
push.ps1 = push.ps1
|
||||
README.md = README.md
|
||||
build\repo.props = build\repo.props
|
||||
build\repo.targets = build\repo.targets
|
||||
test.ps1 = test.ps1
|
||||
test.sh = test.sh
|
||||
version.props = version.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{60A938B2-D95A-403C-AA7A-3683AD64DFA0}"
|
||||
|
|
38
README.md
38
README.md
|
@ -36,8 +36,44 @@ docker-build | Runs the build inside docker. | .\run.ps1 docker-build {jessie\|w
|
|||
default-build| Runs install-tools followed by msbuild (like build.cmd used to). | .\run.ps1 default-build /t:SomeTarget /p:Parameters
|
||||
msbuild | Runs the build normally. | .\run.ps1 msbuild /t:SomeTarget /p:Parameters
|
||||
|
||||
### KoreBuild config
|
||||
|
||||
KoreBuild can be configured by adding a 'korebuild.json' file into the root folder of your repository.
|
||||
|
||||
Example:
|
||||
```js
|
||||
{
|
||||
// add this for editor auto-completion :)
|
||||
"$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json",
|
||||
|
||||
// specifies the channel used to update KoreBuild to new versions when you attempt to upgrade KoreBuild
|
||||
"channel": "dev",
|
||||
|
||||
"toolsets": {
|
||||
// All toolsets listed in this section are treated as required toolsets
|
||||
|
||||
"visualstudio": {
|
||||
// defaults to `true`
|
||||
"includePrerelease": false,
|
||||
|
||||
// see https://aka.ms/vs/workloads
|
||||
"requiredWorkloads": [
|
||||
"Microsoft.VisualStudio.Component.VSSDK"
|
||||
],
|
||||
|
||||
// Default = no minimum version
|
||||
"minVersion": "15.4",
|
||||
|
||||
// This tool is only required on Windows.
|
||||
"required": [ "windows" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Local testing
|
||||
To test changes to this project locally we recomend you do:
|
||||
```
|
||||
|
||||
```ps1
|
||||
./test.ps1 -Command $CommandToTest -RepoPath C:\repo\to\test\against\
|
||||
```
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<SystemReflectionMetadataVersion>1.5.0</SystemReflectionMetadataVersion>
|
||||
<TestSdkVersion>15.3.0</TestSdkVersion>
|
||||
<XunitVersion>2.3.0-rc3-build3818</XunitVersion>
|
||||
<VSWherePackageVersion>2.2.7</VSWherePackageVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
{
|
||||
"$schema": "./tools/korebuild.schema.json",
|
||||
"channel": "dev"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using KoreBuild.Tasks.Utilities;
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
namespace KoreBuild.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds Visual Studio.
|
||||
/// </summary>
|
||||
public class FindVisualStudio : Microsoft.Build.Utilities.Task
|
||||
{
|
||||
/// <summary>
|
||||
/// The path to the korebuild.json file. (Optional)
|
||||
/// </summary>
|
||||
public string ConfigFile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The base path to the installation of VS.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public string InstallationBasePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to MSBuild.exe (x86). It will be empty if this file does not exist.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public string MSBuildx86Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to MSBuild.exe (x64). It will be empty if this file does not exist.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public string MSBuildx64Path { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
Log.LogError("Visual Studio cannot be found on non-Windows platforms");
|
||||
return false;
|
||||
}
|
||||
|
||||
VsInstallation vs;
|
||||
if (!string.IsNullOrEmpty(ConfigFile))
|
||||
{
|
||||
if (!File.Exists(ConfigFile))
|
||||
{
|
||||
Log.LogError($"Could not load the korebuild config file from '{ConfigFile}'");
|
||||
return false;
|
||||
}
|
||||
|
||||
var settings = KoreBuildSettings.Load(ConfigFile);
|
||||
var vsToolset = settings.Toolsets?.OfType<KoreBuildSettings.VisualStudioToolset>().FirstOrDefault();
|
||||
if (vsToolset != null)
|
||||
{
|
||||
vs = VsWhere.FindLatestCompatibleInstallation(vsToolset, Log);
|
||||
if (vs == null)
|
||||
{
|
||||
Log.LogError($"Could not find an installation of Visual Studio that satisifies the specified requirements in {ConfigFile}.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vs = VsWhere.FindLatestInstallation(includePrerelease: true, log: Log);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vs = VsWhere.FindLatestInstallation(includePrerelease: true, log: Log);
|
||||
}
|
||||
|
||||
if (vs == null)
|
||||
{
|
||||
Log.LogError($"Could not find any installation of Visual Studio.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Log.LogMessage(MessageImportance.Normal, "Found {0} in {1}", vs.DisplayName, vs.InstallationPath);
|
||||
|
||||
InstallationBasePath = vs.InstallationPath;
|
||||
MSBuildx86Path = vs.GetMSBuildx86SubPath();
|
||||
MSBuildx64Path = vs.GetMSBuildx64SubPath();
|
||||
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using KoreBuild.Tasks.Utilities;
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
namespace KoreBuild.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds toolset information as listed in korebuild.json
|
||||
/// </summary>
|
||||
public class GetToolsets : Microsoft.Build.Utilities.Task
|
||||
{
|
||||
/// <summary>
|
||||
/// The path to the korebuild.json file.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string ConfigFile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to MSBuild.exe (x86), if the 'visualstudio' toolset was specified. It will be empty if this file does not exist.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public string VisualStudioMSBuildx86Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to MSBuild.exe (x64), if the 'visualstudio' toolset was specified. It will be empty if this file does not exist.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public string VisualStudioMSBuildx64Path { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
if (!File.Exists(ConfigFile))
|
||||
{
|
||||
Log.LogError($"Could not load the korebuild config file from '{ConfigFile}'");
|
||||
return false;
|
||||
}
|
||||
|
||||
var settings = KoreBuildSettings.Load(ConfigFile);
|
||||
|
||||
if (settings?.Toolsets == null)
|
||||
{
|
||||
Log.LogMessage(MessageImportance.Normal, "No recognized toolsets specified.");
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var toolset in settings.Toolsets)
|
||||
{
|
||||
switch (toolset)
|
||||
{
|
||||
case KoreBuildSettings.VisualStudioToolset vs:
|
||||
GetVisualStudio(vs);
|
||||
break;
|
||||
default:
|
||||
Log.LogWarning("Toolset checks not implemented for " + toolset.GetType().Name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
|
||||
private void GetVisualStudio(KoreBuildSettings.VisualStudioToolset vsToolset)
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
if ((vsToolset.Required & KoreBuildSettings.RequiredPlatforms.Windows) != 0)
|
||||
{
|
||||
Log.LogError("Visual Studio is not available on non-Windows. Change korebuild.json to 'required: [\"windows\"]'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.LogMessage(MessageImportance.Low, "Skipping Visual Studio verification on non-Windows platforms.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var vs = VsWhere.FindLatestCompatibleInstallation(vsToolset, Log);
|
||||
if (vs == null)
|
||||
{
|
||||
if (vsToolset.Required != KoreBuildSettings.RequiredPlatforms.None)
|
||||
{
|
||||
Log.LogError($"Could not find an installation of Visual Studio that satisifies the specified requirements in {ConfigFile}. This is required to build.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Log.LogMessage(MessageImportance.High, "Using {0} from {1}", vs.DisplayName, vs.InstallationPath);
|
||||
|
||||
VisualStudioMSBuildx86Path = vs.GetMSBuildx86SubPath();
|
||||
VisualStudioMSBuildx64Path = vs.GetMSBuildx64SubPath();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,8 @@
|
|||
<Content Include="*.targets" CopyToPublishDirectory="PreserveNewest" />
|
||||
<Compile Include="..\..\shared\Microsoft.Extensions.CommandLineUtils.Sources\Utilities\*.cs" />
|
||||
<Compile Include="..\..\shared\Utilities\MSBuildListSplitter.cs" />
|
||||
<Compile Include="..\..\tools\KoreBuildSettings.cs" />
|
||||
<Content Include="$(VSWhereDir)vswhere.exe" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -20,6 +22,7 @@
|
|||
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="$(MicrosoftBuildVersion)" PrivateAssets="All" />
|
||||
<PackageReference Include="NuGet.Build.Tasks" Version="$(NuGetInMSBuildVersion)" PrivateAssets="All" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="$(JsonNetInMSBuildVersion)" PrivateAssets="All" />
|
||||
<PackageReference Include="vswhere" Version="$(VSWherePackageVersion)" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace KoreBuild.Tasks.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// A DTO that is deserialized from the output of 'vswhere.exe -format json'
|
||||
/// </summary>
|
||||
internal class VsInstallation
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
public string InstallationPath { get; set; }
|
||||
|
||||
// Add methods for additional info inferred from the vswhere.exe output.
|
||||
public string GetMSBuildx86SubPath()
|
||||
{
|
||||
var path = Path.Combine(InstallationPath, "MSBuild", "15.0", "Bin", "MSBuild.exe");
|
||||
|
||||
return File.Exists(path)
|
||||
? path
|
||||
: null;
|
||||
}
|
||||
|
||||
public string GetMSBuildx64SubPath()
|
||||
{
|
||||
var path = Path.Combine(InstallationPath, "MSBuild", "15.0", "Bin", "amd64", "MSBuild.exe");
|
||||
|
||||
return File.Exists(path)
|
||||
? path
|
||||
: null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace KoreBuild.Tasks.Utilities
|
||||
{
|
||||
internal class VsWhere
|
||||
{
|
||||
public static VsInstallation FindLatestInstallation(bool includePrerelease, TaskLoggingHelper log)
|
||||
{
|
||||
var args = new List<string>
|
||||
{
|
||||
"-latest",
|
||||
};
|
||||
if (includePrerelease)
|
||||
{
|
||||
args.Add("-prerelease");
|
||||
}
|
||||
|
||||
return GetInstallations(args, log).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static VsInstallation FindLatestCompatibleInstallation(KoreBuildSettings.VisualStudioToolset toolset, TaskLoggingHelper log)
|
||||
{
|
||||
var args = new List<string> { "-latest" };
|
||||
|
||||
if (toolset.IncludePrerelease)
|
||||
{
|
||||
args.Add("-prerelease");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(toolset.MinVersion))
|
||||
{
|
||||
args.Add("-version");
|
||||
args.Add(toolset.MinVersion);
|
||||
}
|
||||
|
||||
if (toolset.RequiredWorkloads != null)
|
||||
{
|
||||
foreach (var workload in toolset.RequiredWorkloads)
|
||||
{
|
||||
args.Add("-requires");
|
||||
args.Add(workload);
|
||||
}
|
||||
}
|
||||
|
||||
return GetInstallations(args, log).FirstOrDefault();
|
||||
}
|
||||
|
||||
private static VsInstallation[] GetInstallations(List<string> args, TaskLoggingHelper log)
|
||||
{
|
||||
args.Add("-format");
|
||||
args.Add("json");
|
||||
|
||||
var vswhere = GetVsWherePath();
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo =
|
||||
{
|
||||
FileName = vswhere,
|
||||
Arguments = ArgumentEscaper.EscapeAndConcatenate(args),
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
}
|
||||
};
|
||||
|
||||
log.LogCommandLine(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
|
||||
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
process.WaitForExit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.LogError("vswhere failed." + ex.Message);
|
||||
return Array.Empty<VsInstallation>();
|
||||
|
||||
}
|
||||
|
||||
var output = process.StandardOutput.ReadToEnd();
|
||||
|
||||
if (process.ExitCode != 0)
|
||||
{
|
||||
log.LogMessage(MessageImportance.Low, "vswhere output = " + output);
|
||||
log.LogError("vswhere failed.");
|
||||
return Array.Empty<VsInstallation>();
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<VsInstallation[]>(output);
|
||||
}
|
||||
|
||||
private static string GetVsWherePath()
|
||||
{
|
||||
var searchPaths = new[]
|
||||
{
|
||||
Path.Combine(Path.GetDirectoryName(typeof(FindVisualStudio).Assembly.Location), "vswhere.exe"),
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Microsoft Visual Studio", "Installer", "vswhere.exe"),
|
||||
};
|
||||
|
||||
var file = searchPaths.FirstOrDefault(File.Exists);
|
||||
|
||||
return file ?? "vswhere";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,8 +2,10 @@
|
|||
<UsingTask TaskName="KoreBuild.Tasks.ApplyNuGetPolicies" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
<UsingTask TaskName="KoreBuild.Tasks.CheckPackageReferences" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
<UsingTask TaskName="KoreBuild.Tasks.DownloadNuGetPackages" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
<UsingTask TaskName="KoreBuild.Tasks.FindVisualStudio" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
<UsingTask TaskName="KoreBuild.Tasks.GenerateDependenciesPropsFile" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
<UsingTask TaskName="KoreBuild.Tasks.GeneratePackageVersionPropsFile" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
<UsingTask TaskName="KoreBuild.Tasks.GenerateDependenciesPropsFile" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
<UsingTask TaskName="KoreBuild.Tasks.GetToolsets" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
<UsingTask TaskName="KoreBuild.Tasks.InstallDotNet" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
<UsingTask TaskName="KoreBuild.Tasks.PackNuSpec" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
<UsingTask TaskName="KoreBuild.Tasks.PushNuGetPackages" AssemblyFile="$(MSBuildThisFileDirectory)Internal.AspNetCore.KoreBuild.Tasks.dll" />
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<PrepareDependsOn>GetToolsets;$(PrepareDependsOn)</PrepareDependsOn>
|
||||
<RestoreDependsOn>ApplyNuGetPolicies;InstallDotNet;CheckPackageReferences;$(RestoreDependsOn)</RestoreDependsOn>
|
||||
<ApplyNuGetPoliciesDependsOn>
|
||||
$(ApplyNuGetPoliciesDependsOn);
|
||||
|
@ -9,6 +10,7 @@
|
|||
</ApplyNuGetPoliciesDependsOn>
|
||||
|
||||
<DisablePackageReferenceRestrictions Condition=" '$(DisablePackageReferenceRestrictions)' == '' ">false</DisablePackageReferenceRestrictions>
|
||||
<KoreBuildConfigFile Condition="'$(KoreBuildConfigFile)' == ''">$(RepositoryRoot)korebuild.json</KoreBuildConfigFile>
|
||||
<DependencyVersionsFile Condition="'$(DependencyVersionsFile)' == ''">$(RepositoryRoot)build\dependencies.props</DependencyVersionsFile>
|
||||
</PropertyGroup>
|
||||
|
||||
|
@ -108,4 +110,12 @@
|
|||
Properties="$(SolutionProperties)" />
|
||||
</Target>
|
||||
|
||||
<!-- This target asserts that all tools listed in korebuild.json are available. -->
|
||||
<Target Name="GetToolsets" Condition="Exists($(KoreBuildConfigFile))">
|
||||
<GetToolsets ConfigFile="$(KoreBuildConfigFile)">
|
||||
<Output TaskParameter="VisualStudioMSBuildx86Path" PropertyName="VisualStudioMSBuildx86Path" />
|
||||
<Output TaskParameter="VisualStudioMSBuildx64Path" PropertyName="VisualStudioMSBuildx64Path" />
|
||||
</GetToolsets>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="..\shared\*" />
|
||||
<Content Include="..\..\files\KoreBuild\scripts\dotnet-install.*" CopyToOutputDirectory="PreserveNewest" />
|
||||
<Content Include="$(VSWhereDir)vswhere.exe" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -19,6 +20,7 @@
|
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
|
||||
<PackageReference Include="Moq" Version="$(MoqVersion)" />
|
||||
<PackageReference Include="NuGet.Build.Tasks" Version="$(NuGetInMSBuildVersion)" />
|
||||
<PackageReference Include="vswhere" Version="$(VsWherePackageVersion)" />
|
||||
<PackageReference Include="xunit" Version="$(XunitVersion)" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace KoreBuild.Tasks.Tests
|
||||
{
|
||||
public class KoreBuildSettingsTest : IDisposable
|
||||
{
|
||||
private readonly string _configFile;
|
||||
|
||||
public KoreBuildSettingsTest()
|
||||
{
|
||||
_configFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (File.Exists(_configFile))
|
||||
{
|
||||
File.Delete(_configFile);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItDeserializesVisualStudioToolset()
|
||||
{
|
||||
File.WriteAllText(_configFile, @"
|
||||
{
|
||||
""toolsets"": {
|
||||
""visualstudio"": {
|
||||
""requiredWorkloads"": [ ""MyTestWorkload"" ],
|
||||
""minVersion"": ""15.4"",
|
||||
""includePrerelease"": false
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
var settings = KoreBuildSettings.Load(_configFile);
|
||||
|
||||
var toolset = Assert.Single(settings.Toolsets);
|
||||
|
||||
var vs = Assert.IsType<KoreBuildSettings.VisualStudioToolset>(toolset);
|
||||
Assert.Collection(vs.RequiredWorkloads, w => Assert.Equal("MyTestWorkload", w));
|
||||
Assert.False(vs.IncludePrerelease);
|
||||
Assert.Equal("15.4", vs.MinVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItDeserializesEmptyVisualStudioToolset()
|
||||
{
|
||||
File.WriteAllText(_configFile, @"
|
||||
{
|
||||
""toolsets"": {
|
||||
""visualstudio"": {}
|
||||
}
|
||||
}
|
||||
");
|
||||
|
||||
var settings = KoreBuildSettings.Load(_configFile);
|
||||
var toolset = Assert.Single(settings.Toolsets);
|
||||
|
||||
var vs = Assert.IsType<KoreBuildSettings.VisualStudioToolset>(toolset);
|
||||
Assert.NotNull(vs.RequiredWorkloads);
|
||||
Assert.Empty(vs.RequiredWorkloads);
|
||||
Assert.True(vs.IncludePrerelease);
|
||||
Assert.Null(vs.MinVersion);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("true", KoreBuildSettings.RequiredPlatforms.All)]
|
||||
[InlineData("null", KoreBuildSettings.RequiredPlatforms.None)]
|
||||
[InlineData("false", KoreBuildSettings.RequiredPlatforms.None)]
|
||||
[InlineData(@"[""windows""]", KoreBuildSettings.RequiredPlatforms.Windows)]
|
||||
[InlineData(@"[""linux""]", KoreBuildSettings.RequiredPlatforms.Linux)]
|
||||
[InlineData(@"[""osx""]", KoreBuildSettings.RequiredPlatforms.MacOS)]
|
||||
[InlineData(@"[""macos""]", KoreBuildSettings.RequiredPlatforms.MacOS)]
|
||||
[InlineData(@"[""macos"", ""linux""]", KoreBuildSettings.RequiredPlatforms.MacOS | KoreBuildSettings.RequiredPlatforms.Linux)]
|
||||
internal void ParsesPlatforms(string json, KoreBuildSettings.RequiredPlatforms platforms)
|
||||
{
|
||||
File.WriteAllText(_configFile, @"
|
||||
{
|
||||
""toolsets"": {
|
||||
""visualstudio"": {
|
||||
""required"": " + json + @"
|
||||
}
|
||||
}
|
||||
}
|
||||
");
|
||||
|
||||
var settings = KoreBuildSettings.Load(_configFile);
|
||||
var toolset = Assert.Single(settings.Toolsets);
|
||||
|
||||
var vs = Assert.IsType<KoreBuildSettings.VisualStudioToolset>(toolset);
|
||||
Assert.Equal(platforms, vs.Required);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using BuildTools.Tasks.Tests;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace KoreBuild.Tasks.Tests
|
||||
{
|
||||
public class VSWhereTests
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public VSWhereTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItFindsVisualStudio()
|
||||
{
|
||||
var engine = new MockEngine(_output) { ContinueOnError = true };
|
||||
var task = new FindVisualStudio
|
||||
{
|
||||
BuildEngine = engine,
|
||||
};
|
||||
|
||||
var result = task.Execute();
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
// Don't fail the test. aspnet/BuildTools might be building without a version of VS installed.
|
||||
// We mostly want to make sure this task doesn't throw exceptions and fails gracefully
|
||||
Assert.NotEmpty(engine.Errors);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.NotEmpty(task.InstallationBasePath);
|
||||
Assert.True(Directory.Exists(task.InstallationBasePath), "VS installation was not found");
|
||||
|
||||
// these output properties are only set if the file exists
|
||||
if (!string.IsNullOrEmpty(task.MSBuildx64Path))
|
||||
{
|
||||
Assert.True(File.Exists(task.MSBuildx64Path), "MSBuild x64 was not found");
|
||||
}
|
||||
|
||||
// these output properties are only set if the file exists
|
||||
if (!string.IsNullOrEmpty(task.MSBuildx86Path))
|
||||
{
|
||||
Assert.True(File.Exists(task.MSBuildx86Path), "MSBuild x86 was not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.False(result, "VSWhere should fail on non-windows platforms");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace KoreBuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the korebuild.json file
|
||||
/// /// </summary>
|
||||
internal class KoreBuildSettings
|
||||
{
|
||||
public string Channel { get; set; }
|
||||
public string ToolsSource { get; set; }
|
||||
|
||||
[JsonConverter(typeof(KoreBuildToolsetConverter))]
|
||||
public IEnumerable<KoreBuildToolset> Toolsets { get; set; } = Array.Empty<KoreBuildToolset>();
|
||||
|
||||
[Flags]
|
||||
public enum RequiredPlatforms
|
||||
{
|
||||
None = 0,
|
||||
Windows = 1 << 0,
|
||||
MacOS = 1 << 1,
|
||||
Linux = 1 << 2,
|
||||
All = Windows | MacOS | Linux,
|
||||
}
|
||||
|
||||
public abstract class KoreBuildToolset
|
||||
{
|
||||
[JsonConverter(typeof(RequiredPlatformConverter))]
|
||||
public RequiredPlatforms Required { get; set; } = RequiredPlatforms.All;
|
||||
}
|
||||
|
||||
public class VisualStudioToolset : KoreBuildToolset
|
||||
{
|
||||
public bool IncludePrerelease { get; set; } = true;
|
||||
public string MinVersion { get; set; }
|
||||
public string[] RequiredWorkloads { get; set; } = Array.Empty<string>();
|
||||
}
|
||||
public static KoreBuildSettings Load(string filePath)
|
||||
{
|
||||
using (var file = File.OpenText(filePath))
|
||||
using (var json = new JsonTextReader(file))
|
||||
{
|
||||
var serializer = new JsonSerializer();
|
||||
return serializer.Deserialize<KoreBuildSettings>(json);
|
||||
}
|
||||
}
|
||||
|
||||
private class KoreBuildToolsetConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => typeof(KoreBuildToolset).IsAssignableFrom(objectType);
|
||||
public override bool CanWrite { get; } = false;
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var toolsets = new List<KoreBuildToolset>();
|
||||
|
||||
var obj = JObject.Load(reader);
|
||||
|
||||
foreach (var prop in obj.Properties())
|
||||
{
|
||||
switch (prop.Name.ToLowerInvariant())
|
||||
{
|
||||
case "visualstudio":
|
||||
var vs = prop.Value.ToObject<VisualStudioToolset>();
|
||||
toolsets.Add(vs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return toolsets;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class RequiredPlatformConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => typeof(RequiredPlatforms).IsAssignableFrom(objectType);
|
||||
public override bool CanWrite { get; } = false;
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.Undefined:
|
||||
case JsonToken.Null:
|
||||
return RequiredPlatforms.None;
|
||||
case JsonToken.Boolean:
|
||||
var asBool = (bool)reader.Value;
|
||||
return asBool
|
||||
? RequiredPlatforms.All
|
||||
: RequiredPlatforms.None;
|
||||
case JsonToken.String:
|
||||
return Parse(reader.Value as string);
|
||||
case JsonToken.StartArray:
|
||||
var jArray = JArray.ReadFrom(reader);
|
||||
var platforms = RequiredPlatforms.None;
|
||||
foreach (var value in jArray)
|
||||
{
|
||||
platforms |= Parse(value.Value<string>());
|
||||
}
|
||||
return platforms;
|
||||
default:
|
||||
throw new JsonReaderException("Unexpected format in korebuild.json at " + reader.Path + ". This should be a boolean or an array.");
|
||||
}
|
||||
}
|
||||
|
||||
private RequiredPlatforms Parse(string name)
|
||||
{
|
||||
switch (name.ToLowerInvariant())
|
||||
{
|
||||
case "windows":
|
||||
return RequiredPlatforms.Windows;
|
||||
case "linux":
|
||||
return RequiredPlatforms.Linux;
|
||||
case "osx":
|
||||
case "macos":
|
||||
return RequiredPlatforms.MacOS;
|
||||
default:
|
||||
throw new ArgumentException("Unrecognized plaform named " + name);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,72 @@
|
|||
{
|
||||
"title": "Config file for KoreBuild",
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"$schema": "http://json-schema.org/draft-06/hyper-schema",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
"platforms": {
|
||||
"oneOf": [
|
||||
{
|
||||
"properties": {
|
||||
"required": {
|
||||
"description": "Visual Studio is required to build this repo. Defaults to true if not specified.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"required": {
|
||||
"description": "Visual Studio is required to build this repo. Defaults to true if not specified.",
|
||||
"type": "array",
|
||||
"default": [
|
||||
"windows",
|
||||
"linux",
|
||||
"macos"
|
||||
],
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"windows",
|
||||
"linux",
|
||||
"macos"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"visualstudio": {
|
||||
"type": "object",
|
||||
"description": "Defines the requirements for Visual Studio installation.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/platforms"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"includePrerelease": {
|
||||
"description": "Include pre-release versions when searching for a version of Visual Studio",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"requiredWorkloads": {
|
||||
"type": "array",
|
||||
"description": "A list of workloads that must be installed. See https://aka.ms/vs/workloads.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"minVersion": {
|
||||
"type": "string",
|
||||
"description": "The minimum version of Visual Studio required."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"toolsSource": {
|
||||
"description": "The remote source used to download KoreBuild. Can be a file path.",
|
||||
|
@ -17,6 +82,15 @@
|
|||
"rel/2.0.0",
|
||||
"rel/2.0.2"
|
||||
]
|
||||
},
|
||||
"toolsets": {
|
||||
"description": "Lists required toolsets for this repository.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"visualstudio": {
|
||||
"$ref": "#/definitions/visualstudio"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче