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

Make Install flow aware of package installed status #2539

Merged
merged 20 commits into from
Oct 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/AppInstallerCLICore/Argument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ namespace AppInstaller::CLI
case Args::Type::InstallLocation:
return Argument{ "location"_liv, 'l', Args::Type::InstallLocation, Resource::String::LocationArgumentDescription, ArgumentType::Standard };
case Args::Type::HashOverride:
return Argument{ "force"_liv, NoAlias, Args::Type::HashOverride, Resource::String::InstallForceArgumentDescription, ArgumentType::Flag, Settings::TogglePolicy::Policy::HashOverride };
return Argument{ "ignore-security-hash"_liv, NoAlias, Args::Type::HashOverride, Resource::String::HashOverrideArgumentDescription, ArgumentType::Flag, Settings::TogglePolicy::Policy::HashOverride };
case Args::Type::AcceptPackageAgreements:
return Argument{ "accept-package-agreements"_liv, NoAlias, Args::Type::AcceptPackageAgreements, Resource::String::AcceptPackageAgreementsArgumentDescription, ArgumentType::Flag };
case Args::Type::HashFile:
Expand Down Expand Up @@ -103,6 +103,8 @@ namespace AppInstaller::CLI
return Argument{ "product-code"_liv, NoAlias, Args::Type::ProductCode, Resource::String::ProductCodeArgumentDescription, ArgumentType::Standard, false };
case Args::Type::OpenLogs:
return Argument{ "open-logs"_liv, NoAlias, "logs"_liv, Args::Type::OpenLogs, Resource::String::OpenLogsArgumentDescription, ArgumentType::Flag, ExperimentalFeature::Feature::OpenLogsArgument};
case Args::Type::Force:
return Argument{ "force"_liv, NoAlias, Args::Type::Force, Resource::String::ForceArgumentDescription, ArgumentType::Flag, false };
default:
THROW_HR(E_UNEXPECTED);
}
Expand Down
32 changes: 25 additions & 7 deletions src/AppInstallerCLICore/Commands/InstallCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "InstallCommand.h"
#include "Workflows/CompletionFlow.h"
#include "Workflows/InstallFlow.h"
#include "Workflows/UpdateFlow.h"
#include "Workflows/WorkflowBase.h"
#include "Resources.h"

Expand Down Expand Up @@ -45,6 +46,7 @@ namespace AppInstaller::CLI
Argument::ForType(Args::Type::CustomHeader),
Argument::ForType(Args::Type::AcceptSourceAgreements),
Argument::ForType(Args::Type::Rename),
Argument::ForType(Args::Type::Force),
};
}

Expand Down Expand Up @@ -122,12 +124,28 @@ namespace AppInstaller::CLI
{
context.SetFlags(ContextFlag::ShowSearchResultsOnPartialFailure);

context <<
Workflow::ReportExecutionStage(ExecutionStage::Discovery) <<
Workflow::GetManifest <<
Workflow::SelectInstaller <<
Workflow::EnsureApplicableInstaller <<
Workflow::CheckForUnsupportedArgs <<
Workflow::InstallSinglePackage;
if (context.Args.Contains(Execution::Args::Type::Manifest))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

side note: I've thought that it would be great to collapse the manifest flow into the normal one by making OpenSource create a simple in-memory source for the manifest so that it could behave exactly as everything else.

{
context <<
Workflow::ReportExecutionStage(ExecutionStage::Discovery) <<
Workflow::GetManifestFromArg <<
Workflow::SelectInstaller <<
Workflow::EnsureApplicableInstaller <<
Workflow::InstallSinglePackage;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't install from a manifest behave as an upgrade as well (when appropriate)?

}
else
{
context <<
Workflow::ReportExecutionStage(ExecutionStage::Discovery) <<
Workflow::OpenSource();

if (!context.Args.Contains(Execution::Args::Type::Force))
{
context <<
Workflow::OpenCompositeSource(Repository::PredefinedSource::Installed, false, Repository::CompositeSearchBehavior::AvailablePackages);
}

context << Workflow::InstallOrUpgradeSinglePackage(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also need to be applied to import? More specifically, does import need to be calling InstallOrUpgradeSinglePackage?

}
}
}
2 changes: 1 addition & 1 deletion src/AppInstallerCLICore/Commands/UninstallCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace AppInstaller::CLI
Argument::ForType(Args::Type::Exact),
Argument::ForType(Args::Type::Interactive),
Argument::ForType(Args::Type::Silent),
Argument::ForType(Args::Type::HashOverride), // TODO: Replace with proper name when behavior changes.
Argument::ForType(Args::Type::Force),
Argument::ForType(Args::Type::Purge),
Argument::ForType(Args::Type::Preserve),
Argument::ForType(Args::Type::Log),
Expand Down
26 changes: 2 additions & 24 deletions src/AppInstallerCLICore/Commands/UpgradeCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ namespace AppInstaller::CLI
Argument::ForType(Execution::Args::Type::CustomHeader),
Argument{ "all"_liv, 'r', "recurse"_liv, Args::Type::All, Resource::String::UpdateAllArgumentDescription, ArgumentType::Flag },
Argument{ "include-unknown"_liv, 'u', "unknown"_liv, Args::Type::IncludeUnknown, Resource::String::IncludeUnknownArgumentDescription, ArgumentType::Flag },
Argument::ForType(Args::Type::Force),
};
}

Expand Down Expand Up @@ -246,30 +247,7 @@ namespace AppInstaller::CLI
else
{
// The remaining case: search for single installed package to update
context <<
SearchSourceForSingle <<
HandleSearchResultFailures <<
EnsureOneMatchFromSearchResult(true) <<
GetInstalledPackageVersion;

if (context.Args.Contains(Execution::Args::Type::Version))
{
// If version specified, use the version and verify applicability
context <<
GetManifestFromPackage <<
EnsureUpdateVersionApplicable <<
SelectInstaller <<
EnsureApplicableInstaller;
}
else
{
// iterate through available versions to find latest applicable update
// This step also populates Manifest and Installer in context data
context << SelectLatestApplicableUpdate(true);
}

context <<
InstallSinglePackage;
context << InstallOrUpgradeSinglePackage(true);
}
}
}
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/ExecutionArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ namespace AppInstaller::CLI::Execution
DisableInteractivity, // Disable interactive prompts
Wait, // Prompts the user to press any key before exiting
OpenLogs, // Opens the default logs directory after executing the command
Force, // Forces the execution of the workflow with non security related issues

DependencySource, // Index source to be queried against for finding dependencies
CustomHeader, // Optional Rest source header
Expand Down
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/ExecutionReporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace AppInstaller::CLI::Execution
const Sequence& IdEmphasis = TextFormat::Foreground::BrightCyan;
const Sequence& UrlEmphasis = TextFormat::Foreground::BrightBlue;
const Sequence& PromptEmphasis = TextFormat::Foreground::Bright;
const Sequence& ConvertToUpgradeFlowEmphasis = TextFormat::Foreground::BrightYellow;

Reporter::Reporter(std::ostream& outStream, std::istream& inStream) :
Reporter(std::make_shared<BaseStream>(outStream, true, ConsoleModeRestore::Instance().IsVTEnabled()), inStream)
Expand Down
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/ExecutionReporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,5 @@ namespace AppInstaller::CLI::Execution
extern const VirtualTerminal::Sequence& IdEmphasis;
extern const VirtualTerminal::Sequence& UrlEmphasis;
extern const VirtualTerminal::Sequence& PromptEmphasis;
extern const VirtualTerminal::Sequence& ConvertToUpgradeFlowEmphasis;
}
3 changes: 1 addition & 2 deletions src/AppInstallerCLICore/PortableInstaller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ namespace AppInstaller::CLI::Portable

if (fileType == PortableFileType::File)
{

if (std::filesystem::exists(filePath))
{
SHA256::HashBuffer fileHash = SHA256::ComputeHashFromFile(filePath);
Expand Down Expand Up @@ -296,7 +295,7 @@ namespace AppInstaller::CLI::Portable
else
{
AICLI_LOG(CLI, Info, << "Unable to remove install directory as there are remaining files in: " << InstallLocation);
m_stream << Resource::String::FilesRemainInInstallDirectory << ' ' << InstallLocation << std::endl;
m_stream << Resource::String::FilesRemainInInstallDirectory << ' ' << InstallLocation.u8string() << std::endl;
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/AppInstallerCLICore/Resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace AppInstaller::CLI::Resource
WINGET_DEFINE_RESOURCE_STRINGID(CommandRequiresAdmin);
WINGET_DEFINE_RESOURCE_STRINGID(CompleteCommandLongDescription);
WINGET_DEFINE_RESOURCE_STRINGID(CompleteCommandShortDescription);
WINGET_DEFINE_RESOURCE_STRINGID(ConvertInstallFlowToUpgrade);
WINGET_DEFINE_RESOURCE_STRINGID(CountArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(CountOutOfBoundsError);
WINGET_DEFINE_RESOURCE_STRINGID(DependenciesFlowInstall);
Expand Down Expand Up @@ -92,9 +93,11 @@ namespace AppInstaller::CLI::Resource
WINGET_DEFINE_RESOURCE_STRINGID(FileArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(FilesRemainInInstallDirectory);
WINGET_DEFINE_RESOURCE_STRINGID(FlagContainAdjoinedError);
WINGET_DEFINE_RESOURCE_STRINGID(ForceArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(GetManifestResultVersionNotFound);
WINGET_DEFINE_RESOURCE_STRINGID(HashCommandLongDescription);
WINGET_DEFINE_RESOURCE_STRINGID(HashCommandShortDescription);
WINGET_DEFINE_RESOURCE_STRINGID(HashOverrideArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(HeaderArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(HeaderArgumentNotApplicableForNonRestSourceWarning);
WINGET_DEFINE_RESOURCE_STRINGID(HeaderArgumentNotApplicableWithoutSource);
Expand Down Expand Up @@ -161,7 +164,6 @@ namespace AppInstaller::CLI::Resource
WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeRebootRequiredForInstall);
WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeRebootRequiredToFinish);
WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowStartingPackageInstall);
WINGET_DEFINE_RESOURCE_STRINGID(InstallForceArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(InstallLocationNotProvided);
WINGET_DEFINE_RESOURCE_STRINGID(InstallScopeDescription);
WINGET_DEFINE_RESOURCE_STRINGID(InteractiveArgumentDescription);
Expand Down
3 changes: 1 addition & 2 deletions src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ namespace AppInstaller::CLI::Workflow
}
else
{
// TODO: replace with proper --force argument when available.
if (context.Args.Contains(Execution::Args::Type::HashOverride))
if (context.Args.Contains(Execution::Args::Type::Force))
{
AICLI_LOG(CLI, Warning, << "Archive malware scan failed; proceeding due to --force override");
context.Reporter.Warn() << Resource::String::ArchiveFailedMalwareScanOverridden << std::endl;
Expand Down
4 changes: 2 additions & 2 deletions src/AppInstallerCLICore/Workflows/DependenciesFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,14 @@ namespace AppInstaller::CLI::Workflow
const auto& packageVersion = context.Get<Execution::Data::PackageVersion>();
context.Add<Execution::Data::DependencySource>(packageVersion->GetSource());
context <<
Workflow::OpenCompositeSource(Repository::PredefinedSource::Installed, true);
Workflow::OpenCompositeSource(Repository::PredefinedSource::Installed, true, Repository::CompositeSearchBehavior::AvailablePackages);
}
else
{
// install from manifest requires --dependency-source to be set
context <<
Workflow::OpenSource(true) <<
Workflow::OpenCompositeSource(Repository::PredefinedSource::Installed, true);
Workflow::OpenCompositeSource(Repository::PredefinedSource::Installed, true, Repository::CompositeSearchBehavior::AvailablePackages);
}
}

Expand Down
31 changes: 18 additions & 13 deletions src/AppInstallerCLICore/Workflows/ImportExportFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,23 +279,28 @@ namespace AppInstaller::CLI::Workflow
searchContext.Add<Execution::Data::Source>(source);
searchContext.Add<Execution::Data::SearchResult>(source.Search(searchRequest));

// TODO: In the future, it would be better to not have to convert back and forth from a string
searchContext.Args.AddArg(Execution::Args::Type::InstallScope, ScopeToString(packageRequest.Scope));
if (packageRequest.Scope != Manifest::ScopeEnum::Unknown)
{
// TODO: In the future, it would be better to not have to convert back and forth from a string
searchContext.Args.AddArg(Execution::Args::Type::InstallScope, ScopeToString(packageRequest.Scope));
}

// Find the single version we want is available
searchContext <<
Workflow::HandleSearchResultFailures <<
Workflow::EnsureOneMatchFromSearchResult(false) <<
Workflow::GetManifestWithVersionFromPackage(packageRequest.VersionAndChannel) <<
Workflow::GetInstalledPackageVersion <<
Workflow::SelectInstaller <<
Workflow::EnsureApplicableInstaller;

if (searchContext.Contains(Execution::Data::InstalledPackageVersion) && searchContext.Get<Execution::Data::InstalledPackageVersion>())
auto versionString = packageRequest.VersionAndChannel.GetVersion().ToString();
if (!versionString.empty())
{
searchContext.Args.AddArg(Execution::Args::Type::Version, versionString);
}

auto channelString = packageRequest.VersionAndChannel.GetChannel().ToString();
if (!channelString.empty())
{
searchContext << Workflow::EnsureUpdateVersionApplicable;
searchContext.Args.AddArg(Execution::Args::Type::Channel, channelString);
}

// Find the single version we want is available
searchContext <<
Workflow::SelectSinglePackageVersionForInstallOrUpgrade(false);

if (searchContext.IsTerminated())
{
if (context.IsTerminated() && context.GetTerminationHR() == E_ABORT)
Expand Down
4 changes: 2 additions & 2 deletions src/AppInstallerCLICore/Workflows/InstallFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,15 @@ namespace AppInstaller::CLI::Workflow
AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_NO_APPLICABLE_INSTALLER);
}

context << EnsureSupportForInstall;

// This installer cannot be run elevated, but we are running elevated.
// Implementation of de-elevation is complex; simply block for now.
if (installer->ElevationRequirement == ElevationRequirementEnum::ElevationProhibited && Runtime::IsRunningAsAdmin())
{
context.Reporter.Error() << Resource::String::InstallerProhibitsElevation << std::endl;
AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_INSTALLER_PROHIBITS_ELEVATION);
}

context << EnsureSupportForInstall;
}

void CheckForUnsupportedArgs(Execution::Context& context)
Expand Down
Loading