From f406f8eaa0293d178d24815b153a989d76a0e755 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Tue, 8 Oct 2024 13:08:53 -0700 Subject: [PATCH 01/24] add rust sdk --- Directory.Packages.props | 3 + src/Rust/CargoBuild.csproj | 26 +++ src/Rust/CargoBuildTask.cs | 375 +++++++++++++++++++++++++++++++++++++ src/Rust/sdk/Sdk.props | 92 +++++++++ src/Rust/sdk/Sdk.targets | 127 +++++++++++++ 5 files changed, 623 insertions(+) create mode 100644 src/Rust/CargoBuild.csproj create mode 100644 src/Rust/CargoBuildTask.cs create mode 100644 src/Rust/sdk/Sdk.props create mode 100644 src/Rust/sdk/Sdk.targets diff --git a/Directory.Packages.props b/Directory.Packages.props index c71c739..eb4210e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,6 +11,8 @@ + + @@ -18,6 +20,7 @@ + diff --git a/src/Rust/CargoBuild.csproj b/src/Rust/CargoBuild.csproj new file mode 100644 index 0000000..f464a59 --- /dev/null +++ b/src/Rust/CargoBuild.csproj @@ -0,0 +1,26 @@ + + + enable + enable + net6.0;net472 + true + 1.0.0 + MSBuild.CargoBuild + https://www.1eswiki.com/wiki/Using_Rust_with_CloudBuild + true + build\ + true + true + + true + false + $(NoWarn);NU1504;NU5100;NU5110;NU5111 + + + + + + + + + diff --git a/src/Rust/CargoBuildTask.cs b/src/Rust/CargoBuildTask.cs new file mode 100644 index 0000000..96c3dc2 --- /dev/null +++ b/src/Rust/CargoBuildTask.cs @@ -0,0 +1,375 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the MIT license. + +using Microsoft.Build.Definition; +using Microsoft.Build.Evaluation; +using Microsoft.Build.Evaluation.Context; +using Microsoft.Build.Execution; +using Microsoft.Build.Framework; +using Microsoft.Build.Graph; +using System.Diagnostics; +using System.Net.Http; +using System.Security.Cryptography; + +using File = System.IO.File; +using Task = Microsoft.Build.Utilities.Task; +using Tasks = System.Threading.Tasks; + +namespace MSBuild.CargoBuild +{ + /// + /// Builds rust projects using cargo. + /// + public class CargoBuildTask : Task + { + private static readonly string _tempPath = $"{Environment.GetEnvironmentVariable("TEMP")}"; + private static readonly string _rustUpBinary = $"{_tempPath}\\cargohome\\bin\\rustup.exe"; + private static readonly string _cargoPath = $"{_tempPath}\\cargohome\\bin\\cargo.exe"; + private static readonly string _rustInstallPath = $"{_tempPath}\\rustinstall"; + private static readonly string _rustUpInitBinary = $"{_rustInstallPath}\\rustup-init.exe"; + private static readonly Dictionary _envVars = new () { { "CARGO_HOME", $"{_tempPath}\\cargohome" }, { "RUSTUP_HOME", $"{_tempPath}\\rustuphome" }, }; + + private bool _shouldCleanRustPath; + private string? _currentRustupInitExeCheckSum; + + private enum ExitCode + { + Succeeded, + Failed, + } + + /// + /// Gets or sets start up project path. + /// + [Required] + public string StartupProj { get; set; } = string.Empty; + + /// + /// Gets or sets a value indicating whether to perform authorization. + /// + public bool EnableAuth { get; set; } = false; + + /// + /// Gets or sets a feed name. + /// + public string RegistryFeedName { get; set; } = string.Empty; + + /// + /// Gets or sets a cargo command to execute. + /// + [Required] + public string Command { get; set; } = string.Empty; + + /// + /// Gets or sets optional cargo command args. + /// + public string CommandArgs { get; set; } = string.Empty; + + /// + public override bool Execute() + { + if (!Command.Equals("fetch", StringComparison.InvariantCultureIgnoreCase)) + { + var dir = Directory.GetParent(StartupProj!); + bool cargoLockFile = File.Exists(Path.Combine(dir!.FullName, "cargo.lock")); + + return !cargoLockFile || CargoRunCommandAsync(Command.ToLower(), CommandArgs).GetAwaiter().GetResult() == ExitCode.Succeeded; + } + + // download & install rust if necessary + if (DownloadRustupAsync().GetAwaiter().GetResult()) + { + if (InstallRust().GetAwaiter().GetResult()) + { + _shouldCleanRustPath = true; + } + } + + return FetchCratesAsync(StartupProj!).GetAwaiter().GetResult(); + } + + private async Task CargoRunCommandAsync(string command, string args) + { + return await ExecuteProcessAsync(_cargoPath, $"{command} {args}", ".", _envVars); + } + + private async Task FetchCratesAsync(string project) + { + var stopwatch = new Stopwatch(); + try + { + stopwatch.Start(); + Log.LogMessage(MessageImportance.Normal, $"---- CargoBuild fetch Starting ----\n\n"); + var graphLoadStopWatch = new Stopwatch(); + graphLoadStopWatch.Start(); + + var evaluationContext = EvaluationContext.Create(EvaluationContext.SharingPolicy.Shared); + + var graph = new ProjectGraph( + [new ProjectGraphEntryPoint(project)], + ProjectCollection.GlobalProjectCollection, + (string projectPath, Dictionary globalProperties, ProjectCollection projCollection) => + { + var loadSettings = ProjectLoadSettings.DoNotEvaluateElementsWithFalseCondition; + + var projectOptions = new ProjectOptions + { + GlobalProperties = globalProperties, + ToolsVersion = projCollection.DefaultToolsVersion, + ProjectCollection = projCollection, + LoadSettings = loadSettings, + EvaluationContext = evaluationContext, + }; + + return ProjectInstance.FromFile(projectPath, projectOptions); + }); + + graphLoadStopWatch.Stop(); + + Log.LogMessage( + MessageImportance.Normal, + $"CargoBuild fetch: Static graph loaded in {{0}} seconds: {{1}} nodes, {{2}} edges", + Math.Round(graph.ConstructionMetrics.ConstructionTime.TotalSeconds, 3), + graph.ConstructionMetrics.NodeCount, + graph.ConstructionMetrics.EdgeCount); + + var rustProjects = new List(); + foreach (ProjectGraphNode node in graph.ProjectNodes) + { + bool cargoLockFiles = File.Exists(Path.Combine(node.ProjectInstance.Directory, "cargo.lock")); + if (!rustProjects.Contains(node.ProjectInstance.Directory) && cargoLockFiles) + { + rustProjects.Add(node.ProjectInstance.Directory); + } + } + + var tasks = new List>(); + + Log.LogMessage(MessageImportance.Normal, $"CargoBuild, Auth Enabled: {EnableAuth}"); + + foreach (var projects in rustProjects) + { + string path = projects; + + var restoreTask = RustFetchAsync(path, EnableAuth); + tasks.Add(restoreTask); + } + + await Tasks.Task.WhenAll(tasks.ToArray()); + bool success = tasks.Select(x => (int)x.Result).Sum() == 0; + stopwatch.Stop(); + if (success) + { + Log.LogMessage(MessageImportance.Normal, $"---- CargoBuild fetching Completed Successfully in {stopwatch.Elapsed.Seconds} seconds ----\n\n"); + } + else + { + Log.LogError($"---- CargoBuild fetching had an issue. Check the build log for details. ----\n\n"); + } + + return success; + } + catch (Exception ex) + { + LogException(ex); + return false; + + void LogException(Exception ex) + { + if (ex is AggregateException aggEx) + { + foreach (Exception innerEx in aggEx.InnerExceptions) + { + LogException(innerEx); + } + } + else + { + Log.LogErrorFromException(ex, showStackTrace: true); + } + } + } + finally + { + if (_shouldCleanRustPath) + { + CleanupRustPath(); + } + } + } + + private async Task RustFetchAsync(string workingDir, bool authorize = false) + { + ExitCode authResult = authorize ? await DoRegistryAuthAsync(workingDir) : ExitCode.Succeeded; + + if (authorize && authResult == ExitCode.Succeeded || !authorize) + { + string path; + string args; + const int RetryCnt = 2; + + path = _cargoPath; + args = "fetch"; + + Log.LogMessage(MessageImportance.Normal, $"Fetching cargo crates for project in {workingDir}"); + var exitCode = await ExecuteWithRetriesAsync(path, processArgs: args, workingDir, retryCount: RetryCnt, processRetryArgs: args); + Log.LogMessage(MessageImportance.Normal, $"Finished fetching cargo crates for project in {workingDir}"); + return exitCode; + } + + return authResult; + } + + private async Task ExecuteWithRetriesAsync(string processFileName, string processArgs, string workingDir, int retryCount, string? processRetryArgs = null) + { + ExitCode exitCode = await ExecuteProcessAsync(processFileName, processArgs, workingDir); + const int InitialWaitTimeSec = 3; + int retries = 0; + while (exitCode != 0 && retries < retryCount) + { + retries++; + int wait = InitialWaitTimeSec * 1000 * retries; + Log.LogMessage(MessageImportance.Normal, $"Process failed with exit code: {exitCode}. Retry #{retries}: {processFileName}. Waiting {wait / 600} seconds before retrying."); + + await Tasks.Task.Delay(wait); + exitCode = await ExecuteProcessAsync(processFileName, processRetryArgs ?? processArgs, workingDir); + } + + return exitCode; + } + + private async Task DoRegistryAuthAsync(string workingDir) + { + return await ExecuteWithRetriesAsync(_cargoPath, $"login --registry {RegistryFeedName}", workingDir, retryCount: 2); + } + + private async Task ExecuteProcessAsync(string fileName, string args, string workingDir, Dictionary? envars = null) + { + try + { + var processTask = new Task(() => + { + var info = new ProcessStartInfo + { + RedirectStandardError = true, + RedirectStandardOutput = true, + UseShellExecute = false, + FileName = fileName, + Arguments = args, + WorkingDirectory = workingDir, + }; + if (envars != null && envars.Count > 0) + { + foreach (var envar in envars) + { + info.EnvironmentVariables.Add(envar.Key, envar.Value); + } + } + + var process = Process.Start(info); + int maxWait = 1000 * 60 * 15; + + var nameAndExtension = fileName.Substring(fileName.LastIndexOf('\\') + 1); + Log.LogMessage(MessageImportance.Normal, $"\t\t\t\t\t\t*********** Start {nameAndExtension} logs ***********\n\n"); + + using StreamReader errReader = process!.StandardError; + _ = Log.LogMessagesFromStream(errReader, MessageImportance.Normal); + + using StreamReader outReader = process!.StandardOutput; + _ = Log.LogMessagesFromStream(outReader, MessageImportance.Normal); + Log.LogMessage(MessageImportance.Normal, $"\t\t\t\t\t\t*********** End {nameAndExtension} logs ***********\n\n"); + bool exited = process.WaitForExit(maxWait); + if (!exited) + { + process.Kill(); + Log.LogError($"Killed process after max timeout reached : '{info.FileName}'"); + return -1; + } + + return process.ExitCode; + }); + + processTask.Start(); + return (ExitCode)await processTask; + } + catch (Exception ex) + { + Log.LogWarningFromException(ex); + return await Tasks.Task.FromResult(ExitCode.Failed); + } + } + + private async Task DownloadRustupAsync() + { + if (File.Exists(_rustUpInitBinary) && await VerifyFileHashAsync()) + { + return true; + } + + string rustupDownloadLink = $@"https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe"; + Log.LogMessage(MessageImportance.Normal, $"Downloading rustup-init.exe -- {rustupDownloadLink}"); + using (var client = new HttpClient()) + { + Task response = client.GetAsync(rustupDownloadLink); + if (!Directory.Exists(_rustInstallPath)) + { + Directory.CreateDirectory(_rustInstallPath); + } + + using var responseStream = new FileStream(_rustUpInitBinary, FileMode.CreateNew); + HttpResponseMessage res = await response; + await res.Content.CopyToAsync(responseStream); + } + + return await VerifyFileHashAsync(); + } + + private async Task InstallRust() + { + var exitCode = await ExecuteProcessAsync(_rustUpInitBinary, "-y", ".", _envVars); + var exitCodeLatest = await ExecuteProcessAsync(_rustUpBinary, "default stable", ".", _envVars); + + return exitCode == 0 && exitCodeLatest == 0; + } + + private async Task VerifyFileHashAsync() + { + using var sha256 = SHA256.Create(); + using FileStream stream = File.OpenRead(_rustUpInitBinary); + byte[] hash = sha256.ComputeHash(stream); + string converted = BitConverter.ToString(hash); + +#if NETFRAMEWORK + converted = converted.Replace("-", string.Empty); +#else + converted = converted.Replace("-", string.Empty, StringComparison.Ordinal); +#endif + return converted == await GetHashAsync(); + } + + private async Task GetHashAsync() + { + string checkSumVerifyUrl = $"https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe.sha256"; + if (!string.IsNullOrEmpty(_currentRustupInitExeCheckSum)) + { + return _currentRustupInitExeCheckSum!; + } + + using var client = new HttpClient(); + string response = await client.GetStringAsync(checkSumVerifyUrl); + _currentRustupInitExeCheckSum = response.Split('\n')[0]; + + _currentRustupInitExeCheckSum = _currentRustupInitExeCheckSum!.ToUpperInvariant(); + return _currentRustupInitExeCheckSum; + } + + private void CleanupRustPath() + { + if (Directory.Exists(_rustUpInitBinary)) + { + Directory.Delete(_rustUpInitBinary, true); + } + } + } +} diff --git a/src/Rust/sdk/Sdk.props b/src/Rust/sdk/Sdk.props new file mode 100644 index 0000000..e400e0b --- /dev/null +++ b/src/Rust/sdk/Sdk.props @@ -0,0 +1,92 @@ + + + + + true + $(MSBuildAllProjects);$(MsBuildThisFileFullPath) + + + + + true + true + true + + + + + + + false + false + + + PackageReference + + + true + + + false + false + + + false + + + false + + + false + + + true + + + false + false + true + + + true + + + + + + false + true + + + + + + + + + + + + + + + false + false + true + cargo.io + + + + + + + \ No newline at end of file diff --git a/src/Rust/sdk/Sdk.targets b/src/Rust/sdk/Sdk.targets new file mode 100644 index 0000000..409b1ca --- /dev/null +++ b/src/Rust/sdk/Sdk.targets @@ -0,0 +1,127 @@ + + + + + + + $(MSBuildToolsPath)\Microsoft.Common.targets + $(MSBuildAllProjects);$(MsBuildThisFileFullPath) + + + + + + + false + + + $(CustomBeforeMicrosoftCommonTargets);$(MSBuildExtensionsPath)\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets + + + + + + + + BuildOnlySettings; + PrepareForBuild; + PreBuildEvent; + ResolveReferences; + Compile; + GetTargetPath; + PrepareForRun; + IncrementalClean; + PostBuildEvent + + + + None + false + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From addaf636a97281a9eaa97b3418bf9c4d424c4e43 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Tue, 8 Oct 2024 17:14:25 -0700 Subject: [PATCH 02/24] add readme, add clearcargocache target --- src/Rust/CargoBuild.csproj | 7 ++-- src/Rust/CargoBuildTask.cs | 23 ++++++++++-- src/Rust/README.md | 72 ++++++++++++++++++++++++++++++++++++++ src/Rust/sdk/Sdk.targets | 19 +++++----- 4 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 src/Rust/README.md diff --git a/src/Rust/CargoBuild.csproj b/src/Rust/CargoBuild.csproj index f464a59..f45d5fd 100644 --- a/src/Rust/CargoBuild.csproj +++ b/src/Rust/CargoBuild.csproj @@ -17,9 +17,12 @@ $(NoWarn);NU1504;NU5100;NU5110;NU5111 - + + + + - + diff --git a/src/Rust/CargoBuildTask.cs b/src/Rust/CargoBuildTask.cs index 96c3dc2..5153f75 100644 --- a/src/Rust/CargoBuildTask.cs +++ b/src/Rust/CargoBuildTask.cs @@ -28,7 +28,9 @@ public class CargoBuildTask : Task private static readonly string _cargoPath = $"{_tempPath}\\cargohome\\bin\\cargo.exe"; private static readonly string _rustInstallPath = $"{_tempPath}\\rustinstall"; private static readonly string _rustUpInitBinary = $"{_rustInstallPath}\\rustup-init.exe"; - private static readonly Dictionary _envVars = new () { { "CARGO_HOME", $"{_tempPath}\\cargohome" }, { "RUSTUP_HOME", $"{_tempPath}\\rustuphome" }, }; + private static readonly string _cargoHome = $"{_tempPath}\\cargohome"; + private static readonly string _rustupHome = $"{_tempPath}\\rustuphome"; + private static readonly Dictionary _envVars = new () { { "CARGO_HOME", _cargoHome }, { "RUSTUP_HOME", _rustupHome }, }; private bool _shouldCleanRustPath; private string? _currentRustupInitExeCheckSum; @@ -69,6 +71,15 @@ private enum ExitCode /// public override bool Execute() { + if (Command.Equals("clearcargocache", StringComparison.InvariantCultureIgnoreCase)) + { + if (Directory.Exists(_cargoHome)) + { + Log.LogMessage(MessageImportance.Normal, $"Clearing cargo cache at {_cargoHome}"); + Directory.Delete(_cargoHome, true); + } + } + if (!Command.Equals("fetch", StringComparison.InvariantCultureIgnoreCase)) { var dir = Directory.GetParent(StartupProj!); @@ -263,7 +274,10 @@ private async Task ExecuteProcessAsync(string fileName, string args, s { foreach (var envar in envars) { - info.EnvironmentVariables.Add(envar.Key, envar.Value); + if (!info.EnvironmentVariables.ContainsKey(envar.Key)) + { + info.EnvironmentVariables.Add(envar.Key, envar.Value); + } } } @@ -327,6 +341,11 @@ private async Task DownloadRustupAsync() private async Task InstallRust() { + foreach (var envVar in _envVars) + { + Environment.SetEnvironmentVariable(envVar.Key, envVar.Value); + } + var exitCode = await ExecuteProcessAsync(_rustUpInitBinary, "-y", ".", _envVars); var exitCodeLatest = await ExecuteProcessAsync(_rustUpBinary, "default stable", ".", _envVars); diff --git a/src/Rust/README.md b/src/Rust/README.md new file mode 100644 index 0000000..a9507c3 --- /dev/null +++ b/src/Rust/README.md @@ -0,0 +1,72 @@ +### CargoBuild Sdk Prototype + +### Project Setup +To use this sdk you will need the following: + +1) in your global.json +```json + "msbuild-sdks": { + ..., + "MSBuild.CargoBuild": "1.0.270-gf406f8eaa0" + }, +``` + +2) foreach rust project a csproj project file at the same level as your cargo.toml file. The project file should import the CargoBuild sdk. +```xml + + + net472 + + +``` + +3) if using a dirs.proj file at the root of your repo, you will need to import the CargoBuild sdk. +```xml + + + + + + + +``` + +### Usage +To restore rust dependencies, you can use the following msbuild command: +```shell +msbuild /t:Restore +``` +or +```shell +msbuild /restore +``` + +To build a rust project, you can use the following msbuild command: +```shell +msbuild /t:Build +``` + +To clean a rust project, you can use the following msbuild command: +```shell +msbuild /p:clean=true +``` + +To run a rust project, you can use the following msbuild command: +```shell +msbuild /p:run=true +``` + +To run cargo tests: +```shell +msbuild /p:test=true +``` + +For cargo docs +```shell +msbuild /p:doc=true +``` + +To clear the cargo home cache +```shell +msbuild /t:clearcargocache +``` \ No newline at end of file diff --git a/src/Rust/sdk/Sdk.targets b/src/Rust/sdk/Sdk.targets index 409b1ca..f74448d 100644 --- a/src/Rust/sdk/Sdk.targets +++ b/src/Rust/sdk/Sdk.targets @@ -112,16 +112,19 @@ - - + + - - + + - - + + - - + + + + + \ No newline at end of file From fd8d0db575b2fd2de47cd928a4e9f54cddd4aa5e Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Tue, 8 Oct 2024 17:27:59 -0700 Subject: [PATCH 03/24] cleanup --- src/Rust/CargoBuildTask.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Rust/CargoBuildTask.cs b/src/Rust/CargoBuildTask.cs index 5153f75..4b047a5 100644 --- a/src/Rust/CargoBuildTask.cs +++ b/src/Rust/CargoBuildTask.cs @@ -341,6 +341,11 @@ private async Task DownloadRustupAsync() private async Task InstallRust() { + if (Directory.Exists(_cargoHome) && Directory.Exists(_rustupHome)) + { + return true; + } + foreach (var envVar in _envVars) { Environment.SetEnvironmentVariable(envVar.Key, envVar.Value); From 5ce6c4f3dcb76b265897b5acd9cf1be8f28e30e4 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Tue, 8 Oct 2024 17:35:11 -0700 Subject: [PATCH 04/24] check for presence of cargo.toml instead of cargo.lock --- src/Rust/CargoBuildTask.cs | 2 +- src/Rust/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Rust/CargoBuildTask.cs b/src/Rust/CargoBuildTask.cs index 4b047a5..604daf0 100644 --- a/src/Rust/CargoBuildTask.cs +++ b/src/Rust/CargoBuildTask.cs @@ -148,7 +148,7 @@ [new ProjectGraphEntryPoint(project)], var rustProjects = new List(); foreach (ProjectGraphNode node in graph.ProjectNodes) { - bool cargoLockFiles = File.Exists(Path.Combine(node.ProjectInstance.Directory, "cargo.lock")); + bool cargoLockFiles = File.Exists(Path.Combine(node.ProjectInstance.Directory, "cargo.toml")); if (!rustProjects.Contains(node.ProjectInstance.Directory) && cargoLockFiles) { rustProjects.Add(node.ProjectInstance.Directory); diff --git a/src/Rust/README.md b/src/Rust/README.md index a9507c3..5a98a65 100644 --- a/src/Rust/README.md +++ b/src/Rust/README.md @@ -26,7 +26,7 @@ To use this sdk you will need the following: - + ``` From ba031a32d16a6812b76ceb50f1bb54b5ada412fb Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Tue, 8 Oct 2024 17:47:43 -0700 Subject: [PATCH 05/24] lock -> toml --- src/Rust/CargoBuildTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rust/CargoBuildTask.cs b/src/Rust/CargoBuildTask.cs index 604daf0..d34351f 100644 --- a/src/Rust/CargoBuildTask.cs +++ b/src/Rust/CargoBuildTask.cs @@ -83,7 +83,7 @@ public override bool Execute() if (!Command.Equals("fetch", StringComparison.InvariantCultureIgnoreCase)) { var dir = Directory.GetParent(StartupProj!); - bool cargoLockFile = File.Exists(Path.Combine(dir!.FullName, "cargo.lock")); + bool cargoLockFile = File.Exists(Path.Combine(dir!.FullName, "cargo.toml")); return !cargoLockFile || CargoRunCommandAsync(Command.ToLower(), CommandArgs).GetAwaiter().GetResult() == ExitCode.Succeeded; } From 5c1358680c8f4803a9426e694f0cccf8dcde6641 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Tue, 19 Nov 2024 12:19:14 -0800 Subject: [PATCH 06/24] Update README.md Update with local testing instructions --- src/Rust/README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Rust/README.md b/src/Rust/README.md index 5a98a65..a959e3a 100644 --- a/src/Rust/README.md +++ b/src/Rust/README.md @@ -66,7 +66,27 @@ For cargo docs msbuild /p:doc=true ``` +### How to test locally + +1) After build the project the nuget package will exist in the `bin\Debug` or `bin\Release` folder. A file `MSBuild.CargoBuild..nupkg` will be created + +2) In repo with the repo that contains your rust project(s), update your nuget.config file to point to the CargoBuild `bin\Debug` or `bin\Release` folder. + +```xml + + + + ``` + 3) In your the repo that contains your rust project, update your `global.json` to include the Sdk. Use the version number from the nupkg file above as the sdk version. + ```xml + "msbuild-sdks": { + ..., + "MSBuild.CargoBuild": "" + } + ``` + 4) Once you run `msbuild /restore` your rust project, the CargoBuild sdk will be restored from the local nuget source. You can now use the sdk locally. + To clear the cargo home cache ```shell msbuild /t:clearcargocache -``` \ No newline at end of file +``` From 2a85ae973c405ee5c4d9e3b072d8d274a46ef6ed Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Tue, 19 Nov 2024 12:24:28 -0800 Subject: [PATCH 07/24] Update README.md update typos --- src/Rust/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Rust/README.md b/src/Rust/README.md index a959e3a..b7f3a41 100644 --- a/src/Rust/README.md +++ b/src/Rust/README.md @@ -68,9 +68,9 @@ msbuild /p:doc=true ### How to test locally -1) After build the project the nuget package will exist in the `bin\Debug` or `bin\Release` folder. A file `MSBuild.CargoBuild..nupkg` will be created +1) After building the cargo build project, a nupkg file will be created in the `bin\Debug` or `bin\Release` folder. A file like `MSBuild.CargoBuild..nupkg` will be created -2) In repo with the repo that contains your rust project(s), update your nuget.config file to point to the CargoBuild `bin\Debug` or `bin\Release` folder. +2) In repo that contains your rust project(s), update your nuget.config file to point to the CargoBuild `bin\Debug` or `bin\Release` folder. ```xml @@ -84,7 +84,7 @@ msbuild /p:doc=true "MSBuild.CargoBuild": "" } ``` - 4) Once you run `msbuild /restore` your rust project, the CargoBuild sdk will be restored from the local nuget source. You can now use the sdk locally. + 4) Once you run `msbuild /restore` in your rust project, the CargoBuild sdk will be restored from the local nuget source. You can now use the sdk locally. To clear the cargo home cache ```shell From a828175eb450eed57e8b255992caee68706f6798 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Tue, 19 Nov 2024 12:25:53 -0800 Subject: [PATCH 08/24] Update README.md typos --- src/Rust/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Rust/README.md b/src/Rust/README.md index b7f3a41..0d1ec30 100644 --- a/src/Rust/README.md +++ b/src/Rust/README.md @@ -74,10 +74,10 @@ msbuild /p:doc=true ```xml - + ``` - 3) In your the repo that contains your rust project, update your `global.json` to include the Sdk. Use the version number from the nupkg file above as the sdk version. + 3) In the repo that contains your rust project, update your `global.json` to include the Sdk. Use the version number from the nupkg file above as the sdk version. ```xml "msbuild-sdks": { ..., From 270c64006639079c6e4ee3d22a55623961adfc3d Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Tue, 19 Nov 2024 13:43:42 -0800 Subject: [PATCH 09/24] Update README.md clean up --- src/Rust/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Rust/README.md b/src/Rust/README.md index 0d1ec30..89a6129 100644 --- a/src/Rust/README.md +++ b/src/Rust/README.md @@ -66,6 +66,10 @@ For cargo docs msbuild /p:doc=true ``` +To clear the cargo home cache +```shell +msbuild /t:clearcargocache +``` ### How to test locally 1) After building the cargo build project, a nupkg file will be created in the `bin\Debug` or `bin\Release` folder. A file like `MSBuild.CargoBuild..nupkg` will be created @@ -86,7 +90,4 @@ msbuild /p:doc=true ``` 4) Once you run `msbuild /restore` in your rust project, the CargoBuild sdk will be restored from the local nuget source. You can now use the sdk locally. -To clear the cargo home cache -```shell -msbuild /t:clearcargocache -``` + From 39f378399b2feee80151e6156955f182691d97f5 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Wed, 8 Jan 2025 10:49:42 -0800 Subject: [PATCH 10/24] add msrustup support --- src/Rust/CargoBuild.csproj | 6 ++- src/Rust/CargoBuildTask.cs | 104 +++++++++++++++++++++++++------------ src/Rust/README.md | 21 +++++++- src/Rust/sdk/Sdk.props | 3 +- 4 files changed, 99 insertions(+), 35 deletions(-) diff --git a/src/Rust/CargoBuild.csproj b/src/Rust/CargoBuild.csproj index f45d5fd..3805de7 100644 --- a/src/Rust/CargoBuild.csproj +++ b/src/Rust/CargoBuild.csproj @@ -17,7 +17,11 @@ $(NoWarn);NU1504;NU5100;NU5110;NU5111 - + + PreserveNewest + true + + diff --git a/src/Rust/CargoBuildTask.cs b/src/Rust/CargoBuildTask.cs index d34351f..7f8cbd4 100644 --- a/src/Rust/CargoBuildTask.cs +++ b/src/Rust/CargoBuildTask.cs @@ -30,8 +30,10 @@ public class CargoBuildTask : Task private static readonly string _rustUpInitBinary = $"{_rustInstallPath}\\rustup-init.exe"; private static readonly string _cargoHome = $"{_tempPath}\\cargohome"; private static readonly string _rustupHome = $"{_tempPath}\\rustuphome"; + private static readonly string _cargoHomeBin = $"{_tempPath}\\cargohome\\bin\\"; + private static readonly string _msRustupBinary = $"{_tempPath}\\cargohome\\bin\\msrustup.exe"; private static readonly Dictionary _envVars = new () { { "CARGO_HOME", _cargoHome }, { "RUSTUP_HOME", _rustupHome }, }; - + private static readonly string _rustupDownloadLink = "https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe"; private bool _shouldCleanRustPath; private string? _currentRustupInitExeCheckSum; @@ -41,6 +43,12 @@ private enum ExitCode Failed, } + /// + /// Gets or sets a cargo command to execute. + /// + [Required] + public string Command { get; set; } = string.Empty; + /// /// Gets or sets start up project path. /// @@ -58,19 +66,29 @@ private enum ExitCode public string RegistryFeedName { get; set; } = string.Empty; /// - /// Gets or sets a cargo command to execute. + /// Gets or sets optional cargo command args. /// - [Required] - public string Command { get; set; } = string.Empty; + public string CommandArgs { get; set; } = string.Empty; /// - /// Gets or sets optional cargo command args. + /// Gets or sets a value indicating whether to use msrust up or not. /// - public string CommandArgs { get; set; } = string.Empty; + public bool UseMsRustUp { get; set; } = false; /// public override bool Execute() { + Debugger.Launch(); + + // download & install rust if necessary + if (DownloadRustupAsync().GetAwaiter().GetResult()) + { + if (InstallRust().GetAwaiter().GetResult()) + { + _shouldCleanRustPath = true; + } + } + if (Command.Equals("clearcargocache", StringComparison.InvariantCultureIgnoreCase)) { if (Directory.Exists(_cargoHome)) @@ -80,21 +98,12 @@ public override bool Execute() } } - if (!Command.Equals("fetch", StringComparison.InvariantCultureIgnoreCase)) + if (!Command.Equals("fetch", StringComparison.InvariantCultureIgnoreCase)) // build { var dir = Directory.GetParent(StartupProj!); - bool cargoLockFile = File.Exists(Path.Combine(dir!.FullName, "cargo.toml")); + bool cargoFile = File.Exists(Path.Combine(dir!.FullName, "cargo.toml")); - return !cargoLockFile || CargoRunCommandAsync(Command.ToLower(), CommandArgs).GetAwaiter().GetResult() == ExitCode.Succeeded; - } - - // download & install rust if necessary - if (DownloadRustupAsync().GetAwaiter().GetResult()) - { - if (InstallRust().GetAwaiter().GetResult()) - { - _shouldCleanRustPath = true; - } + return !cargoFile || CargoRunCommandAsync(Command.ToLower(), CommandArgs).GetAwaiter().GetResult() == ExitCode.Succeeded; } return FetchCratesAsync(StartupProj!).GetAwaiter().GetResult(); @@ -102,6 +111,7 @@ public override bool Execute() private async Task CargoRunCommandAsync(string command, string args) { + Log.LogMessage(MessageImportance.Normal, $"Running cargo command: {command} {args}"); return await ExecuteProcessAsync(_cargoPath, $"{command} {args}", ".", _envVars); } @@ -148,8 +158,8 @@ [new ProjectGraphEntryPoint(project)], var rustProjects = new List(); foreach (ProjectGraphNode node in graph.ProjectNodes) { - bool cargoLockFiles = File.Exists(Path.Combine(node.ProjectInstance.Directory, "cargo.toml")); - if (!rustProjects.Contains(node.ProjectInstance.Directory) && cargoLockFiles) + bool cargoFile = File.Exists(Path.Combine(node.ProjectInstance.Directory, "cargo.toml")); + if (!rustProjects.Contains(node.ProjectInstance.Directory) && cargoFile) { rustProjects.Add(node.ProjectInstance.Directory); } @@ -163,8 +173,8 @@ [new ProjectGraphEntryPoint(project)], { string path = projects; - var restoreTask = RustFetchAsync(path, EnableAuth); - tasks.Add(restoreTask); + var fetchTask = RustFetchAsync(path, EnableAuth); + tasks.Add(fetchTask); } await Tasks.Task.WhenAll(tasks.ToArray()); @@ -316,13 +326,18 @@ private async Task ExecuteProcessAsync(string fileName, string args, s private async Task DownloadRustupAsync() { - if (File.Exists(_rustUpInitBinary) && await VerifyFileHashAsync()) + if (File.Exists(_rustUpInitBinary) && await VerifyInitHashAsync()) { return true; } + else if (File.Exists(_rustUpInitBinary)) + { + // If the hash doesn't match, that likely means there is a new version of rustup-init.exe available. + File.Delete(_rustUpInitBinary); + } - string rustupDownloadLink = $@"https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe"; - Log.LogMessage(MessageImportance.Normal, $"Downloading rustup-init.exe -- {rustupDownloadLink}"); + string rustupDownloadLink = _rustupDownloadLink; + Log.LogMessage(MessageImportance.Normal, $"Downloading -- {rustupDownloadLink}"); using (var client = new HttpClient()) { Task response = client.GetAsync(rustupDownloadLink); @@ -336,14 +351,26 @@ private async Task DownloadRustupAsync() await res.Content.CopyToAsync(responseStream); } - return await VerifyFileHashAsync(); + return await VerifyInitHashAsync(); } private async Task InstallRust() { - if (Directory.Exists(_cargoHome) && Directory.Exists(_rustupHome)) + var rustupBinary = UseMsRustUp ? _msRustupBinary : _rustUpBinary; + if (File.Exists(_cargoPath) && Directory.Exists(_rustupHome) && File.Exists(_rustUpBinary) || File.Exists(_cargoHome) && UseMsRustUp != true || File.Exists(_msRustupBinary)) { - return true; + return false; + } + + if (UseMsRustUp) + { + string? workingDirPart = new DirectoryInfo(BuildEngine.ProjectFileOfTaskNode).Parent?.Parent?.FullName; + if (Directory.Exists(workingDirPart)) + { + Log.LogMessage(MessageImportance.Normal, "Installing MS Rustup"); + string sdkRootPath = Path.Combine(workingDirPart!, "content\\dist"); + ExecuteProcessAsync("powershell.exe", $".\\msrustup.ps1 '{_cargoHomeBin}'", sdkRootPath, _envVars).GetAwaiter().GetResult(); + } } foreach (var envVar in _envVars) @@ -351,13 +378,26 @@ private async Task InstallRust() Environment.SetEnvironmentVariable(envVar.Key, envVar.Value); } - var exitCode = await ExecuteProcessAsync(_rustUpInitBinary, "-y", ".", _envVars); - var exitCodeLatest = await ExecuteProcessAsync(_rustUpBinary, "default stable", ".", _envVars); + ExitCode exitCode = ExitCode.Succeeded; + ExitCode exitCodeToolChainLatest = ExitCode.Succeeded; + ExitCode exitCodeLatest = ExitCode.Succeeded; + + if (UseMsRustUp && File.Exists("rust-toolchain.toml")) + { + Log.LogMessage(MessageImportance.Normal, "Installing Custom Toolchain"); + exitCodeToolChainLatest = await ExecuteProcessAsync(rustupBinary, "toolchain install", ".", _envVars); + } + else + { + Log.LogMessage(MessageImportance.Normal, "Installing Rust"); + exitCode = await ExecuteProcessAsync(_rustUpInitBinary, "-y", ".", _envVars); + exitCodeLatest = await ExecuteProcessAsync(rustupBinary, "default stable", ".", _envVars); // ensure we have the latest stable version + } - return exitCode == 0 && exitCodeLatest == 0; + return exitCode == 0 && exitCodeToolChainLatest == 0 && exitCodeLatest == 0; } - private async Task VerifyFileHashAsync() + private async Task VerifyInitHashAsync() { using var sha256 = SHA256.Create(); using FileStream stream = File.OpenRead(_rustUpInitBinary); diff --git a/src/Rust/README.md b/src/Rust/README.md index 5a98a65..963d98f 100644 --- a/src/Rust/README.md +++ b/src/Rust/README.md @@ -69,4 +69,23 @@ msbuild /p:doc=true To clear the cargo home cache ```shell msbuild /t:clearcargocache -``` \ No newline at end of file +``` +### How to test locally + +1) After building the cargo build project, a nupkg file will be created in the `bin\Debug` or `bin\Release` folder. A file like `MSBuild.CargoBuild..nupkg` will be created + +2) In repo that contains your rust project(s), update your nuget.config file to point to the CargoBuild `bin\Debug` or `bin\Release` folder. + +```xml + + + + ``` + 3) In the repo that contains your rust project, update your `global.json` to include the Sdk. Use the version number from the nupkg file above as the sdk version. + ```xml + "msbuild-sdks": { + ..., + "MSBuild.CargoBuild": "" + } + ``` + 4) Once you run `msbuild /restore` in your rust project, the CargoBuild sdk will be restored from the local nuget source. You can now use the sdk locally. diff --git a/src/Rust/sdk/Sdk.props b/src/Rust/sdk/Sdk.props index e400e0b..02afa96 100644 --- a/src/Rust/sdk/Sdk.props +++ b/src/Rust/sdk/Sdk.props @@ -76,7 +76,7 @@ - + false @@ -88,5 +88,6 @@ + false \ No newline at end of file From 895b951822002b9fbba4aba8059844c589da3e19 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Wed, 8 Jan 2025 11:32:14 -0800 Subject: [PATCH 11/24] add msrustup download script --- src/Rust/dist/msrustup.ps1 | 83 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/Rust/dist/msrustup.ps1 diff --git a/src/Rust/dist/msrustup.ps1 b/src/Rust/dist/msrustup.ps1 new file mode 100644 index 0000000..36ddabd --- /dev/null +++ b/src/Rust/dist/msrustup.ps1 @@ -0,0 +1,83 @@ +# Originally from https://aka.ms/install-msrustup.ps1 +# Version 5 +# This script is expected to be copied into any build system that needs to install the internal Rust toolchain, if +# that system cannot use an ADO pipeline and the Rust installer pipeline task. +# Updates to this script will be avoided if possible, but if it stops working in your environment, please check the above +# source location in case of any changes. + +# Downloads msrustup from Azure Artifacts. +# Requires MSRUSTUP_ACCESS_TOKEN or MSRUSTUP_PAT environment variables to be set with a token. +# See https://aka.ms/rust for more information. + +$ErrorActionPreference = "Stop" +$destinationDirectory = $env:Temp + "\cargohome\bin" + + # Create directory if it doesn't exist + Write-Host $destinationDirectory + if (-Not (Test-Path $destinationDirectory)) { + New-Item -Path $destinationDirectory -ItemType Directory + } + +Switch ([System.Environment]::OSVersion.Platform.ToString()) { + "Win32NT" { $target_rest = 'pc-windows-msvc'; Break } + "MacOSX" { $target_rest = 'apple-darwin'; Break } + "Unix" { $target_rest = 'unknown-linux-gnu'; Break } + Default { + Write-Error "Could not determine host environment" + exit 1 + } +} + +# Need to specify mscorlib to make this work on Windows +# https://blog.nerdbank.net/2023/02/how-to-get-os-architecture-in-windows-powershell +Switch ([System.Runtime.InteropServices.RuntimeInformation,mscorlib]::OSArchitecture.ToString()) { + "X64" { $target_arch = 'x86_64'; Break } + "Arm64" { $target_arch = 'aarch64'; Break } + Default { + Write-Error "Could not determine host architecture" + exit 1 + } +} + +$package = "rust.msrustup-$target_arch-$target_rest" + +# Feed configuration +$feed = if (Test-Path env:MSRUSTUP_FEED_URL) { + $env:MSRUSTUP_FEED_URL +} else { + 'https://mscodehub.pkgs.visualstudio.com/Rust/_packaging/Rust%40Release/nuget/v3/index.json' +} + +# Get authentication token +$token = if (Test-Path env:MSRUSTUP_ACCESS_TOKEN) { + "Bearer $env:MSRUSTUP_ACCESS_TOKEN" +} elseif (Test-Path env:MSRUSTUP_PAT) { + "Basic $([System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$($env:MSRUSTUP_PAT)")))" +} elseif ((Get-Command "azureauth" -ErrorAction SilentlyContinue) -ne $null) { + azureauth ado token --output headervalue +} else { + Write-Error "MSRUSTUP_ACCESS_TOKEN or MSRUSTUP_PAT must be set or azureauth must be present." + exit 1 +} + +$h = @{'Authorization' = "$token"} + +# Download latest NuGet package +$response = Invoke-RestMethod -Headers $h $feed +$base = ($response.resources | Where-Object { $_.'@type' -eq 'PackageBaseAddress/3.0.0' }).'@id' +$version = (Invoke-RestMethod -Headers $h "$base/$package/index.json").versions[0] +Invoke-WebRequest -Headers $h "${base}${package}/$version/$package.$version.nupkg" -OutFile 'msrustup.zip' + +try { + # Extract archive + Expand-Archive 'msrustup.zip' + try { + Move-Item .\msrustup\tools\msrustup* $destinationDirectory + } + finally { + Remove-Item -Recurse 'msrustup' + } +} +finally { + Remove-Item 'msrustup.zip' +} From 424daf577fc64c6d945debbd21dc7fcbe7cb8577 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Wed, 8 Jan 2025 15:33:08 -0800 Subject: [PATCH 12/24] whitespace --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 32b47d0..08b2ce0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -47,4 +47,4 @@ - \ No newline at end of file + From 4aed5ba2d327abf7016eb13bdb38bd9990a2f449 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Thu, 9 Jan 2025 14:10:17 -0800 Subject: [PATCH 13/24] update project name --- Directory.Packages.props | 3 + MSBuildSdks.sln | 20 +- src/CargoBuild.UnitTests/CargoBuildTest.cs | 424 ++++++++++++++++++ .../CustomProjectCreatorTemplates.cs | 51 +++ ...icrosoft.Build.CargoBuild.UnitTests.csproj | 25 ++ src/{Rust => CargoBuild}/CargoBuildTask.cs | 10 +- .../Microsoft.Build.CargoBuild.csproj} | 11 +- src/{Rust => CargoBuild}/README.md | 14 +- src/{Rust => CargoBuild}/dist/msrustup.ps1 | 0 .../DisableCopyFilesMarkedCopyLocal.targets | 4 + src/{Rust => CargoBuild}/sdk/Sdk.props | 2 +- src/{Rust => CargoBuild}/sdk/Sdk.targets | 4 +- 12 files changed, 542 insertions(+), 26 deletions(-) create mode 100644 src/CargoBuild.UnitTests/CargoBuildTest.cs create mode 100644 src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs create mode 100644 src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj rename src/{Rust => CargoBuild}/CargoBuildTask.cs (97%) rename src/{Rust/CargoBuild.csproj => CargoBuild/Microsoft.Build.CargoBuild.csproj} (80%) rename src/{Rust => CargoBuild}/README.md (80%) rename src/{Rust => CargoBuild}/dist/msrustup.ps1 (100%) create mode 100644 src/CargoBuild/sdk/DisableCopyFilesMarkedCopyLocal.targets rename src/{Rust => CargoBuild}/sdk/Sdk.props (98%) rename src/{Rust => CargoBuild}/sdk/Sdk.targets (96%) diff --git a/Directory.Packages.props b/Directory.Packages.props index 08b2ce0..ebd70d2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,11 +10,14 @@ + + + diff --git a/MSBuildSdks.sln b/MSBuildSdks.sln index 6e29c00..598ca2f 100644 --- a/MSBuildSdks.sln +++ b/MSBuildSdks.sln @@ -86,6 +86,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Build.CopyOnWrite EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Build.RunVSTest", "src\RunTests\Microsoft.Build.RunVSTest.csproj", "{B4CA4749-4CDE-499F-8372-C71966C6DB16}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Build.CargoBuild", "src\CargoBuild\Microsoft.Build.CargoBuild.csproj", "{40E51B6A-2807-4A28-8846-4E3ED2C39EBD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Build.CargoBuild.UnitTests", "src\CargoBuild.UnitTests\Microsoft.Build.CargoBuild.UnitTests.csproj", "{60C10404-E99C-4B8D-B2D8-1B9297A9D36B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -144,14 +148,22 @@ Global {153D1183-2953-4D4D-A5AD-AA2CF99B0DE3}.Debug|Any CPU.Build.0 = Debug|Any CPU {153D1183-2953-4D4D-A5AD-AA2CF99B0DE3}.Release|Any CPU.ActiveCfg = Release|Any CPU {153D1183-2953-4D4D-A5AD-AA2CF99B0DE3}.Release|Any CPU.Build.0 = Release|Any CPU - {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Release|Any CPU.Build.0 = Release|Any CPU {AF9F2AFE-04D4-40B3-B17F-54ABD3DE7E4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AF9F2AFE-04D4-40B3-B17F-54ABD3DE7E4E}.Debug|Any CPU.Build.0 = Debug|Any CPU {AF9F2AFE-04D4-40B3-B17F-54ABD3DE7E4E}.Release|Any CPU.ActiveCfg = Release|Any CPU {AF9F2AFE-04D4-40B3-B17F-54ABD3DE7E4E}.Release|Any CPU.Build.0 = Release|Any CPU + {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Release|Any CPU.Build.0 = Release|Any CPU + {40E51B6A-2807-4A28-8846-4E3ED2C39EBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40E51B6A-2807-4A28-8846-4E3ED2C39EBD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40E51B6A-2807-4A28-8846-4E3ED2C39EBD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40E51B6A-2807-4A28-8846-4E3ED2C39EBD}.Release|Any CPU.Build.0 = Release|Any CPU + {60C10404-E99C-4B8D-B2D8-1B9297A9D36B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60C10404-E99C-4B8D-B2D8-1B9297A9D36B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60C10404-E99C-4B8D-B2D8-1B9297A9D36B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60C10404-E99C-4B8D-B2D8-1B9297A9D36B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/CargoBuild.UnitTests/CargoBuildTest.cs b/src/CargoBuild.UnitTests/CargoBuildTest.cs new file mode 100644 index 0000000..52e7cc7 --- /dev/null +++ b/src/CargoBuild.UnitTests/CargoBuildTest.cs @@ -0,0 +1,424 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the MIT license. + +using Microsoft.Build.Evaluation; +using Microsoft.Build.Execution; +using Microsoft.Build.Framework; +using Microsoft.Build.Graph; +using Microsoft.Build.UnitTests.Common; +using Microsoft.Build.Utilities.ProjectCreation; +using Shouldly; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Xunit; + +namespace Microsoft.Build.CargoBuild.UnitTests +{ + public class CargoBuildTest : MSBuildSdkTestBase + { + [Fact] + public void CanDisableCopyFilesMarkedCopyLocal() + { + ProjectCreator.Templates.CargoBuildProject( + path: GetTempFileWithExtension(".cargoproj")) + .Property("SkipCopyFilesMarkedCopyLocal", bool.TrueString) + .ItemInclude("ReferenceCopyLocalPaths", Assembly.GetExecutingAssembly().Location) + .TryBuild("_CopyFilesMarkedCopyLocal", out bool result, out BuildOutput buildOutput); + + result.ShouldBeTrue(buildOutput.GetConsoleLog()); + } + + [Theory] + [InlineData("BeforeCompile")] + [InlineData("AfterCompile")] + public void CompileIsExtensibleWithBeforeAfterTargets(string targetName) + { + ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( + path: Path.Combine(TestRootPath, "Rust", "Microsoft.Build.CargoBuild.UnitTests.csproj")) + .Target(targetName) + .TaskMessage("503CF1EBA6DC415F95F4DB630E7C1817", MessageImportance.High) + .Save(); + + cargoBuildProject.TryBuild(restore: true, out bool result, out BuildOutput buildOutput); + + result.ShouldBeTrue(buildOutput.GetConsoleLog()); + + buildOutput.Messages.High.ShouldContain("503CF1EBA6DC415F95F4DB630E7C1817", buildOutput.GetConsoleLog()); + } + + [Fact] + public void CoreCompileIsExtensibleWithCoreCompileDependsOn() + { + ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( + path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj")) + .Property("CoreCompileDependsOn", "$(CoreCompileDependsOn);TestThatCoreCompileIsExtensible") + .Target("TestThatCoreCompileIsExtensible") + .TaskMessage("35F1C217730445E0AC0F30E70F5C7826", MessageImportance.High) + .Save(); + + cargoBuildProject.TryBuild(restore: true, out bool result, out BuildOutput buildOutput); + + result.ShouldBeTrue(buildOutput.GetConsoleLog()); + + buildOutput.Messages.High.ShouldContain("35F1C217730445E0AC0F30E70F5C7826", buildOutput.GetConsoleLog()); + } + + [Fact] + public void CoreCompileIsExtensibleWithTargetsTriggeredByCompilation() + { + ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( + path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj")) + .Property("TargetsTriggeredByCompilation", "TestThatCoreCompileIsExtensible") + .Target("TestThatCoreCompileIsExtensible") + .TaskMessage("D031211C98F1454CA47A424ADC86A8F7", MessageImportance.High) + .Save(); + + cargoBuildProject.TryBuild(restore: true, out bool result, out BuildOutput buildOutput); + + result.ShouldBeTrue(buildOutput.GetConsoleLog()); + + buildOutput.Messages.High.ShouldContain("D031211C98F1454CA47A424ADC86A8F7", buildOutput.GetConsoleLog()); + } + + [Fact] + public void DoNotReferenceOutputAssemblies() + { + ProjectCreator projectA = ProjectCreator.Templates.SdkCsproj( + path: Path.Combine(TestRootPath, "ProjectA", "ProjectA.csproj"), +#if NETFRAMEWORK || NET8_0 + targetFramework: "net8.0") +#elif NET9_0 + targetFramework: "net9.0") +#endif + .Save(); + + ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( + path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj")) + .ItemProjectReference(projectA) + .Save(); + + cargoBuildProject.TryRestore(out bool result, out BuildOutput buildOutput); + + result.ShouldBeTrue(buildOutput.GetConsoleLog()); + } + + [Theory] + [InlineData(".cargoproj")] + [InlineData(".csproj")] + [InlineData(".proj")] + public void ProjectContainsStaticGraphImplementation(string projectExtension) + { + ProjectCreator cargoBuild = ProjectCreator.Templates.CargoBuildProject( + path: GetTempFileWithExtension(projectExtension), + globalProperties: new Dictionary + { + ["IsGraphBuild"] = bool.TrueString, + }, + customAction: creator => + { + creator.Target("TakeAction", afterTargets: "Build") + .TaskMessage("86F00AF59170450E9D687652D74A6394", MessageImportance.High); + }) + .Property("GenerateDependencyFile", "false") + .Save(); + + ICollection projectReferenceTargets = cargoBuild.Project.GetItems("ProjectReferenceTargets"); + + TargetProtocolShouldContainValuesForTarget("Build"); + TargetProtocolShouldContainValuesForTarget("Clean"); + TargetProtocolShouldContainValuesForTarget("Rebuild"); + TargetProtocolShouldContainValuesForTarget("Publish"); + + void TargetProtocolShouldContainValuesForTarget(string target) + { + IEnumerable buildTargets = + projectReferenceTargets.Where(i => i.EvaluatedInclude.Equals(target, StringComparison.OrdinalIgnoreCase)) + .Select(i => i.GetMetadata("Targets")?.EvaluatedValue) + .Where(t => !string.IsNullOrEmpty(t)); + + buildTargets.ShouldNotBeEmpty(); + } + } + + [Fact] + public void ProjectsCanDependOnCargoBuildProjects() + { + ProjectCreator project1 = ProjectCreator.Templates.LegacyCsproj( + Path.Combine(TestRootPath, "project1", "project1.csproj")) + .Save(); + + ProjectCreator project2 = ProjectCreator.Templates.CargoBuildProject( + path: Path.Combine(TestRootPath, "project2", "project2.csproj")) + .Property("DesignTimeBuild", "true") + .Property("GenerateDependencyFile", "false") + .Target("_GetProjectReferenceTargetFrameworkProperties") + .ItemProjectReference(project1) + .Save(); + + ProjectCreator project3 = ProjectCreator.Templates.CargoBuildProject( + path: Path.Combine(TestRootPath, "project3", "project3.csproj")) + .Property("DesignTimeBuild", "true") + .Property("GenerateDependencyFile", "false") + .ItemProjectReference(project2) + .Target("_GetProjectReferenceTargetFrameworkProperties") + .Save(); + + project3.TryBuild(out bool result, out BuildOutput buildOutput); + + result.ShouldBeTrue(buildOutput.GetConsoleLog()); + } + + [Theory] + [InlineData("AutomaticallyUseReferenceAssemblyPackages", "true", "true")] + [InlineData("AutomaticallyUseReferenceAssemblyPackages", null, "false")] + [InlineData("DebugSymbols", "true", "false")] + [InlineData("DebugSymbols", null, "false")] + [InlineData("DebugType", "Full", "None")] + [InlineData("DebugType", null, "None")] + [InlineData("DisableFastUpToDateCheck", "false", "false")] + [InlineData("DisableFastUpToDateCheck", null, "true")] + [InlineData("DisableImplicitFrameworkReferences", "false", "false")] + [InlineData("DisableImplicitFrameworkReferences", null, "true")] + [InlineData("EnableDefaultCompileItems", "true", "true")] + [InlineData("EnableDefaultCompileItems", null, "false")] + [InlineData("EnableDefaultEmbeddedResourceItems", "true", "true")] + [InlineData("EnableDefaultEmbeddedResourceItems", null, "false")] + [InlineData("GenerateAssemblyInfo", "true", "true")] + [InlineData("GenerateAssemblyInfo", null, "false")] + [InlineData("GenerateMSBuildEditorConfigFile", "true", "true")] + [InlineData("GenerateMSBuildEditorConfigFile", null, "false")] + [InlineData("IncludeBuildOutput", "true", "true")] + [InlineData("IncludeBuildOutput", null, "false")] + [InlineData("NoCompilerStandardLib", "true", "true")] + [InlineData("NoCompilerStandardLib", null, "false")] + [InlineData("ProduceReferenceAssembly", "true", "false")] + [InlineData("ProduceReferenceAssembly", null, "false")] + [InlineData("SkipCopyBuildProduct", "false", "false")] + [InlineData("SkipCopyBuildProduct", null, "true")] + [InlineData("SkipCopyFilesMarkedCopyLocal", "false", "false")] + [InlineData("SkipCopyFilesMarkedCopyLocal", "true", "true")] + [InlineData("SkipCopyFilesMarkedCopyLocal", null, "")] + public void PropertiesHaveExpectedValues(string propertyName, string value, string expectedValue) + { + ProjectCreator.Templates.CargoBuildProject( + path: GetTempFileWithExtension(".cargoproj")) + .Property(propertyName, value) + .Save() + .TryGetPropertyValue(propertyName, out string actualValue); + + actualValue.ShouldBe(expectedValue, StringComparer.OrdinalIgnoreCase, customMessage: $"Property {propertyName} should have a value of \"{expectedValue}\" but its value was \"{actualValue}\""); + } + + [Theory] + [InlineData(".cargoproj")] + [InlineData(".csproj")] + [InlineData(".proj")] + public void PublishWithNoBuild(string projectExtension) + { + ProjectCreator.Templates.CargoBuildProject( + path: GetTempFileWithExtension(projectExtension), + customAction: creator => + { + creator + .Property("RuntimeIdentifier", "win-x64") + .Property("Platforms", "x64") + .Target("TakeAction", afterTargets: "Build") + .TaskMessage("2EA26E6FC5C842B682AA26096A769E07", MessageImportance.High); + }) + .Save() + .TryBuild(restore: true, "Build", out bool buildResult, out BuildOutput buildOutput) + .TryBuild("Publish", new Dictionary { ["NoBuild"] = "true" }, out bool publishResult, out BuildOutput publishOutput); + + buildResult.ShouldBeTrue(buildOutput.GetConsoleLog()); + + buildOutput.Messages.High.ShouldContain("2EA26E6FC5C842B682AA26096A769E07"); + + publishResult.ShouldBeTrue(publishOutput.GetConsoleLog()); + + publishOutput.Messages.High.ShouldNotContain("2EA26E6FC5C842B682AA26096A769E07"); + } + + [Theory] + [InlineData(".cargoproj")] + [InlineData(".csproj")] + [InlineData(".proj")] + public void SimpleBuild(string projectExtension) + { + ProjectCreator.Templates.CargoBuildProject( + path: GetTempFileWithExtension(projectExtension), + projectCollection: new ProjectCollection( + new Dictionary + { + ["DesignTimeBuild"] = "true", + }), + customAction: creator => + { + creator.Target("TakeAction", afterTargets: "Build") + .TaskMessage("86F00AF59170450E9D687652D74A6394", MessageImportance.High); + }) + .Property("GenerateDependencyFile", "false") + .Save() + .TryBuild("Build", out bool result, out BuildOutput buildOutput); + + result.ShouldBeTrue(buildOutput.GetConsoleLog()); + + buildOutput.Messages.High.ShouldContain("86F00AF59170450E9D687652D74A6394"); + } + + [Fact] + public void StaticGraphBuildsSucceed() + { + ProjectCreator sdkReference = ProjectCreator.Templates.SdkCsproj( + Path.Combine(TestRootPath, "sdkstyle", "sdkstyle.csproj")) + .Save(); + + ProjectCreator cargoBuild = ProjectCreator.Templates.CargoBuildProject( + path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj"), + customAction: creator => + { + creator.ItemProjectReference(sdkReference, referenceOutputAssembly: false); + }).Save(); + + ProjectCreator project = ProjectCreator.Templates.SdkCsproj( + Path.Combine(TestRootPath, "main", $"main.csproj"), + projectCreator: creator => + { + creator.ItemProjectReference(cargoBuild, referenceOutputAssembly: false); + }) + .Save() + .TryBuild("Restore", out bool result, out BuildOutput restoreOutput); + + result.ShouldBeTrue(restoreOutput.GetConsoleLog()); + + using (BuildManager buildManager = new BuildManager()) + using (ProjectCollection projectCollection = new ProjectCollection()) + { + try + { + BuildOutput buildOutput = BuildOutput.Create(); + + buildManager.BeginBuild( + new BuildParameters(projectCollection) + { + Loggers = new[] { buildOutput }, + IsolateProjects = true, + }); + GraphBuildResult graphResult = buildManager.BuildRequest( + new GraphBuildRequestData( + [new ProjectGraphEntryPoint(project.FullPath, new Dictionary())], + new List { "Build" })); + var console = buildOutput.GetConsoleLog(); + graphResult.OverallResult.ShouldBe(BuildResultCode.Success, graphResult.Exception?.ToString()); + } + finally + { + buildManager.EndBuild(); + } + } + } + +#if NETFRAMEWORK + [Fact] + public void StaticGraphBuildsSucceedLegacyCsproj() + { + ProjectCreator legacyReference = ProjectCreator.Templates.LegacyCsproj( + Path.Combine(TestRootPath, "legacy", "legacy.csproj"), + targetFrameworkVersion: "v4.7.2") + .Save(); + + ProjectCreator cargoBuild = ProjectCreator.Templates.CargoBuildProject( + path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj"), + customAction: creator => + { + creator.ItemProjectReference(legacyReference, referenceOutputAssembly: false); + }).Save(); + + ProjectCreator project = ProjectCreator.Templates.SdkCsproj( + Path.Combine(TestRootPath, "main", $"main.csproj"), + projectCreator: creator => + { + creator.ItemProjectReference(cargoBuild, referenceOutputAssembly: false); + }) + .Save() + .TryBuild("Restore", out bool result, out BuildOutput restoreOutput); + + result.ShouldBeTrue(restoreOutput.GetConsoleLog()); + + using (BuildManager buildManager = new BuildManager()) + using (ProjectCollection projectCollection = new ProjectCollection()) + { + try + { + BuildOutput buildOutput = BuildOutput.Create(); + + buildManager.BeginBuild( + new BuildParameters(projectCollection) + { + Loggers = new[] { buildOutput }, + IsolateProjects = true, + }); + + GraphBuildResult graphResult = buildManager.BuildRequest( + new GraphBuildRequestData( + new[] { new ProjectGraphEntryPoint(project.FullPath, new Dictionary()) }, + new List { "Build" })); + + graphResult.OverallResult.ShouldBe(BuildResultCode.Success, graphResult.Exception?.ToString()); + } + finally + { + buildManager.EndBuild(); + } + } + } +#endif + + [Theory] + [InlineData(".csproj", "Build")] + [InlineData(".csproj", "Compile")] + [InlineData(".csproj", "CoreCompile")] + [InlineData(".msbuildproj", "Build")] + [InlineData(".msbuildproj", "Compile")] + [InlineData(".msbuildproj", "CoreCompile")] + public void SupportedTargetsExecute(string extension, string target) + { + Dictionary globalProperties = new Dictionary + { + ["DesignTimeBuild"] = bool.TrueString, + }; + + bool result; + BuildOutput buildOutput; + + using (ProjectCollection projectCollection = new ProjectCollection(globalProperties)) + { + ProjectCreator.Create() + .Target("EnableIntermediateOutputPathMismatchWarning") + .Save(Path.Combine(TestRootPath, "Directory.Build.targets")); + + ProjectCreator.Templates.CargoBuildProject( + path: GetTempFileWithExtension(extension), + projectCollection: projectCollection) + .Property("GenerateDependencyFile", "false") + .Save() + .TryBuild(target, out result, out buildOutput); + } + + result.ShouldBeTrue(buildOutput.GetConsoleLog()); + } + + [Fact] + public void UsingMicrosoftCargoBuildSdkValueSet() + { + ProjectCreator.Templates.CargoBuildProject( + path: GetTempFileWithExtension(".cargoproj")) + .TryGetPropertyValue("UsingMicrosoftCargoBuildSdk", out string propertyValue); + + propertyValue.ShouldBe("true"); + } + } +} \ No newline at end of file diff --git a/src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs b/src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs new file mode 100644 index 0000000..351081f --- /dev/null +++ b/src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the MIT license. + +using Microsoft.Build.Evaluation; +using Microsoft.Build.Utilities.ProjectCreation; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Microsoft.Build.CargoBuild.UnitTests +{ + public static class CustomProjectCreatorTemplates + { + private static readonly string ThisAssemblyDirectory = Path.GetDirectoryName(typeof(CustomProjectCreatorTemplates).Assembly.Location); + + public static ProjectCreator CargoBuildProject( + this ProjectCreatorTemplates templates, + Action customAction = null, + string path = null, +#if NETFRAMEWORK + string targetFramework = "net472", +#else + string targetFramework = "netstandard2.0", +#endif + string defaultTargets = null, + string initialTargets = null, + string sdk = null, + string toolsVersion = null, + string treatAsLocalProperty = null, + ProjectCollection projectCollection = null, + IDictionary globalProperties = null, + NewProjectFileOptions? projectFileOptions = NewProjectFileOptions.None) + { + return ProjectCreator.Create( + path, + defaultTargets, + initialTargets, + sdk, + toolsVersion, + treatAsLocalProperty, + projectCollection, + projectFileOptions, + globalProperties) + .Import(Path.Combine(ThisAssemblyDirectory, "Sdk", "Sdk.props")) + .Property("TargetFramework", targetFramework) + .CustomAction(customAction) + .Import(Path.Combine(ThisAssemblyDirectory, "Sdk", "Sdk.targets")); + } + } +} \ No newline at end of file diff --git a/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj b/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj new file mode 100644 index 0000000..0d98038 --- /dev/null +++ b/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj @@ -0,0 +1,25 @@ + + + net472;net8.0;net9.0 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Rust/CargoBuildTask.cs b/src/CargoBuild/CargoBuildTask.cs similarity index 97% rename from src/Rust/CargoBuildTask.cs rename to src/CargoBuild/CargoBuildTask.cs index 7f8cbd4..6445c13 100644 --- a/src/Rust/CargoBuildTask.cs +++ b/src/CargoBuild/CargoBuildTask.cs @@ -34,6 +34,7 @@ public class CargoBuildTask : Task private static readonly string _msRustupBinary = $"{_tempPath}\\cargohome\\bin\\msrustup.exe"; private static readonly Dictionary _envVars = new () { { "CARGO_HOME", _cargoHome }, { "RUSTUP_HOME", _rustupHome }, }; private static readonly string _rustupDownloadLink = "https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe"; + private static readonly string _checkSumVerifyUrl = "https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe.sha256"; private bool _shouldCleanRustPath; private string? _currentRustupInitExeCheckSum; @@ -78,8 +79,6 @@ private enum ExitCode /// public override bool Execute() { - Debugger.Launch(); - // download & install rust if necessary if (DownloadRustupAsync().GetAwaiter().GetResult()) { @@ -98,7 +97,7 @@ public override bool Execute() } } - if (!Command.Equals("fetch", StringComparison.InvariantCultureIgnoreCase)) // build + if (!Command.Equals("fetch", StringComparison.InvariantCultureIgnoreCase)) { var dir = Directory.GetParent(StartupProj!); bool cargoFile = File.Exists(Path.Combine(dir!.FullName, "cargo.toml")); @@ -111,7 +110,7 @@ public override bool Execute() private async Task CargoRunCommandAsync(string command, string args) { - Log.LogMessage(MessageImportance.Normal, $"Running cargo command: {command} {args}"); + Log.LogMessage(MessageImportance.Normal, $"Executing cargo command: {command} {args}"); return await ExecuteProcessAsync(_cargoPath, $"{command} {args}", ".", _envVars); } @@ -414,14 +413,13 @@ private async Task VerifyInitHashAsync() private async Task GetHashAsync() { - string checkSumVerifyUrl = $"https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe.sha256"; if (!string.IsNullOrEmpty(_currentRustupInitExeCheckSum)) { return _currentRustupInitExeCheckSum!; } using var client = new HttpClient(); - string response = await client.GetStringAsync(checkSumVerifyUrl); + string response = await client.GetStringAsync(_checkSumVerifyUrl); _currentRustupInitExeCheckSum = response.Split('\n')[0]; _currentRustupInitExeCheckSum = _currentRustupInitExeCheckSum!.ToUpperInvariant(); diff --git a/src/Rust/CargoBuild.csproj b/src/CargoBuild/Microsoft.Build.CargoBuild.csproj similarity index 80% rename from src/Rust/CargoBuild.csproj rename to src/CargoBuild/Microsoft.Build.CargoBuild.csproj index 3805de7..458d009 100644 --- a/src/Rust/CargoBuild.csproj +++ b/src/CargoBuild/Microsoft.Build.CargoBuild.csproj @@ -5,8 +5,8 @@ net6.0;net472 true 1.0.0 - MSBuild.CargoBuild - https://www.1eswiki.com/wiki/Using_Rust_with_CloudBuild + Microsoft.Build.CargoBuild + Builds rust projects within msbuild using cargo. true build\ true @@ -24,10 +24,9 @@ - - - + + + - diff --git a/src/Rust/README.md b/src/CargoBuild/README.md similarity index 80% rename from src/Rust/README.md rename to src/CargoBuild/README.md index 963d98f..dff3957 100644 --- a/src/Rust/README.md +++ b/src/CargoBuild/README.md @@ -7,13 +7,13 @@ To use this sdk you will need the following: ```json "msbuild-sdks": { ..., - "MSBuild.CargoBuild": "1.0.270-gf406f8eaa0" + "Microsoft.Build.CargoBuild": "1.0.270-gf406f8eaa0" }, ``` -2) foreach rust project a csproj project file at the same level as your cargo.toml file. The project file should import the CargoBuild sdk. +2) foreach rust project a .cargosproj project file at the same level as your cargo.toml file. The project file should import the CargoBuild sdk. ```xml - + net472 @@ -24,10 +24,10 @@ To use this sdk you will need the following: ```xml - + - + ``` @@ -72,7 +72,7 @@ msbuild /t:clearcargocache ``` ### How to test locally -1) After building the cargo build project, a nupkg file will be created in the `bin\Debug` or `bin\Release` folder. A file like `MSBuild.CargoBuild..nupkg` will be created +1) After building the cargo build project, a nupkg file will be created in the `bin\Debug` or `bin\Release` folder. A file like `Microsoft.Build.CargoBuild..nupkg` will be created 2) In repo that contains your rust project(s), update your nuget.config file to point to the CargoBuild `bin\Debug` or `bin\Release` folder. @@ -85,7 +85,7 @@ msbuild /t:clearcargocache ```xml "msbuild-sdks": { ..., - "MSBuild.CargoBuild": "" + "Microsoft.Build.CargoBuild": "" } ``` 4) Once you run `msbuild /restore` in your rust project, the CargoBuild sdk will be restored from the local nuget source. You can now use the sdk locally. diff --git a/src/Rust/dist/msrustup.ps1 b/src/CargoBuild/dist/msrustup.ps1 similarity index 100% rename from src/Rust/dist/msrustup.ps1 rename to src/CargoBuild/dist/msrustup.ps1 diff --git a/src/CargoBuild/sdk/DisableCopyFilesMarkedCopyLocal.targets b/src/CargoBuild/sdk/DisableCopyFilesMarkedCopyLocal.targets new file mode 100644 index 0000000..6be7cc0 --- /dev/null +++ b/src/CargoBuild/sdk/DisableCopyFilesMarkedCopyLocal.targets @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Rust/sdk/Sdk.props b/src/CargoBuild/sdk/Sdk.props similarity index 98% rename from src/Rust/sdk/Sdk.props rename to src/CargoBuild/sdk/Sdk.props index 02afa96..5fcda96 100644 --- a/src/Rust/sdk/Sdk.props +++ b/src/CargoBuild/sdk/Sdk.props @@ -6,7 +6,7 @@ - true + true $(MSBuildAllProjects);$(MsBuildThisFileFullPath) diff --git a/src/Rust/sdk/Sdk.targets b/src/CargoBuild/sdk/Sdk.targets similarity index 96% rename from src/Rust/sdk/Sdk.targets rename to src/CargoBuild/sdk/Sdk.targets index f74448d..becee84 100644 --- a/src/Rust/sdk/Sdk.targets +++ b/src/CargoBuild/sdk/Sdk.targets @@ -104,8 +104,8 @@ - - + + From e0426355b56e2887d54bf7b0f32844e2e457779d Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Fri, 10 Jan 2025 10:03:43 -0800 Subject: [PATCH 14/24] readme updates, update version, cleanup --- .../Microsoft.Build.CargoBuild.csproj | 1 - src/CargoBuild/README.md | 76 +++++++++++++------ src/CargoBuild/sdk/Sdk.props | 1 + src/CargoBuild/version.json | 4 + 4 files changed, 58 insertions(+), 24 deletions(-) create mode 100644 src/CargoBuild/version.json diff --git a/src/CargoBuild/Microsoft.Build.CargoBuild.csproj b/src/CargoBuild/Microsoft.Build.CargoBuild.csproj index 458d009..7a257de 100644 --- a/src/CargoBuild/Microsoft.Build.CargoBuild.csproj +++ b/src/CargoBuild/Microsoft.Build.CargoBuild.csproj @@ -4,7 +4,6 @@ enable net6.0;net472 true - 1.0.0 Microsoft.Build.CargoBuild Builds rust projects within msbuild using cargo. true diff --git a/src/CargoBuild/README.md b/src/CargoBuild/README.md index dff3957..a7e4c21 100644 --- a/src/CargoBuild/README.md +++ b/src/CargoBuild/README.md @@ -14,20 +14,9 @@ To use this sdk you will need the following: 2) foreach rust project a .cargosproj project file at the same level as your cargo.toml file. The project file should import the CargoBuild sdk. ```xml - - net472 - - -``` - -3) if using a dirs.proj file at the root of your repo, you will need to import the CargoBuild sdk. -```xml - - - - - - + + your framework version + ``` @@ -70,6 +59,27 @@ To clear the cargo home cache ```shell msbuild /t:clearcargocache ``` + +### Opening .cargoproj files in Visual Studio +To work with .cargoproj files in Visual Studio, you will need to add the following to your .cargoproj file. +Specifically an itemgroup with a None item for the rust source files. + +```xml + + + your framework version + target + + + + + +``` +Next you will need to run [slngen](https://github.com/microsoft/slngen) to generate the .sln file for the project. +```shell +slngen +``` + ### How to test locally 1) After building the cargo build project, a nupkg file will be created in the `bin\Debug` or `bin\Release` folder. A file like `Microsoft.Build.CargoBuild..nupkg` will be created @@ -77,15 +87,35 @@ msbuild /t:clearcargocache 2) In repo that contains your rust project(s), update your nuget.config file to point to the CargoBuild `bin\Debug` or `bin\Release` folder. ```xml - - - + + + ``` + 3) In the repo that contains your rust project, update your `global.json` to include the Sdk. Use the version number from the nupkg file above as the sdk version. - ```xml - "msbuild-sdks": { - ..., - "Microsoft.Build.CargoBuild": "" - } - ``` +```json + "msbuild-sdks": { + ..., + "Microsoft.Build.CargoBuild": "" + } +``` 4) Once you run `msbuild /restore` in your rust project, the CargoBuild sdk will be restored from the local nuget source. You can now use the sdk locally. + + + ### Using MSRustup (Microsoft internal use only) + To enable use of MSRustup, you will need to set the following MSBuild property in one of the following places: + + ```shell + msbuild /p:UseMsRustup=true + ``` + or in your Directory.Build.rsp + ``` + -Property:UseMsRustup=True + ``` + or + in your .cargosproj +```xml + + true + +``` \ No newline at end of file diff --git a/src/CargoBuild/sdk/Sdk.props b/src/CargoBuild/sdk/Sdk.props index 5fcda96..dd7cbc9 100644 --- a/src/CargoBuild/sdk/Sdk.props +++ b/src/CargoBuild/sdk/Sdk.props @@ -88,6 +88,7 @@ + false \ No newline at end of file diff --git a/src/CargoBuild/version.json b/src/CargoBuild/version.json new file mode 100644 index 0000000..3810166 --- /dev/null +++ b/src/CargoBuild/version.json @@ -0,0 +1,4 @@ +{ + "inherit": true, + "version": "1.0-preview" +} From 5d85227c02e85bccc931ef66483c44b07da5aad0 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Wed, 15 Jan 2025 15:14:48 -0800 Subject: [PATCH 15/24] clean up --- src/CargoBuild.UnitTests/CargoBuildTest.cs | 110 +++------- .../CustomProjectCreatorTemplates.cs | 32 +++ ...icrosoft.Build.CargoBuild.UnitTests.csproj | 22 +- src/CargoBuild/CargoBuildTask.cs | 144 ++++++------- .../Microsoft.Build.CargoBuild.csproj | 61 +++--- src/CargoBuild/README.md | 41 +--- src/CargoBuild/sdk/Sdk.props | 128 ++++++----- src/CargoBuild/sdk/Sdk.targets | 202 +++++++++--------- 8 files changed, 350 insertions(+), 390 deletions(-) diff --git a/src/CargoBuild.UnitTests/CargoBuildTest.cs b/src/CargoBuild.UnitTests/CargoBuildTest.cs index 52e7cc7..6369766 100644 --- a/src/CargoBuild.UnitTests/CargoBuildTest.cs +++ b/src/CargoBuild.UnitTests/CargoBuildTest.cs @@ -39,6 +39,8 @@ public void CompileIsExtensibleWithBeforeAfterTargets(string targetName) { ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( path: Path.Combine(TestRootPath, "Rust", "Microsoft.Build.CargoBuild.UnitTests.csproj")) + .Target("CargoFetch") + .Target("CargoBuild") .Target(targetName) .TaskMessage("503CF1EBA6DC415F95F4DB630E7C1817", MessageImportance.High) .Save(); @@ -56,6 +58,8 @@ public void CoreCompileIsExtensibleWithCoreCompileDependsOn() ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj")) .Property("CoreCompileDependsOn", "$(CoreCompileDependsOn);TestThatCoreCompileIsExtensible") + .Target("CargoFetch") + .Target("CargoBuild") .Target("TestThatCoreCompileIsExtensible") .TaskMessage("35F1C217730445E0AC0F30E70F5C7826", MessageImportance.High) .Save(); @@ -73,6 +77,9 @@ public void CoreCompileIsExtensibleWithTargetsTriggeredByCompilation() ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj")) .Property("TargetsTriggeredByCompilation", "TestThatCoreCompileIsExtensible") + .Property("TargetsTriggeredByCompilation", "TestThatCoreCompileIsExtensible") + .Target("CargoFetch") + .Target("CargoBuild") .Target("TestThatCoreCompileIsExtensible") .TaskMessage("D031211C98F1454CA47A424ADC86A8F7", MessageImportance.High) .Save(); @@ -98,6 +105,8 @@ public void DoNotReferenceOutputAssemblies() ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj")) + .Target("CargoFetch") + .Target("CargoBuild") .ItemProjectReference(projectA) .Save(); @@ -108,8 +117,6 @@ public void DoNotReferenceOutputAssemblies() [Theory] [InlineData(".cargoproj")] - [InlineData(".csproj")] - [InlineData(".proj")] public void ProjectContainsStaticGraphImplementation(string projectExtension) { ProjectCreator cargoBuild = ProjectCreator.Templates.CargoBuildProject( @@ -123,6 +130,8 @@ public void ProjectContainsStaticGraphImplementation(string projectExtension) creator.Target("TakeAction", afterTargets: "Build") .TaskMessage("86F00AF59170450E9D687652D74A6394", MessageImportance.High); }) + .Target("CargoFetch") + .Target("CargoBuild") .Property("GenerateDependencyFile", "false") .Save(); @@ -145,29 +154,26 @@ void TargetProtocolShouldContainValuesForTarget(string target) } [Fact] - public void ProjectsCanDependOnCargoBuildProjects() + public void ProjectsCanDependOnEachOtherProjects() { - ProjectCreator project1 = ProjectCreator.Templates.LegacyCsproj( - Path.Combine(TestRootPath, "project1", "project1.csproj")) + ProjectCreator project1 = ProjectCreator.Templates.VcxProjProject( + path: Path.Combine(TestRootPath, "project1", "project1.vcxproj")) + .Target("GetTargetPath") + .Target("_GetCopyToOutputDirectoryItemsFromTransitiveProjectReferences") .Save(); ProjectCreator project2 = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "project2", "project2.csproj")) + path: Path.Combine(TestRootPath, "project2", "project2.cargoproj")) .Property("DesignTimeBuild", "true") .Property("GenerateDependencyFile", "false") .Target("_GetProjectReferenceTargetFrameworkProperties") + .Target("_GetCopyToOutputDirectoryItemsFromTransitiveProjectReferences") + .Target("CargoFetch") + .Target("CargoBuild") .ItemProjectReference(project1) .Save(); - ProjectCreator project3 = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "project3", "project3.csproj")) - .Property("DesignTimeBuild", "true") - .Property("GenerateDependencyFile", "false") - .ItemProjectReference(project2) - .Target("_GetProjectReferenceTargetFrameworkProperties") - .Save(); - - project3.TryBuild(out bool result, out BuildOutput buildOutput); + project2.TryBuild(out bool result, out BuildOutput buildOutput); result.ShouldBeTrue(buildOutput.GetConsoleLog()); } @@ -207,6 +213,8 @@ public void PropertiesHaveExpectedValues(string propertyName, string value, stri ProjectCreator.Templates.CargoBuildProject( path: GetTempFileWithExtension(".cargoproj")) .Property(propertyName, value) + .Target("CargoFetch") + .Target("CargoBuild") .Save() .TryGetPropertyValue(propertyName, out string actualValue); @@ -215,8 +223,6 @@ public void PropertiesHaveExpectedValues(string propertyName, string value, stri [Theory] [InlineData(".cargoproj")] - [InlineData(".csproj")] - [InlineData(".proj")] public void PublishWithNoBuild(string projectExtension) { ProjectCreator.Templates.CargoBuildProject( @@ -229,6 +235,8 @@ public void PublishWithNoBuild(string projectExtension) .Target("TakeAction", afterTargets: "Build") .TaskMessage("2EA26E6FC5C842B682AA26096A769E07", MessageImportance.High); }) + .Target("CargoFetch") + .Target("CargoBuild") .Save() .TryBuild(restore: true, "Build", out bool buildResult, out BuildOutput buildOutput) .TryBuild("Publish", new Dictionary { ["NoBuild"] = "true" }, out bool publishResult, out BuildOutput publishOutput); @@ -244,8 +252,6 @@ public void PublishWithNoBuild(string projectExtension) [Theory] [InlineData(".cargoproj")] - [InlineData(".csproj")] - [InlineData(".proj")] public void SimpleBuild(string projectExtension) { ProjectCreator.Templates.CargoBuildProject( @@ -261,6 +267,8 @@ public void SimpleBuild(string projectExtension) .TaskMessage("86F00AF59170450E9D687652D74A6394", MessageImportance.High); }) .Property("GenerateDependencyFile", "false") + .Target("CargoFetch") + .Target("CargoBuild") .Save() .TryBuild("Build", out bool result, out BuildOutput buildOutput); @@ -269,58 +277,6 @@ public void SimpleBuild(string projectExtension) buildOutput.Messages.High.ShouldContain("86F00AF59170450E9D687652D74A6394"); } - [Fact] - public void StaticGraphBuildsSucceed() - { - ProjectCreator sdkReference = ProjectCreator.Templates.SdkCsproj( - Path.Combine(TestRootPath, "sdkstyle", "sdkstyle.csproj")) - .Save(); - - ProjectCreator cargoBuild = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj"), - customAction: creator => - { - creator.ItemProjectReference(sdkReference, referenceOutputAssembly: false); - }).Save(); - - ProjectCreator project = ProjectCreator.Templates.SdkCsproj( - Path.Combine(TestRootPath, "main", $"main.csproj"), - projectCreator: creator => - { - creator.ItemProjectReference(cargoBuild, referenceOutputAssembly: false); - }) - .Save() - .TryBuild("Restore", out bool result, out BuildOutput restoreOutput); - - result.ShouldBeTrue(restoreOutput.GetConsoleLog()); - - using (BuildManager buildManager = new BuildManager()) - using (ProjectCollection projectCollection = new ProjectCollection()) - { - try - { - BuildOutput buildOutput = BuildOutput.Create(); - - buildManager.BeginBuild( - new BuildParameters(projectCollection) - { - Loggers = new[] { buildOutput }, - IsolateProjects = true, - }); - GraphBuildResult graphResult = buildManager.BuildRequest( - new GraphBuildRequestData( - [new ProjectGraphEntryPoint(project.FullPath, new Dictionary())], - new List { "Build" })); - var console = buildOutput.GetConsoleLog(); - graphResult.OverallResult.ShouldBe(BuildResultCode.Success, graphResult.Exception?.ToString()); - } - finally - { - buildManager.EndBuild(); - } - } - } - #if NETFRAMEWORK [Fact] public void StaticGraphBuildsSucceedLegacyCsproj() @@ -343,6 +299,8 @@ public void StaticGraphBuildsSucceedLegacyCsproj() { creator.ItemProjectReference(cargoBuild, referenceOutputAssembly: false); }) + .Target("CargoFetch") + .Target("CargoBuild") .Save() .TryBuild("Restore", out bool result, out BuildOutput restoreOutput); @@ -378,9 +336,9 @@ public void StaticGraphBuildsSucceedLegacyCsproj() #endif [Theory] - [InlineData(".csproj", "Build")] - [InlineData(".csproj", "Compile")] - [InlineData(".csproj", "CoreCompile")] + [InlineData(".cargoproj", "Build")] + [InlineData(".cargoproj", "Compile")] + [InlineData(".cargoproj", "CoreCompile")] [InlineData(".msbuildproj", "Build")] [InlineData(".msbuildproj", "Compile")] [InlineData(".msbuildproj", "CoreCompile")] @@ -404,6 +362,8 @@ public void SupportedTargetsExecute(string extension, string target) path: GetTempFileWithExtension(extension), projectCollection: projectCollection) .Property("GenerateDependencyFile", "false") + .Target("CargoFetch") + .Target("CargoBuild") .Save() .TryBuild(target, out result, out buildOutput); } @@ -412,7 +372,7 @@ public void SupportedTargetsExecute(string extension, string target) } [Fact] - public void UsingMicrosoftCargoBuildSdkValueSet() + public void UsingMicrosofCargoBuildSdkValueSet() { ProjectCreator.Templates.CargoBuildProject( path: GetTempFileWithExtension(".cargoproj")) diff --git a/src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs b/src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs index 351081f..868ba1d 100644 --- a/src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs +++ b/src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs @@ -47,5 +47,37 @@ public static ProjectCreator CargoBuildProject( .CustomAction(customAction) .Import(Path.Combine(ThisAssemblyDirectory, "Sdk", "Sdk.targets")); } + + public static ProjectCreator VcxProjProject( + this ProjectCreatorTemplates templates, + Action customAction = null, + string path = null, +#if NETFRAMEWORK + string targetFramework = "net472", +#else + string targetFramework = "netstandard2.0", +#endif + string defaultTargets = null, + string initialTargets = null, + string sdk = null, + string toolsVersion = null, + string treatAsLocalProperty = null, + ProjectCollection projectCollection = null, + IDictionary globalProperties = null, + NewProjectFileOptions? projectFileOptions = NewProjectFileOptions.None) + { + return ProjectCreator.Create( + path, + defaultTargets, + initialTargets, + sdk, + toolsVersion, + treatAsLocalProperty, + projectCollection, + projectFileOptions, + globalProperties) + .Property("TargetFramework", targetFramework) + .CustomAction(customAction); + } } } \ No newline at end of file diff --git a/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj b/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj index 0d98038..1d5dc41 100644 --- a/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj +++ b/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj @@ -1,25 +1,35 @@  - net472;net8.0;net9.0 + net8.0 + ShadeDependencies="NuGet.Frameworks" /> + + + - + + Link="Sdk\%(RecursiveDir)%(Filename)%(Extension)" + CopyToOutputDirectory="PreserveNewest" /> + + + + + + \ No newline at end of file diff --git a/src/CargoBuild/CargoBuildTask.cs b/src/CargoBuild/CargoBuildTask.cs index 6445c13..b7eafd8 100644 --- a/src/CargoBuild/CargoBuildTask.cs +++ b/src/CargoBuild/CargoBuildTask.cs @@ -23,7 +23,7 @@ namespace MSBuild.CargoBuild /// public class CargoBuildTask : Task { - private static readonly string _tempPath = $"{Environment.GetEnvironmentVariable("TEMP")}"; + private static readonly string? _tempPath = Environment.GetEnvironmentVariable("TEMP"); private static readonly string _rustUpBinary = $"{_tempPath}\\cargohome\\bin\\rustup.exe"; private static readonly string _cargoPath = $"{_tempPath}\\cargohome\\bin\\cargo.exe"; private static readonly string _rustInstallPath = $"{_tempPath}\\rustinstall"; @@ -61,11 +61,6 @@ private enum ExitCode /// public bool EnableAuth { get; set; } = false; - /// - /// Gets or sets a feed name. - /// - public string RegistryFeedName { get; set; } = string.Empty; - /// /// Gets or sets optional cargo command args. /// @@ -78,34 +73,52 @@ private enum ExitCode /// public override bool Execute() + { + return ExecuteAsync().GetAwaiter().GetResult(); + } + + private static void CleanupRustPath() + { + if (Directory.Exists(_rustUpInitBinary)) + { + Directory.Delete(_rustUpInitBinary, true); + } + } + + private async Task ExecuteAsync() { // download & install rust if necessary - if (DownloadRustupAsync().GetAwaiter().GetResult()) + if (Command.Equals("fetch") && await DownloadRustupAsync()) { - if (InstallRust().GetAwaiter().GetResult()) + if (await InstallRust()) { _shouldCleanRustPath = true; } - } - if (Command.Equals("clearcargocache", StringComparison.InvariantCultureIgnoreCase)) + return await FetchCratesAsync(StartupProj); + } + else if (Command.Equals("clearcargocache", StringComparison.InvariantCultureIgnoreCase)) { if (Directory.Exists(_cargoHome)) { Log.LogMessage(MessageImportance.Normal, $"Clearing cargo cache at {_cargoHome}"); Directory.Delete(_cargoHome, true); } - } - if (!Command.Equals("fetch", StringComparison.InvariantCultureIgnoreCase)) + return true; + } + else { - var dir = Directory.GetParent(StartupProj!); - bool cargoFile = File.Exists(Path.Combine(dir!.FullName, "cargo.toml")); + var dir = Directory.GetParent(StartupProj) ?? throw new InvalidOperationException("Invalid project path"); + bool cargoFileExists = File.Exists(Path.Combine(dir.FullName, "cargo.toml")); // toml file should be the same dir as the cargoproj file. + if (!cargoFileExists) + { + Log.LogError("Cargo.toml file not found in the project directory."); + return false; + } - return !cargoFile || CargoRunCommandAsync(Command.ToLower(), CommandArgs).GetAwaiter().GetResult() == ExitCode.Succeeded; + return await CargoRunCommandAsync(Command.ToLower(), CommandArgs) == ExitCode.Succeeded; } - - return FetchCratesAsync(StartupProj!).GetAwaiter().GetResult(); } private async Task CargoRunCommandAsync(string command, string args) @@ -120,7 +133,7 @@ private async Task FetchCratesAsync(string project) try { stopwatch.Start(); - Log.LogMessage(MessageImportance.Normal, $"---- CargoBuild fetch Starting ----\n\n"); + Log.LogMessage(MessageImportance.Normal, "CargoBuild fetch Starting"); var graphLoadStopWatch = new Stopwatch(); graphLoadStopWatch.Start(); @@ -131,7 +144,7 @@ [new ProjectGraphEntryPoint(project)], ProjectCollection.GlobalProjectCollection, (string projectPath, Dictionary globalProperties, ProjectCollection projCollection) => { - var loadSettings = ProjectLoadSettings.DoNotEvaluateElementsWithFalseCondition; + var loadSettings = ProjectLoadSettings.IgnoreEmptyImports | ProjectLoadSettings.IgnoreInvalidImports | ProjectLoadSettings.IgnoreMissingImports | ProjectLoadSettings.DoNotEvaluateElementsWithFalseCondition; var projectOptions = new ProjectOptions { @@ -176,16 +189,17 @@ [new ProjectGraphEntryPoint(project)], tasks.Add(fetchTask); } - await Tasks.Task.WhenAll(tasks.ToArray()); - bool success = tasks.Select(x => (int)x.Result).Sum() == 0; + await Tasks.Task.WhenAll(tasks); + ExitCode[] exitCodes = await Tasks.Task.WhenAll(tasks); + bool success = exitCodes.All(exitCode => exitCode == ExitCode.Succeeded); stopwatch.Stop(); if (success) { - Log.LogMessage(MessageImportance.Normal, $"---- CargoBuild fetching Completed Successfully in {stopwatch.Elapsed.Seconds} seconds ----\n\n"); + Log.LogMessage(MessageImportance.Normal, $"CargoBuild fetching Completed Successfully in {stopwatch.Elapsed.Seconds} seconds"); } else { - Log.LogError($"---- CargoBuild fetching had an issue. Check the build log for details. ----\n\n"); + Log.LogError("CargoBuild fetching had an issue. Check the build log for details."); } return success; @@ -223,17 +237,13 @@ private async Task RustFetchAsync(string workingDir, bool authorize = { ExitCode authResult = authorize ? await DoRegistryAuthAsync(workingDir) : ExitCode.Succeeded; - if (authorize && authResult == ExitCode.Succeeded || !authorize) + if (authResult == ExitCode.Succeeded) { - string path; - string args; - const int RetryCnt = 2; - - path = _cargoPath; - args = "fetch"; + string path = _cargoPath; + string args = "fetch"; Log.LogMessage(MessageImportance.Normal, $"Fetching cargo crates for project in {workingDir}"); - var exitCode = await ExecuteWithRetriesAsync(path, processArgs: args, workingDir, retryCount: RetryCnt, processRetryArgs: args); + var exitCode = await ExecuteProcessAsync(path, args, workingDir); Log.LogMessage(MessageImportance.Normal, $"Finished fetching cargo crates for project in {workingDir}"); return exitCode; } @@ -241,27 +251,9 @@ private async Task RustFetchAsync(string workingDir, bool authorize = return authResult; } - private async Task ExecuteWithRetriesAsync(string processFileName, string processArgs, string workingDir, int retryCount, string? processRetryArgs = null) - { - ExitCode exitCode = await ExecuteProcessAsync(processFileName, processArgs, workingDir); - const int InitialWaitTimeSec = 3; - int retries = 0; - while (exitCode != 0 && retries < retryCount) - { - retries++; - int wait = InitialWaitTimeSec * 1000 * retries; - Log.LogMessage(MessageImportance.Normal, $"Process failed with exit code: {exitCode}. Retry #{retries}: {processFileName}. Waiting {wait / 600} seconds before retrying."); - - await Tasks.Task.Delay(wait); - exitCode = await ExecuteProcessAsync(processFileName, processRetryArgs ?? processArgs, workingDir); - } - - return exitCode; - } - private async Task DoRegistryAuthAsync(string workingDir) { - return await ExecuteWithRetriesAsync(_cargoPath, $"login --registry {RegistryFeedName}", workingDir, retryCount: 2); + return await ExecuteProcessAsync(_cargoPath, $"login", workingDir); } private async Task ExecuteProcessAsync(string fileName, string args, string workingDir, Dictionary? envars = null) @@ -314,22 +306,24 @@ private async Task ExecuteProcessAsync(string fileName, string args, s }); processTask.Start(); - return (ExitCode)await processTask; + int exitCode = await processTask; + return exitCode == 0 ? ExitCode.Succeeded : ExitCode.Failed; } catch (Exception ex) { Log.LogWarningFromException(ex); - return await Tasks.Task.FromResult(ExitCode.Failed); + return ExitCode.Failed; } } private async Task DownloadRustupAsync() { - if (File.Exists(_rustUpInitBinary) && await VerifyInitHashAsync()) + var rustupBinExists = File.Exists(_rustUpInitBinary); + if (rustupBinExists && await VerifyInitHashAsync()) { return true; } - else if (File.Exists(_rustUpInitBinary)) + else if (rustupBinExists) { // If the hash doesn't match, that likely means there is a new version of rustup-init.exe available. File.Delete(_rustUpInitBinary); @@ -337,26 +331,25 @@ private async Task DownloadRustupAsync() string rustupDownloadLink = _rustupDownloadLink; Log.LogMessage(MessageImportance.Normal, $"Downloading -- {rustupDownloadLink}"); - using (var client = new HttpClient()) + using var client = new HttpClient(); + HttpResponseMessage response = await client.GetAsync(rustupDownloadLink); + response.EnsureSuccessStatusCode(); + if (!Directory.Exists(_rustInstallPath)) { - Task response = client.GetAsync(rustupDownloadLink); - if (!Directory.Exists(_rustInstallPath)) - { - Directory.CreateDirectory(_rustInstallPath); - } - - using var responseStream = new FileStream(_rustUpInitBinary, FileMode.CreateNew); - HttpResponseMessage res = await response; - await res.Content.CopyToAsync(responseStream); + Directory.CreateDirectory(_rustInstallPath); } + using var fileStream = new FileStream(_rustUpInitBinary, FileMode.CreateNew); + HttpResponseMessage res = response; + await res.Content.CopyToAsync(fileStream); + return await VerifyInitHashAsync(); } private async Task InstallRust() { var rustupBinary = UseMsRustUp ? _msRustupBinary : _rustUpBinary; - if (File.Exists(_cargoPath) && Directory.Exists(_rustupHome) && File.Exists(_rustUpBinary) || File.Exists(_cargoHome) && UseMsRustUp != true || File.Exists(_msRustupBinary)) + if ((File.Exists(_cargoPath) && Directory.Exists(_rustupHome) && File.Exists(_rustUpBinary)) || (File.Exists(_cargoHome) && UseMsRustUp != true) || File.Exists(_msRustupBinary)) { return false; } @@ -372,15 +365,11 @@ private async Task InstallRust() } } - foreach (var envVar in _envVars) - { - Environment.SetEnvironmentVariable(envVar.Key, envVar.Value); - } - ExitCode exitCode = ExitCode.Succeeded; ExitCode exitCodeToolChainLatest = ExitCode.Succeeded; ExitCode exitCodeLatest = ExitCode.Succeeded; + // toml should be relative to the project dir. if (UseMsRustUp && File.Exists("rust-toolchain.toml")) { Log.LogMessage(MessageImportance.Normal, "Installing Custom Toolchain"); @@ -408,7 +397,7 @@ private async Task VerifyInitHashAsync() #else converted = converted.Replace("-", string.Empty, StringComparison.Ordinal); #endif - return converted == await GetHashAsync(); + return converted.Equals(await GetHashAsync(), StringComparison.InvariantCultureIgnoreCase); } private async Task GetHashAsync() @@ -421,17 +410,12 @@ private async Task GetHashAsync() using var client = new HttpClient(); string response = await client.GetStringAsync(_checkSumVerifyUrl); _currentRustupInitExeCheckSum = response.Split('\n')[0]; - - _currentRustupInitExeCheckSum = _currentRustupInitExeCheckSum!.ToUpperInvariant(); - return _currentRustupInitExeCheckSum; - } - - private void CleanupRustPath() - { - if (Directory.Exists(_rustUpInitBinary)) + if (_currentRustupInitExeCheckSum == null) { - Directory.Delete(_rustUpInitBinary, true); + throw new InvalidOperationException("Failed to get the checksum of the rustup-init.exe"); } + + return _currentRustupInitExeCheckSum; } } } diff --git a/src/CargoBuild/Microsoft.Build.CargoBuild.csproj b/src/CargoBuild/Microsoft.Build.CargoBuild.csproj index 7a257de..bd2f2f2 100644 --- a/src/CargoBuild/Microsoft.Build.CargoBuild.csproj +++ b/src/CargoBuild/Microsoft.Build.CargoBuild.csproj @@ -1,31 +1,32 @@  - - enable - enable - net6.0;net472 - true - Microsoft.Build.CargoBuild - Builds rust projects within msbuild using cargo. - true - build\ - true - true - - true - false - $(NoWarn);NU1504;NU5100;NU5110;NU5111 - - - - PreserveNewest - true - - - - - - - - - - + + enable + enable + net8.0;net472 + true + Microsoft.Build.CargoBuild + Builds rust projects within msbuild using cargo. + true + build\ + true + true + + true + false + $(NoWarn);NU1504;NU5100;NU5110;NU5111 + + + + PreserveNewest + true + + + + + + + + + + \ No newline at end of file diff --git a/src/CargoBuild/README.md b/src/CargoBuild/README.md index a7e4c21..ce2d53f 100644 --- a/src/CargoBuild/README.md +++ b/src/CargoBuild/README.md @@ -11,48 +11,41 @@ To use this sdk you will need the following: }, ``` -2) foreach rust project a .cargosproj project file at the same level as your cargo.toml file. The project file should import the CargoBuild sdk. +2) For each rust project a .cargoproj project file at the same level as your cargo.toml file. The project file should include the CargoBuild sdk. ```xml - - your framework version - ``` ### Usage To restore rust dependencies, you can use the following msbuild command: ```shell -msbuild /t:Restore +msbuild /t:restore ``` -or -```shell -msbuild /restore -``` To build a rust project, you can use the following msbuild command: ```shell -msbuild /t:Build +msbuild ``` To clean a rust project, you can use the following msbuild command: ```shell -msbuild /p:clean=true +msbuild /t:clean ``` To run a rust project, you can use the following msbuild command: ```shell -msbuild /p:run=true +msbuild /t:run ``` To run cargo tests: ```shell -msbuild /p:test=true +msbuild /t:test ``` For cargo docs ```shell -msbuild /p:doc=true +msbuild /t:doc ``` To clear the cargo home cache @@ -60,26 +53,6 @@ To clear the cargo home cache msbuild /t:clearcargocache ``` -### Opening .cargoproj files in Visual Studio -To work with .cargoproj files in Visual Studio, you will need to add the following to your .cargoproj file. -Specifically an itemgroup with a None item for the rust source files. - -```xml - - - your framework version - target - - - - - -``` -Next you will need to run [slngen](https://github.com/microsoft/slngen) to generate the .sln file for the project. -```shell -slngen -``` - ### How to test locally 1) After building the cargo build project, a nupkg file will be created in the `bin\Debug` or `bin\Release` folder. A file like `Microsoft.Build.CargoBuild..nupkg` will be created diff --git a/src/CargoBuild/sdk/Sdk.props b/src/CargoBuild/sdk/Sdk.props index dd7cbc9..e9fb4b3 100644 --- a/src/CargoBuild/sdk/Sdk.props +++ b/src/CargoBuild/sdk/Sdk.props @@ -4,91 +4,89 @@ Licensed under the MIT license. --> - - + true $(MSBuildAllProjects);$(MsBuildThisFileFullPath) - - - true - true - true - + + true + true + true + - + - - + + false false - + - PackageReference + PackageReference - - true + + true - - false - false + + false + false - - false + + false - - false + + false - - false + + false - - true + + true - - false - false - true + + false + false + true - - true - + + true + - - - - false - true - - - - - - - - - - - - - - - false - false - true - cargo.io - - - - - - - false + false + true + + + + + + + + + + + + + + + false + + + + + + + false + + + \ No newline at end of file diff --git a/src/CargoBuild/sdk/Sdk.targets b/src/CargoBuild/sdk/Sdk.targets index becee84..08df54e 100644 --- a/src/CargoBuild/sdk/Sdk.targets +++ b/src/CargoBuild/sdk/Sdk.targets @@ -5,8 +5,10 @@ Licensed under the MIT license. --> - - - - $(MSBuildToolsPath)\Microsoft.Common.targets - $(MSBuildAllProjects);$(MsBuildThisFileFullPath) - - - - - - - false - - - $(CustomBeforeMicrosoftCommonTargets);$(MSBuildExtensionsPath)\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets - - - - - - - - BuildOnlySettings; - PrepareForBuild; - PreBuildEvent; - ResolveReferences; - Compile; - GetTargetPath; - PrepareForRun; - IncrementalClean; - PostBuildEvent - - - - None - false - - - false - - - - - - - - - - - - + false + + + $(CustomBeforeMicrosoftCommonTargets);$(MSBuildExtensionsPath)\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets + + + + + + + + BuildOnlySettings; + PrepareForBuild; + PreBuildEvent; + ResolveReferences; + Compile; + GetTargetPath; + PrepareForRun; + IncrementalClean; + PostBuildEvent + + + + None + false + + + false + + + + + + + + + + + + - + - - + - - + - - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 10a53d442502695521d336cd60907ac3192ba201 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Thu, 16 Jan 2025 10:06:04 -0800 Subject: [PATCH 16/24] update tests --- src/CargoBuild.UnitTests/CargoBuildTest.cs | 22 +++++++++++++++++----- src/CargoBuild/sdk/Sdk.targets | 4 ++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/CargoBuild.UnitTests/CargoBuildTest.cs b/src/CargoBuild.UnitTests/CargoBuildTest.cs index 6369766..7f531f3 100644 --- a/src/CargoBuild.UnitTests/CargoBuildTest.cs +++ b/src/CargoBuild.UnitTests/CargoBuildTest.cs @@ -26,6 +26,7 @@ public void CanDisableCopyFilesMarkedCopyLocal() ProjectCreator.Templates.CargoBuildProject( path: GetTempFileWithExtension(".cargoproj")) .Property("SkipCopyFilesMarkedCopyLocal", bool.TrueString) + .Property("ShouldImportSkdDll", bool.FalseString) .ItemInclude("ReferenceCopyLocalPaths", Assembly.GetExecutingAssembly().Location) .TryBuild("_CopyFilesMarkedCopyLocal", out bool result, out BuildOutput buildOutput); @@ -38,7 +39,8 @@ public void CanDisableCopyFilesMarkedCopyLocal() public void CompileIsExtensibleWithBeforeAfterTargets(string targetName) { ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "Rust", "Microsoft.Build.CargoBuild.UnitTests.csproj")) + path: Path.Combine(TestRootPath, "CargoBuild", "rust.cargoproj")) + .Property("ShouldImportSkdDll", bool.FalseString) .Target("CargoFetch") .Target("CargoBuild") .Target(targetName) @@ -56,8 +58,9 @@ public void CompileIsExtensibleWithBeforeAfterTargets(string targetName) public void CoreCompileIsExtensibleWithCoreCompileDependsOn() { ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj")) + path: Path.Combine(TestRootPath, "CargoBuild", "rust.cargoproj")) .Property("CoreCompileDependsOn", "$(CoreCompileDependsOn);TestThatCoreCompileIsExtensible") + .Property("ShouldImportSkdDll", bool.FalseString) .Target("CargoFetch") .Target("CargoBuild") .Target("TestThatCoreCompileIsExtensible") @@ -75,9 +78,10 @@ public void CoreCompileIsExtensibleWithCoreCompileDependsOn() public void CoreCompileIsExtensibleWithTargetsTriggeredByCompilation() { ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj")) + path: Path.Combine(TestRootPath, "CargoBuild", "rust.cargoproj")) .Property("TargetsTriggeredByCompilation", "TestThatCoreCompileIsExtensible") .Property("TargetsTriggeredByCompilation", "TestThatCoreCompileIsExtensible") + .Property("ShouldImportSkdDll", bool.FalseString) .Target("CargoFetch") .Target("CargoBuild") .Target("TestThatCoreCompileIsExtensible") @@ -104,7 +108,8 @@ public void DoNotReferenceOutputAssemblies() .Save(); ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj")) + path: Path.Combine(TestRootPath, "CargoBuild", "rust.cargoproj")) + .Property("ShouldImportSkdDll", bool.FalseString) .Target("CargoFetch") .Target("CargoBuild") .ItemProjectReference(projectA) @@ -166,6 +171,7 @@ public void ProjectsCanDependOnEachOtherProjects() path: Path.Combine(TestRootPath, "project2", "project2.cargoproj")) .Property("DesignTimeBuild", "true") .Property("GenerateDependencyFile", "false") + .Property("ShouldImportSkdDll", bool.FalseString) .Target("_GetProjectReferenceTargetFrameworkProperties") .Target("_GetCopyToOutputDirectoryItemsFromTransitiveProjectReferences") .Target("CargoFetch") @@ -213,6 +219,7 @@ public void PropertiesHaveExpectedValues(string propertyName, string value, stri ProjectCreator.Templates.CargoBuildProject( path: GetTempFileWithExtension(".cargoproj")) .Property(propertyName, value) + .Property("ShouldImportSkdDll", bool.FalseString) .Target("CargoFetch") .Target("CargoBuild") .Save() @@ -235,6 +242,7 @@ public void PublishWithNoBuild(string projectExtension) .Target("TakeAction", afterTargets: "Build") .TaskMessage("2EA26E6FC5C842B682AA26096A769E07", MessageImportance.High); }) + .Property("ShouldImportSkdDll", bool.FalseString) .Target("CargoFetch") .Target("CargoBuild") .Save() @@ -267,6 +275,7 @@ public void SimpleBuild(string projectExtension) .TaskMessage("86F00AF59170450E9D687652D74A6394", MessageImportance.High); }) .Property("GenerateDependencyFile", "false") + .Property("ShouldImportSkdDll", bool.FalseString) .Target("CargoFetch") .Target("CargoBuild") .Save() @@ -291,7 +300,9 @@ public void StaticGraphBuildsSucceedLegacyCsproj() customAction: creator => { creator.ItemProjectReference(legacyReference, referenceOutputAssembly: false); - }).Save(); + }) + .Property("ShouldImportSkdDll", bool.FalseString) + .Save(); ProjectCreator project = ProjectCreator.Templates.SdkCsproj( Path.Combine(TestRootPath, "main", $"main.csproj"), @@ -362,6 +373,7 @@ public void SupportedTargetsExecute(string extension, string target) path: GetTempFileWithExtension(extension), projectCollection: projectCollection) .Property("GenerateDependencyFile", "false") + .Property("ShouldImportSkdDll", bool.FalseString) .Target("CargoFetch") .Target("CargoBuild") .Save() diff --git a/src/CargoBuild/sdk/Sdk.targets b/src/CargoBuild/sdk/Sdk.targets index 08df54e..78fa748 100644 --- a/src/CargoBuild/sdk/Sdk.targets +++ b/src/CargoBuild/sdk/Sdk.targets @@ -106,8 +106,8 @@ - - + + From b0637b82c453d70b8bed92f4087a01126d290b0c Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Thu, 16 Jan 2025 10:27:52 -0800 Subject: [PATCH 17/24] rm target --- .../Microsoft.Build.CargoBuild.UnitTests.csproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj b/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj index 1d5dc41..bd3fd37 100644 --- a/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj +++ b/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj @@ -24,12 +24,4 @@ Link="Sdk\%(RecursiveDir)%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" /> - - - - - - \ No newline at end of file From 74643fb9f3e30b95122997952d31e128a7b657e0 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Thu, 16 Jan 2025 11:31:48 -0800 Subject: [PATCH 18/24] attempt test fix --- .../Microsoft.Build.CargoBuild.UnitTests.csproj | 4 ++-- src/CargoBuild/Microsoft.Build.CargoBuild.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj b/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj index bd3fd37..e34dd49 100644 --- a/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj +++ b/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj @@ -1,6 +1,6 @@  - net8.0 + net472;net8.0;net9.0 @@ -17,7 +17,7 @@ - + enable enable - net8.0;net472 + net472;net8.0;net9.0 true Microsoft.Build.CargoBuild Builds rust projects within msbuild using cargo. From ad12634b9f4cc173cf65ea1cc64b2232ef1b8691 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Thu, 16 Jan 2025 16:17:57 -0800 Subject: [PATCH 19/24] rename cargobuild -> cargo, fix tests --- MSBuildSdks.sln | 20 +-- .../CargoTest.cs} | 128 +++++------------- .../CustomProjectCreatorTemplates.cs | 7 +- .../Microsoft.Build.Cargo.UnitTests.csproj | 25 ++++ .../CargoBuildTask.cs => Cargo/CargoTask.cs} | 18 +-- src/Cargo/Microsoft.Build.Cargo.csproj | 32 +++++ src/{CargoBuild => Cargo}/README.md | 12 +- src/{CargoBuild => Cargo}/dist/msrustup.ps1 | 0 .../DisableCopyFilesMarkedCopyLocal.targets | 0 src/{CargoBuild => Cargo}/sdk/Sdk.props | 36 ++--- src/{CargoBuild => Cargo}/sdk/Sdk.targets | 34 ++--- src/{CargoBuild => Cargo}/version.json | 0 ...icrosoft.Build.CargoBuild.UnitTests.csproj | 27 ---- .../Microsoft.Build.CargoBuild.csproj | 32 ----- 14 files changed, 155 insertions(+), 216 deletions(-) rename src/{CargoBuild.UnitTests/CargoBuildTest.cs => Cargo.UnitTests/CargoTest.cs} (71%) rename src/{CargoBuild.UnitTests => Cargo.UnitTests}/CustomProjectCreatorTemplates.cs (90%) create mode 100644 src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj rename src/{CargoBuild/CargoBuildTask.cs => Cargo/CargoTask.cs} (96%) create mode 100644 src/Cargo/Microsoft.Build.Cargo.csproj rename src/{CargoBuild => Cargo}/README.md (85%) rename src/{CargoBuild => Cargo}/dist/msrustup.ps1 (100%) rename src/{CargoBuild => Cargo}/sdk/DisableCopyFilesMarkedCopyLocal.targets (100%) rename src/{CargoBuild => Cargo}/sdk/Sdk.props (76%) rename src/{CargoBuild => Cargo}/sdk/Sdk.targets (72%) rename src/{CargoBuild => Cargo}/version.json (100%) delete mode 100644 src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj delete mode 100644 src/CargoBuild/Microsoft.Build.CargoBuild.csproj diff --git a/MSBuildSdks.sln b/MSBuildSdks.sln index 598ca2f..edc0f6e 100644 --- a/MSBuildSdks.sln +++ b/MSBuildSdks.sln @@ -86,9 +86,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Build.CopyOnWrite EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Build.RunVSTest", "src\RunTests\Microsoft.Build.RunVSTest.csproj", "{B4CA4749-4CDE-499F-8372-C71966C6DB16}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Build.CargoBuild", "src\CargoBuild\Microsoft.Build.CargoBuild.csproj", "{40E51B6A-2807-4A28-8846-4E3ED2C39EBD}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Build.Cargo", "src\Cargo\Microsoft.Build.Cargo.csproj", "{D80866C1-FF2A-441B-984F-D256164BB56E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Build.CargoBuild.UnitTests", "src\CargoBuild.UnitTests\Microsoft.Build.CargoBuild.UnitTests.csproj", "{60C10404-E99C-4B8D-B2D8-1B9297A9D36B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Build.Cargo.UnitTests", "src\Cargo.UnitTests\Microsoft.Build.Cargo.UnitTests.csproj", "{D6EF1644-D06C-4877-A8F7-3543E5D3175B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -156,14 +156,14 @@ Global {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Debug|Any CPU.Build.0 = Debug|Any CPU {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Release|Any CPU.ActiveCfg = Release|Any CPU {B4CA4749-4CDE-499F-8372-C71966C6DB16}.Release|Any CPU.Build.0 = Release|Any CPU - {40E51B6A-2807-4A28-8846-4E3ED2C39EBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {40E51B6A-2807-4A28-8846-4E3ED2C39EBD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {40E51B6A-2807-4A28-8846-4E3ED2C39EBD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {40E51B6A-2807-4A28-8846-4E3ED2C39EBD}.Release|Any CPU.Build.0 = Release|Any CPU - {60C10404-E99C-4B8D-B2D8-1B9297A9D36B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {60C10404-E99C-4B8D-B2D8-1B9297A9D36B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {60C10404-E99C-4B8D-B2D8-1B9297A9D36B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {60C10404-E99C-4B8D-B2D8-1B9297A9D36B}.Release|Any CPU.Build.0 = Release|Any CPU + {D80866C1-FF2A-441B-984F-D256164BB56E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D80866C1-FF2A-441B-984F-D256164BB56E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D80866C1-FF2A-441B-984F-D256164BB56E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D80866C1-FF2A-441B-984F-D256164BB56E}.Release|Any CPU.Build.0 = Release|Any CPU + {D6EF1644-D06C-4877-A8F7-3543E5D3175B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6EF1644-D06C-4877-A8F7-3543E5D3175B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6EF1644-D06C-4877-A8F7-3543E5D3175B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6EF1644-D06C-4877-A8F7-3543E5D3175B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/CargoBuild.UnitTests/CargoBuildTest.cs b/src/Cargo.UnitTests/CargoTest.cs similarity index 71% rename from src/CargoBuild.UnitTests/CargoBuildTest.cs rename to src/Cargo.UnitTests/CargoTest.cs index 7f531f3..27e18e5 100644 --- a/src/CargoBuild.UnitTests/CargoBuildTest.cs +++ b/src/Cargo.UnitTests/CargoTest.cs @@ -16,17 +16,18 @@ using System.Reflection; using Xunit; -namespace Microsoft.Build.CargoBuild.UnitTests +namespace Microsoft.Build.Cargo.UnitTests { - public class CargoBuildTest : MSBuildSdkTestBase + public class CargoTest : MSBuildSdkTestBase { + private static readonly string ThisAssemblyDirectory = Path.GetDirectoryName(typeof(CustomProjectCreatorTemplates).Assembly.Location); + [Fact] public void CanDisableCopyFilesMarkedCopyLocal() { - ProjectCreator.Templates.CargoBuildProject( + ProjectCreator.Templates.CargoProject( path: GetTempFileWithExtension(".cargoproj")) .Property("SkipCopyFilesMarkedCopyLocal", bool.TrueString) - .Property("ShouldImportSkdDll", bool.FalseString) .ItemInclude("ReferenceCopyLocalPaths", Assembly.GetExecutingAssembly().Location) .TryBuild("_CopyFilesMarkedCopyLocal", out bool result, out BuildOutput buildOutput); @@ -38,16 +39,15 @@ public void CanDisableCopyFilesMarkedCopyLocal() [InlineData("AfterCompile")] public void CompileIsExtensibleWithBeforeAfterTargets(string targetName) { - ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "CargoBuild", "rust.cargoproj")) - .Property("ShouldImportSkdDll", bool.FalseString) + ProjectCreator cargoProject = ProjectCreator.Templates.CargoProject( + path: Path.Combine(TestRootPath, "Cargo", "rust.cargoproj")) .Target("CargoFetch") .Target("CargoBuild") .Target(targetName) .TaskMessage("503CF1EBA6DC415F95F4DB630E7C1817", MessageImportance.High) .Save(); - cargoBuildProject.TryBuild(restore: true, out bool result, out BuildOutput buildOutput); + cargoProject.TryBuild(restore: true, out bool result, out BuildOutput buildOutput); result.ShouldBeTrue(buildOutput.GetConsoleLog()); @@ -57,17 +57,16 @@ public void CompileIsExtensibleWithBeforeAfterTargets(string targetName) [Fact] public void CoreCompileIsExtensibleWithCoreCompileDependsOn() { - ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "CargoBuild", "rust.cargoproj")) + ProjectCreator cargoProject = ProjectCreator.Templates.CargoProject( + path: Path.Combine(TestRootPath, "Cargo", "rust.cargoproj")) .Property("CoreCompileDependsOn", "$(CoreCompileDependsOn);TestThatCoreCompileIsExtensible") - .Property("ShouldImportSkdDll", bool.FalseString) .Target("CargoFetch") .Target("CargoBuild") .Target("TestThatCoreCompileIsExtensible") .TaskMessage("35F1C217730445E0AC0F30E70F5C7826", MessageImportance.High) .Save(); - cargoBuildProject.TryBuild(restore: true, out bool result, out BuildOutput buildOutput); + cargoProject.TryBuild(restore: true, out bool result, out BuildOutput buildOutput); result.ShouldBeTrue(buildOutput.GetConsoleLog()); @@ -77,18 +76,17 @@ public void CoreCompileIsExtensibleWithCoreCompileDependsOn() [Fact] public void CoreCompileIsExtensibleWithTargetsTriggeredByCompilation() { - ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "CargoBuild", "rust.cargoproj")) + ProjectCreator cargoProject = ProjectCreator.Templates.CargoProject( + path: Path.Combine(TestRootPath, "Cargo", "rust.cargoproj")) .Property("TargetsTriggeredByCompilation", "TestThatCoreCompileIsExtensible") .Property("TargetsTriggeredByCompilation", "TestThatCoreCompileIsExtensible") - .Property("ShouldImportSkdDll", bool.FalseString) .Target("CargoFetch") .Target("CargoBuild") .Target("TestThatCoreCompileIsExtensible") .TaskMessage("D031211C98F1454CA47A424ADC86A8F7", MessageImportance.High) .Save(); - cargoBuildProject.TryBuild(restore: true, out bool result, out BuildOutput buildOutput); + cargoProject.TryBuild(restore: true, out bool result, out BuildOutput buildOutput); result.ShouldBeTrue(buildOutput.GetConsoleLog()); @@ -107,15 +105,15 @@ public void DoNotReferenceOutputAssemblies() #endif .Save(); - ProjectCreator cargoBuildProject = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "CargoBuild", "rust.cargoproj")) - .Property("ShouldImportSkdDll", bool.FalseString) + ProjectCreator cargoProject = ProjectCreator.Templates.CargoProject( + path: Path.Combine(TestRootPath, "Cargo", "rust.cargoproj")) + .Target("CargoFetch") .Target("CargoBuild") .ItemProjectReference(projectA) .Save(); - cargoBuildProject.TryRestore(out bool result, out BuildOutput buildOutput); + cargoProject.TryRestore(out bool result, out BuildOutput buildOutput); result.ShouldBeTrue(buildOutput.GetConsoleLog()); } @@ -124,7 +122,7 @@ public void DoNotReferenceOutputAssemblies() [InlineData(".cargoproj")] public void ProjectContainsStaticGraphImplementation(string projectExtension) { - ProjectCreator cargoBuild = ProjectCreator.Templates.CargoBuildProject( + ProjectCreator cargoProject = ProjectCreator.Templates.CargoProject( path: GetTempFileWithExtension(projectExtension), globalProperties: new Dictionary { @@ -140,7 +138,7 @@ public void ProjectContainsStaticGraphImplementation(string projectExtension) .Property("GenerateDependencyFile", "false") .Save(); - ICollection projectReferenceTargets = cargoBuild.Project.GetItems("ProjectReferenceTargets"); + ICollection projectReferenceTargets = cargoProject.Project.GetItems("ProjectReferenceTargets"); TargetProtocolShouldContainValuesForTarget("Build"); TargetProtocolShouldContainValuesForTarget("Clean"); @@ -167,11 +165,11 @@ public void ProjectsCanDependOnEachOtherProjects() .Target("_GetCopyToOutputDirectoryItemsFromTransitiveProjectReferences") .Save(); - ProjectCreator project2 = ProjectCreator.Templates.CargoBuildProject( + ProjectCreator project2 = ProjectCreator.Templates.CargoProject( path: Path.Combine(TestRootPath, "project2", "project2.cargoproj")) .Property("DesignTimeBuild", "true") .Property("GenerateDependencyFile", "false") - .Property("ShouldImportSkdDll", bool.FalseString) + .Target("_GetProjectReferenceTargetFrameworkProperties") .Target("_GetCopyToOutputDirectoryItemsFromTransitiveProjectReferences") .Target("CargoFetch") @@ -216,10 +214,10 @@ public void ProjectsCanDependOnEachOtherProjects() [InlineData("SkipCopyFilesMarkedCopyLocal", null, "")] public void PropertiesHaveExpectedValues(string propertyName, string value, string expectedValue) { - ProjectCreator.Templates.CargoBuildProject( + ProjectCreator.Templates.CargoProject( path: GetTempFileWithExtension(".cargoproj")) .Property(propertyName, value) - .Property("ShouldImportSkdDll", bool.FalseString) + .Target("CargoFetch") .Target("CargoBuild") .Save() @@ -232,7 +230,7 @@ public void PropertiesHaveExpectedValues(string propertyName, string value, stri [InlineData(".cargoproj")] public void PublishWithNoBuild(string projectExtension) { - ProjectCreator.Templates.CargoBuildProject( + ProjectCreator.Templates.CargoProject( path: GetTempFileWithExtension(projectExtension), customAction: creator => { @@ -242,7 +240,7 @@ public void PublishWithNoBuild(string projectExtension) .Target("TakeAction", afterTargets: "Build") .TaskMessage("2EA26E6FC5C842B682AA26096A769E07", MessageImportance.High); }) - .Property("ShouldImportSkdDll", bool.FalseString) + .Target("CargoFetch") .Target("CargoBuild") .Save() @@ -262,7 +260,7 @@ public void PublishWithNoBuild(string projectExtension) [InlineData(".cargoproj")] public void SimpleBuild(string projectExtension) { - ProjectCreator.Templates.CargoBuildProject( + ProjectCreator.Templates.CargoProject( path: GetTempFileWithExtension(projectExtension), projectCollection: new ProjectCollection( new Dictionary @@ -275,7 +273,7 @@ public void SimpleBuild(string projectExtension) .TaskMessage("86F00AF59170450E9D687652D74A6394", MessageImportance.High); }) .Property("GenerateDependencyFile", "false") - .Property("ShouldImportSkdDll", bool.FalseString) + .Target("CargoFetch") .Target("CargoBuild") .Save() @@ -286,66 +284,6 @@ public void SimpleBuild(string projectExtension) buildOutput.Messages.High.ShouldContain("86F00AF59170450E9D687652D74A6394"); } -#if NETFRAMEWORK - [Fact] - public void StaticGraphBuildsSucceedLegacyCsproj() - { - ProjectCreator legacyReference = ProjectCreator.Templates.LegacyCsproj( - Path.Combine(TestRootPath, "legacy", "legacy.csproj"), - targetFrameworkVersion: "v4.7.2") - .Save(); - - ProjectCreator cargoBuild = ProjectCreator.Templates.CargoBuildProject( - path: Path.Combine(TestRootPath, "CargoBuild", "Rust.cargoproj"), - customAction: creator => - { - creator.ItemProjectReference(legacyReference, referenceOutputAssembly: false); - }) - .Property("ShouldImportSkdDll", bool.FalseString) - .Save(); - - ProjectCreator project = ProjectCreator.Templates.SdkCsproj( - Path.Combine(TestRootPath, "main", $"main.csproj"), - projectCreator: creator => - { - creator.ItemProjectReference(cargoBuild, referenceOutputAssembly: false); - }) - .Target("CargoFetch") - .Target("CargoBuild") - .Save() - .TryBuild("Restore", out bool result, out BuildOutput restoreOutput); - - result.ShouldBeTrue(restoreOutput.GetConsoleLog()); - - using (BuildManager buildManager = new BuildManager()) - using (ProjectCollection projectCollection = new ProjectCollection()) - { - try - { - BuildOutput buildOutput = BuildOutput.Create(); - - buildManager.BeginBuild( - new BuildParameters(projectCollection) - { - Loggers = new[] { buildOutput }, - IsolateProjects = true, - }); - - GraphBuildResult graphResult = buildManager.BuildRequest( - new GraphBuildRequestData( - new[] { new ProjectGraphEntryPoint(project.FullPath, new Dictionary()) }, - new List { "Build" })); - - graphResult.OverallResult.ShouldBe(BuildResultCode.Success, graphResult.Exception?.ToString()); - } - finally - { - buildManager.EndBuild(); - } - } - } -#endif - [Theory] [InlineData(".cargoproj", "Build")] [InlineData(".cargoproj", "Compile")] @@ -369,11 +307,11 @@ public void SupportedTargetsExecute(string extension, string target) .Target("EnableIntermediateOutputPathMismatchWarning") .Save(Path.Combine(TestRootPath, "Directory.Build.targets")); - ProjectCreator.Templates.CargoBuildProject( + ProjectCreator.Templates.CargoProject( path: GetTempFileWithExtension(extension), projectCollection: projectCollection) .Property("GenerateDependencyFile", "false") - .Property("ShouldImportSkdDll", bool.FalseString) + .Target("CargoFetch") .Target("CargoBuild") .Save() @@ -384,11 +322,11 @@ public void SupportedTargetsExecute(string extension, string target) } [Fact] - public void UsingMicrosofCargoBuildSdkValueSet() + public void UsingMicrosofCargoSdkValueSet() { - ProjectCreator.Templates.CargoBuildProject( + ProjectCreator.Templates.CargoProject( path: GetTempFileWithExtension(".cargoproj")) - .TryGetPropertyValue("UsingMicrosoftCargoBuildSdk", out string propertyValue); + .TryGetPropertyValue("UsingMicrosoftCargoSdk", out string propertyValue); propertyValue.ShouldBe("true"); } diff --git a/src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs b/src/Cargo.UnitTests/CustomProjectCreatorTemplates.cs similarity index 90% rename from src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs rename to src/Cargo.UnitTests/CustomProjectCreatorTemplates.cs index 868ba1d..b6813b1 100644 --- a/src/CargoBuild.UnitTests/CustomProjectCreatorTemplates.cs +++ b/src/Cargo.UnitTests/CustomProjectCreatorTemplates.cs @@ -8,13 +8,13 @@ using System.Collections.Generic; using System.IO; -namespace Microsoft.Build.CargoBuild.UnitTests +namespace Microsoft.Build.Cargo.UnitTests { public static class CustomProjectCreatorTemplates { private static readonly string ThisAssemblyDirectory = Path.GetDirectoryName(typeof(CustomProjectCreatorTemplates).Assembly.Location); - public static ProjectCreator CargoBuildProject( + public static ProjectCreator CargoProject( this ProjectCreatorTemplates templates, Action customAction = null, string path = null, @@ -44,6 +44,9 @@ public static ProjectCreator CargoBuildProject( globalProperties) .Import(Path.Combine(ThisAssemblyDirectory, "Sdk", "Sdk.props")) .Property("TargetFramework", targetFramework) + .Property("TargetPlatformSdkPath", Path.Combine(ThisAssemblyDirectory, "Sdk")) + .Property("TargetPlatformDisplayName", "Windows, 7.0") + .Property("ShouldImportSkdDll", bool.FalseString) .CustomAction(customAction) .Import(Path.Combine(ThisAssemblyDirectory, "Sdk", "Sdk.targets")); } diff --git a/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj b/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj new file mode 100644 index 0000000..f0ec72e --- /dev/null +++ b/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj @@ -0,0 +1,25 @@ + + + net472;net8.0;net9.0 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/CargoBuild/CargoBuildTask.cs b/src/Cargo/CargoTask.cs similarity index 96% rename from src/CargoBuild/CargoBuildTask.cs rename to src/Cargo/CargoTask.cs index b7eafd8..abcad1b 100644 --- a/src/CargoBuild/CargoBuildTask.cs +++ b/src/Cargo/CargoTask.cs @@ -16,12 +16,12 @@ using Task = Microsoft.Build.Utilities.Task; using Tasks = System.Threading.Tasks; -namespace MSBuild.CargoBuild +namespace Microsoft.Build.Cargo { /// /// Builds rust projects using cargo. /// - public class CargoBuildTask : Task + public class CargoTask : Task { private static readonly string? _tempPath = Environment.GetEnvironmentVariable("TEMP"); private static readonly string _rustUpBinary = $"{_tempPath}\\cargohome\\bin\\rustup.exe"; @@ -133,7 +133,7 @@ private async Task FetchCratesAsync(string project) try { stopwatch.Start(); - Log.LogMessage(MessageImportance.Normal, "CargoBuild fetch Starting"); + Log.LogMessage(MessageImportance.Normal, "Cargo fetch Starting"); var graphLoadStopWatch = new Stopwatch(); graphLoadStopWatch.Start(); @@ -162,7 +162,7 @@ [new ProjectGraphEntryPoint(project)], Log.LogMessage( MessageImportance.Normal, - $"CargoBuild fetch: Static graph loaded in {{0}} seconds: {{1}} nodes, {{2}} edges", + $"Cargo fetch: Static graph loaded in {{0}} seconds: {{1}} nodes, {{2}} edges", Math.Round(graph.ConstructionMetrics.ConstructionTime.TotalSeconds, 3), graph.ConstructionMetrics.NodeCount, graph.ConstructionMetrics.EdgeCount); @@ -179,7 +179,7 @@ [new ProjectGraphEntryPoint(project)], var tasks = new List>(); - Log.LogMessage(MessageImportance.Normal, $"CargoBuild, Auth Enabled: {EnableAuth}"); + Log.LogMessage(MessageImportance.Normal, $"Cargo, Auth Enabled: {EnableAuth}"); foreach (var projects in rustProjects) { @@ -189,17 +189,17 @@ [new ProjectGraphEntryPoint(project)], tasks.Add(fetchTask); } - await Tasks.Task.WhenAll(tasks); - ExitCode[] exitCodes = await Tasks.Task.WhenAll(tasks); + await System.Threading.Tasks.Task.WhenAll(tasks); + ExitCode[] exitCodes = await System.Threading.Tasks.Task.WhenAll(tasks); bool success = exitCodes.All(exitCode => exitCode == ExitCode.Succeeded); stopwatch.Stop(); if (success) { - Log.LogMessage(MessageImportance.Normal, $"CargoBuild fetching Completed Successfully in {stopwatch.Elapsed.Seconds} seconds"); + Log.LogMessage(MessageImportance.Normal, $"Cargo fetching Completed Successfully in {stopwatch.Elapsed.Seconds} seconds"); } else { - Log.LogError("CargoBuild fetching had an issue. Check the build log for details."); + Log.LogError("Cargo fetching had an issue. Check the build log for details."); } return success; diff --git a/src/Cargo/Microsoft.Build.Cargo.csproj b/src/Cargo/Microsoft.Build.Cargo.csproj new file mode 100644 index 0000000..ec48399 --- /dev/null +++ b/src/Cargo/Microsoft.Build.Cargo.csproj @@ -0,0 +1,32 @@ + + + enable + enable + net472;net8.0;net9.0 + true + Microsoft.Build.Cargo + Builds rust projects within msbuild using cargo. + true + build\ + true + true + + true + false + $(NoWarn);NU1504;NU5100;NU5110;NU5111 + + + + PreserveNewest + true + + + + + + + + + + \ No newline at end of file diff --git a/src/CargoBuild/README.md b/src/Cargo/README.md similarity index 85% rename from src/CargoBuild/README.md rename to src/Cargo/README.md index ce2d53f..4f2fdbb 100644 --- a/src/CargoBuild/README.md +++ b/src/Cargo/README.md @@ -7,13 +7,13 @@ To use this sdk you will need the following: ```json "msbuild-sdks": { ..., - "Microsoft.Build.CargoBuild": "1.0.270-gf406f8eaa0" + "Microsoft.Build.Cargo": "1.0.270-gf406f8eaa0" }, ``` -2) For each rust project a .cargoproj project file at the same level as your cargo.toml file. The project file should include the CargoBuild sdk. +2) For each rust project a .cargoproj project file at the same level as your cargo.toml file. The project file should include the Cargo sdk. ```xml - + ``` @@ -57,7 +57,7 @@ msbuild /t:clearcargocache 1) After building the cargo build project, a nupkg file will be created in the `bin\Debug` or `bin\Release` folder. A file like `Microsoft.Build.CargoBuild..nupkg` will be created -2) In repo that contains your rust project(s), update your nuget.config file to point to the CargoBuild `bin\Debug` or `bin\Release` folder. +2) In repo that contains your rust project(s), update your nuget.config file to point to the Cargo `bin\Debug` or `bin\Release` folder. ```xml @@ -69,10 +69,10 @@ msbuild /t:clearcargocache ```json "msbuild-sdks": { ..., - "Microsoft.Build.CargoBuild": "" + "Microsoft.Build.Cargo": "" } ``` - 4) Once you run `msbuild /restore` in your rust project, the CargoBuild sdk will be restored from the local nuget source. You can now use the sdk locally. + 4) Once you run `msbuild /restore` in your rust project, the Cargo sdk will be restored from the local nuget source. You can now use the sdk locally. ### Using MSRustup (Microsoft internal use only) diff --git a/src/CargoBuild/dist/msrustup.ps1 b/src/Cargo/dist/msrustup.ps1 similarity index 100% rename from src/CargoBuild/dist/msrustup.ps1 rename to src/Cargo/dist/msrustup.ps1 diff --git a/src/CargoBuild/sdk/DisableCopyFilesMarkedCopyLocal.targets b/src/Cargo/sdk/DisableCopyFilesMarkedCopyLocal.targets similarity index 100% rename from src/CargoBuild/sdk/DisableCopyFilesMarkedCopyLocal.targets rename to src/Cargo/sdk/DisableCopyFilesMarkedCopyLocal.targets diff --git a/src/CargoBuild/sdk/Sdk.props b/src/Cargo/sdk/Sdk.props similarity index 76% rename from src/CargoBuild/sdk/Sdk.props rename to src/Cargo/sdk/Sdk.props index e9fb4b3..8863595 100644 --- a/src/CargoBuild/sdk/Sdk.props +++ b/src/Cargo/sdk/Sdk.props @@ -5,9 +5,9 @@ --> - true - $(MSBuildAllProjects);$(MsBuildThisFileFullPath) - + true + $(MSBuildAllProjects);$(MsBuildThisFileFullPath) + true @@ -15,19 +15,19 @@ true - + - - false - false - - + false + false + + PackageReference - + true @@ -46,7 +46,7 @@ true - + false false true @@ -58,7 +58,7 @@ false @@ -70,7 +70,7 @@ - + @@ -85,8 +85,8 @@ false - - - - + + + + \ No newline at end of file diff --git a/src/CargoBuild/sdk/Sdk.targets b/src/Cargo/sdk/Sdk.targets similarity index 72% rename from src/CargoBuild/sdk/Sdk.targets rename to src/Cargo/sdk/Sdk.targets index 78fa748..6845f48 100644 --- a/src/CargoBuild/sdk/Sdk.targets +++ b/src/Cargo/sdk/Sdk.targets @@ -21,7 +21,7 @@ $(MSBuildAllProjects);$(MsBuildThisFileFullPath) - + @@ -65,13 +65,13 @@ @@ -86,7 +86,7 @@ - + - - + + - + - - + + - - + + - + - - + + - - + + - + \ No newline at end of file diff --git a/src/CargoBuild/version.json b/src/Cargo/version.json similarity index 100% rename from src/CargoBuild/version.json rename to src/Cargo/version.json diff --git a/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj b/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj deleted file mode 100644 index e34dd49..0000000 --- a/src/CargoBuild.UnitTests/Microsoft.Build.CargoBuild.UnitTests.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - net472;net8.0;net9.0 - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/CargoBuild/Microsoft.Build.CargoBuild.csproj b/src/CargoBuild/Microsoft.Build.CargoBuild.csproj deleted file mode 100644 index dd93900..0000000 --- a/src/CargoBuild/Microsoft.Build.CargoBuild.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - enable - enable - net472;net8.0;net9.0 - true - Microsoft.Build.CargoBuild - Builds rust projects within msbuild using cargo. - true - build\ - true - true - - true - false - $(NoWarn);NU1504;NU5100;NU5110;NU5111 - - - - PreserveNewest - true - - - - - - - - - - \ No newline at end of file From 3406005ef846273ddac241f2fca6b9c6068719e7 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Thu, 16 Jan 2025 17:22:44 -0800 Subject: [PATCH 20/24] sdk name update, continued --- src/Cargo/Microsoft.Build.Cargo.csproj | 18 ++++++++++++++++-- src/Cargo/README.md | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Cargo/Microsoft.Build.Cargo.csproj b/src/Cargo/Microsoft.Build.Cargo.csproj index ec48399..cc1ec64 100644 --- a/src/Cargo/Microsoft.Build.Cargo.csproj +++ b/src/Cargo/Microsoft.Build.Cargo.csproj @@ -25,8 +25,22 @@ - + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + \ No newline at end of file diff --git a/src/Cargo/README.md b/src/Cargo/README.md index 4f2fdbb..3ffd739 100644 --- a/src/Cargo/README.md +++ b/src/Cargo/README.md @@ -1,4 +1,4 @@ -### CargoBuild Sdk Prototype +### Cargo Sdk Prototype ### Project Setup To use this sdk you will need the following: @@ -55,7 +55,7 @@ msbuild /t:clearcargocache ### How to test locally -1) After building the cargo build project, a nupkg file will be created in the `bin\Debug` or `bin\Release` folder. A file like `Microsoft.Build.CargoBuild..nupkg` will be created +1) After building the cargo build project, a nupkg file will be created in the `bin\Debug` or `bin\Release` folder. A file like `Microsoft.Build.Cargo..nupkg` will be created 2) In repo that contains your rust project(s), update your nuget.config file to point to the Cargo `bin\Debug` or `bin\Release` folder. From d23cff8ce8856a01acc7e62fb160df9ce92c9ac6 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Thu, 16 Jan 2025 18:02:09 -0800 Subject: [PATCH 21/24] attempt fix linux test --- src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj b/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj index f0ec72e..a61ec74 100644 --- a/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj +++ b/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj @@ -16,10 +16,13 @@ - + + + + CopyToOutputDirectory="PreserveNewest" > + \ No newline at end of file From ec7f3efde9b47662d8a4746beeb43a768b9e470e Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Fri, 17 Jan 2025 09:19:31 -0800 Subject: [PATCH 22/24] attempt fix linux test - missing props file --- src/Cargo/Microsoft.Build.Cargo.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Cargo/Microsoft.Build.Cargo.csproj b/src/Cargo/Microsoft.Build.Cargo.csproj index cc1ec64..844ed42 100644 --- a/src/Cargo/Microsoft.Build.Cargo.csproj +++ b/src/Cargo/Microsoft.Build.Cargo.csproj @@ -29,17 +29,17 @@ - + PreserveNewest - + PreserveNewest - + PreserveNewest From c2e8aade985ad3555554ca37737fec3f9af12941 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Fri, 17 Jan 2025 09:34:57 -0800 Subject: [PATCH 23/24] attempt linux test fix - file path casing --- src/Cargo.UnitTests/CustomProjectCreatorTemplates.cs | 4 ++-- src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj | 2 +- src/Cargo/Microsoft.Build.Cargo.csproj | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Cargo.UnitTests/CustomProjectCreatorTemplates.cs b/src/Cargo.UnitTests/CustomProjectCreatorTemplates.cs index b6813b1..3fc01ab 100644 --- a/src/Cargo.UnitTests/CustomProjectCreatorTemplates.cs +++ b/src/Cargo.UnitTests/CustomProjectCreatorTemplates.cs @@ -42,13 +42,13 @@ public static ProjectCreator CargoProject( projectCollection, projectFileOptions, globalProperties) - .Import(Path.Combine(ThisAssemblyDirectory, "Sdk", "Sdk.props")) + .Import(Path.Combine(ThisAssemblyDirectory, "sdk", "Sdk.props")) .Property("TargetFramework", targetFramework) .Property("TargetPlatformSdkPath", Path.Combine(ThisAssemblyDirectory, "Sdk")) .Property("TargetPlatformDisplayName", "Windows, 7.0") .Property("ShouldImportSkdDll", bool.FalseString) .CustomAction(customAction) - .Import(Path.Combine(ThisAssemblyDirectory, "Sdk", "Sdk.targets")); + .Import(Path.Combine(ThisAssemblyDirectory, "sdk", "Sdk.targets")); } public static ProjectCreator VcxProjProject( diff --git a/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj b/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj index a61ec74..539a436 100644 --- a/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj +++ b/src/Cargo.UnitTests/Microsoft.Build.Cargo.UnitTests.csproj @@ -20,7 +20,7 @@ - diff --git a/src/Cargo/Microsoft.Build.Cargo.csproj b/src/Cargo/Microsoft.Build.Cargo.csproj index 844ed42..fd34e11 100644 --- a/src/Cargo/Microsoft.Build.Cargo.csproj +++ b/src/Cargo/Microsoft.Build.Cargo.csproj @@ -29,17 +29,17 @@ - + PreserveNewest - + PreserveNewest - + PreserveNewest From 2b048f8eaf51ad88ad83dc29e6cc613201749214 Mon Sep 17 00:00:00 2001 From: Cole Carter Date: Fri, 17 Jan 2025 14:06:29 -0800 Subject: [PATCH 24/24] whitespace change, to rerun pipeline in an attempt to get license/cla stage unstuck --- src/Cargo/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cargo/README.md b/src/Cargo/README.md index 3ffd739..c71ef5e 100644 --- a/src/Cargo/README.md +++ b/src/Cargo/README.md @@ -9,7 +9,7 @@ To use this sdk you will need the following: ..., "Microsoft.Build.Cargo": "1.0.270-gf406f8eaa0" }, -``` +``` 2) For each rust project a .cargoproj project file at the same level as your cargo.toml file. The project file should include the Cargo sdk. ```xml