From 6d1f677177fcd48ce21ff922f4744ffe89f93745 Mon Sep 17 00:00:00 2001 From: June Rhodes Date: Tue, 18 Jun 2024 00:34:01 +1000 Subject: [PATCH 1/2] wip: platform extension --- .../BuildServerBuildExecutor.cs | 21 +- .../GitLabBuildNodeExecutor.cs | 134 +++++++++---- .../LocalBuildExecutor.cs | 157 ++++++++++----- .../BuildGraphGeneratorTests.cs | 52 +++-- .../InterpolatedStringTests.cs | 26 +++ .../BuildGraph/BuildGraphArgumentContext.cs | 11 ++ .../BuildGraph/BuildGraph_Plugin.xml | 42 ++++ .../DefaultBuildGraphArgumentGenerator.cs | 36 ++-- .../BuildGraph/DefaultBuildGraphExecutor.cs | 79 ++++---- .../IBuildGraphArgumentGenerator.cs | 12 +- .../BuildGraph/IBuildGraphExecutor.cs | 12 +- .../BuildGraph/RepositoryRoot.cs | 14 ++ .../Executors/BuildSpecification.cs | 7 +- .../DefaultMultiWorkspaceAllocator.cs | 79 ++++++++ .../IMultiWorkspaceAllocator.cs | 14 ++ .../MultiWorkspace/InterpolatedString.cs | 30 +++ .../MultiWorkspace/MultiWorkspace.cs | 28 +++ .../MultiWorkspaceDescriptor.cs | 11 ++ .../Plugin/BuildConfigPlugin.cs | 6 + .../BuildConfigPluginPlatformExtensionInfo.cs | 33 ++++ UET/uet/Commands/Build/BuildCommand.cs | 2 +- .../DefaultBuildSpecificationGenerator.cs | 183 +++++++++++------- 22 files changed, 721 insertions(+), 268 deletions(-) create mode 100644 UET/Redpoint.Uet.BuildPipeline.Tests/InterpolatedStringTests.cs create mode 100644 UET/Redpoint.Uet.BuildPipeline/BuildGraph/BuildGraphArgumentContext.cs create mode 100644 UET/Redpoint.Uet.BuildPipeline/BuildGraph/RepositoryRoot.cs create mode 100644 UET/Redpoint.Uet.BuildPipeline/MultiWorkspace/DefaultMultiWorkspaceAllocator.cs create mode 100644 UET/Redpoint.Uet.BuildPipeline/MultiWorkspace/IMultiWorkspaceAllocator.cs create mode 100644 UET/Redpoint.Uet.BuildPipeline/MultiWorkspace/InterpolatedString.cs create mode 100644 UET/Redpoint.Uet.BuildPipeline/MultiWorkspace/MultiWorkspace.cs create mode 100644 UET/Redpoint.Uet.BuildPipeline/MultiWorkspace/MultiWorkspaceDescriptor.cs create mode 100644 UET/Redpoint.Uet.Configuration/Plugin/BuildConfigPluginPlatformExtensionInfo.cs diff --git a/UET/Redpoint.Uet.BuildPipeline.Executors.BuildServer/BuildServerBuildExecutor.cs b/UET/Redpoint.Uet.BuildPipeline.Executors.BuildServer/BuildServerBuildExecutor.cs index be577ca1..d62e5b77 100644 --- a/UET/Redpoint.Uet.BuildPipeline.Executors.BuildServer/BuildServerBuildExecutor.cs +++ b/UET/Redpoint.Uet.BuildPipeline.Executors.BuildServer/BuildServerBuildExecutor.cs @@ -495,15 +495,22 @@ public virtual async Task ExecuteBuildAsync( { _logger.LogInformation("Generating BuildGraph JSON based on settings..."); buildGraph = await _buildGraphExecutor.GenerateGraphAsync( - engineWorkspace.Path, - temporaryWorkspace.Path, - buildSpecification.UETPath, - buildSpecification.ArtifactExportPath, + new BuildGraphArgumentContext + { + RepositoryRoot = new RepositoryRoot + { + BaseCodePath = temporaryWorkspace.Path, + PlatformCodePath = string.Empty, + }, + UetPath = buildSpecification.UETPath, + EnginePath = engineWorkspace.Path, + SharedStoragePath = OperatingSystem.IsWindows() + ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath + : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, + ArtifactExportPath = buildSpecification.ArtifactExportPath, + }, buildSpecification.BuildGraphScript, buildSpecification.BuildGraphTarget, - OperatingSystem.IsWindows() - ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath - : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, buildSpecification.BuildGraphSettings, buildSpecification.BuildGraphSettingReplacements, generationCaptureSpecification, diff --git a/UET/Redpoint.Uet.BuildPipeline.Executors.GitLab/GitLabBuildNodeExecutor.cs b/UET/Redpoint.Uet.BuildPipeline.Executors.GitLab/GitLabBuildNodeExecutor.cs index 7a7bfe42..b2a36478 100644 --- a/UET/Redpoint.Uet.BuildPipeline.Executors.GitLab/GitLabBuildNodeExecutor.cs +++ b/UET/Redpoint.Uet.BuildPipeline.Executors.GitLab/GitLabBuildNodeExecutor.cs @@ -15,6 +15,7 @@ using System.Threading; using System.Threading.Tasks; using Redpoint.Concurrency; + using Redpoint.Uet.BuildPipeline.MultiWorkspace; public class GitLabBuildNodeExecutor : IBuildNodeExecutor { @@ -24,6 +25,7 @@ public class GitLabBuildNodeExecutor : IBuildNodeExecutor private readonly IDynamicWorkspaceProvider _workspaceProvider; private readonly ISdkSetupForBuildExecutor _sdkSetupForBuildExecutor; private readonly IBuildGraphArgumentGenerator _buildGraphArgumentGenerator; + private readonly IMultiWorkspaceAllocator _multiWorkspaceAllocator; private readonly IDynamicProvider[] _pluginPrepare; private readonly IDynamicProvider[] _projectPrepare; @@ -34,7 +36,8 @@ public GitLabBuildNodeExecutor( IEngineWorkspaceProvider engineWorkspaceProvider, IDynamicWorkspaceProvider workspaceProvider, ISdkSetupForBuildExecutor sdkSetupForBuildExecutor, - IBuildGraphArgumentGenerator buildGraphArgumentGenerator) + IBuildGraphArgumentGenerator buildGraphArgumentGenerator, + IMultiWorkspaceAllocator multiWorkspaceAllocator) { _logger = logger; _buildGraphExecutor = buildGraphExecutor; @@ -42,6 +45,7 @@ public GitLabBuildNodeExecutor( _workspaceProvider = workspaceProvider; _sdkSetupForBuildExecutor = sdkSetupForBuildExecutor; _buildGraphArgumentGenerator = buildGraphArgumentGenerator; + _multiWorkspaceAllocator = multiWorkspaceAllocator; _pluginPrepare = serviceProvider.GetServices>().ToArray(); _projectPrepare = serviceProvider.GetServices>().ToArray(); } @@ -72,6 +76,9 @@ public async Task ExecuteBuildNodesAsync( var commit = System.Environment.GetEnvironmentVariable("CI_COMMIT_SHA")!; var executingNode = new NodeNameExecutionState(); + var baseRepository = System.Environment.GetEnvironmentVariable("BASE_CI_REPOSITORY_URL"); + var baseCommit = System.Environment.GetEnvironmentVariable("BASE_CI_COMMIT_SHA"); + _logger.LogTrace("Starting execution of nodes..."); try { @@ -80,8 +87,21 @@ public async Task ExecuteBuildNodesAsync( string.Empty, cancellationToken).ConfigureAwait(false)).AsAsyncDisposable(out var engineWorkspace).ConfigureAwait(false)) { - async Task ExecuteNodeInWorkspaceAsync(string nodeName, string targetWorkspacePath) + async Task ExecuteNodeInWorkspaceAsync( + string nodeName, + RepositoryRoot repositoryRoot) { + var buildGraphArgumentContext = new BuildGraphArgumentContext + { + RepositoryRoot = repositoryRoot, + UetPath = buildSpecification.UETPath, + EnginePath = engineWorkspace.Path, + SharedStoragePath = OperatingSystem.IsWindows() + ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath + : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, + ArtifactExportPath = buildSpecification.ArtifactExportPath, + }; + var globalEnvironmentVariablesWithSdk = await _sdkSetupForBuildExecutor.SetupForBuildAsync( buildSpecification, nodeName, @@ -92,13 +112,7 @@ async Task ExecuteNodeInWorkspaceAsync(string nodeName, string targetWorksp var preBuildGraphArguments = _buildGraphArgumentGenerator.GeneratePreBuildGraphArguments( buildSpecification.BuildGraphSettings, buildSpecification.BuildGraphSettingReplacements, - targetWorkspacePath, - buildSpecification.UETPath, - engineWorkspace.Path, - OperatingSystem.IsWindows() - ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath - : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, - buildSpecification.ArtifactExportPath); + buildGraphArgumentContext); if (preparePlugin != null && preparePlugin.Length > 0) { @@ -111,7 +125,7 @@ async Task ExecuteNodeInWorkspaceAsync(string nodeName, string targetWorksp .First(); var exitCode = await provider.RunBeforeBuildGraphAsync( byType, - targetWorkspacePath, + repositoryRoot.OutputPath, preBuildGraphArguments, cancellationToken).ConfigureAwait(false); if (exitCode != 0) @@ -133,7 +147,7 @@ async Task ExecuteNodeInWorkspaceAsync(string nodeName, string targetWorksp .First(); var exitCode = await provider.RunBeforeBuildGraphAsync( byType, - targetWorkspacePath, + repositoryRoot.OutputPath, preBuildGraphArguments, cancellationToken).ConfigureAwait(false); if (exitCode != 0) @@ -146,16 +160,10 @@ async Task ExecuteNodeInWorkspaceAsync(string nodeName, string targetWorksp _logger.LogTrace($"Starting: {nodeName}"); return await _buildGraphExecutor.ExecuteGraphNodeAsync( - engineWorkspace.Path, - targetWorkspacePath, - buildSpecification.UETPath, - buildSpecification.ArtifactExportPath, + buildGraphArgumentContext, buildSpecification.BuildGraphScript, buildSpecification.BuildGraphTarget, nodeName, - OperatingSystem.IsWindows() - ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath - : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, buildSpecification.BuildGraphSettings, buildSpecification.BuildGraphSettingReplacements, globalEnvironmentVariablesWithSdk, @@ -176,13 +184,15 @@ async Task ExecuteNodeInWorkspaceAsync(string nodeName, string targetWorksp cancellationToken).ConfigureAwait(false); } - async Task ExecuteNodesInWorkspaceAsync(string targetWorkspacePath) + async Task ExecuteNodesInWorkspaceAsync(RepositoryRoot repositoryRoot) { foreach (var nodeName in nodeNames) { await buildExecutionEvents.OnNodeStarted(nodeName).ConfigureAwait(false); executingNode.NodeName = nodeName; - var exitCode = await ExecuteNodeInWorkspaceAsync(nodeName, targetWorkspacePath).ConfigureAwait(false); + var exitCode = await ExecuteNodeInWorkspaceAsync( + nodeName, + repositoryRoot).ConfigureAwait(false); if (exitCode == 0) { _logger.LogTrace($"Finished: {nodeName} = Success"); @@ -204,31 +214,79 @@ async Task ExecuteNodesInWorkspaceAsync(string targetWorkspacePath) int overallExitCode; if (buildSpecification.Engine.IsEngineBuild) { - overallExitCode = await ExecuteNodesInWorkspaceAsync(engineWorkspace.Path).ConfigureAwait(false); + overallExitCode = await ExecuteNodesInWorkspaceAsync( + new RepositoryRoot + { + BaseCodePath = engineWorkspace.Path, + PlatformCodePath = string.Empty, + }).ConfigureAwait(false); } else { - _logger.LogTrace($"Obtaining workspace for build."); - await using ((await _workspaceProvider.GetWorkspaceAsync( - new GitWorkspaceDescriptor - { - RepositoryUrl = repository, - RepositoryCommitOrRef = commit, - AdditionalFolderLayers = Array.Empty(), - AdditionalFolderZips = Array.Empty(), - WorkspaceDisambiguators = nodeNames, - ProjectFolderName = buildSpecification.ProjectFolderName, - IsEngineBuild = false, - WindowsSharedGitCachePath = null, - MacSharedGitCachePath = null, - }, - cancellationToken).ConfigureAwait(false)).AsAsyncDisposable(out var targetWorkspace).ConfigureAwait(false)) + await using (await _multiWorkspaceAllocator.AllocateAsync()) + + var workspaces = new Dictionary(); + try { + _logger.LogTrace($"Obtaining workspace for build."); + workspaces.Add("base", await _workspaceProvider.GetWorkspaceAsync( + new GitWorkspaceDescriptor + { + RepositoryUrl = repository, + RepositoryCommitOrRef = commit, + AdditionalFolderLayers = Array.Empty(), + AdditionalFolderZips = Array.Empty(), + WorkspaceDisambiguators = nodeNames, + ProjectFolderName = buildSpecification.ProjectFolderName, + IsEngineBuild = false, + WindowsSharedGitCachePath = null, + MacSharedGitCachePath = null, + }, + cancellationToken).ConfigureAwait(false)); + + if (!string.IsNullOrWhiteSpace(baseRepository) && + !string.IsNullOrWhiteSpace(baseCommit)) + { + _logger.LogTrace($"Obtaining platform-specific workspace for build."); + workspaces.Add("platform", await _workspaceProvider.GetWorkspaceAsync( + new GitWorkspaceDescriptor + { + RepositoryUrl = baseRepository, + RepositoryCommitOrRef = baseCommit, + AdditionalFolderLayers = Array.Empty(), + AdditionalFolderZips = Array.Empty(), + WorkspaceDisambiguators = nodeNames, + ProjectFolderName = buildSpecification.ProjectFolderName, + IsEngineBuild = false, + WindowsSharedGitCachePath = null, + MacSharedGitCachePath = null, + }, + cancellationToken).ConfigureAwait(false)); + } + else + { + workspaces.Add("platform", null); + } + _logger.LogTrace($"Calling ExecuteNodesInWorkspaceAsync inside allocated workspace."); - overallExitCode = await ExecuteNodesInWorkspaceAsync(targetWorkspace.Path).ConfigureAwait(false); + overallExitCode = await ExecuteNodesInWorkspaceAsync(new RepositoryRoot + { + BaseCodePath = workspaces["base"]!.Path, + PlatformCodePath = workspaces["platform"]?.Path ?? string.Empty, + }).ConfigureAwait(false); _logger.LogTrace($"Finished ExecuteNodesInWorkspaceAsync with exit code '{overallExitCode}'."); } - _logger.LogTrace($"Released workspace for build."); + finally + { + foreach (var kv in workspaces) + { + if (kv.Value != null) + { + await kv.Value.DisposeAsync().ConfigureAwait(false); + } + } + _logger.LogTrace($"Released workspace for build."); + } } _logger.LogTrace($"Returning overall exit code '{overallExitCode}' from ExecuteBuildNodesAsync."); return overallExitCode; diff --git a/UET/Redpoint.Uet.BuildPipeline.Executors.Local/LocalBuildExecutor.cs b/UET/Redpoint.Uet.BuildPipeline.Executors.Local/LocalBuildExecutor.cs index d20be292..0df1f3ae 100644 --- a/UET/Redpoint.Uet.BuildPipeline.Executors.Local/LocalBuildExecutor.cs +++ b/UET/Redpoint.Uet.BuildPipeline.Executors.Local/LocalBuildExecutor.cs @@ -71,15 +71,15 @@ private sealed class DAGDependency } private async Task GetFolderWorkspaceAsync( - string buildGraphRepositoryRoot, + string sourcePath, string nodeName) { - if (_workspaceProvider.ProvidesFastCopyOnWrite && !string.IsNullOrWhiteSpace(buildGraphRepositoryRoot)) + if (_workspaceProvider.ProvidesFastCopyOnWrite && !string.IsNullOrWhiteSpace(sourcePath)) { return await _workspaceProvider.GetWorkspaceAsync( new FolderSnapshotWorkspaceDescriptor { - SourcePath = buildGraphRepositoryRoot, + SourcePath = sourcePath, WorkspaceDisambiguators = new[] { nodeName }, }, CancellationToken.None).ConfigureAwait(false); @@ -89,12 +89,47 @@ private async Task GetFolderWorkspaceAsync( return await _workspaceProvider.GetWorkspaceAsync( new FolderAliasWorkspaceDescriptor { - AliasedPath = buildGraphRepositoryRoot + AliasedPath = sourcePath }, CancellationToken.None).ConfigureAwait(false); } } + private static async Task ExecuteWithWorkspaces( + BuildSpecification buildSpecification, + Func> allocateWorkspace, + Func> execute) + { + var workspaces = new Dictionary(); + try + { + workspaces.Add( + "baseCode", + string.IsNullOrWhiteSpace(buildSpecification.BuildGraphRepositoryRootBaseCode) + ? null + : await allocateWorkspace(buildSpecification.BuildGraphRepositoryRootBaseCode).ConfigureAwait(false)); + workspaces.Add( + "platformCode", + string.IsNullOrWhiteSpace(buildSpecification.BuildGraphRepositoryRootPlatformCode) + ? null + : await allocateWorkspace(buildSpecification.BuildGraphRepositoryRootPlatformCode).ConfigureAwait(false)); + + return await execute( + workspaces["baseCode"]?.Path ?? string.Empty, + workspaces["platformCode"]?.Path ?? string.Empty).ConfigureAwait(false); + } + finally + { + foreach (var kv in workspaces) + { + if (kv.Value != null) + { + await kv.Value.DisposeAsync().ConfigureAwait(false); + } + } + } + } + private async Task ExecuteDAGNode( BuildSpecification buildSpecification, BuildConfigDynamic[]? preparePlugin, @@ -166,18 +201,24 @@ private async Task ExecuteDAGNode( globalEnvironmentVariables, cancellationToken).ConfigureAwait(false); - async Task ExecuteBuildInWorkspaceAsync(string targetWorkspacePath) + async Task ExecuteBuildInWorkspaceAsync( + string repositoryRootBaseCode, + string repositoryRootPlatformCode) { var preBuildGraphArguments = _buildGraphArgumentGenerator.GeneratePreBuildGraphArguments( buildSpecification.BuildGraphSettings, buildSpecification.BuildGraphSettingReplacements, - targetWorkspacePath, - buildSpecification.UETPath, - engineWorkspace.Path, - OperatingSystem.IsWindows() - ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath - : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, - buildSpecification.ArtifactExportPath); + new BuildGraphArgumentContext + { + RepositoryRootBaseCode = repositoryRootBaseCode, + RepositoryRootPlatformCode = repositoryRootPlatformCode, + UetPath = buildSpecification.UETPath, + EnginePath = engineWorkspace.Path, + SharedStoragePath = OperatingSystem.IsWindows() + ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath + : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, + ArtifactExportPath = buildSpecification.ArtifactExportPath, + }); if (preparePlugin != null && preparePlugin.Length > 0) { @@ -190,7 +231,9 @@ async Task ExecuteBuildInWorkspaceAsync(string targetWorkspacePath) .First(); var exitCode = await provider.RunBeforeBuildGraphAsync( byType, - targetWorkspacePath, + !string.IsNullOrWhiteSpace(repositoryRootPlatformCode) + ? repositoryRootPlatformCode + : repositoryRootBaseCode, preBuildGraphArguments, cancellationToken).ConfigureAwait(false); if (exitCode != 0) @@ -212,7 +255,9 @@ async Task ExecuteBuildInWorkspaceAsync(string targetWorkspacePath) .First(); var exitCode = await provider.RunBeforeBuildGraphAsync( byType, - targetWorkspacePath, + !string.IsNullOrWhiteSpace(repositoryRootPlatformCode) + ? repositoryRootPlatformCode + : repositoryRootBaseCode, preBuildGraphArguments, cancellationToken).ConfigureAwait(false); if (exitCode != 0) @@ -225,14 +270,20 @@ async Task ExecuteBuildInWorkspaceAsync(string targetWorkspacePath) _logger.LogTrace($"Starting: {node.Node.Name}"); return await _buildGraphExecutor.ExecuteGraphNodeAsync( - engineWorkspace!.Path, - targetWorkspacePath, - buildSpecification.UETPath, - buildSpecification.ArtifactExportPath, + new BuildGraphArgumentContext + { + RepositoryRootBaseCode = repositoryRootBaseCode, + RepositoryRootPlatformCode = repositoryRootPlatformCode, + UetPath = buildSpecification.UETPath, + EnginePath = engineWorkspace!.Path, + SharedStoragePath = OperatingSystem.IsWindows() + ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath + : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, + ArtifactExportPath = buildSpecification.ArtifactExportPath, + }, buildSpecification.BuildGraphScript, buildSpecification.BuildGraphTarget, node.Node.Name, - OperatingSystem.IsWindows() ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, buildSpecification.BuildGraphSettings, buildSpecification.BuildGraphSettingReplacements, globalEnvironmentVariablesWithSdk!, @@ -256,16 +307,23 @@ async Task ExecuteBuildInWorkspaceAsync(string targetWorkspacePath) int exitCode; if (buildSpecification.Engine.IsEngineBuild) { - exitCode = await ExecuteBuildInWorkspaceAsync(engineWorkspace.Path).ConfigureAwait(false); + exitCode = await ExecuteBuildInWorkspaceAsync( + engineWorkspace.Path, + string.Empty).ConfigureAwait(false); } else { - await using ((await GetFolderWorkspaceAsync( - buildSpecification.BuildGraphRepositoryRoot, - node.Node.Name).ConfigureAwait(false)).AsAsyncDisposable(out var targetWorkspace).ConfigureAwait(false)) - { - exitCode = await ExecuteBuildInWorkspaceAsync(targetWorkspace.Path).ConfigureAwait(false); - } + exitCode = await ExecuteWithWorkspaces( + buildSpecification, + async path => await GetFolderWorkspaceAsync( + path, + node.Node.Name).ConfigureAwait(false), + async (baseCode, platformCode) => + { + return await ExecuteBuildInWorkspaceAsync( + baseCode, + platformCode).ConfigureAwait(false); + }).ConfigureAwait(false); } if (exitCode == 0) { @@ -318,26 +376,33 @@ public async Task ExecuteBuildAsync( string.Empty, cancellationToken).ConfigureAwait(false)).AsAsyncDisposable(out var engineWorkspace).ConfigureAwait(false)) { - await using ((await GetFolderWorkspaceAsync( - buildSpecification.BuildGraphRepositoryRoot, - "Generate BuildGraph JSON").ConfigureAwait(false)).AsAsyncDisposable(out var targetWorkspace).ConfigureAwait(false)) - { - _logger.LogInformation("Generating BuildGraph JSON based on settings..."); - buildGraph = await _buildGraphExecutor.GenerateGraphAsync( - engineWorkspace.Path, - targetWorkspace.Path, - buildSpecification.UETPath, - buildSpecification.ArtifactExportPath, - buildSpecification.BuildGraphScript, - buildSpecification.BuildGraphTarget, - OperatingSystem.IsWindows() - ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath - : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, - buildSpecification.BuildGraphSettings, - buildSpecification.BuildGraphSettingReplacements, - generationCaptureSpecification, - cancellationToken).ConfigureAwait(false); - } + buildGraph = await ExecuteWithWorkspaces( + buildSpecification, + async path => await GetFolderWorkspaceAsync( + path, + "Generate BuildGraph JSON").ConfigureAwait(false), + async (baseCode, platformCode) => + { + _logger.LogInformation("Generating BuildGraph JSON based on settings..."); + return await _buildGraphExecutor.GenerateGraphAsync( + new BuildGraphArgumentContext + { + RepositoryRootBaseCode = baseCode, + RepositoryRootPlatformCode = platformCode, + UetPath = buildSpecification.UETPath, + EnginePath = engineWorkspace.Path, + SharedStoragePath = OperatingSystem.IsWindows() + ? buildSpecification.BuildGraphEnvironment.Windows.SharedStorageAbsolutePath + : buildSpecification.BuildGraphEnvironment.Mac!.SharedStorageAbsolutePath, + ArtifactExportPath = buildSpecification.ArtifactExportPath, + }, + buildSpecification.BuildGraphScript, + buildSpecification.BuildGraphTarget, + buildSpecification.BuildGraphSettings, + buildSpecification.BuildGraphSettingReplacements, + generationCaptureSpecification, + cancellationToken).ConfigureAwait(false); + }).ConfigureAwait(false); } var globalEnvironmentVariables = buildSpecification.GlobalEnvironmentVariables ?? new Dictionary(); diff --git a/UET/Redpoint.Uet.BuildPipeline.Tests/BuildGraphGeneratorTests.cs b/UET/Redpoint.Uet.BuildPipeline.Tests/BuildGraphGeneratorTests.cs index e58e40b8..de74b64b 100644 --- a/UET/Redpoint.Uet.BuildPipeline.Tests/BuildGraphGeneratorTests.cs +++ b/UET/Redpoint.Uet.BuildPipeline.Tests/BuildGraphGeneratorTests.cs @@ -40,20 +40,25 @@ public async void CanGenerateBuildGraphForProject() var generator = serviceProvider.GetRequiredService(); var buildGraph = await generator.GenerateGraphAsync( - @"E:\EpicGames\UE_5.2", - projectPath, - string.Empty, - string.Empty, + new BuildGraphArgumentContext + { + RepositoryRootOutput = projectPath, + RepositoryRootBaseCode = projectPath, + RepositoryRootPlatformCode = string.Empty, + UetPath = string.Empty, + EnginePath = @"E:\EpicGames\UE_5.2", + SharedStoragePath = Path.Combine(projectPath, ".uet", "shared-storage"), + ArtifactExportPath = string.Empty, + }, BuildGraphScriptSpecification.ForProject(), "End", - Path.Combine(projectPath, ".uet", "shared-storage"), new Dictionary { { $"UETPath", $"uet" }, - { $"TempPath", $"__REPOSITORY_ROOT__/.uet/tmp" }, - { $"ProjectRoot", $"__REPOSITORY_ROOT__" }, - { $"RepositoryRoot", $"__REPOSITORY_ROOT__" }, - { $"UProjectPath", $"__REPOSITORY_ROOT__/ExampleOSS.uproject" }, + { $"TempPath", $"__REPOSITORY_ROOT_OUTPUT__/.uet/tmp" }, + { $"ProjectRoot", $"__REPOSITORY_ROOT_BASE_CODE__" }, + { $"RepositoryRoot", $"__REPOSITORY_ROOT_BASE_CODE__" }, + { $"UProjectPath", $"__REPOSITORY_ROOT_BASE_CODE__/ExampleOSS.uproject" }, { $"Distribution", $"Default" }, { $"ExecuteBuild", $"true" }, { $"EditorTarget", $"ExampleOSSEditor" }, @@ -68,11 +73,12 @@ public async void CanGenerateBuildGraphForProject() { $"ServerConfigurations", $"" }, { $"MacPlatforms", $"IOS;Mac" }, { $"StrictIncludes", $"false" }, - { $"StageDirectory", $"__REPOSITORY_ROOT__/Saved/StagedBuilds" }, + { $"StageDirectory", $"__REPOSITORY_ROOT_OUTPUT__/Saved/StagedBuilds" }, }, new Dictionary { - { "__REPOSITORY_ROOT__", projectPath }, + { "__REPOSITORY_ROOT_OUTPUT__", projectPath }, + { "__REPOSITORY_ROOT_BASE_CODE__", projectPath }, }, CaptureSpecification.Passthrough, CancellationToken.None); @@ -96,19 +102,24 @@ public async void CanGenerateBuildGraphForPlugin() var generator = serviceProvider.GetRequiredService(); var buildGraph = await generator.GenerateGraphAsync( - @"E:\EpicGames\UE_5.2", - pluginPath, - string.Empty, - string.Empty, + new BuildGraphArgumentContext + { + RepositoryRootOutput = pluginPath, + RepositoryRootBaseCode = pluginPath, + RepositoryRootPlatformCode = string.Empty, + UetPath = string.Empty, + EnginePath = @"E:\EpicGames\UE_5.2", + SharedStoragePath = Path.Combine(pluginPath, ".uet", "shared-storage"), + ArtifactExportPath = string.Empty, + }, BuildGraphScriptSpecification.ForPlugin(), "End", - Path.Combine(pluginPath, ".uet", "shared-storage"), new Dictionary { { $"UETPath", $"uet" }, - { $"TempPath", $"__REPOSITORY_ROOT__/.uet/tmp" }, - { $"ProjectRoot", $"__REPOSITORY_ROOT__" }, - { $"PluginDirectory", $"__REPOSITORY_ROOT__/OnlineSubsystemRedpointEOS" }, + { $"TempPath", $"__REPOSITORY_ROOT_OUTPUT__/.uet/tmp" }, + { $"ProjectRoot", $"__REPOSITORY_ROOT_BASE_CODE__" }, + { $"PluginDirectory", $"__REPOSITORY_ROOT_BASE_CODE__/OnlineSubsystemRedpointEOS" }, { $"PluginName", $"OnlineSubsystemRedpointEOS" }, { $"Distribution", $"Default" }, { $"IsUnrealEngine5", $"true" }, @@ -137,7 +148,8 @@ public async void CanGenerateBuildGraphForPlugin() }, new Dictionary { - { "__REPOSITORY_ROOT__", pluginPath }, + { "__REPOSITORY_ROOT_OUTPUT__", pluginPath }, + { "__REPOSITORY_ROOT_BASE_CODE__", pluginPath }, }, CaptureSpecification.Passthrough, CancellationToken.None); diff --git a/UET/Redpoint.Uet.BuildPipeline.Tests/InterpolatedStringTests.cs b/UET/Redpoint.Uet.BuildPipeline.Tests/InterpolatedStringTests.cs new file mode 100644 index 00000000..ec2d4aa0 --- /dev/null +++ b/UET/Redpoint.Uet.BuildPipeline.Tests/InterpolatedStringTests.cs @@ -0,0 +1,26 @@ +namespace Redpoint.Uet.BuildPipeline.Tests +{ + using Redpoint.Uet.BuildPipeline.MultiWorkspace; + + public class InterpolatedStringTests + { + [Fact] + public void InterpolatedStringWorks() + { + var i = new InterpolatedString("abc_${env:INTERPOLATED_STRING_TEST}"); + + Assert.Equal( + "abc_${env:INTERPOLATED_STRING_TEST}", + i.PatternValue); + Assert.Equal( + "abc_", + i.EvaluatedString); + + System.Environment.SetEnvironmentVariable("INTERPOLATED_STRING_TEST", "abc"); + + Assert.Equal( + "abc_abc", + i.PatternValue); + } + } +} \ No newline at end of file diff --git a/UET/Redpoint.Uet.BuildPipeline/BuildGraph/BuildGraphArgumentContext.cs b/UET/Redpoint.Uet.BuildPipeline/BuildGraph/BuildGraphArgumentContext.cs new file mode 100644 index 00000000..19d0a780 --- /dev/null +++ b/UET/Redpoint.Uet.BuildPipeline/BuildGraph/BuildGraphArgumentContext.cs @@ -0,0 +1,11 @@ +namespace Redpoint.Uet.BuildPipeline.BuildGraph +{ + public readonly record struct BuildGraphArgumentContext + { + public required RepositoryRoot RepositoryRoot { get; init; } + public required string UetPath { get; init; } + public required string EnginePath { get; init; } + public required string SharedStoragePath { get; init; } + public required string ArtifactExportPath { get; init; } + } +} diff --git a/UET/Redpoint.Uet.BuildPipeline/BuildGraph/BuildGraph_Plugin.xml b/UET/Redpoint.Uet.BuildPipeline/BuildGraph/BuildGraph_Plugin.xml index 9da5e5f3..7fea7ce6 100644 --- a/UET/Redpoint.Uet.BuildPipeline/BuildGraph/BuildGraph_Plugin.xml +++ b/UET/Redpoint.Uet.BuildPipeline/BuildGraph/BuildGraph_Plugin.xml @@ -15,6 +15,10 @@