Skip to content

Commit 4103696

Browse files
authored
Handle msrustup auth for multiple registries (#611)
* add files to sign * get all registries from config * clean up * slight refactoring * handle multiple registries
1 parent 394663e commit 4103696

File tree

2 files changed

+134
-78
lines changed

2 files changed

+134
-78
lines changed

src/Cargo/CargoTask.cs

Lines changed: 133 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,31 @@ namespace Microsoft.Build.Cargo
2323
/// </summary>
2424
public class CargoTask : Task
2525
{
26-
private static readonly string? _tempPath = Environment.GetEnvironmentVariable("TEMP");
27-
private static readonly string _rustUpBinary = $"{_tempPath}\\cargohome\\bin\\rustup.exe";
28-
private static readonly string _cargoPath = $"{_tempPath}\\cargohome\\bin\\cargo.exe";
29-
private static readonly string _rustInstallPath = $"{_tempPath}\\rustinstall";
30-
private static readonly string _rustUpInitBinary = $"{_rustInstallPath}\\rustup-init.exe";
31-
private static readonly string _cargoHome = $"{_tempPath}\\cargohome";
32-
private static readonly string _rustUpHome = $"{_tempPath}\\rustuphome";
33-
private static readonly string _cargoHomeBin = $"{_tempPath}\\cargohome\\bin\\";
34-
private static readonly string _msRustUpBinary = $"{_tempPath}\\cargohome\\bin\\msrustup.exe";
26+
private static readonly string? _tempPath = Environment.GetEnvironmentVariable("TEMP") ?? throw new Exception("%TEMP% directory not defined");
27+
private static readonly string _rustUpBinary = Path.Combine(_tempPath, "cargohome", "bin", "rustup.exe");
28+
private static readonly string _cargoPath = Path.Combine(_tempPath, "cargohome", "bin", "cargo.exe");
29+
private static readonly string _rustInstallPath = Path.Combine(_tempPath, "rustinstall");
30+
private static readonly string _rustUpInitBinary = Path.Combine(_rustInstallPath, "rustup-init.exe");
31+
private static readonly string _cargoHome = Path.Combine(_tempPath, "cargohome");
32+
private static readonly string _rustUpHome = Path.Combine(_tempPath, "rustuphome");
33+
private static readonly string _cargoHomeBin = Path.Combine(_tempPath, "cargohome", "bin");
34+
private static readonly string _msRustUpBinary = Path.Combine(_tempPath, "cargohome", "bin", "msrustup.exe");
3535
private static readonly Dictionary<string, string> _envVars = new () { { "CARGO_HOME", _cargoHome }, { "RUSTUP_HOME", _rustUpHome } };
3636
private static readonly string _rustUpDownloadLink = "https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe";
3737
private static readonly string _checkSumVerifyUrl = "https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe.sha256";
3838
private static readonly string _rustToolChainFileName = "rust-toolchain.toml";
39-
private static readonly string _configFileName = "config.toml";
39+
private static readonly string _cargoConfigFilePath = Path.Combine(".cargo", "config.toml");
4040
private static readonly string _cargoFileName = "cargo.toml";
4141
private static readonly string _nugetConfigFileName = "nuget.config";
4242
private static readonly string _clearCacheCommand = "clearcargocache";
4343
private static readonly string _installCommand = "install";
4444
private static readonly string _fetchCommand = "fetch";
4545
private static readonly string _loginCommand = "login";
4646
private string? _rustUpFile = Environment.GetEnvironmentVariable("MSRUSTUP_FILE");
47-
private bool _shouldCleanRustPath;
47+
private bool _shouldCleanRustPath = false;
4848
private bool _isMsRustUp = false;
4949
private string? _currentRustUpInitExeCheckSum;
50+
private List<string> _cargoRegistries = new ();
5051

5152
private enum ExitCode
5253
{
@@ -114,6 +115,41 @@ private async Task<bool> ExecuteAsync()
114115
}
115116
else if (Command.Equals(_fetchCommand))
116117
{
118+
if (_isMsRustUp)
119+
{
120+
if (string.IsNullOrEmpty(_rustUpFile) || !File.Exists(_rustUpFile))
121+
{
122+
Log.LogMessage($"MSRUSTUP_FILE environment variable is not set or the file does not exist. Assuming local build.");
123+
}
124+
else
125+
{
126+
try
127+
{
128+
var val = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(File.ReadAllText(_rustUpFile)));
129+
130+
if (!_envVars.ContainsKey("CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS"))
131+
{
132+
_envVars.Add("CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS", "cargo:token");
133+
}
134+
135+
foreach (var registry in GetRegistries(Path.Combine(RepoRoot, _cargoConfigFilePath)))
136+
{
137+
var registryName = registry.Trim().ToUpper();
138+
_cargoRegistries.Add(registryName);
139+
var tokenName = $"CARGO_REGISTRIES_{registryName}_TOKEN";
140+
if (!_envVars.ContainsKey(tokenName))
141+
{
142+
_envVars.Add(tokenName, $"Bearer {val}");
143+
}
144+
}
145+
}
146+
catch (FormatException ex)
147+
{
148+
Log.LogError($"Failed to decode MSRUSTUP_FILE content: {ex.Message}");
149+
}
150+
}
151+
}
152+
117153
return await FetchCratesAsync(StartupProj);
118154
}
119155
else if (Command.Equals(_clearCacheCommand, StringComparison.InvariantCultureIgnoreCase))
@@ -151,16 +187,16 @@ private async Task<ExitCode> CargoRunCommandAsync(string command, string args)
151187
Log.LogMessage(MessageImportance.Normal, $"Executing cargo command: {command} {args}");
152188
if (_isMsRustUp)
153189
{
154-
var customCargoBin = GetCustomToolChainPath();
190+
var customCargoBin = GetCustomToolChainCargoPath();
155191
if (!string.IsNullOrEmpty(customCargoBin))
156192
{
157-
bool debugConfig = true;
193+
bool isDebugConfiguration = true;
158194
if (!Configuration.Equals("debug", StringComparison.InvariantCultureIgnoreCase))
159195
{
160-
debugConfig = false;
196+
isDebugConfiguration = false;
161197
}
162198

163-
return await ExecuteProcessAsync(customCargoBin!, $"{command} {args} --offline {(debugConfig ? string.Empty : "--" + Configuration.ToLowerInvariant())} --config {Path.Combine(RepoRoot, _configFileName)}", ".", _envVars);
199+
return await ExecuteProcessAsync(customCargoBin!, $"{command} {args} --offline {(isDebugConfiguration ? string.Empty : "--" + Configuration.ToLowerInvariant())} --config {Path.Combine(RepoRoot, _cargoConfigFilePath)}", ".", _envVars);
164200
}
165201

166202
// if we don't have the toolchain, we need to install it.
@@ -172,15 +208,18 @@ private async Task<ExitCode> CargoRunCommandAsync(string command, string args)
172208

173209
private async Task<bool> DownloadAndInstallRust()
174210
{
175-
if (await DownloadRustUpAsync())
211+
bool downloadSuccess = await DownloadRustUpAsync();
212+
bool installSuccess = false;
213+
if (downloadSuccess)
176214
{
177-
if (await InstallRust())
215+
installSuccess = await InstallRust();
216+
if (installSuccess)
178217
{
179218
_shouldCleanRustPath = true;
180219
}
181220
}
182221

183-
return true;
222+
return downloadSuccess && installSuccess;
184223
}
185224

186225
private async Task<bool> FetchCratesAsync(string project)
@@ -237,30 +276,6 @@ [new ProjectGraphEntryPoint(project)],
237276

238277
Log.LogMessage(MessageImportance.Normal, $"Cargo, Auth Enabled: {EnableAuth}");
239278

240-
if (_isMsRustUp)
241-
{
242-
if (string.IsNullOrEmpty(_rustUpFile) || !File.Exists(_rustUpFile))
243-
{
244-
Log.LogError($"MSRUSTUP_FILE environment variable is not set or the file does not exist.");
245-
return false;
246-
}
247-
248-
var val = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(File.ReadAllText(_rustUpFile)));
249-
250-
if (_envVars.ContainsKey("CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS"))
251-
{
252-
_envVars.Remove("CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS");
253-
}
254-
255-
if (_envVars.ContainsKey("CARGO_REGISTRIES_RUST_PUBLICPACKAGES_TOKEN"))
256-
{
257-
_envVars.Remove("CARGO_REGISTRIES_RUST_PUBLICPACKAGES_TOKEN");
258-
}
259-
260-
_envVars.Add("CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS", "cargo:token");
261-
_envVars.Add("CARGO_REGISTRIES_RUST_PUBLICPACKAGES_TOKEN", $"Bearer {val}");
262-
}
263-
264279
foreach (var projects in rustProjects)
265280
{
266281
string path = projects;
@@ -276,10 +291,6 @@ [new ProjectGraphEntryPoint(project)],
276291
if (success)
277292
{
278293
Log.LogMessage(MessageImportance.Normal, $"Cargo fetching completed successfully in {stopwatch.Elapsed.Seconds} seconds");
279-
if (_isMsRustUp)
280-
{
281-
_envVars.Remove("CARGO_REGISTRIES_RUST_PUBLICPACKAGES_TOKEN");
282-
}
283294
}
284295
else
285296
{
@@ -324,13 +335,13 @@ private async Task<ExitCode> RustFetchAsync(string workingDir, bool authorize =
324335
if (authResult == ExitCode.Succeeded)
325336
{
326337
string path = _cargoPath;
327-
string args = $"fetch {(_isMsRustUp ? "--config " + Path.Combine(RepoRoot, _configFileName) : string.Empty)}";
338+
string args = $"fetch {(_isMsRustUp ? "--config " + Path.Combine(RepoRoot, _cargoConfigFilePath) : string.Empty)}";
328339
ExitCode exitCode = ExitCode.Failed;
329340
Log.LogMessage(MessageImportance.Normal, $"Fetching cargo crates for project in {workingDir}");
330341

331342
if (File.Exists(Path.Combine(RepoRoot, _rustToolChainFileName)))
332343
{
333-
var customCargoBin = GetCustomToolChainPath();
344+
var customCargoBin = GetCustomToolChainCargoPath();
334345
if (!string.IsNullOrEmpty(customCargoBin))
335346
{
336347
exitCode = await ExecuteProcessAsync(customCargoBin!, args, workingDir, _envVars);
@@ -449,36 +460,52 @@ private async Task<bool> InstallRust()
449460
var rootToolchainPath = Path.Combine(StartupProj, _rustToolChainFileName);
450461
var useMsRustUp = File.Exists(rootToolchainPath) && IsMSToolChain(rootToolchainPath);
451462
var rustUpBinary = useMsRustUp ? _msRustUpBinary : _rustUpBinary;
452-
if ((File.Exists(_cargoPath) && Directory.Exists(_rustUpHome) && File.Exists(_rustUpBinary)) || (File.Exists(_cargoHome) && useMsRustUp != true) || File.Exists(_msRustUpBinary))
463+
bool msRustupToolChainExists = useMsRustUp && !string.IsNullOrEmpty(GetCustomToolChainCargoPath());
464+
bool cargoPathAndRustPathsExists = Directory.Exists(_cargoHome) && Directory.Exists(_rustUpHome);
465+
bool cargoBinaryExists = File.Exists(_cargoPath);
466+
if ((msRustupToolChainExists && cargoPathAndRustPathsExists && useMsRustUp) || cargoPathAndRustPathsExists && cargoBinaryExists && !useMsRustUp)
453467
{
454-
return false;
468+
return true;
455469
}
456470

457471
ExitCode exitCode = ExitCode.Succeeded;
458472
ExitCode exitCodeLatest = ExitCode.Succeeded;
459-
Log.LogMessage(MessageImportance.Normal, "Installing Rust");
460-
exitCode = await ExecuteProcessAsync(_rustUpInitBinary, "-y", ".", _envVars);
461-
if (exitCode != ExitCode.Succeeded)
473+
474+
if (useMsRustUp)
462475
{
463-
Log.LogMessage(MessageImportance.Normal, "Installed Rust successfully");
476+
if (!_envVars.ContainsKey("MSRUSTUP_FEED_URL"))
477+
{
478+
_envVars.Add("MSRUSTUP_FEED_URL", GetNugetFeedUrl() ?? string.Empty);
479+
}
464480
}
465481

466-
if (useMsRustUp)
482+
if ((!cargoBinaryExists && !useMsRustUp) || !cargoPathAndRustPathsExists)
467483
{
468-
string? workingDirPart = new DirectoryInfo(BuildEngine.ProjectFileOfTaskNode).Parent?.Parent?.FullName;
469-
if (Directory.Exists(workingDirPart))
484+
Log.LogMessage(MessageImportance.Normal, "Installing Rust");
485+
exitCode = await ExecuteProcessAsync(_rustUpInitBinary, "-y", ".", _envVars);
486+
if (exitCode != ExitCode.Succeeded)
470487
{
471-
Log.LogMessage(MessageImportance.Normal, "Installing MSRustup");
472-
string distRootPath = Path.Combine(workingDirPart!, "content\\dist");
473-
var installationExitCode = await ExecuteProcessAsync("powershell.exe", $".\\msrustup.ps1 '{_cargoHomeBin}'", distRootPath, _envVars);
474-
if (installationExitCode == ExitCode.Succeeded)
475-
{
476-
Log.LogMessage(MessageImportance.Normal, "Installed MSRustup successfully");
477-
}
478-
else
488+
Log.LogMessage(MessageImportance.Normal, "Installed Rust successfully");
489+
}
490+
491+
if (useMsRustUp)
492+
{
493+
string? workingDirPart = new DirectoryInfo(BuildEngine.ProjectFileOfTaskNode).Parent?.Parent?.FullName;
494+
495+
if (Directory.Exists(workingDirPart))
479496
{
480-
Log.LogError("MSRustup failed to installed successfully");
481-
return false;
497+
Log.LogMessage(MessageImportance.Normal, "Installing MSRustup");
498+
string distRootPath = Path.Combine(workingDirPart!, "content\\dist");
499+
var installationExitCode = await ExecuteProcessAsync("powershell.exe", $".\\msrustup.ps1 '{_cargoHomeBin}'", distRootPath, _envVars);
500+
if (installationExitCode == ExitCode.Succeeded)
501+
{
502+
Log.LogMessage(MessageImportance.Normal, "Installed MSRustup successfully");
503+
}
504+
else
505+
{
506+
Log.LogError("MSRustup failed to installed successfully");
507+
return false;
508+
}
482509
}
483510
}
484511
}
@@ -489,16 +516,24 @@ private async Task<bool> InstallRust()
489516

490517
if (string.IsNullOrEmpty(_rustUpFile) || !File.Exists(_rustUpFile))
491518
{
492-
Log.LogError($"MSRUSTUP_FILE environment variable is not set or the file does not exist.");
493-
return false;
519+
Log.LogMessage($"MSRUSTUP_FILE environment variable is not set or the file does not exist. Assuming local build.");
494520
}
521+
else
522+
{
523+
var val = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(File.ReadAllText(_rustUpFile)));
524+
if (!_envVars.ContainsKey("MSRUSTUP_PAT"))
525+
{
526+
_envVars.Add("MSRUSTUP_PAT", val);
527+
}
528+
}
529+
530+
if (!_envVars.ContainsKey("MSRUSTUP_HOME"))
531+
{
532+
_envVars.Add("MSRUSTUP_HOME", _cargoHome);
533+
}
534+
535+
exitCodeLatest = await ExecuteProcessAsync(rustUpBinary, $"toolchain install {GetToolChainVersion()}", StartupProj, _envVars);
495536

496-
var val = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(File.ReadAllText(_rustUpFile)));
497-
_envVars.Add("MSRUSTUP_PAT", val);
498-
_envVars.Add("MSRUSTUP_HOME", _cargoHome);
499-
_envVars.Add("MSRUSTUP_FEED_URL", GetNugetFeedUrl() ?? string.Empty);
500-
exitCodeLatest = await ExecuteProcessAsync(rustUpBinary, "toolchain install", StartupProj, _envVars);
501-
_envVars.Remove("MSRUSTUP_PAT");
502537
if (exitCodeLatest == ExitCode.Succeeded)
503538
{
504539
Log.LogMessage(MessageImportance.Normal, "Installed custom toolchain successfully");
@@ -559,7 +594,7 @@ private string GetToolChainVersion()
559594
return string.Empty;
560595
}
561596

562-
private string? GetCustomToolChainPath()
597+
private string? GetCustomToolChainCargoPath()
563598
{
564599
var toolchainVersion = GetToolChainVersion();
565600
if (!string.IsNullOrEmpty(toolchainVersion))
@@ -568,7 +603,6 @@ private string GetToolChainVersion()
568603
var toolchainPath = Path.Combine(_cargoHome, "toolchains", toolchainVersion);
569604
if (!Directory.Exists(toolchainPath))
570605
{
571-
Log.LogError($"Toolchain {toolchainVersion} not found. Please run 'cargo install' to install the required toolchain.");
572606
return null;
573607
}
574608

@@ -595,5 +629,27 @@ private async Task<string> GetHashAsync()
595629

596630
return _currentRustUpInitExeCheckSum;
597631
}
632+
633+
private List<string> GetRegistries(string configPath)
634+
{
635+
string config = File.ReadAllText(configPath);
636+
Regex regex = new (@"(?<=\[registries\]).*?(?=\[|#)", RegexOptions.Singleline);
637+
var matches = regex.Matches(config);
638+
List<string> registries = new ();
639+
foreach (Match match in matches)
640+
{
641+
if (string.IsNullOrWhiteSpace(match.Value) || !match.Value.Contains('='))
642+
{
643+
continue;
644+
}
645+
646+
var registryNames = match.Value.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
647+
.Select(line => line.Split('=')[0].Trim())
648+
.ToList();
649+
registries.AddRange(registryNames);
650+
}
651+
652+
return registries;
653+
}
598654
}
599655
}

src/Cargo/sdk/Sdk.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
<MSBuild
113113
Projects="$(MSBuildThisFileDirectory)CargoInstall.proj"
114114
Targets="CargoInstall"
115-
Properties="EnableTelemetryLoggerCopy=$(EnableTelemetryLoggerCopy);TelemetryLoggerLocation=$(TelemetryLoggerLocation);TelemetryLoggerSourcePath=$(TelemetryLoggerSourcePath);TelemetryLoggerInstallId=$(TelemetryLoggerInstallId)"
115+
Properties="EnableTelemetryLoggerCopy=$(EnableTelemetryLoggerCopy);TelemetryLoggerLocation=$(TelemetryLoggerLocation);TelemetryLoggerSourcePath=$(TelemetryLoggerSourcePath);TelemetryLoggerInstallId=$(TelemetryLoggerInstallId);RepoRoot=$(RepoRoot)"
116116
RemoveProperties="NuGetInteractive;MSBuildRestoreSessionId;TargetFramework;RuntimeIdentifier" />
117117
</Target>
118118
<Target Name="CargoFetch" AfterTargets="CargoInstall">

0 commit comments

Comments
 (0)