Skip to content

Commit d84e27b

Browse files
authored
Search version in set (#43096)
2 parents 8128f39 + c01b11b commit d84e27b

23 files changed

+687
-54
lines changed

src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ public FileBasedInstaller(IReporter reporter,
4848
string tempDirPath = null,
4949
VerbosityOptions verbosity = VerbosityOptions.normal,
5050
PackageSourceLocation packageSourceLocation = null,
51-
RestoreActionConfig restoreActionConfig = null)
51+
RestoreActionConfig restoreActionConfig = null,
52+
VerbosityOptions nugetPackageDownloaderVerbosity = VerbosityOptions.normal)
5253
{
5354
_userProfileDir = userProfileDir;
5455
_dotnetDir = dotnetDir ?? Path.GetDirectoryName(Environment.ProcessPath);
@@ -58,7 +59,8 @@ public FileBasedInstaller(IReporter reporter,
5859
_nugetPackageDownloader = nugetPackageDownloader ??
5960
new NuGetPackageDownloader(_tempPackagesDir, filePermissionSetter: null,
6061
new FirstPartyNuGetPackageSigningVerifier(), logger,
61-
restoreActionConfig: _restoreActionConfig);
62+
restoreActionConfig: _restoreActionConfig,
63+
verbosityOptions: nugetPackageDownloaderVerbosity);
6264
bool userLocal = WorkloadFileBasedInstall.IsUserLocal(_dotnetDir, sdkFeatureBand.ToString());
6365
_workloadRootDir = userLocal ? _userProfileDir : _dotnetDir;
6466
_workloadMetadataDir = Path.Combine(_workloadRootDir, "metadata", "workloads");
@@ -92,9 +94,8 @@ IEnumerable<PackInfo> GetPacksInWorkloads(IEnumerable<WorkloadId> workloadIds)
9294

9395
public WorkloadSet InstallWorkloadSet(ITransactionContext context, string workloadSetVersion, DirectoryPath? offlineCache = null)
9496
{
95-
SdkFeatureBand workloadSetFeatureBand;
96-
string workloadSetPackageVersion = WorkloadSet.WorkloadSetVersionToWorkloadSetPackageVersion(workloadSetVersion, out workloadSetFeatureBand);
97-
var workloadSetPackageId = GetManifestPackageId(new ManifestId("Microsoft.NET.Workloads"), workloadSetFeatureBand);
97+
string workloadSetPackageVersion = WorkloadSet.WorkloadSetVersionToWorkloadSetPackageVersion(workloadSetVersion, out SdkFeatureBand workloadSetFeatureBand);
98+
var workloadSetPackageId = GetManifestPackageId(new ManifestId(WorkloadManifestUpdater.WorkloadSetManifestId), workloadSetFeatureBand);
9899

99100
var workloadSetPath = Path.Combine(_workloadRootDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", workloadSetVersion);
100101

@@ -119,6 +120,18 @@ public WorkloadSet InstallWorkloadSet(ITransactionContext context, string worklo
119120
return WorkloadSet.FromWorkloadSetFolder(workloadSetPath, workloadSetVersion, _sdkFeatureBand);
120121
}
121122

123+
public WorkloadSet GetWorkloadSetContents(string workloadSetVersion) => GetWorkloadSetContentsAsync(workloadSetVersion).GetAwaiter().GetResult();
124+
125+
public async Task<WorkloadSet> GetWorkloadSetContentsAsync(string workloadSetVersion)
126+
{
127+
string workloadSetPackageVersion = WorkloadSet.WorkloadSetVersionToWorkloadSetPackageVersion(workloadSetVersion, out var workloadSetFeatureBand);
128+
var packagePath = await _nugetPackageDownloader.DownloadPackageAsync(GetManifestPackageId(new ManifestId(WorkloadManifestUpdater.WorkloadSetManifestId), workloadSetFeatureBand),
129+
new NuGetVersion(workloadSetPackageVersion), _packageSourceLocation);
130+
var tempExtractionDir = Path.Combine(_tempPackagesDir.Value, $"{WorkloadManifestUpdater.WorkloadSetManifestId}-{workloadSetPackageVersion}-extracted");
131+
await ExtractManifestAsync(packagePath, tempExtractionDir);
132+
return WorkloadSet.FromWorkloadSetFolder(tempExtractionDir, workloadSetVersion, _sdkFeatureBand);
133+
}
134+
122135
public void InstallWorkloads(IEnumerable<WorkloadId> workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null)
123136
{
124137
var packInfos = GetPacksInWorkloads(workloadIds);

src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace Microsoft.DotNet.Workloads.Workload.Install
2020
{
2121
internal class WorkloadManifestUpdater : IWorkloadManifestUpdater
2222
{
23-
readonly string WorkloadSetManifestId = "Microsoft.NET.Workloads";
23+
public static readonly string WorkloadSetManifestId = "Microsoft.NET.Workloads";
2424

2525
private readonly IReporter _reporter;
2626
private readonly IWorkloadResolver _workloadResolver;

src/Cli/dotnet/commands/dotnet-workload/search/LocalizableStrings.resx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,23 @@
145145
<data name="TakeOptionMustBePositive" xml:space="preserve">
146146
<value>The --take option must be positive.</value>
147147
</data>
148+
<data name="WorkloadVersionArgument" xml:space="preserve">
149+
<value>WORKLOAD_VERSION</value>
150+
</data>
151+
<data name="WorkloadVersionArgumentDescription" xml:space="preserve">
152+
<value>Output workload manifest versions associated with the provided workload version.</value>
153+
</data>
154+
<data name="CannotCombineSearchStringAndVersion" xml:space="preserve">
155+
<value>Cannot specify both the {0} and {1} arguments.</value>
156+
</data>
157+
<data name="NoWorkloadVersionsFound" xml:space="preserve">
158+
<value>No workload versions found for SDK feature band {0}.</value>
159+
</data>
160+
<data name="WorkloadManifestIdColumn" xml:space="preserve">
161+
<value>Workload manifest ID</value>
162+
</data>
163+
<data name="WorkloadManifestFeatureBandColumn" xml:space="preserve">
164+
<value>Manifest feature band</value>
165+
</data>
166+
148167
</root>

src/Cli/dotnet/commands/dotnet-workload/search/WorkloadSearchCommand.cs

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

44
using System.CommandLine;
5-
using System.Text.Json;
6-
using Microsoft.Deployment.DotNet.Releases;
75
using Microsoft.DotNet.Cli;
86
using Microsoft.DotNet.Cli.NuGetPackageDownloader;
97
using Microsoft.DotNet.Cli.Utils;
@@ -16,12 +14,7 @@ namespace Microsoft.DotNet.Workloads.Workload.Search
1614
internal class WorkloadSearchCommand : WorkloadCommandBase
1715
{
1816
private readonly IWorkloadResolver _workloadResolver;
19-
private readonly ReleaseVersion _sdkVersion;
2017
private readonly string _workloadIdStub;
21-
private readonly int _numberOfWorkloadSetsToTake;
22-
private readonly string _workloadSetOutputFormat;
23-
private readonly IWorkloadManifestInstaller _installer;
24-
internal bool ListWorkloadSetVersions { get; set; } = false;
2518

2619
public WorkloadSearchCommand(
2720
ParseResult result,
@@ -30,7 +23,7 @@ public WorkloadSearchCommand(
3023
{
3124
_workloadIdStub = result.GetValue(WorkloadSearchCommandParser.WorkloadIdStubArgument);
3225

33-
workloadResolverFactory = workloadResolverFactory ?? new WorkloadResolverFactory();
26+
workloadResolverFactory ??= new WorkloadResolverFactory();
3427

3528
if (!string.IsNullOrEmpty(result.GetValue(WorkloadSearchCommandParser.VersionOption)))
3629
{
@@ -39,45 +32,11 @@ public WorkloadSearchCommand(
3932

4033
var creationResult = workloadResolverFactory.Create();
4134

42-
_sdkVersion = creationResult.SdkVersion;
4335
_workloadResolver = creationResult.WorkloadResolver;
44-
45-
_numberOfWorkloadSetsToTake = result.GetValue(SearchWorkloadSetsParser.TakeOption);
46-
_workloadSetOutputFormat = result.GetValue(SearchWorkloadSetsParser.FormatOption);
47-
48-
_installer = WorkloadInstallerFactory.GetWorkloadInstaller(
49-
reporter,
50-
new SdkFeatureBand(_sdkVersion),
51-
_workloadResolver,
52-
Verbosity,
53-
creationResult.UserProfileDir,
54-
!SignCheck.IsDotNetSigned(),
55-
restoreActionConfig: new RestoreActionConfig(result.HasOption(SharedOptions.InteractiveOption)),
56-
elevationRequired: false,
57-
shouldLog: false);
5836
}
5937

6038
public override int Execute()
6139
{
62-
if (ListWorkloadSetVersions)
63-
{
64-
var featureBand = new SdkFeatureBand(_sdkVersion);
65-
var packageId = _installer.GetManifestPackageId(new ManifestId("Microsoft.NET.Workloads"), featureBand);
66-
var versions = PackageDownloader.GetLatestPackageVersions(packageId, _numberOfWorkloadSetsToTake, packageSourceLocation: null, includePreview: !string.IsNullOrWhiteSpace(_sdkVersion.Prerelease))
67-
.GetAwaiter().GetResult()
68-
.Select(version => WorkloadManifestUpdater.WorkloadSetPackageVersionToWorkloadSetVersion(featureBand, version.Version.ToString()));
69-
if (_workloadSetOutputFormat?.Equals("json", StringComparison.OrdinalIgnoreCase) == true)
70-
{
71-
Reporter.WriteLine(JsonSerializer.Serialize(versions.Select(version => version.ToDictionary(_ => "workloadVersion", v => v))));
72-
}
73-
else
74-
{
75-
Reporter.WriteLine(string.Join('\n', versions));
76-
}
77-
78-
return 0;
79-
}
80-
8140
IEnumerable<WorkloadResolver.WorkloadInfo> availableWorkloads = _workloadResolver.GetAvailableWorkloads()
8241
.OrderBy(workload => workload.Id);
8342

src/Cli/dotnet/commands/dotnet-workload/search/WorkloadSearchCommandParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public static CliCommand GetCommand()
2929
private static CliCommand ConstructCommand()
3030
{
3131
var command = new CliCommand("search", LocalizableStrings.CommandDescription);
32-
command.Subcommands.Add(SearchWorkloadSetsParser.GetCommand());
32+
command.Subcommands.Add(WorkloadSearchVersionsCommandParser.GetCommand());
3333
command.Arguments.Add(WorkloadIdStubArgument);
3434
command.Options.Add(CommonOptions.HiddenVerbosityOption);
3535
command.Options.Add(VersionOption);
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.CommandLine;
6+
using System.Text.Json;
7+
using Microsoft.Deployment.DotNet.Releases;
8+
using Microsoft.DotNet.Cli;
9+
using Microsoft.DotNet.Cli.NuGetPackageDownloader;
10+
using Microsoft.DotNet.Cli.Utils;
11+
using Microsoft.DotNet.Configurer;
12+
using Microsoft.DotNet.ToolPackage;
13+
using Microsoft.DotNet.Workloads.Workload.Install;
14+
using Microsoft.NET.Sdk.WorkloadManifestReader;
15+
using Microsoft.TemplateEngine.Cli.Commands;
16+
using NuGet.Versioning;
17+
18+
using InformationStrings = Microsoft.DotNet.Workloads.Workload.LocalizableStrings;
19+
20+
namespace Microsoft.DotNet.Workloads.Workload.Search
21+
{
22+
internal class WorkloadSearchVersionsCommand : WorkloadCommandBase
23+
{
24+
private readonly ReleaseVersion _sdkVersion;
25+
private readonly int _numberOfWorkloadSetsToTake;
26+
private readonly string _workloadSetOutputFormat;
27+
private readonly FileBasedInstaller _installer;
28+
private readonly string _workloadVersion;
29+
30+
public WorkloadSearchVersionsCommand(
31+
ParseResult result,
32+
IReporter reporter = null,
33+
IWorkloadResolverFactory workloadResolverFactory = null) : base(result, CommonOptions.HiddenVerbosityOption, reporter)
34+
{
35+
workloadResolverFactory = workloadResolverFactory ?? new WorkloadResolverFactory();
36+
37+
if (!string.IsNullOrEmpty(result.GetValue(WorkloadSearchCommandParser.VersionOption)))
38+
{
39+
throw new GracefulException(Install.LocalizableStrings.SdkVersionOptionNotSupported);
40+
}
41+
42+
var creationResult = workloadResolverFactory.Create();
43+
44+
_sdkVersion = creationResult.SdkVersion;
45+
var workloadResolver = creationResult.WorkloadResolver;
46+
47+
_numberOfWorkloadSetsToTake = result.GetValue(WorkloadSearchVersionsCommandParser.TakeOption);
48+
_workloadSetOutputFormat = result.GetValue(WorkloadSearchVersionsCommandParser.FormatOption);
49+
50+
// For these operations, we don't have to respect 'msi' because they're equivalent between the two workload
51+
// install types, and FileBased is much easier to work with.
52+
_installer = new FileBasedInstaller(
53+
reporter,
54+
new SdkFeatureBand(_sdkVersion),
55+
workloadResolver,
56+
CliFolderPathCalculator.DotnetUserProfileFolderPath,
57+
nugetPackageDownloader: null,
58+
dotnetDir: Path.GetDirectoryName(Environment.ProcessPath),
59+
tempDirPath: null,
60+
verbosity: Verbosity,
61+
packageSourceLocation: null,
62+
restoreActionConfig: new RestoreActionConfig(result.HasOption(SharedOptions.InteractiveOption)),
63+
nugetPackageDownloaderVerbosity: VerbosityOptions.quiet
64+
);
65+
66+
_workloadVersion = result.GetValue(WorkloadSearchVersionsCommandParser.WorkloadVersionArgument);
67+
}
68+
69+
public override int Execute()
70+
{
71+
if (_workloadVersion is null)
72+
{
73+
var featureBand = new SdkFeatureBand(_sdkVersion);
74+
var packageId = _installer.GetManifestPackageId(new ManifestId("Microsoft.NET.Workloads"), featureBand);
75+
76+
List<string> versions;
77+
try
78+
{
79+
versions = PackageDownloader.GetLatestPackageVersions(packageId, _numberOfWorkloadSetsToTake, packageSourceLocation: null, includePreview: !string.IsNullOrWhiteSpace(_sdkVersion.Prerelease))
80+
.GetAwaiter().GetResult()
81+
.Select(version => WorkloadManifestUpdater.WorkloadSetPackageVersionToWorkloadSetVersion(featureBand, version.ToString()))
82+
.ToList();
83+
}
84+
catch (NuGetPackageNotFoundException)
85+
{
86+
Microsoft.DotNet.Cli.Utils.Reporter.Error.WriteLine(string.Format(LocalizableStrings.NoWorkloadVersionsFound, featureBand));
87+
return 0;
88+
}
89+
if (_workloadSetOutputFormat?.Equals("json", StringComparison.OrdinalIgnoreCase) == true)
90+
{
91+
Reporter.WriteLine(JsonSerializer.Serialize(versions.Select(version => version.ToDictionary(_ => "workloadVersion", v => v))));
92+
}
93+
else
94+
{
95+
Reporter.WriteLine(string.Join('\n', versions));
96+
}
97+
}
98+
else
99+
{
100+
var workloadSet = _installer.GetWorkloadSetContents(_workloadVersion);
101+
if (_workloadSetOutputFormat?.Equals("json", StringComparison.OrdinalIgnoreCase) == true)
102+
{
103+
var set = new WorkloadSet() { ManifestVersions = workloadSet.ManifestVersions };
104+
Reporter.WriteLine(JsonSerializer.Serialize(new Dictionary<string, Dictionary<string, string>>()
105+
{
106+
{ "manifestVersions", set.ToDictionaryForJson() }
107+
}, new JsonSerializerOptions { WriteIndented = true }));
108+
}
109+
else
110+
{
111+
PrintableTable<KeyValuePair<ManifestId, (ManifestVersion Version, SdkFeatureBand FeatureBand)>> table = new();
112+
table.AddColumn(LocalizableStrings.WorkloadManifestIdColumn, manifest => manifest.Key.ToString());
113+
table.AddColumn(LocalizableStrings.WorkloadManifestFeatureBandColumn, manifest => manifest.Value.FeatureBand.ToString());
114+
table.AddColumn(InformationStrings.WorkloadManifestVersionColumn, manifest => manifest.Value.Version.ToString());
115+
table.PrintRows(workloadSet.ManifestVersions, l => Reporter.WriteLine(l));
116+
}
117+
}
118+
119+
return 0;
120+
}
121+
}
122+
}

src/Cli/dotnet/commands/dotnet-workload/search/SearchWorkloadSetsParser.cs renamed to src/Cli/dotnet/commands/dotnet-workload/search/WorkloadSearchVersionsCommandParser.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,15 @@
77

88
namespace Microsoft.DotNet.Cli
99
{
10-
internal static class SearchWorkloadSetsParser
10+
internal static class WorkloadSearchVersionsCommandParser
1111
{
12+
public static readonly CliArgument<string> WorkloadVersionArgument =
13+
new(LocalizableStrings.WorkloadVersionArgument)
14+
{
15+
Arity = ArgumentArity.ZeroOrOne,
16+
Description = LocalizableStrings.WorkloadVersionArgumentDescription
17+
};
18+
1219
public static readonly CliOption<int> TakeOption = new("--take") { DefaultValueFactory = (_) => 5 };
1320

1421
public static readonly CliOption<string> FormatOption = new("--format")
@@ -26,21 +33,27 @@ public static CliCommand GetCommand()
2633
private static CliCommand ConstructCommand()
2734
{
2835
var command = new CliCommand("version", LocalizableStrings.PrintSetVersionsDescription);
36+
command.Arguments.Add(WorkloadVersionArgument);
2937
command.Options.Add(FormatOption);
3038
command.Options.Add(TakeOption);
3139

3240
TakeOption.Validators.Add(optionResult =>
3341
{
3442
if (optionResult.GetValueOrDefault<int>() <= 0)
3543
{
36-
throw new ArgumentException(LocalizableStrings.TakeOptionMustBePositive);
44+
throw new ArgumentException("The --take option must be positive.");
3745
}
3846
});
3947

40-
command.SetAction(parseResult => new WorkloadSearchCommand(parseResult)
48+
command.Validators.Add(result =>
4149
{
42-
ListWorkloadSetVersions = true
43-
}.Execute());
50+
if (result.GetValue(WorkloadSearchCommandParser.WorkloadIdStubArgument) != null)
51+
{
52+
result.AddError(string.Format(LocalizableStrings.CannotCombineSearchStringAndVersion, WorkloadSearchCommandParser.WorkloadIdStubArgument.Name, command.Name));
53+
}
54+
});
55+
56+
command.SetAction(parseResult => new WorkloadSearchVersionsCommand(parseResult).Execute());
4457

4558
return command;
4659
}

src/Cli/dotnet/commands/dotnet-workload/search/xlf/LocalizableStrings.cs.xlf

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)