namespace ReleaseBuilder.Build; public static partial class Command { /// /// Main compilation of projects /// private static class Compile { /// /// Builds the projects listed in for the distinct /// /// The base solution folder /// The folder where builds should be placed /// The projects to build /// Projects that are only for the Windows targets /// Projects that are only needed for GUI builds /// The targets to build /// The release info to use for the build /// A flag that allows re-using existing builds /// The runtime configuration /// A task that completes when the build is done public static async Task BuildProjects(string baseDir, string buildDir, IEnumerable sourceProjects, IEnumerable windowsOnlyProjects, IEnumerable guiProjects, IEnumerable buildTargets, ReleaseInfo releaseInfo, bool keepBuilds, RuntimeConfig rtcfg) { // For tracing, create a log folder and store all logs there var logFolder = Path.Combine(buildDir, "logs"); Directory.CreateDirectory(logFolder); // Get the unique build targets (ignoring the package type) var buildArchTargets = buildTargets.DistinctBy(x => (x.OS, x.Arch, x.Interface)).ToArray(); if (buildArchTargets.Length == 1) Console.WriteLine($"Building single release: {buildArchTargets.First().BuildTargetString}"); else Console.WriteLine($"Building {buildArchTargets.Length} versions"); foreach (var target in buildArchTargets) { var outputFolder = Path.Combine(buildDir, target.BuildTargetString); // Faster iteration for debugging is to keep the build folder if (keepBuilds && Directory.Exists(outputFolder)) { Console.WriteLine($"Skipping build as output exists for {target.BuildTargetString}"); } else { var tmpfolder = Path.Combine(buildDir, target.BuildTargetString + "-tmp"); Console.WriteLine($"Building {target.BuildTargetString} ..."); foreach (var proj in sourceProjects) { if (target.OS != OSType.Windows && windowsOnlyProjects.Contains(proj)) continue; if (target.Interface == InterfaceType.Cli && guiProjects.Contains(proj)) continue; // TODO: Self contained builds are bloating the build size // Alternative is to require the .NET runtime to be installed // Fix any RIDs that differ from .NET SDK var archstring = target.Arch switch { ArchType.Arm7 => $"{target.OSString}-arm", _ => target.BuildArchString }; var command = new string[] { "dotnet", "publish", proj, "-c", "Release", "-o", tmpfolder, "-r", archstring, $"/p:AssemblyVersion={releaseInfo.Version}", $"/p:Version={releaseInfo.Version}-{releaseInfo.Channel}-{releaseInfo.Timestamp:yyyyMMdd}", "--self-contained", "true" }; await ProcessHelper.ExecuteWithLog(command, workingDirectory: tmpfolder, logFolder: logFolder, logFilename: (pid, isStdOut) => $"{Path.GetFileNameWithoutExtension(proj)}.{target.BuildTargetString}.{pid}.{(isStdOut ? "stdout" : "stderr")}.log"); } // Perform any post-build steps, cleaning and signing as needed await PostCompile.PrepareTargetDirectory(baseDir, tmpfolder, target.OS, target.BuildTargetString, rtcfg, keepBuilds); Directory.Move(tmpfolder, outputFolder); } Console.WriteLine("Completed!"); } } } }