Add support for specifying NodeJS as a required toolset
This commit is contained in:
Родитель
7e24ef1862
Коммит
502f38938f
|
@ -42,6 +42,8 @@ KoreBuild can be configured by adding a 'korebuild.json' file into the root fold
|
|||
|
||||
Example:
|
||||
```js
|
||||
// NB: Don't actually use comments in JSON files. PowerShell's ConvertFrom-Json will throw an error.
|
||||
|
||||
{
|
||||
// add this for editor auto-completion :)
|
||||
"$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json",
|
||||
|
@ -66,6 +68,11 @@ Example:
|
|||
|
||||
// This tool is only required on Windows.
|
||||
"required": [ "windows" ]
|
||||
},
|
||||
|
||||
"nodejs": {
|
||||
"required": true,
|
||||
"minVersion": "8.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// 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.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using KoreBuild.Tasks.Utilities;
|
||||
|
@ -20,17 +22,26 @@ namespace KoreBuild.Tasks
|
|||
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.
|
||||
/// The path to MSBuild.exe (x86) if the 'visualstudio' toolset was specified in korebuild.json.
|
||||
/// It will be empty if not specified or 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.
|
||||
/// The path to MSBuild.exe (x64) if the 'visualstudio' toolset was specified in korebuild.json.
|
||||
/// It will be empty if not specified or if this file does not exist.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public string VisualStudioMSBuildx64Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to NodeJS.exe if the 'nodejs' toolset was specified in korebuild.json.
|
||||
/// It will be empty if not specified.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public string NodeJSPath { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
if (!File.Exists(ConfigFile))
|
||||
|
@ -54,6 +65,9 @@ namespace KoreBuild.Tasks
|
|||
case KoreBuildSettings.VisualStudioToolset vs:
|
||||
GetVisualStudio(vs);
|
||||
break;
|
||||
case KoreBuildSettings.NodeJSToolset node:
|
||||
GetNode(node);
|
||||
break;
|
||||
default:
|
||||
Log.LogWarning("Toolset checks not implemented for " + toolset.GetType().Name);
|
||||
break;
|
||||
|
@ -93,5 +107,94 @@ namespace KoreBuild.Tasks
|
|||
VisualStudioMSBuildx86Path = vs.GetMSBuildx86SubPath();
|
||||
VisualStudioMSBuildx64Path = vs.GetMSBuildx64SubPath();
|
||||
}
|
||||
|
||||
private void GetNode(KoreBuildSettings.NodeJSToolset nodeToolset)
|
||||
{
|
||||
var nodePath = EnvironmentHelper.GetCommandOnPath("nodejs") ?? EnvironmentHelper.GetCommandOnPath("node");
|
||||
|
||||
var required = IsRequiredOnThisPlatform(nodeToolset.Required);
|
||||
|
||||
if (string.IsNullOrEmpty(nodePath))
|
||||
{
|
||||
LogFailure(
|
||||
isError: required,
|
||||
message: $"Could not find NodeJS on PATH.");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.LogMessage(MessageImportance.Low, "Found NodeJS in " + nodePath);
|
||||
|
||||
if (nodeToolset.MinVersion == null)
|
||||
{
|
||||
NodeJSPath = nodePath;
|
||||
return;
|
||||
}
|
||||
|
||||
var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = nodePath,
|
||||
Arguments = "--version",
|
||||
RedirectStandardOutput = true,
|
||||
});
|
||||
process.WaitForExit();
|
||||
|
||||
if (process.ExitCode != 0)
|
||||
{
|
||||
LogFailure(
|
||||
isError: required,
|
||||
message: $"Found NodeJS in '{nodePath}', but could not determine the version of NodeJS installed. 'node --version' failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
var nodeVersionString = process.StandardOutput.ReadToEnd()?.Trim()?.TrimStart('v');
|
||||
if (!Version.TryParse(nodeVersionString, out var nodeVersion))
|
||||
{
|
||||
LogFailure(
|
||||
isError: required,
|
||||
message: $"Found NodeJS in '{nodePath}', but could not determine the version of NodeJS installed. 'node --version' returned '{nodeVersionString}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodeVersion < nodeToolset.MinVersion)
|
||||
{
|
||||
LogFailure(
|
||||
isError: required,
|
||||
message: $"Found NodeJS in '{nodePath}', but its version '{nodeVersionString}' did not meet the required minimum version '{nodeToolset.MinVersion}' as specified in '{ConfigFile}'");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.LogMessage(MessageImportance.High, "Using NodeJS {0} from {1}", nodeVersionString, nodePath);
|
||||
NodeJSPath = nodePath;
|
||||
}
|
||||
|
||||
private void LogFailure(bool isError, string message)
|
||||
{
|
||||
if (isError)
|
||||
{
|
||||
Log.LogError(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.LogWarning(message);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsRequiredOnThisPlatform(KoreBuildSettings.RequiredPlatforms platforms)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return (platforms & KoreBuildSettings.RequiredPlatforms.Windows) != 0;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return (platforms & KoreBuildSettings.RequiredPlatforms.Linux) != 0;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return (platforms & KoreBuildSettings.RequiredPlatforms.MacOS) != 0;
|
||||
}
|
||||
|
||||
return platforms != KoreBuildSettings.RequiredPlatforms.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
// 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 System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace KoreBuild.Tasks.Utilities
|
||||
{
|
||||
internal class EnvironmentHelper
|
||||
{
|
||||
private static string[] _searchPaths;
|
||||
private static string[] _executableExtensions;
|
||||
|
||||
static EnvironmentHelper()
|
||||
{
|
||||
_searchPaths = Environment.GetEnvironmentVariable("PATH")
|
||||
.Split(Path.PathSeparator)
|
||||
.Select(p => p.Trim('"'))
|
||||
.ToArray();
|
||||
|
||||
_executableExtensions = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
? Environment.GetEnvironmentVariable("PATHEXT").Split(';').Select(e => e.ToLower().Trim('"')).ToArray()
|
||||
: Array.Empty<string>();
|
||||
}
|
||||
|
||||
public static string GetCommandOnPath(string exeName)
|
||||
{
|
||||
return _searchPaths.Join(
|
||||
_executableExtensions,
|
||||
p => true,
|
||||
e => true,
|
||||
(p, e) => Path.Combine(p, exeName + e))
|
||||
.FirstOrDefault(File.Exists);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -115,6 +115,7 @@
|
|||
<GetToolsets ConfigFile="$(KoreBuildConfigFile)">
|
||||
<Output TaskParameter="VisualStudioMSBuildx86Path" PropertyName="VisualStudioMSBuildx86Path" />
|
||||
<Output TaskParameter="VisualStudioMSBuildx64Path" PropertyName="VisualStudioMSBuildx64Path" />
|
||||
<Output TaskParameter="NodeJSPath" PropertyName="NodeJSPath" />
|
||||
</GetToolsets>
|
||||
</Target>
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace KoreBuild.Tasks.Tests
|
||||
|
@ -96,5 +97,37 @@ namespace KoreBuild.Tasks.Tests
|
|||
var vs = Assert.IsType<KoreBuildSettings.VisualStudioToolset>(toolset);
|
||||
Assert.Equal(platforms, vs.Required);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItDeserializesNodeJSToolsetWithVersion()
|
||||
{
|
||||
File.WriteAllText(_configFile, @"
|
||||
{
|
||||
""toolsets"": {
|
||||
""nodejs"": {
|
||||
""minVersion"": ""8.0""
|
||||
}
|
||||
}
|
||||
}");
|
||||
var settings = KoreBuildSettings.Load(_configFile);
|
||||
var toolset = Assert.Single(settings.Toolsets);
|
||||
|
||||
var node = Assert.IsType<KoreBuildSettings.NodeJSToolset>(toolset);
|
||||
Assert.Equal(new Version(8, 0), node.MinVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItFailsIfVersionIsNotValid()
|
||||
{
|
||||
File.WriteAllText(_configFile, @"
|
||||
{
|
||||
""toolsets"": {
|
||||
""nodejs"": {
|
||||
""minVersion"": ""banana""
|
||||
}
|
||||
}
|
||||
}");
|
||||
Assert.Throws<JsonSerializationException>(() => KoreBuildSettings.Load(_configFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace KoreBuild
|
||||
|
@ -42,6 +43,13 @@ namespace KoreBuild
|
|||
public string MinVersion { get; set; }
|
||||
public string[] RequiredWorkloads { get; set; } = Array.Empty<string>();
|
||||
}
|
||||
|
||||
public class NodeJSToolset : KoreBuildToolset
|
||||
{
|
||||
[JsonConverter(typeof(VersionConverter))]
|
||||
public Version MinVersion { get; set; }
|
||||
}
|
||||
|
||||
public static KoreBuildSettings Load(string filePath)
|
||||
{
|
||||
using (var file = File.OpenText(filePath))
|
||||
|
@ -65,14 +73,22 @@ namespace KoreBuild
|
|||
|
||||
foreach (var prop in obj.Properties())
|
||||
{
|
||||
KoreBuildToolset toolset;
|
||||
switch (prop.Name.ToLowerInvariant())
|
||||
{
|
||||
case "visualstudio":
|
||||
var vs = prop.Value.ToObject<VisualStudioToolset>();
|
||||
toolsets.Add(vs);
|
||||
toolset = prop.Value.ToObject<VisualStudioToolset>();
|
||||
break;
|
||||
case "nodejs":
|
||||
toolset = prop.Value.ToObject<NodeJSToolset>();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (toolset != null)
|
||||
{
|
||||
toolsets.Add(toolset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
{
|
||||
"properties": {
|
||||
"required": {
|
||||
"description": "Visual Studio is required to build this repo. Defaults to true if not specified.",
|
||||
"description": "This toolset is required to build this repo. Defaults to true if not specified.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
|||
{
|
||||
"properties": {
|
||||
"required": {
|
||||
"description": "Visual Studio is required to build this repo. Defaults to true if not specified.",
|
||||
"description": "This toolset is required to build this repo. Defaults to true if not specified.",
|
||||
"type": "array",
|
||||
"default": [
|
||||
"windows",
|
||||
|
@ -37,6 +37,23 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"nodejs": {
|
||||
"type": "object",
|
||||
"description": "Defines the requirements for a NodeJS installation.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/platforms"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"minVersion": {
|
||||
"type": "string",
|
||||
"description": "The minimum version of NodeJS required. Must contain at least <major>.<minor>, but can also be <major>.<minor>.<patch>"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"visualstudio": {
|
||||
"type": "object",
|
||||
"description": "Defines the requirements for Visual Studio installation.",
|
||||
|
@ -89,6 +106,9 @@
|
|||
"properties": {
|
||||
"visualstudio": {
|
||||
"$ref": "#/definitions/visualstudio"
|
||||
},
|
||||
"nodejs": {
|
||||
"$ref": "#/definitions/nodejs"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче