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 }