Skip to content

Commit 5c1df1f

Browse files
authored
Add support for --os option to the restore command (#49166)
2 parents 3443c0e + 5a4097c commit 5c1df1f

File tree

6 files changed

+119
-2
lines changed

6 files changed

+119
-2
lines changed

.github/copilot-instructions.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ Output Considerations:
1212

1313
Localization:
1414
- Avoid modifying .xlf files and instead prompt the user to update them using the `/t:UpdateXlf` target on MSBuild.
15-
- Consider localizing strings in .resx files when possible.
15+
- Consider localizing strings in .resx files when possible.
16+
17+
Documentation:
18+
- Do not manually edit files under documentation/manpages/sdk as these are generated based on documentation and should not be manually modified.

src/Cli/dotnet/Commands/Restore/RestoreCommandParser.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ private static Command ConstructCommand()
7373
}
7474

7575
command.Options.Add(CommonOptions.ArchitectureOption);
76+
command.Options.Add(CommonOptions.OperatingSystemOption);
7677
command.SetAction(RestoreCommand.Run);
7778

7879
return command;

test/dotnet.Tests/CommandTests/Restore/GivenThatIWantToRestoreApp.cs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using Microsoft.DotNet.Tools.Test.Utilities;
5+
using Newtonsoft.Json.Linq;
6+
using System.Runtime.InteropServices;
57

68
namespace Microsoft.DotNet.Restore.Test
79
{
@@ -167,6 +169,115 @@ public void ItAcceptsArgumentsAfterProperties()
167169
.Should()
168170
.Pass();
169171
}
172+
173+
/// <summary>
174+
/// Tests for RID-specific restore options: -r/--runtime, --os, and -a/--arch
175+
/// </summary>
176+
[Theory]
177+
[InlineData("-r", "linux-x64")]
178+
[InlineData("--runtime", "win-x64")]
179+
[InlineData("--os", "linux")]
180+
[InlineData("-a", "arm64")]
181+
[InlineData("--arch", "x64")]
182+
[InlineData("--os", "linux", "-a", "arm64")]
183+
public void ItRestoresWithRidSpecificOptions(params string[] ridOptions)
184+
{
185+
// Skip test for #24251
186+
var testProject = new TestProject()
187+
{
188+
Name = "RestoreWithRidOptions",
189+
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
190+
};
191+
192+
testProject.PackageReferences.Add(new TestPackageReference("Newtonsoft.Json", ToolsetInfo.GetNewtonsoftJsonPackageVersion()));
193+
194+
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: string.Join("_", ridOptions));
195+
196+
var rootPath = Path.Combine(testAsset.TestRoot, testProject.Name);
197+
198+
// Create the command with the RID-specific options
199+
var restoreCommand = new DotnetRestoreCommand(Log)
200+
.WithWorkingDirectory(rootPath)
201+
.Execute(ridOptions);
202+
203+
// Verify that the command runs successfully
204+
restoreCommand.Should().Pass();
205+
206+
// Verify that assets file was created
207+
var assetsFilePath = Path.Combine(rootPath, "obj", "project.assets.json");
208+
File.Exists(assetsFilePath).Should().BeTrue();
209+
210+
// Verify that the assets file contains the expected RID-specific target
211+
var assetsContents = JObject.Parse(File.ReadAllText(assetsFilePath));
212+
var targets = assetsContents["targets"];
213+
targets.Should().NotBeNull("assets file should contain targets section");
214+
215+
// Determine the expected RID based on the options provided
216+
string expectedRid = GetExpectedRid(ridOptions);
217+
string expectedTarget = $"{ToolsetInfo.CurrentTargetFramework}/{expectedRid}";
218+
219+
// Check that the specific target exists
220+
var specificTarget = targets[expectedTarget];
221+
specificTarget.Should().NotBeNull($"assets file should contain target '{expectedTarget}' when using RID options: {string.Join(" ", ridOptions)}");
222+
}
223+
224+
private static string GetExpectedRid(string[] ridOptions)
225+
{
226+
// Check if explicit runtime is provided
227+
for (int i = 0; i < ridOptions.Length; i++)
228+
{
229+
if ((ridOptions[i] == "-r" || ridOptions[i] == "--runtime") && i + 1 < ridOptions.Length)
230+
{
231+
return ridOptions[i + 1];
232+
}
233+
}
234+
235+
// Get current platform defaults
236+
string currentOs = GetCurrentOsPart();
237+
string currentArch = GetCurrentArchPart();
238+
239+
// Check for --os and --arch options to synthesize RID
240+
string targetOs = currentOs;
241+
string targetArch = currentArch;
242+
243+
for (int i = 0; i < ridOptions.Length; i++)
244+
{
245+
if (ridOptions[i] == "--os" && i + 1 < ridOptions.Length)
246+
{
247+
targetOs = ridOptions[i + 1];
248+
}
249+
else if ((ridOptions[i] == "-a" || ridOptions[i] == "--arch") && i + 1 < ridOptions.Length)
250+
{
251+
targetArch = ridOptions[i + 1];
252+
}
253+
}
254+
255+
return $"{targetOs}-{targetArch}";
256+
}
257+
258+
private static string GetCurrentOsPart()
259+
{
260+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
261+
return "win";
262+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
263+
return "linux";
264+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
265+
return "osx";
266+
else
267+
throw new PlatformNotSupportedException("Unsupported platform for RID determination");
268+
}
269+
270+
private static string GetCurrentArchPart()
271+
{
272+
return RuntimeInformation.OSArchitecture switch
273+
{
274+
Architecture.X64 => "x64",
275+
Architecture.X86 => "x86",
276+
Architecture.Arm64 => "arm64",
277+
Architecture.Arm => "arm",
278+
_ => throw new PlatformNotSupportedException($"Unsupported architecture: {RuntimeInformation.OSArchitecture}")
279+
};
280+
}
170281

171282
private static string[] HandleStaticGraphEvaluation(bool useStaticGraphEvaluation, string[] args) =>
172283
useStaticGraphEvaluation ?

test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,7 @@ _testhost_restore() {
13321332
prev="${COMP_WORDS[COMP_CWORD-1]}"
13331333
COMPREPLY=()
13341334

1335-
opts="--disable-build-servers --source --packages --use-current-runtime --disable-parallel --configfile --no-http-cache --ignore-failed-sources --force --runtime --no-dependencies --verbosity --interactive --artifacts-path --use-lock-file --locked-mode --lock-file-path --force-evaluate --arch --help"
1335+
opts="--disable-build-servers --source --packages --use-current-runtime --disable-parallel --configfile --no-http-cache --ignore-failed-sources --force --runtime --no-dependencies --verbosity --interactive --artifacts-path --use-lock-file --locked-mode --lock-file-path --force-evaluate --arch --os --help"
13361336

13371337
if [[ $COMP_CWORD == "$1" ]]; then
13381338
COMPREPLY=( $(compgen -W "$opts" -- "$cur") )

test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,7 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock {
795795
[CompletionResult]::new('--force-evaluate', '--force-evaluate', [CompletionResultType]::ParameterName, "Forces restore to reevaluate all dependencies even if a lock file already exists.")
796796
[CompletionResult]::new('--arch', '--arch', [CompletionResultType]::ParameterName, "The target architecture.")
797797
[CompletionResult]::new('--arch', '-a', [CompletionResultType]::ParameterName, "The target architecture.")
798+
[CompletionResult]::new('--os', '--os', [CompletionResultType]::ParameterName, "The target operating system.")
798799
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, "Show command line help.")
799800
[CompletionResult]::new('--help', '-h', [CompletionResultType]::ParameterName, "Show command line help.")
800801
)

test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,7 @@ _testhost() {
821821
'--force-evaluate[Forces restore to reevaluate all dependencies even if a lock file already exists.]' \
822822
'--arch=[The target architecture.]:ARCH: ' \
823823
'-a=[The target architecture.]:ARCH: ' \
824+
'--os=[The target operating system.]:OS: ' \
824825
'--help[Show command line help.]' \
825826
'-h[Show command line help.]' \
826827
'*::PROJECT | SOLUTION | FILE -- The project or solution or C# (file-based program) file to operate on. If a file is not specified, the command will search the current directory for a project or solution.: ' \

0 commit comments

Comments
 (0)