Skip to content

Commit 75a439c

Browse files
authored
Merge pull request #10 from microdee/bugfix/standalone-xmake
More isolated handling of XMake, CMake and VCPKG
2 parents 4278a14 + 5bff687 commit 75a439c

File tree

7 files changed

+178
-31
lines changed

7 files changed

+178
-31
lines changed

md.Nuke.Cola/ErrorHandling.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public record Attempt(Exception[]? Error = null)
2323
public record ValueOrError<T>(T? Value = default, Exception[]? Error = null)
2424
{
2525
public static implicit operator ValueOrError<T> (T val) => new(val);
26-
public static implicit operator ValueOrError<T> (Exception[] e) => new(Error: e);
26+
public static implicit operator ValueOrError<T> (Exception[]? e) => new(Error: e);
2727
public static implicit operator ValueOrError<T> (Exception e) => new(Error: [e]);
2828
public static implicit operator T? (ValueOrError<T> from) => from.Value;
2929
public static implicit operator Exception? (ValueOrError<T> from) => from.Error?[0];
@@ -51,6 +51,21 @@ public static ValueOrError<T> TryGet<T>(Func<T> getter, Action<Exception>? onFai
5151
}
5252
}
5353

54+
/// <summary>
55+
/// Work on the value inside a ValueOrError but only if input ValueOrError is valid. Return aggregated errors
56+
/// otherwise.
57+
/// </summary>
58+
/// <param name="self"></param>
59+
/// <param name="transform"></param>
60+
/// <typeparam name="TResult"></typeparam>
61+
/// <typeparam name="TInput"></typeparam>
62+
/// <returns></returns>
63+
public static ValueOrError<TResult> Transform<TResult, TInput>(this ValueOrError<TInput> self, Func<TInput, TResult> transform)
64+
{
65+
if (!self) return self.Error;
66+
return TryGet(() => transform(self.Get()));
67+
}
68+
5469
/// <summary>
5570
/// If input ValueOrError is an error then attempt to execute the input getter function
5671
/// (which may also fail)

md.Nuke.Cola/Tooling/CMakeTasks.cs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Runtime.CompilerServices;
5+
using System.Runtime.InteropServices;
6+
using System.Threading.Tasks;
7+
using Microsoft.CodeAnalysis;
8+
using Nuke.Common;
9+
using Nuke.Common.IO;
10+
using Nuke.Common.Tooling;
11+
using Nuke.Common.Tools.PowerShell;
12+
using Nuke.Common.Utilities;
13+
using Serilog;
14+
using static Nuke.Cola.Cola;
15+
16+
namespace Nuke.Cola.Tooling;
17+
18+
/// <summary>
19+
/// CMake is a versatile build tool for C and C++ (in 99% of cases)
20+
/// </summary>
21+
public static class CMakeTasks
22+
{
23+
public const string LatestVersion = "4.1.2";
24+
internal static string GetArchiveName(string version = LatestVersion)
25+
=> (plat: EnvironmentInfo.Platform, arch: RuntimeInformation.OSArchitecture) switch
26+
{
27+
(PlatformFamily.Windows, Architecture.X64) => $"cmake-{version}-windows-x86_64.zip",
28+
(PlatformFamily.Windows, Architecture.X86) => $"cmake-{version}-windows-i386.zip",
29+
(PlatformFamily.Windows, Architecture.Arm64) => $"cmake-{version}-windows-arm64.zip",
30+
(PlatformFamily.Linux, Architecture.X64) => $"cmake-{version}-linux-x86_64.tar.gz",
31+
(PlatformFamily.Linux, Architecture.Arm64) => $"cmake-{version}-linux-aarch64.tar.gz",
32+
(PlatformFamily.OSX, _) => $"cmake-{version}-macos-universal.tar.gz",
33+
var other => throw new Exception($"Trying to use CMake on an unsupported platform: {other.plat} {other.arch}")
34+
};
35+
36+
public static AbsolutePath GetLocalCMakeBin(string version = LatestVersion)
37+
{
38+
var archiveName = GetArchiveName(version);
39+
var subfolderName = archiveName
40+
.Replace(".zip", "")
41+
.Replace(".tar.gz", "");
42+
43+
var localPath = NukeBuild.TemporaryDirectory / "cmake";
44+
return EnvironmentInfo.Platform == PlatformFamily.OSX
45+
? localPath / subfolderName
46+
: localPath / subfolderName / "bin";
47+
}
48+
49+
/// <summary>
50+
/// Get CMake or an error if downloading it has failed.
51+
/// </summary>
52+
public static ValueOrError<Tool> TryGetCMake(string version = LatestVersion) => ErrorHandling.TryGet(() =>
53+
{
54+
var archiveName = GetArchiveName(version);
55+
var subfolderName = archiveName
56+
.Replace(".zip", "")
57+
.Replace(".tar.gz", "");
58+
59+
var localPath = NukeBuild.TemporaryDirectory / "cmake";
60+
if (!(localPath / subfolderName).DirectoryExists())
61+
{
62+
var downloadPath = localPath / archiveName;
63+
Log.Information("Downloading CMake {0}", archiveName);
64+
HttpTasks.HttpDownloadFile(
65+
$"https://github.com/Kitware/CMake/releases/download/v{LatestVersion}/{archiveName}",
66+
downloadPath
67+
);
68+
69+
Log.Information("Extracting CMake {0}", subfolderName);
70+
if (archiveName.EndsWithOrdinalIgnoreCase(".zip"))
71+
{
72+
downloadPath.UnZipTo(localPath);
73+
}
74+
else if (archiveName.EndsWithOrdinalIgnoreCase(".tar.gz"))
75+
{
76+
downloadPath.UnTarGZipTo(localPath);
77+
}
78+
}
79+
var programPath = EnvironmentInfo.Platform switch
80+
{
81+
PlatformFamily.Windows => localPath / subfolderName / "bin" / "cmake.exe",
82+
PlatformFamily.Linux => localPath / subfolderName / "bin" / "cmake",
83+
PlatformFamily.OSX => localPath / subfolderName / "CMake.app",
84+
var other => throw new Exception($"Trying to use CMake on an unsupported platform: {other}")
85+
};
86+
return ToolResolver.GetTool(programPath);
87+
});
88+
89+
public static ValueOrError<Tool> EnsureCMake => TryGetCMake();
90+
91+
/// <summary>
92+
/// Get CMake. It throws an exception if setup has failed.
93+
/// </summary>
94+
public static Tool CMake => EnsureCMake.Get();
95+
}

md.Nuke.Cola/Tooling/ToolCola.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Text;
55
using System.Threading.Tasks;
66
using Nuke.Common;
7+
using Nuke.Common.IO;
78
using Nuke.Common.Tooling;
89
using Nuke.Common.Utilities;
910
using Serilog;
@@ -315,6 +316,15 @@ public static Tool WithEnvVars(this Tool tool, bool includeParentEnvironment, pa
315316
/// </summary>
316317
public static Tool WithEnvVars(this Tool tool, params (string key, object value)[] items)
317318
=> tool.With(EnvVars(items));
319+
320+
/// <summary>
321+
/// Add an input path to this tool's PATH list. It won't be added if input path is already in there.
322+
/// </summary>
323+
public static Tool WithPathVar(this Tool tool, AbsolutePath path)
324+
=> tool.WithEnvVar(
325+
"PATH",
326+
EnvironmentInfo.Paths.Union([ path.ToString() ]).JoinSemicolon()
327+
);
318328

319329
/// <summary>
320330
/// A more comfortable passing of environment variables. This will also pass on parent environment
@@ -334,6 +344,15 @@ public static ToolEx WithEnvVars(this ToolEx tool, params (string key, object va
334344
public static ToolEx WithEnvVars(this ToolEx tool, bool includeParentEnvironment, params (string key, object value)[] items)
335345
=> tool.With(EnvVars(includeParentEnvironment, items));
336346

347+
/// <summary>
348+
/// Add an input path to this tool's PATH list. It won't be added if input path is already in there.
349+
/// </summary>
350+
public static ToolEx WithPathVar(this ToolEx tool, AbsolutePath path)
351+
=> tool.WithEnvVar(
352+
"PATH",
353+
EnvironmentInfo.Paths.Union([ path.ToString() ]).JoinSemicolon()
354+
);
355+
337356
/// <summary>
338357
/// Removes ANSI escape sequences from the output of a Tool (remove color data for example)
339358
/// </summary>

md.Nuke.Cola/Tooling/VcpkgTasks.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,10 @@ public static ValueOrError<Tool> EnsureVcpkg { get
4848

4949
if (vcpkgPath.FileExists())
5050
return ToolResolver.GetTool(vcpkgPath);
51-
52-
return ErrorHandling.TryGet(() => ToolResolver.GetPathTool("vcpkg"))
53-
.Else(() =>
54-
{
55-
Log.Warning("VCPKG was not installed or not yet setup for this project. Setting up a project specific instance");
56-
Setup();
57-
return ToolResolver.GetTool(vcpkgPath);
58-
})
59-
.Get();
51+
52+
Log.Warning("Installing VCPKG for this project in {0}", VcpkgPathInProject);
53+
Setup();
54+
return ToolResolver.GetTool(vcpkgPath);
6055
}}
6156

6257
/// <summary>

md.Nuke.Cola/Tooling/XMakeTasks.cs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Runtime.CompilerServices;
5+
using System.Runtime.InteropServices;
56
using System.Threading.Tasks;
7+
using Microsoft.CodeAnalysis;
68
using Nuke.Common;
9+
using Nuke.Common.IO;
710
using Nuke.Common.Tooling;
811
using Nuke.Common.Tools.PowerShell;
12+
using Serilog;
913
using static Nuke.Cola.Cola;
1014

1115
namespace Nuke.Cola.Tooling;
@@ -16,21 +20,38 @@ namespace Nuke.Cola.Tooling;
1620
/// </summary>
1721
public static class XMakeTasks
1822
{
19-
internal static void Setup()
20-
{
21-
if (EnvironmentInfo.Platform == PlatformFamily.Windows)
22-
PowerShellTasks.PowerShell(
23-
"-Command { iex (iwr 'https://xmake.io/psget.text').ToString() }",
24-
environmentVariables: MakeDictionary(("CI", "1"))
25-
);
26-
else
27-
ProcessTasks.StartShell("curl -fsSL https://xmake.io/shget.text | bash").AssertWaitForExit();
28-
}
23+
public const string LatestVersion = "3.0.4";
24+
internal static string GetBundleAppName(string version = LatestVersion)
25+
=> (plat: EnvironmentInfo.Platform, arch: RuntimeInformation.OSArchitecture) switch
26+
{
27+
(PlatformFamily.Windows, Architecture.X64) => $"xmake-bundle-v{version}.win64.exe",
28+
(PlatformFamily.Windows, Architecture.X86) => $"xmake-bundle-v{version}.win32.exe",
29+
(PlatformFamily.Windows, Architecture.Arm64) => $"xmake-bundle-v{version}.arm64.exe",
30+
(PlatformFamily.Linux, Architecture.X64) => $"xmake-bundle-v{version}.linux.x86_64",
31+
(PlatformFamily.OSX, Architecture.Arm64) => $"xmake-bundle-v{version}.macos.arm64",
32+
(PlatformFamily.OSX, Architecture.X64) => $"xmake-bundle-v{version}.macos.x86_64",
33+
var other => throw new Exception($"Trying to use XMake on an unsupported platform: {other.plat} {other.arch}")
34+
};
2935

3036
/// <summary>
31-
/// Get XMake or an error if setup has failed.
37+
/// Get XMake or an error if downloading it has failed.
3238
/// </summary>
33-
public static ValueOrError<Tool> EnsureXMake => ToolCola.Use("xmake", Setup);
39+
public static ValueOrError<Tool> TryGetXMake(string version = LatestVersion) => ErrorHandling.TryGet(() =>
40+
{
41+
var bundleAppName = GetBundleAppName(version);
42+
var xmakePath = NukeBuild.TemporaryDirectory / bundleAppName;
43+
if (!xmakePath.FileExists())
44+
{
45+
Log.Information("Downloading XMake {0}", bundleAppName);
46+
HttpTasks.HttpDownloadFile(
47+
$"https://github.com/xmake-io/xmake/releases/download/v{LatestVersion}/{bundleAppName}",
48+
xmakePath
49+
);
50+
}
51+
return ToolResolver.GetTool(xmakePath);
52+
});
53+
54+
public static ValueOrError<Tool> EnsureXMake => TryGetXMake();
3455

3556
/// <summary>
3657
/// Get XMake. It throws an exception if setup has failed.

md.Nuke.Cola/Tooling/XRepoTasks.cs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ namespace Nuke.Cola.Tooling;
2020
public static class XRepoTasks
2121
{
2222
/// <summary>
23-
/// Get XRepo or an error if setup has failed.
23+
/// Get XRepo or an error if downloading it has failed.
2424
/// </summary>
25-
public static ValueOrError<Tool> EnsureXRepo => ToolCola.Use("xrepo", XMakeTasks.Setup);
25+
public static ValueOrError<Tool> EnsureXRepo => XMakeTasks.EnsureXMake
26+
.Transform(t => t.With("lua private.xrepo"));
2627

2728
/// <summary>
28-
/// Get XRepo. It throws an exception if setup has failed.
29+
/// Get XRepo. It throws an exception if downloading it has failed.
2930
/// </summary>
3031
public static Tool XRepo => EnsureXRepo.Get();
3132

@@ -36,12 +37,7 @@ private static void EnsureSupportedPackageManagers(ref Tool xrepo, string packag
3637
VcpkgTasks.EnsureVcpkg.Get($"VCPKG is needed for package(s) {package} but it couldn't be installed");
3738
if (VcpkgTasks.VcpkgPathInProject.DirectoryExists())
3839
{
39-
// xrepo = xrepo.With(
40-
// environmentVariables: Cola.MakeDictionary(
41-
// ("VCPKG_ROOT", VcpkgTasks.VcpkgPathInProject.ToString())
42-
// )
43-
// );
44-
Environment.SetEnvironmentVariable("VCPKG_ROOT", VcpkgTasks.VcpkgPathInProject);
40+
xrepo = xrepo.WithEnvVar("VCPKG_ROOT", VcpkgTasks.VcpkgPathInProject);
4541
}
4642
}
4743
else if (package.Contains("conan::"))

tests/TestBuild/Build.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ public class Build : NukeBuild
5757
Log.Information("Linkdirs: {0}", conanSpdlogInfo[conanSpdlogSpec]?["fetchinfo"]?["linkdirs"]?.Value);
5858
});
5959

60+
public Target TestCMake => _ => _
61+
.Executes(() =>
62+
{
63+
CMakeTasks.CMake("--version");
64+
});
65+
6066
public Target BuildTestProgram => _ => _
6167
.Executes(() =>
6268
{

0 commit comments

Comments
 (0)