winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

RootCommand.cpp (13807B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "RootCommand.h"
      5 #include <AppInstallerRuntime.h>
      6 
      7 #include "InstallCommand.h"
      8 #include "ShowCommand.h"
      9 #include "SourceCommand.h"
     10 #include "SearchCommand.h"
     11 #include "ListCommand.h"
     12 #include "UpgradeCommand.h"
     13 #include "UninstallCommand.h"
     14 #include "HashCommand.h"
     15 #include "ValidateCommand.h"
     16 #include "SettingsCommand.h"
     17 #include "FeaturesCommand.h"
     18 #include "FontCommand.h"
     19 #include "ExperimentalCommand.h"
     20 #include "CompleteCommand.h"
     21 #include "ExportCommand.h"
     22 #include "ImportCommand.h"
     23 #include "PinCommand.h"
     24 #include "ConfigureCommand.h"
     25 #include "DebugCommand.h"
     26 #include "TestCommand.h"
     27 #include "DownloadCommand.h"
     28 #include "ErrorCommand.h"
     29 #include "ResumeCommand.h"
     30 #include "RepairCommand.h"
     31 #include "DscCommand.h"
     32 #include "McpCommand.h"
     33 
     34 #include "Resources.h"
     35 #include "TableOutput.h"
     36 
     37 namespace AppInstaller::CLI
     38 {
     39     using namespace AppInstaller::Utility::literals;
     40     using namespace Settings;
     41 
     42     namespace
     43     {
     44         void OutputGroupPolicySourceList(Execution::Context& context, const std::vector<Settings::SourceFromPolicy>& sources, Resource::StringId header)
     45         {
     46             Execution::TableOutput<3> sourcesTable{ context.Reporter, { header, Resource::String::SourceListType, Resource::String::SourceListArg } };
     47             for (const auto& source : sources)
     48             {
     49                 sourcesTable.OutputLine({ source.Name, source.Type, source.Arg });
     50             }
     51 
     52             sourcesTable.Complete();
     53         }
     54 
     55         void OutputGroupPolicies(Execution::Context& context)
     56         {
     57             const auto& groupPolicies = Settings::GroupPolicies();
     58 
     59             // Get the state of policies that are a simple enabled/disabled toggle
     60             std::map<Settings::TogglePolicy::Policy, Settings::PolicyState> activePolicies;
     61             for (const auto& togglePolicy : Settings::TogglePolicy::GetAllPolicies())
     62             {
     63                 auto state = groupPolicies.GetState(togglePolicy.GetPolicy());
     64                 if (state != Settings::PolicyState::NotConfigured)
     65                 {
     66                     activePolicies[togglePolicy.GetPolicy()] = state;
     67                 }
     68             }
     69 
     70             // The source update interval is the only ValuePolicy that is not gated by a TogglePolicy.
     71             // We need to output the table if there is a TogglePolicy configured or if this one is configured.
     72             // We can rework this when more policies are added.
     73             auto sourceAutoUpdateIntervalPolicy = groupPolicies.GetValue<Settings::ValuePolicy::SourceAutoUpdateIntervalInMinutes>();
     74 
     75             if (!activePolicies.empty() || sourceAutoUpdateIntervalPolicy.has_value())
     76             {
     77                 auto info = context.Reporter.Info();
     78                 info << std::endl;
     79 
     80                 Execution::TableOutput<2> policiesTable{ context.Reporter, { Resource::String::PoliciesPolicy, Resource::String::StateHeader } };
     81 
     82                 // Output the toggle policies.
     83                 for (const auto& activePolicy : activePolicies)
     84                 {
     85                     auto policy = Settings::TogglePolicy::GetPolicy(activePolicy.first);
     86                     policiesTable.OutputLine({
     87                         Resource::LocString{ policy.PolicyName() }.get(),
     88                         Resource::LocString{ activePolicy.second == Settings::PolicyState::Enabled ? Resource::String::StateEnabled : Resource::String::StateDisabled }.get() });
     89                 }
     90 
     91                 // Output the update interval in the same table if needed.
     92                 if (sourceAutoUpdateIntervalPolicy.has_value())
     93                 {
     94                     policiesTable.OutputLine({
     95                         Resource::LocString{ AppInstaller::StringResource::String::PolicySourceAutoUpdateInterval },
     96                         std::to_string(sourceAutoUpdateIntervalPolicy.value()) });
     97                 }
     98 
     99                 policiesTable.Complete();
    100 
    101                 // Output the additional and allowed sources as separate tables.
    102                 if (groupPolicies.GetState(Settings::TogglePolicy::Policy::AdditionalSources) == Settings::PolicyState::Enabled)
    103                 {
    104                     info << std::endl;
    105                     auto sources = groupPolicies.GetValueRef<Settings::ValuePolicy::AdditionalSources>();
    106                     if (sources.has_value() && !sources->get().empty())
    107                     {
    108                         OutputGroupPolicySourceList(context, sources->get(), Resource::String::SourceListAdditionalSource);
    109                     }
    110                 }
    111 
    112                 if (groupPolicies.GetState(Settings::TogglePolicy::Policy::AllowedSources) == Settings::PolicyState::Enabled)
    113                 {
    114                     info << std::endl;
    115                     auto sources = groupPolicies.GetValueRef<Settings::ValuePolicy::AllowedSources>();
    116                     if (sources.has_value() && !sources->get().empty())
    117                     {
    118                         OutputGroupPolicySourceList(context, sources->get(), Resource::String::SourceListAllowedSource);
    119                     }
    120                 }
    121                 info << std::endl;
    122             }
    123         }
    124 
    125         void OutputAdminSettings(Execution::Context& context)
    126         {
    127             Execution::TableOutput<2> adminSettingsTable{ context.Reporter, { Resource::String::AdminSettingHeader, Resource::String::StateHeader } };
    128 
    129             // Output the admin settings.
    130             for (const auto& setting : Settings::GetAllBoolAdminSettings())
    131             {
    132                 adminSettingsTable.OutputLine({
    133                     std::string{ AdminSettingToString(setting)},
    134                     Resource::LocString{ IsAdminSettingEnabled(setting) ? Resource::String::StateEnabled : Resource::String::StateDisabled }
    135                 });
    136             }
    137             for (const auto& setting : Settings::GetAllStringAdminSettings())
    138             {
    139                 auto settingValue = GetAdminSetting(setting);
    140                 adminSettingsTable.OutputLine({
    141                     std::string{ AdminSettingToString(setting)},
    142                     settingValue ? Utility::LocIndString{ settingValue.value() } : Resource::LocString{ Resource::String::StateDisabled }
    143                     });
    144             }
    145             adminSettingsTable.Complete();
    146         }
    147 
    148         void OutputKeyDirectories(Execution::Context& context)
    149         {
    150             Execution::TableOutput<2> keyDirectories{ context.Reporter, { Resource::String::KeyDirectoriesHeader, {} } };
    151             keyDirectories.OutputLine({ Resource::LocString{ Resource::String::Logs }, Runtime::GetPathTo(Runtime::PathName::DefaultLogLocation, true).u8string() });
    152             keyDirectories.OutputLine({ Resource::LocString{ Resource::String::UserSettings }, UserSettings::SettingsFilePath(true).u8string() });
    153             keyDirectories.OutputLine({ Resource::LocString{ Resource::String::PortableLinksUser }, Runtime::GetPathTo(Runtime::PathName::PortableLinksUserLocation, true).u8string() });
    154             keyDirectories.OutputLine({ Resource::LocString{ Resource::String::PortableLinksMachine }, Runtime::GetPathTo(Runtime::PathName::PortableLinksMachineLocation, true).u8string() });
    155             keyDirectories.OutputLine({ Resource::LocString{ Resource::String::PortableRootUser }, Runtime::GetPathTo(Runtime::PathName::PortablePackageUserRoot, true).u8string() });
    156             keyDirectories.OutputLine({ Resource::LocString{ Resource::String::PortableRoot }, Runtime::GetPathTo(Runtime::PathName::PortablePackageMachineRoot, true).u8string() });
    157             keyDirectories.OutputLine({ Resource::LocString{ Resource::String::PortableRoot86 }, Runtime::GetPathTo(Runtime::PathName::PortablePackageMachineRootX86, true).u8string() });
    158             keyDirectories.OutputLine({ Resource::LocString{ Resource::String::InstallerDownloads }, Runtime::GetPathTo(Runtime::PathName::UserProfileDownloads, true).u8string() });
    159             keyDirectories.OutputLine({ Resource::LocString{ Resource::String::ConfigurationModules }, Runtime::GetPathTo(Runtime::PathName::ConfigurationModules, true).u8string() });
    160             keyDirectories.Complete();
    161             context.Reporter.Info() << std::endl;
    162         }
    163 
    164         void OutputLinks(Execution::Context& context)
    165         {
    166             Execution::TableOutput<2> links{ context.Reporter, { Resource::String::Links, {} } };
    167             links.OutputLine({ Resource::LocString{ Resource::String::PrivacyStatement }, "https://aka.ms/winget-privacy" });
    168             links.OutputLine({ Resource::LocString{ Resource::String::LicenseAgreement }, "https://aka.ms/winget-license" });
    169             links.OutputLine({ Resource::LocString{ Resource::String::ThirdPartSoftwareNotices }, "https://aka.ms/winget-3rdPartyNotice" });
    170             links.OutputLine({ Resource::LocString{ Resource::String::MainHomepage }, "https://aka.ms/winget" });
    171             links.OutputLine({ Resource::LocString{ Resource::String::WindowsStoreTerms }, "https://www.microsoft.com/en-us/storedocs/terms-of-sale" });
    172             links.Complete();
    173             context.Reporter.Info() << std::endl;
    174         }
    175     }
    176 
    177     std::vector<std::unique_ptr<Command>> RootCommand::GetCommands() const
    178     {
    179         return InitializeFromMoveOnly<std::vector<std::unique_ptr<Command>>>({
    180             std::make_unique<InstallCommand>(FullName()),
    181             std::make_unique<ShowCommand>(FullName()),
    182             std::make_unique<SourceCommand>(FullName()),
    183             std::make_unique<SearchCommand>(FullName()),
    184             std::make_unique<ListCommand>(FullName()),
    185             std::make_unique<UpgradeCommand>(FullName()),
    186             std::make_unique<UninstallCommand>(FullName()),
    187             std::make_unique<HashCommand>(FullName()),
    188             std::make_unique<ValidateCommand>(FullName()),
    189             std::make_unique<SettingsCommand>(FullName()),
    190             std::make_unique<FeaturesCommand>(FullName()),
    191             std::make_unique<ExperimentalCommand>(FullName()),
    192             std::make_unique<CompleteCommand>(FullName()),
    193             std::make_unique<ExportCommand>(FullName()),
    194             std::make_unique<ImportCommand>(FullName()),
    195             std::make_unique<PinCommand>(FullName()),
    196             std::make_unique<ConfigureCommand>(FullName()),
    197             std::make_unique<DownloadCommand>(FullName()),
    198             std::make_unique<ErrorCommand>(FullName()),
    199             std::make_unique<ResumeCommand>(FullName()),
    200             std::make_unique<RepairCommand>(FullName()),
    201             std::make_unique<FontCommand>(FullName()),
    202             std::make_unique<DscCommand>(FullName()),
    203             std::make_unique<McpCommand>(FullName()),
    204 #if _DEBUG
    205             std::make_unique<DebugCommand>(FullName()),
    206 #endif
    207 #ifndef AICLI_DISABLE_TEST_HOOKS
    208             std::make_unique<TestCommand>(FullName()),
    209 #endif
    210         });
    211     }
    212 
    213     std::vector<Argument> RootCommand::GetArguments() const
    214     {
    215         return
    216         {
    217             Argument{ Execution::Args::Type::ToolVersion, Resource::String::ToolVersionArgumentDescription, ArgumentType::Flag, Argument::Visibility::Help },
    218             Argument{ Execution::Args::Type::Info, Resource::String::ToolInfoArgumentDescription, ArgumentType::Flag, Argument::Visibility::Help },
    219         };
    220     }
    221 
    222     Resource::LocString RootCommand::ShortDescription() const
    223     {
    224         return {};
    225     }
    226 
    227     Resource::LocString RootCommand::LongDescription() const
    228     {
    229         return { Resource::String::ToolDescription };
    230     }
    231 
    232     Utility::LocIndView RootCommand::HelpLink() const
    233     {
    234         return "https://aka.ms/winget-command-help"_liv;
    235     }
    236 
    237     void RootCommand::Execute(Execution::Context& context) const
    238     {
    239         AICLI_LOG(CLI, Info, << "Executing command: " << Name());
    240         if (context.Args.Contains(Execution::Args::Type::Help))
    241         {
    242             OutputHelp(context.Reporter);
    243         }
    244         else
    245         {
    246             ExecuteInternal(context);
    247         }
    248 
    249         if (context.Args.Contains(Execution::Args::Type::OpenLogs))
    250         {
    251             ShellExecute(NULL, NULL, Runtime::GetPathTo(Runtime::PathName::DefaultLogLocation).wstring().c_str(), NULL, NULL, SW_SHOWNORMAL);
    252         }
    253 
    254         if (context.Args.Contains(Execution::Args::Type::Wait))
    255         {
    256             context.Reporter.PromptForEnter();
    257         }
    258     }
    259 
    260     void RootCommand::ExecuteInternal(Execution::Context& context) const
    261     {
    262         if (context.Args.Contains(Execution::Args::Type::Info))
    263         {
    264             OutputIntroHeader(context.Reporter);
    265 
    266             auto info = context.Reporter.Info();
    267 
    268             info << std::endl <<
    269                 "Windows: "_liv << Runtime::GetOSVersion() << std::endl;
    270 
    271             info << Resource::String::SystemArchitecture(Utility::ToString(Utility::GetSystemArchitecture())) << std::endl;
    272 
    273             if (Runtime::IsRunningInPackagedContext())
    274             {
    275                 info << Resource::String::Package(Runtime::GetPackageVersion()) << std::endl;
    276             };
    277 
    278             info << std::endl;
    279 
    280             OutputKeyDirectories(context);
    281             OutputLinks(context);
    282             OutputGroupPolicies(context);
    283             OutputAdminSettings(context);
    284         }
    285         else if (context.Args.Contains(Execution::Args::Type::ToolVersion))
    286         {
    287             context.Reporter.Info() << 'v' << Runtime::GetClientVersion() << std::endl;
    288         }
    289         else
    290         {
    291             OutputHelp(context.Reporter);
    292         }
    293     }
    294 }