Skip to content

Commit

Permalink
Add workload restore command
Browse files Browse the repository at this point in the history
Adding _FindAllReferenceWorkload target to find workloads in project.
Discover the projects and then pipe all arguements to workload install
command
  • Loading branch information
William Li committed Jul 14, 2021
1 parent 4f46c01 commit 3912692
Show file tree
Hide file tree
Showing 28 changed files with 394 additions and 1,007 deletions.
9 changes: 4 additions & 5 deletions src/Cli/dotnet/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,18 @@ public static class Parser
// Argument
public static readonly Argument DotnetSubCommand = new Argument<string>() { Arity = ArgumentArity.ExactlyOne, IsHidden = true };

private static Command ConfigureCommandLine(Command rootCommand, bool includeWorkloadCommands = false)
private static Command ConfigureCommandLine(Command rootCommand)
{
// Add subcommands
foreach (var subcommand in Subcommands)
{
rootCommand.AddCommand(subcommand);
}

// Workload command is behind a feature flag during development
rootCommand.AddCommand(WorkloadCommandParser.GetCommand(includeWorkloadCommands || Env.GetEnvironmentVariableAsBool("DEVENABLEWORKLOADCOMMAND", defaultValue: false)));
rootCommand.AddCommand(WorkloadCommandParser.GetCommand());

//Add internal commands
rootCommand.AddCommand(InstallSuccessCommand);
rootCommand.AddCommand(InstallSuccessCommand);

// Add options
rootCommand.AddOption(DiagOption);
Expand Down Expand Up @@ -112,7 +111,7 @@ private static CommandLineBuilder DisablePosixBinding(this CommandLineBuilder bu
.DisablePosixBinding()
.Build();

public static System.CommandLine.Parsing.Parser GetWorkloadsInstance { get; } = new CommandLineBuilder(ConfigureCommandLine(new RootCommand(), true))
public static System.CommandLine.Parsing.Parser GetWorkloadsInstance { get; } = new CommandLineBuilder(ConfigureCommandLine(new RootCommand()))
.UseExceptionHandler(ExceptionHandler)
.UseHelp()
.UseHelpBuilder(context => new DotnetHelpBuilder(context.Console))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Microsoft.DotNet.Cli
{
internal static class WorkloadCommandParser
{
public static Command GetCommand(bool includeAllCommands)
public static Command GetCommand()
{
var command = new Command("workload", LocalizableStrings.CommandDescription);

Expand All @@ -18,11 +18,7 @@ public static Command GetCommand(bool includeAllCommands)
command.AddCommand(WorkloadSearchCommandParser.GetCommand());
command.AddCommand(WorkloadUninstallCommandParser.GetCommand());
command.AddCommand(WorkloadRepairCommandParser.GetCommand());
if (includeAllCommands)
{
command.AddCommand(WorkloadRestoreCommandParser.GetCommand());
}

command.AddCommand(WorkloadRestoreCommandParser.GetCommand());
command.AddCommand(WorkloadElevateCommandParser.GetCommand());

return command;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public WorkloadInstallCommand(
string dotnetDir = null,
string userHome = null,
string tempDirPath = null,
string version = null)
string version = null,
IReadOnlyCollection<string> workloadIds = null)
: base(parseResult)
{
_reporter = reporter ?? Reporter.Output;
Expand All @@ -66,7 +67,7 @@ public WorkloadInstallCommand(
_printDownloadLinkOnly = parseResult.ValueForOption<bool>(WorkloadInstallCommandParser.PrintDownloadLinkOnlyOption);
_fromCacheOption = parseResult.ValueForOption<string>(WorkloadInstallCommandParser.FromCacheOption);
_downloadToCacheOption = parseResult.ValueForOption<string>(WorkloadInstallCommandParser.DownloadToCacheOption);
_workloadIds = parseResult.ValueForArgument<IEnumerable<string>>(WorkloadInstallCommandParser.WorkloadIdArgument).ToList().AsReadOnly();
_workloadIds = workloadIds ?? parseResult.ValueForArgument<IEnumerable<string>>(WorkloadInstallCommandParser.WorkloadIdArgument).ToList().AsReadOnly();
_verbosity = parseResult.ValueForOption<VerbosityOptions>(WorkloadInstallCommandParser.VerbosityOption);
_dotnetPath = dotnetDir ?? Path.GetDirectoryName(Environment.ProcessPath);
_sdkVersion = WorkloadOptionsExtensions.GetValidatedSdkVersion(parseResult.ValueForOption<string>(WorkloadInstallCommandParser.VersionOption), version, _dotnetPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ public static Command GetCommand()
var command = new Command("install", LocalizableStrings.CommandDescription);

command.AddArgument(WorkloadIdArgument);
AddWorkloadInstallCommandOptions(command);

return command;
}

internal static void AddWorkloadInstallCommandOptions(Command command)
{
command.AddOption(VersionOption);
command.AddOption(ConfigOption);
command.AddOption(SourceOption);
Expand All @@ -68,8 +75,6 @@ public static Command GetCommand()
command.AddOption(TempDirOption);
command.AddWorkloadCommandNuGetRestoreActionConfigOptions();
command.AddOption(VerbosityOption);

return command;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,49 +120,10 @@
<data name="CommandDescription" xml:space="preserve">
<value>Restore workloads required for the project.</value>
</data>
<data name="InvalidPackageWarning" xml:space="preserve">
<value>Warning: workload package '{0}' is invalid</value>
<data name="InstallingWorkloads" xml:space="preserve">
<value>Installing workloads: {0}</value>
</data>
<data name="PackageIdColumn" xml:space="preserve">
<value>Package Id</value>
</data>
<data name="VersionColumn" xml:space="preserve">
<value>Version</value>
</data>
<data name="CommandsColumn" xml:space="preserve">
<value>Commands</value>
</data>
<data name="AddSourceOptionDescription" xml:space="preserve">
<value>Add an additional NuGet package source to use during installation.</value>
</data>
<data name="AddSourceOptionName" xml:space="preserve">
<value>SOURCE</value>
</data>
<data name="ConfigFileOptionDescription" xml:space="preserve">
<value>The NuGet configuration file to use.</value>
</data>
<data name="ConfigFileOptionName" xml:space="preserve">
<value>FILE</value>
</data>
<data name="VersionOptionDescription" xml:space="preserve">
<value>The version of the workload package to install.</value>
</data>
<data name="VersionOptionName" xml:space="preserve">
<value>VERSION</value>
</data>
<data name="PackageFailedToRestore" xml:space="preserve">
<value>Package "{0}" failed to restore, due to {1}</value>
</data>
<data name="RestoreSuccessful" xml:space="preserve">
<value>Workload '{0}' (version '{1}') was restored. Available commands: {2}</value>
</data>
<data name="RestorePartiallyFailed" xml:space="preserve">
<value>Restore partially failed.</value>
</data>
<data name="RestoreFailed" xml:space="preserve">
<value>Restore failed.</value>
</data>
<data name="NoWorkloadsWereRestored" xml:space="preserve">
<value>No workloads were restored.</value>
<data name="CouldNotFindAProject" xml:space="preserve">
<value>Couldn't find a project. Ensure a project exists in {0}, or pass the path to the project using {1}.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,119 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.CommandLine.Parsing;
using System.IO;
using System.Linq;
using Microsoft.Build.Construction;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Workloads.Workload.Install;
using Microsoft.Extensions.EnvironmentAbstractions;
using Microsoft.NET.Sdk.WorkloadManifestReader;

namespace Microsoft.DotNet.Workloads.Workload.Restore
{
internal class WorkloadRestoreCommand : CommandBase
{
private readonly string _configFilePath;
private readonly IReporter _errorReporter;
private readonly IFileSystem _fileSystem;
private readonly ParseResult _result;
private readonly IReporter _reporter;
private readonly string[] _sources;
private readonly string _verbosity;
private readonly IEnumerable<string> _slnOrProjectArgument;

public WorkloadRestoreCommand(
ParseResult result,
IFileSystem fileSystem = null,
IReporter reporter = null)
: base(result)
{
_fileSystem = fileSystem ?? new FileSystemWrapper();

_result = result;
_reporter = reporter ?? Reporter.Output;
_errorReporter = reporter ?? Reporter.Error;

_configFilePath = result.ValueForOption<string>(WorkloadRestoreCommandParser.ConfigOption);
_sources = result.ValueForOption<string[]>(WorkloadRestoreCommandParser.SourceOption);
_verbosity =
Enum.GetName(result.ValueForOption<VerbosityOptions>(WorkloadRestoreCommandParser.VerbosityOption));
_slnOrProjectArgument =
result.ValueForArgument<IEnumerable<string>>(RestoreCommandParser.SlnOrProjectArgument);
}

public override int Execute()
{
_reporter.WriteLine("WIP workload restore stub");
var allProjects = DiscoverAllProjects(Directory.GetCurrentDirectory(), _slnOrProjectArgument).Distinct();

List<WorkloadId> allWorkloadId = RunTargetToGetWorkloadIds(allProjects);

_reporter.WriteLine(string.Format(LocalizableStrings.InstallingWorkloads, string.Join(" ", allWorkloadId)));

var workloadInstallCommand = new WorkloadInstallCommand(_result,
workloadIds: new ReadOnlyCollection<string>(allWorkloadId.Select(a => a.ToString()).ToList()));

workloadInstallCommand.Execute();
return 0;
}

private static List<WorkloadId> RunTargetToGetWorkloadIds(IEnumerable<string> allProjects)
{
var globalProperties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{Constants.MSBuildExtensionsPath, AppContext.BaseDirectory}
};

var allWorkloadId = new List<WorkloadId>();
foreach (string projectFile in allProjects)
{
var project = new ProjectInstance(projectFile, globalProperties, null);

project.Build(new[] {"_FindAllReferenceWorkload"},
loggers: Enumerable.Empty<ILogger>(),
remoteLoggers: Enumerable.Empty<ForwardingLoggerRecord>(),
targetOutputs: out var targetOutputs);

var targetResult = targetOutputs["_FindAllReferenceWorkload"];
allWorkloadId.AddRange(targetResult.Items.Select(item => new WorkloadId(item.ItemSpec)));
}

allWorkloadId = allWorkloadId.Distinct().ToList();
return allWorkloadId;
}

internal static List<string> DiscoverAllProjects(string currentDirectory,
IEnumerable<string> slnOrProjectArgument = null)
{
var slnFiles = new List<string>();
var projectFiles = new List<string>();
if (slnOrProjectArgument == null || !slnOrProjectArgument.Any())
{
slnFiles = Directory.GetFiles(currentDirectory, "*.sln").ToList();
projectFiles.AddRange(Directory.GetFiles(currentDirectory, "*.*proj"));
}
else
{
slnFiles = slnOrProjectArgument
.Where(s => Path.GetExtension(s).Equals(".sln", StringComparison.OrdinalIgnoreCase))
.Select(Path.GetFullPath).ToList();
projectFiles = slnOrProjectArgument
.Where(s => Path.GetExtension(s).EndsWith("proj", StringComparison.OrdinalIgnoreCase))
.Select(Path.GetFullPath).ToList();
}

foreach (string file in slnFiles)
{
var solutionFile = SolutionFile.Parse(file);
var projects = solutionFile.ProjectsInOrder;
foreach (var p in projects)
{
projectFiles.Add(p.AbsolutePath);
}
}

if (projectFiles.Count == 0)
{
throw new GracefulException(
LocalizableStrings.CouldNotFindAProject,
currentDirectory, "--project");
}

return projectFiles;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,12 @@ namespace Microsoft.DotNet.Cli
{
internal static class WorkloadRestoreCommandParser
{
public static readonly Option ConfigOption = WorkloadInstallCommandParser.ConfigOption;

public static readonly Option SourceOption = WorkloadInstallCommandParser.SourceOption;

public static readonly Option VerbosityOption = WorkloadInstallCommandParser.VerbosityOption;

public static Command GetCommand()
{
Command command = new Command("restore", LocalizableStrings.CommandDescription);

command.AddOption(ConfigOption);
command.AddOption(SourceOption);
command.AddWorkloadCommandNuGetRestoreActionConfigOptions();
command.AddOption(VerbosityOption);

command.AddArgument(RestoreCommandParser.SlnOrProjectArgument);
WorkloadInstallCommandParser.AddWorkloadInstallCommandOptions(command);
return command;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,79 +7,14 @@
<target state="needs-review-translation">Obnoví nástroje definované v manifestu místního nástroje.</target>
<note />
</trans-unit>
<trans-unit id="InvalidPackageWarning">
<source>Warning: workload package '{0}' is invalid</source>
<target state="new">Warning: workload package '{0}' is invalid</target>
<trans-unit id="CouldNotFindAProject">
<source>Couldn't find a project. Ensure a project exists in {0}, or pass the path to the project using {1}.</source>
<target state="new">Couldn't find a project. Ensure a project exists in {0}, or pass the path to the project using {1}.</target>
<note />
</trans-unit>
<trans-unit id="NoWorkloadsWereRestored">
<source>No workloads were restored.</source>
<target state="translated">Neobnovily se žádné nástroje.</target>
<note />
</trans-unit>
<trans-unit id="PackageIdColumn">
<source>Package Id</source>
<target state="translated">ID balíčku</target>
<note />
</trans-unit>
<trans-unit id="VersionColumn">
<source>Version</source>
<target state="translated">Verze</target>
<note />
</trans-unit>
<trans-unit id="CommandsColumn">
<source>Commands</source>
<target state="translated">Příkazy</target>
<note />
</trans-unit>
<trans-unit id="AddSourceOptionDescription">
<source>Add an additional NuGet package source to use during installation.</source>
<target state="translated">Přidá další zdroj balíčku NuGet, který se použije při instalaci.</target>
<note />
</trans-unit>
<trans-unit id="AddSourceOptionName">
<source>SOURCE</source>
<target state="translated">SOURCE</target>
<note />
</trans-unit>
<trans-unit id="ConfigFileOptionDescription">
<source>The NuGet configuration file to use.</source>
<target state="translated">Konfigurační soubor NuGet, který se použije.</target>
<note />
</trans-unit>
<trans-unit id="ConfigFileOptionName">
<source>FILE</source>
<target state="translated">FILE</target>
<note />
</trans-unit>
<trans-unit id="VersionOptionDescription">
<source>The version of the workload package to install.</source>
<target state="translated">Verze balíčku nástroje, který se má nainstalovat</target>
<note />
</trans-unit>
<trans-unit id="VersionOptionName">
<source>VERSION</source>
<target state="translated">VERSION</target>
<note />
</trans-unit>
<trans-unit id="PackageFailedToRestore">
<source>Package "{0}" failed to restore, due to {1}</source>
<target state="translated">Balíček {0} se nepovedlo obnovit. Příčina: {1}</target>
<note />
</trans-unit>
<trans-unit id="RestoreFailed">
<source>Restore failed.</source>
<target state="translated">Obnovení selhalo.</target>
<note />
</trans-unit>
<trans-unit id="RestoreSuccessful">
<source>Workload '{0}' (version '{1}') was restored. Available commands: {2}</source>
<target state="translated">Nástroj {0} (verze {1}) se obnovil. Dostupné příkazy: {2}</target>
<note />
</trans-unit>
<trans-unit id="RestorePartiallyFailed">
<source>Restore partially failed.</source>
<target state="translated">Obnovení bylo částečně neúspěšné.</target>
<trans-unit id="InstallingWorkloads">
<source>Installing workloads: {0}</source>
<target state="new">Installing workloads: {0}</target>
<note />
</trans-unit>
</body>
Expand Down
Loading

0 comments on commit 3912692

Please sign in to comment.