Skip to content

Commit

Permalink
Add scope support to more commands and add provisioning support for m…
Browse files Browse the repository at this point in the history
…six and msstore types (#2766)
  • Loading branch information
yao-msft authored Dec 16, 2022
1 parent 8a65748 commit 0853f0e
Show file tree
Hide file tree
Showing 52 changed files with 1,246 additions and 572 deletions.
1 change: 0 additions & 1 deletion src/AppInstallerCLI.sln
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Project", "Project", "{8D53D749-D51C-46F8-A162-9371AAA6C2E7}"
ProjectSection(SolutionItems) = preProject
..\azure-pipelines.loc.yml = ..\azure-pipelines.loc.yml
..\azure-pipelines.nuget.in-proc-com.yml = ..\azure-pipelines.nuget.in-proc-com.yml
..\azure-pipelines.nuget.yml = ..\azure-pipelines.nuget.yml
..\azure-pipelines.yml = ..\azure-pipelines.yml
..\cgmanifest.json = ..\cgmanifest.json
Expand Down
4 changes: 4 additions & 0 deletions src/AppInstallerCLICore/Argument.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <winget/ExperimentalFeature.h>
#include <winget/GroupPolicy.h>
#include <winget/AdminSettings.h>
#include <winget/LocIndependent.h>

#include <string>
#include <string_view>
Expand All @@ -21,6 +22,9 @@

namespace AppInstaller::CLI
{
using namespace AppInstaller::Utility::literals;
constexpr Utility::LocIndView s_ArgumentName_Scope = "scope"_liv;

// The type of argument.
enum class ArgumentType
{
Expand Down
9 changes: 9 additions & 0 deletions src/AppInstallerCLICore/Command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,15 @@ namespace AppInstaller::CLI
}
}

if (execArgs.Contains(Execution::Args::Type::InstallScope))
{
if (Manifest::ConvertToScopeEnum(execArgs.GetArg(Execution::Args::Type::InstallScope)) == Manifest::ScopeEnum::Unknown)
{
auto validOptions = Utility::Join(", "_liv, std::vector<Utility::LocIndString>{ "user"_lis, "machine"_lis});
throw CommandException(Resource::String::InvalidArgumentValueError(s_ArgumentName_Scope, validOptions));
}
}

ValidateArgumentsInternal(execArgs);
}

Expand Down
13 changes: 0 additions & 13 deletions src/AppInstallerCLICore/Commands/InstallCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ using namespace AppInstaller::Utility::literals;

namespace AppInstaller::CLI
{
namespace
{
constexpr Utility::LocIndView s_ArgumentName_Scope = "scope"_liv;
}

std::vector<Argument> InstallCommand::GetArguments() const
{
return {
Expand Down Expand Up @@ -113,14 +108,6 @@ namespace AppInstaller::CLI
throw CommandException(Resource::String::BothManifestAndSearchQueryProvided);
}

if (execArgs.Contains(Args::Type::InstallScope))
{
if (ConvertToScopeEnum(execArgs.GetArg(Args::Type::InstallScope)) == Manifest::ScopeEnum::Unknown)
{
auto validOptions = Utility::Join(", "_liv, std::vector<Utility::LocIndString>{ "user"_lis, "machine"_lis});
throw CommandException(Resource::String::InvalidArgumentValueError(s_ArgumentName_Scope, validOptions));
}
}
}

void InstallCommand::ExecuteInternal(Context& context) const
Expand Down
3 changes: 2 additions & 1 deletion src/AppInstallerCLICore/Commands/ListCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace AppInstaller::CLI
Argument::ForType(Execution::Args::Type::Command),
Argument::ForType(Execution::Args::Type::Count),
Argument::ForType(Execution::Args::Type::Exact),
Argument{ s_ArgumentName_Scope, Argument::NoAlias, Execution::Args::Type::InstallScope, Resource::String::InstalledScopeArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help },
Argument::ForType(Execution::Args::Type::CustomHeader),
Argument::ForType(Execution::Args::Type::AcceptSourceAgreements),
};
Expand Down Expand Up @@ -74,7 +75,7 @@ namespace AppInstaller::CLI

context <<
Workflow::OpenSource() <<
Workflow::OpenCompositeSource(Repository::PredefinedSource::Installed) <<
Workflow::OpenCompositeSource(Workflow::DetermineInstalledSource(context)) <<
Workflow::SearchSourceForMany <<
Workflow::HandleSearchResultFailures <<
Workflow::EnsureMatchesFromSearchResult(true) <<
Expand Down
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/Commands/ShowCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace AppInstaller::CLI
Argument::ForType(Execution::Args::Type::Channel),
Argument::ForType(Execution::Args::Type::Source),
Argument::ForType(Execution::Args::Type::Exact),
Argument{ s_ArgumentName_Scope, Argument::NoAlias, Args::Type::InstallScope, Resource::String::InstallScopeDescription, ArgumentType::Standard, Argument::Visibility::Help },
Argument::ForType(Execution::Args::Type::InstallArchitecture),
Argument::ForType(Execution::Args::Type::Locale),
Argument::ForType(Execution::Args::Type::ListVersions),
Expand Down
3 changes: 2 additions & 1 deletion src/AppInstallerCLICore/Commands/UninstallCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace AppInstaller::CLI
Argument::ForType(Args::Type::Channel),
Argument::ForType(Args::Type::Source),
Argument::ForType(Args::Type::Exact),
Argument{ s_ArgumentName_Scope, Argument::NoAlias, Execution::Args::Type::InstallScope, Resource::String::InstalledScopeArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help },
Argument::ForType(Args::Type::Interactive),
Argument::ForType(Args::Type::Silent),
Argument::ForType(Args::Type::Force),
Expand Down Expand Up @@ -118,7 +119,7 @@ namespace AppInstaller::CLI
context <<
Workflow::ReportExecutionStage(ExecutionStage::Discovery) <<
Workflow::OpenSource() <<
Workflow::OpenCompositeSource(Repository::PredefinedSource::Installed);
Workflow::OpenCompositeSource(Workflow::DetermineInstalledSource(context));

// find the uninstaller
if (context.Args.Contains(Execution::Args::Type::Manifest))
Expand Down
3 changes: 2 additions & 1 deletion src/AppInstallerCLICore/Commands/UpgradeCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ namespace AppInstaller::CLI
Argument::ForType(Args::Type::Log), // -o
Argument::ForType(Args::Type::Override),
Argument::ForType(Args::Type::InstallLocation), // -l
Argument{ s_ArgumentName_Scope, Argument::NoAlias, Execution::Args::Type::InstallScope, Resource::String::InstalledScopeArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help },
Argument::ForType(Args::Type::InstallArchitecture), // -a
Argument::ForType(Args::Type::Locale),
Argument::ForType(Args::Type::HashOverride),
Expand Down Expand Up @@ -212,7 +213,7 @@ namespace AppInstaller::CLI
context <<
Workflow::ReportExecutionStage(ExecutionStage::Discovery) <<
Workflow::OpenSource() <<
Workflow::OpenCompositeSource(Repository::PredefinedSource::Installed);
Workflow::OpenCompositeSource(Workflow::DetermineInstalledSource(context));

if (ShouldListUpgrade(context.Args))
{
Expand Down
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/Resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ namespace AppInstaller::CLI::Resource
WINGET_DEFINE_RESOURCE_STRINGID(InstallCommandShortDescription);
WINGET_DEFINE_RESOURCE_STRINGID(InstalledPackageNotAvailable);
WINGET_DEFINE_RESOURCE_STRINGID(InstalledPackageVersionNotAvailable);
WINGET_DEFINE_RESOURCE_STRINGID(InstalledScopeArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(InstallerAbortsTerminal);
WINGET_DEFINE_RESOURCE_STRINGID(InstallerElevationExpected);
WINGET_DEFINE_RESOURCE_STRINGID(InstallerBlockedByPolicy);
Expand Down
28 changes: 26 additions & 2 deletions src/AppInstallerCLICore/Workflows/InstallFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "WorkflowBase.h"
#include "DependenciesFlow.h"
#include "PromptFlow.h"
#include <AppInstallerMsixInfo.h>
#include <AppInstallerDeployment.h>
#include <winget/ARPCorrelation.h>
#include <winget/Archive.h>
Expand Down Expand Up @@ -296,6 +297,21 @@ namespace AppInstaller::CLI::Workflow
}
}

void EnsureRunningAsAdminForMachineScopeInstall(Execution::Context& context)
{
// Admin is required for machine scope install for installer types like portable, msix and msstore.
auto installerType = context.Get<Execution::Data::Installer>().value().EffectiveInstallerType();

if (Manifest::DoesInstallerTypeRequireAdminForMachineScopeInstall(installerType))
{
Manifest::ScopeEnum scope = ConvertToScopeEnum(context.Args.GetArg(Execution::Args::Type::InstallScope));
if (scope == Manifest::ScopeEnum::Machine)
{
context << Workflow::EnsureRunningAsAdmin;
}
}
}

void ExecuteInstaller(Execution::Context& context)
{
context << Workflow::ExecuteInstallerForType(context.Get<Execution::Data::Installer>().value().BaseInstallerType);
Expand Down Expand Up @@ -354,8 +370,15 @@ namespace AppInstaller::CLI::Workflow
try
{
registrationDeferred = context.Reporter.ExecuteWithProgress([&](IProgressCallback& callback)
{
return Deployment::AddPackageWithDeferredFallback(uri, WI_IsFlagSet(context.GetFlags(), Execution::ContextFlag::InstallerTrusted), callback);
{
if (Manifest::ConvertToScopeEnum(context.Args.GetArg(Execution::Args::Type::InstallScope)) == Manifest::ScopeEnum::Machine)
{
return Deployment::AddPackageMachineScope(uri, callback);
}
else
{
return Deployment::AddPackageWithDeferredFallback(uri, WI_IsFlagSet(context.GetFlags(), Execution::ContextFlag::InstallerTrusted), callback);
}
});
}
catch (const wil::ResultException& re)
Expand Down Expand Up @@ -472,6 +495,7 @@ namespace AppInstaller::CLI::Workflow
void EnsureSupportForInstall(Execution::Context& context)
{
context <<
Workflow::EnsureRunningAsAdminForMachineScopeInstall <<
Workflow::EnsureSupportForPortableInstall <<
Workflow::EnsureValidNestedInstallerMetadataForArchiveInstall;
}
Expand Down
6 changes: 6 additions & 0 deletions src/AppInstallerCLICore/Workflows/InstallFlow.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ namespace AppInstaller::CLI::Workflow
// Outputs: None
void CheckForUnsupportedArgs(Execution::Context& context);

// Admin is required for machine scope install for installer types like portable, msix and msstore.
// Required Args: None
// Inputs: Installer
// Outputs: None
void EnsureRunningAsAdminForMachineScopeInstall(Execution::Context& context);

// Composite flow that chooses what to do based on the installer type.
// Required Args: None
// Inputs: Installer, InstallerPath
Expand Down
6 changes: 6 additions & 0 deletions src/AppInstallerCLICore/Workflows/MSStoreInstallerHandler.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include <winget/ManifestCommon.h>
#include "MSStoreInstallerHandler.h"

namespace AppInstaller::CLI::Workflow
Expand Down Expand Up @@ -140,6 +141,11 @@ namespace AppInstaller::CLI::Workflow
installOptions.CompletedInstallToastNotificationMode(AppInstallationToastNotificationMode::NoToast);
}

if (Manifest::ConvertToScopeEnum(context.Args.GetArg(Execution::Args::Type::InstallScope)) == Manifest::ScopeEnum::Machine)
{
installOptions.InstallForAllUsers(true);
}

IVectorView<AppInstallItem> installItems = installManager.StartProductInstallAsync(
productId, // ProductId
winrt::hstring(), // FlightId
Expand Down
25 changes: 0 additions & 25 deletions src/AppInstallerCLICore/Workflows/PortableFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,6 @@ namespace AppInstaller::CLI::Workflow
AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_PORTABLE_REPARSE_POINT_NOT_SUPPORTED);
}
}

void EnsureRunningAsAdminForMachineScopeInstall(Execution::Context& context)
{
// Admin is required for machine scope install or else creating a symlink in the %PROGRAMFILES% link location will fail.
Manifest::ScopeEnum scope = ConvertToScopeEnum(context.Args.GetArg(Execution::Args::Type::InstallScope));
if (scope == Manifest::ScopeEnum::Machine)
{
context << Workflow::EnsureRunningAsAdmin;
}
}
}

void VerifyPackageAndSourceMatch(Execution::Context& context)
Expand Down Expand Up @@ -334,23 +324,8 @@ namespace AppInstaller::CLI::Workflow
if (installerType == InstallerTypeEnum::Portable)
{
context <<
EnsureRunningAsAdminForMachineScopeInstall <<
EnsureValidArgsForPortableInstall <<
EnsureVolumeSupportsReparsePoints;
}
}

void EnsureSupportForPortableUninstall(Execution::Context& context)
{
auto installedPackageVersion = context.Get<Execution::Data::InstalledPackageVersion>();
const std::string installedTypeString = installedPackageVersion->GetMetadata()[PackageVersionMetadata::InstalledType];
if (ConvertToInstallerTypeEnum(installedTypeString) == InstallerTypeEnum::Portable)
{
const std::string installedScope = installedPackageVersion->GetMetadata()[Repository::PackageVersionMetadata::InstalledScope];
if (ConvertToScopeEnum(installedScope) == Manifest::ScopeEnum::Machine)
{
context << EnsureRunningAsAdmin;
}
}
}
}
6 changes: 0 additions & 6 deletions src/AppInstallerCLICore/Workflows/PortableFlow.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ namespace AppInstaller::CLI::Workflow
// Outputs: None
void EnsureSupportForPortableInstall(Execution::Context& context);

// Verifies that the portable uninstall operation is supported.
// Required Args: None
// Inputs: Scope
// Outputs: None
void EnsureSupportForPortableUninstall(Execution::Context& context);

// Initializes the portable installer.
// Required Args: None
// Inputs: Scope, Architecture, Manifest, Installer
Expand Down
33 changes: 31 additions & 2 deletions src/AppInstallerCLICore/Workflows/UninstallFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ namespace AppInstaller::CLI::Workflow
{
context <<
Workflow::GetInstalledPackageVersion <<
Workflow::EnsureSupportForPortableUninstall <<
Workflow::EnsureSupportForUninstall <<
Workflow::GetUninstallInfo <<
Workflow::GetDependenciesInfoForUninstall <<
Workflow::ReportDependencies(Resource::String::UninstallCommandReportDependencies) <<
Expand Down Expand Up @@ -203,7 +203,14 @@ namespace AppInstaller::CLI::Workflow
AICLI_LOG(CLI, Info, << "Removing MSIX package: " << packageFullName.value());
try
{
context.Reporter.ExecuteWithProgress(std::bind(Deployment::RemovePackage, packageFullName.value(), std::placeholders::_1));
if (Manifest::ConvertToScopeEnum(context.Args.GetArg(Execution::Args::Type::InstallScope)) == Manifest::ScopeEnum::Machine)
{
context.Reporter.ExecuteWithProgress(std::bind(Deployment::RemovePackageMachineScope, packageFamilyName, packageFullName.value(), std::placeholders::_1));
}
else
{
context.Reporter.ExecuteWithProgress(std::bind(Deployment::RemovePackage, packageFullName.value(), winrt::Windows::Management::Deployment::RemovalOptions::None, std::placeholders::_1));
}
}
catch (const wil::ResultException& re)
{
Expand Down Expand Up @@ -278,4 +285,26 @@ namespace AppInstaller::CLI::Workflow
context.Reporter.Info() << Resource::String::UninstallFlowUninstallSuccess << std::endl;
}
}

void EnsureSupportForUninstall(Execution::Context& context)
{
auto installedPackageVersion = context.Get<Execution::Data::InstalledPackageVersion>();
const std::string installedTypeString = installedPackageVersion->GetMetadata()[PackageVersionMetadata::InstalledType];
auto installedType = ConvertToInstallerTypeEnum(installedTypeString);
if (installedType == InstallerTypeEnum::Portable)
{
const std::string installedScope = installedPackageVersion->GetMetadata()[Repository::PackageVersionMetadata::InstalledScope];
if (Manifest::ConvertToScopeEnum(installedScope) == Manifest::ScopeEnum::Machine)
{
context << EnsureRunningAsAdmin;
}
}
else if (installedType == InstallerTypeEnum::Msix)
{
if (Manifest::ConvertToScopeEnum(context.Args.GetArg(Execution::Args::Type::InstallScope)) == Manifest::ScopeEnum::Machine)
{
context << EnsureRunningAsAdmin;
}
}
}
}
6 changes: 6 additions & 0 deletions src/AppInstallerCLICore/Workflows/UninstallFlow.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,10 @@ namespace AppInstaller::CLI::Workflow
// Whether the Uninstaller result is an HRESULT. This guides how we show it.
bool m_isHResult;
};

// Verifies that the uninstall operation is supported.
// Required Args: None
// Inputs: InstalledPackageVersion
// Outputs: None
void EnsureSupportForUninstall(Execution::Context& context);
}
16 changes: 16 additions & 0 deletions src/AppInstallerCLICore/Workflows/WorkflowBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,22 @@ namespace AppInstaller::CLI::Workflow
m_func(context);
}

Repository::PredefinedSource DetermineInstalledSource(const Execution::Context& context)
{
Repository::PredefinedSource installedSource = Repository::PredefinedSource::Installed;
Manifest::ScopeEnum scope = Manifest::ConvertToScopeEnum(context.Args.GetArg(Execution::Args::Type::InstallScope));
if (scope == Manifest::ScopeEnum::Machine)
{
installedSource = Repository::PredefinedSource::InstalledMachine;
}
else if (scope == Manifest::ScopeEnum::User)
{
installedSource = Repository::PredefinedSource::InstalledUser;
}

return installedSource;
}

HRESULT HandleException(Execution::Context& context, std::exception_ptr exception)
{
try
Expand Down
3 changes: 3 additions & 0 deletions src/AppInstallerCLICore/Workflows/WorkflowBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ namespace AppInstaller::CLI::Workflow
std::string m_name;
};

// Helper to determine installed source to use based on context input.
Repository::PredefinedSource DetermineInstalledSource(const Execution::Context& context);

// Helper to report exceptions and return the HRESULT.
HRESULT HandleException(Execution::Context& context, std::exception_ptr exception);

Expand Down
Loading

0 comments on commit 0853f0e

Please sign in to comment.