Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Download command #3376

Merged
merged 37 commits into from Jul 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8b43d55
save work
Jun 2, 2023
d178be5
Merge branch 'master' of https://github.com/ryfu-msft/winget-cli into…
Jun 8, 2023
8557576
initial implementation for download command
Jun 9, 2023
99ea470
remove context flag, add installerType argument
Jun 13, 2023
7c413a9
save work for com and e2e tests
Jun 15, 2023
32dab46
add E2E tests
Jun 15, 2023
c019ba7
save work
Jun 16, 2023
ed07786
remove force arg
Jun 16, 2023
89b1f07
save work
Jun 20, 2023
33f06bb
save work
Jun 22, 2023
0b27a2e
cleanup com and add tests
Jun 22, 2023
c315bd3
resolve merge conflicts
Jun 22, 2023
bf8a107
fix out of proc com registration
Jun 22, 2023
5fa8f61
resolve merge conflicts
Jun 23, 2023
d78ed8d
fix tests and refactor
Jun 26, 2023
dedb403
revert comment change
Jun 26, 2023
a458ddb
refresh path variable
Jun 26, 2023
1444fc2
try again
Jun 26, 2023
23465bd
try again diagnostic
Jun 27, 2023
8bda4bb
use packagemanagersettings for inproc
Jun 27, 2023
51f6b56
manually set experimental feature for inproc com
Jun 27, 2023
3d47c21
try again
Jun 27, 2023
be14705
address initial comments
Jun 28, 2023
8b849e4
remove experimental feature
Jun 28, 2023
bd8c1ed
fix line spacing
Jun 28, 2023
a7a9eee
revert and fix logs
Jun 28, 2023
64dd740
configure settings at start
Jun 29, 2023
5afd9a2
fix COM E2E test and revert pipeline yml
Jun 29, 2023
790dae7
change locale test manifest
Jun 29, 2023
14474b8
resolve merge conflicts
Jun 29, 2023
fbb8224
fix locale test
Jun 30, 2023
05757f8
address PR feedback
Jul 8, 2023
43b76b3
resolve ambiguous reference
Jul 10, 2023
5ec8894
fix hang
Jul 10, 2023
24e7573
resolve merge conflicts
Jul 10, 2023
4613a22
address final comments
Jul 15, 2023
78e68db
move installer download check
Jul 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/Settings.md
Expand Up @@ -281,4 +281,15 @@ You can enable the feature as shown below.
"experimentalFeatures": {
"windowsFeature": true
},
```

### download

This feature enables the download command. This command allows users to download the installers of a specified package.
You can enable the feature as shown below.

```json
"experimentalFeatures": {
"download": true
},
```
1 change: 1 addition & 0 deletions doc/windows/package-manager/winget/returnCodes.md
Expand Up @@ -118,6 +118,7 @@ ms.localizationpriority: medium
| 0x8A150068 | -1978335128 | APPINSTALLER_CLI_ERROR_PACKAGE_IS_PINNED | The package has a pin that prevents upgrade. |
| 0x8A150069 | -1978335127 | APPINSTALLER_CLI_ERROR_PACKAGE_IS_STUB | The package currently installed is the stub package |
| 0x8A15006A | -1978335126 | APPINSTALLER_CLI_ERROR_APPTERMINATION_RECEIVED | Application shutdown signal received |
| 0x8A15006B | -1978335125 | APPINSTALLER_CLI_ERROR_DOWNLOAD_DEPENDENCIES | Failed to download package dependencies. |

## Install errors.

Expand Down
18 changes: 17 additions & 1 deletion schemas/JSON/settings/settings.schema.0.2.json
Expand Up @@ -136,7 +136,18 @@
"purgePortablePackage": {
"description": "Controls whether the default behavior for uninstall removes all files and directories relevant to this package. Only applies to the portable installerType.",
"type": "boolean",
"default": false
"default": false
}
}
},
"DownloadBehavior": {
"description": "Download settings",
"type": "object",
"properties": {
"defaultDownloadDirectory": {
"description": "The default directory where installers are downloaded to.",
"type": "string",
"default": "%USERPROFILE%/Downloads/"
}
}
},
Expand Down Expand Up @@ -213,6 +224,11 @@
"description": "Enable support for configuration",
"type": "boolean",
"default": false
},
"download": {
"description": "Enable support for the download command",
"type": "boolean",
"default": false
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/AppInstallerCLICore/AppInstallerCLICore.vcxproj
Expand Up @@ -358,6 +358,7 @@
<ClInclude Include="Commands\ConfigureTestCommand.h" />
<ClInclude Include="Commands\ConfigureValidateCommand.h" />
<ClInclude Include="Commands\DebugCommand.h" />
<ClInclude Include="Commands\DownloadCommand.h" />
<ClInclude Include="Commands\ExperimentalCommand.h" />
<ClInclude Include="Commands\ExportCommand.h" />
<ClInclude Include="Commands\ImportCommand.h" />
Expand Down Expand Up @@ -425,6 +426,7 @@
<ClCompile Include="Commands\ConfigureTestCommand.cpp" />
<ClCompile Include="Commands\ConfigureValidateCommand.cpp" />
<ClCompile Include="Commands\DebugCommand.cpp" />
<ClCompile Include="Commands\DownloadCommand.cpp" />
<ClCompile Include="Commands\ImportCommand.cpp" />
<ClCompile Include="Commands\PinCommand.cpp" />
<ClCompile Include="Commands\TestCommand.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters
Expand Up @@ -224,6 +224,9 @@
<ClInclude Include="Commands\TestCommand.h">
<Filter>Commands</Filter>
</ClInclude>
<ClInclude Include="Commands\DownloadCommand.h">
<Filter>Commands</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
Expand Down Expand Up @@ -415,6 +418,9 @@
<ClCompile Include="Commands\TestCommand.cpp">
<Filter>Commands</Filter>
</ClCompile>
<ClInclude Include="Commands\DownloadCommand.cpp">
<Filter>Commands</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
Expand Down
13 changes: 11 additions & 2 deletions src/AppInstallerCLICore/Argument.cpp
Expand Up @@ -77,6 +77,8 @@ namespace AppInstaller::CLI
return { type, "scope"_liv, ArgTypeCategory::InstallerSelection | ArgTypeCategory::CopyValueToSubContext };
case Execution::Args::Type::InstallArchitecture:
return { type, "architecture"_liv, 'a', ArgTypeCategory::InstallerSelection | ArgTypeCategory::CopyValueToSubContext };
case Execution::Args::Type::InstallerType:
return { type, "installer-type"_liv, ArgTypeCategory::InstallerSelection };
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
case Execution::Args::Type::HashOverride:
return { type, "ignore-security-hash"_liv, ArgTypeCategory::InstallerBehavior | ArgTypeCategory::CopyFlagToSubContext };
case Execution::Args::Type::IgnoreLocalArchiveMalwareScan:
Expand Down Expand Up @@ -164,7 +166,6 @@ namespace AppInstaller::CLI
case Execution::Args::Type::Upgrade:
return { type, "upgrade-available"_liv};


// Pin command
case Execution::Args::Type::GatedVersion:
return { type, "version"_liv, 'v', ArgTypeCategory::None, ArgTypeExclusiveSet::PinType };
Expand All @@ -183,6 +184,10 @@ namespace AppInstaller::CLI
case Execution::Args::Type::ConfigurationDisable:
return { type, "disable"_liv, ArgTypeCategory::None, ArgTypeExclusiveSet::StubType };

// Download command
case Execution::Args::Type::DownloadDirectory:
return { type, "download-directory"_liv, 'd', ArgTypeCategory::None };

// Common arguments
case Execution::Args::Type::NoVT:
return { type, "no-vt"_liv, ArgTypeCategory::None, ArgTypeExclusiveSet::ProgressBarOption };
Expand Down Expand Up @@ -271,7 +276,7 @@ namespace AppInstaller::CLI
case Args::Type::Locale:
return Argument{ type, Resource::String::LocaleArgumentDescription, ArgumentType::Standard };
case Args::Type::InstallArchitecture:
return Argument{ type, Resource::String::InstallArchitectureArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help };
return Argument{ type, Resource::String::ArchitectureArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help };
case Args::Type::Log:
return Argument{ type, Resource::String::LogArgumentDescription, ArgumentType::Standard };
case Args::Type::CustomSwitches:
Expand Down Expand Up @@ -336,6 +341,10 @@ namespace AppInstaller::CLI
return Argument{ type, Resource::String::UninstallPreviousArgumentDescription, ArgumentType::Flag, Argument::Visibility::Help };
case Args::Type::Force:
return Argument{ type, Resource::String::ForceArgumentDescription, ArgumentType::Flag, false };
case Args::Type::DownloadDirectory:
return Argument{ type, Resource::String::DownloadDirectoryArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help, false };
case Args::Type::InstallerType:
return Argument{ type, Resource::String::InstallerTypeArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help, false };
default:
THROW_HR(E_UNEXPECTED);
}
Expand Down
9 changes: 9 additions & 0 deletions src/AppInstallerCLICore/Command.cpp
Expand Up @@ -720,6 +720,15 @@ namespace AppInstaller::CLI
}
}

if (execArgs.Contains(Execution::Args::Type::InstallerType))
{
Manifest::InstallerTypeEnum selectedInstallerType = Manifest::ConvertToInstallerTypeEnum(std::string(execArgs.GetArg(Execution::Args::Type::InstallerType)));
if (selectedInstallerType == Manifest::InstallerTypeEnum::Unknown)
{
throw CommandException(Resource::String::InvalidArgumentValueErrorWithoutValidValues(Argument::ForType(Execution::Args::Type::InstallerType).Name()));
}
}

Argument::ValidateExclusiveArguments(execArgs);

ValidateArgumentsInternal(execArgs);
Expand Down
7 changes: 5 additions & 2 deletions src/AppInstallerCLICore/Commands/COMCommand.cpp
Expand Up @@ -7,6 +7,7 @@
#include "Workflows/PromptFlow.h"
#include "Workflows/UninstallFlow.h"
#include "Workflows/WorkflowBase.h"
#include "Workflows/DependenciesFlow.h"

namespace AppInstaller::CLI
{
Expand All @@ -24,15 +25,17 @@ namespace AppInstaller::CLI
Workflow::EnsureApplicableInstaller <<
Workflow::ReportIdentityAndInstallationDisclaimer <<
Workflow::ShowPromptsForSinglePackage(/* ensureAcceptance */ true) <<
Workflow::ManageDependencies << // TODO: Separate handling dependencies from download flow.
Workflow::SetDownloadDirectory <<
Workflow::DownloadPackageDependencies <<
Workflow::DownloadInstaller;
}

// IMPORTANT: To use this command, the caller should have already executed the COMDownloadCommand
void COMInstallCommand::ExecuteInternal(Context& context) const
{
context <<
Workflow::ReverifyInstallerHash <<
Workflow::InstallDependencies <<
Workflow::ReverifyInstallerHash <<
Workflow::InstallPackageInstaller;
}

Expand Down
91 changes: 91 additions & 0 deletions src/AppInstallerCLICore/Commands/DownloadCommand.cpp
@@ -0,0 +1,91 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "DownloadCommand.h"
#include "Workflows/DownloadFlow.h"
#include "Workflows/InstallFlow.h"
#include "Workflows/PromptFlow.h"
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
#include "Resources.h"
#include <AppInstallerRuntime.h>

namespace AppInstaller::CLI
{
using namespace AppInstaller::CLI::Execution;
using namespace AppInstaller::CLI::Workflow;
using namespace AppInstaller::Utility::literals;

std::vector<Argument> DownloadCommand::GetArguments() const
{
return {
Argument::ForType(Args::Type::Query),
Argument::ForType(Args::Type::DownloadDirectory),
Argument::ForType(Args::Type::Manifest),
Argument::ForType(Args::Type::Id),
Argument::ForType(Args::Type::Name),
Argument::ForType(Args::Type::Moniker),
Argument::ForType(Args::Type::Version),
Argument::ForType(Args::Type::Channel),
Argument::ForType(Args::Type::Source),
Argument{ Args::Type::InstallScope, Resource::String::InstallScopeDescription, ArgumentType::Standard, Argument::Visibility::Help },
Argument::ForType(Args::Type::InstallArchitecture),
Argument::ForType(Args::Type::InstallerType),
Argument::ForType(Args::Type::Exact),
Argument::ForType(Args::Type::Locale),
Argument::ForType(Args::Type::HashOverride),
Argument::ForType(Args::Type::SkipDependencies),
Argument::ForType(Execution::Args::Type::AcceptPackageAgreements),
Argument::ForType(Execution::Args::Type::AcceptSourceAgreements),
};
}

Resource::LocString DownloadCommand::ShortDescription() const
{
return { Resource::String::DownloadCommandShortDescription };
}

Resource::LocString DownloadCommand::LongDescription() const
{
return { Resource::String::DownloadCommandLongDescription };
}

Utility::LocIndView DownloadCommand::HelpLink() const
{
return "https://aka.ms/winget-command-download"_liv;
}

void DownloadCommand::ValidateArgumentsInternal(Args& execArgs) const
{
Argument::ValidateCommonArguments(execArgs);
}

void DownloadCommand::ExecuteInternal(Context& context) const
{
context.SetFlags(AppInstaller::CLI::Execution::ContextFlag::InstallerDownloadOnly);

if (context.Args.Contains(Execution::Args::Type::Manifest))
{
context <<
Workflow::ReportExecutionStage(ExecutionStage::Discovery) <<
Workflow::GetManifestFromArg;
}
else
{
context <<
Workflow::ReportExecutionStage(ExecutionStage::Discovery) <<
Workflow::OpenSource() <<
Workflow::SearchSourceForSingle <<
Workflow::HandleSearchResultFailures <<
Workflow::EnsureOneMatchFromSearchResult(OperationType::Download) <<
Workflow::GetManifestFromPackage(false);
}

context <<
Workflow::SetDownloadDirectory <<
Workflow::SelectInstaller <<
Workflow::EnsureApplicableInstaller <<
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
Workflow::ReportIdentityAndInstallationDisclaimer <<
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
Workflow::ShowPromptsForSinglePackage(/* ensureAcceptance */ true) <<
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
Workflow::DownloadPackageDependencies <<
Workflow::DownloadInstaller;
}
}
23 changes: 23 additions & 0 deletions src/AppInstallerCLICore/Commands/DownloadCommand.h
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "Command.h"

namespace AppInstaller::CLI
{
struct DownloadCommand final : public Command
{
DownloadCommand(std::string_view parent) : Command("download", {} /* aliases */, parent, Settings::ExperimentalFeature::Feature::Download) {}

std::vector<Argument> GetArguments() const override;

Resource::LocString ShortDescription() const override;
Resource::LocString LongDescription() const override;

Utility::LocIndView HelpLink() const override;

protected:
void ValidateArgumentsInternal(Execution::Args& execArgs) const override;
void ExecuteInternal(Execution::Context& context) const override;
};
}
4 changes: 2 additions & 2 deletions src/AppInstallerCLICore/Commands/InstallCommand.cpp
Expand Up @@ -132,8 +132,8 @@ namespace AppInstaller::CLI
Workflow::GetMultiSearchRequests <<
Workflow::SearchSubContextsForSingle() <<
Workflow::ReportExecutionStage(Workflow::ExecutionStage::Execution) <<
Workflow::InstallMultiplePackages(
Resource::String::InstallAndUpgradeCommandsReportDependencies,
Workflow::ProcessMultiplePackages(
Resource::String::PackageRequiresDependencies,
APPINSTALLER_CLI_ERROR_MULTIPLE_INSTALL_FAILED);
}
else
Expand Down
3 changes: 3 additions & 0 deletions src/AppInstallerCLICore/Commands/RootCommand.cpp
Expand Up @@ -23,6 +23,7 @@
#include "ConfigureCommand.h"
#include "DebugCommand.h"
#include "TestCommand.h"
#include "DownloadCommand.h"

#include "Resources.h"
#include "TableOutput.h"
Expand Down Expand Up @@ -140,6 +141,7 @@ namespace AppInstaller::CLI
keyDirectories.OutputLine({ Resource::LocString{ Resource::String::PortableRootUser }, Runtime::GetPathTo(Runtime::PathName::PortablePackageUserRoot, true).u8string() });
keyDirectories.OutputLine({ Resource::LocString{ Resource::String::PortableRoot }, Runtime::GetPathTo(Runtime::PathName::PortablePackageMachineRoot, true).u8string() });
keyDirectories.OutputLine({ Resource::LocString{ Resource::String::PortableRoot86 }, Runtime::GetPathTo(Runtime::PathName::PortablePackageMachineRootX86, true).u8string() });
keyDirectories.OutputLine({ Resource::LocString{ Resource::String::InstallerDownloads }, Runtime::GetPathTo(Runtime::PathName::UserProfileDownloads, true).u8string() });
keyDirectories.Complete();
context.Reporter.Info() << std::endl;
}
Expand Down Expand Up @@ -177,6 +179,7 @@ namespace AppInstaller::CLI
std::make_unique<ImportCommand>(FullName()),
std::make_unique<PinCommand>(FullName()),
std::make_unique<ConfigureCommand>(FullName()),
std::make_unique<DownloadCommand>(FullName()),
#if _DEBUG
std::make_unique<DebugCommand>(FullName()),
#endif
Expand Down
4 changes: 2 additions & 2 deletions src/AppInstallerCLICore/Commands/UpgradeCommand.cpp
Expand Up @@ -202,8 +202,8 @@ namespace AppInstaller::CLI
Workflow::GetMultiSearchRequests <<
Workflow::SearchSubContextsForSingle(OperationType::Upgrade) <<
Workflow::ReportExecutionStage(Workflow::ExecutionStage::Execution) <<
Workflow::InstallMultiplePackages(
Resource::String::InstallAndUpgradeCommandsReportDependencies,
Workflow::ProcessMultiplePackages(
Resource::String::PackageRequiresDependencies,
APPINSTALLER_CLI_ERROR_MULTIPLE_INSTALL_FAILED);
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/AppInstallerCLICore/ContextOrchestrator.cpp
Expand Up @@ -362,6 +362,7 @@ namespace AppInstaller::CLI::Execution
case PackageOperationType::Install: return "root:install"sv;
case PackageOperationType::Upgrade: return "root:upgrade"sv;
case PackageOperationType::Uninstall: return "root:uninstall"sv;
case PackageOperationType::Download: return "root:download"sv;
default: return "unknown";
}
}
Expand All @@ -386,4 +387,11 @@ namespace AppInstaller::CLI::Execution
std::unique_ptr<OrchestratorQueueItem> item = std::make_unique<OrchestratorQueueItem>(OrchestratorQueueItemId(std::move(packageId), std::move(sourceId)), std::move(context), PackageOperationType::Search);
return item;
}

std::unique_ptr<OrchestratorQueueItem> OrchestratorQueueItemFactory::CreateItemForDownload(std::wstring packageId, std::wstring sourceId, std::unique_ptr<COMContext> context)
{
std::unique_ptr<OrchestratorQueueItem> item = std::make_unique<OrchestratorQueueItem>(OrchestratorQueueItemId(std::move(packageId), std::move(sourceId)), std::move(context), PackageOperationType::Download);
item->AddCommand(std::make_unique<::AppInstaller::CLI::COMDownloadCommand>(RootCommand::CommandName));
return item;
}
}
3 changes: 3 additions & 0 deletions src/AppInstallerCLICore/ContextOrchestrator.h
Expand Up @@ -46,6 +46,7 @@ namespace AppInstaller::CLI::Execution
Install,
Upgrade,
Uninstall,
Download,
};

struct OrchestratorQueueItem
Expand Down Expand Up @@ -98,6 +99,8 @@ namespace AppInstaller::CLI::Execution
static std::unique_ptr<OrchestratorQueueItem> CreateItemForUninstall(std::wstring packageId, std::wstring sourceId, std::unique_ptr<COMContext> context);
// Create queue item for finding existing entry from the orchestrator queue
static std::unique_ptr<OrchestratorQueueItem> CreateItemForSearch(std::wstring packageId, std::wstring sourceId, std::unique_ptr<COMContext> context);
// Create queue item for download
static std::unique_ptr<OrchestratorQueueItem> CreateItemForDownload(std::wstring packageId, std::wstring sourceId, std::unique_ptr<COMContext> context);
};

struct ContextOrchestrator
Expand Down