UserSettings.h (13599B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include "AppInstallerStrings.h" 5 #include "AppInstallerLogging.h" 6 #include "winget/Archive.h" 7 #include "winget/GroupPolicy.h" 8 #include "winget/Resources.h" 9 #include "winget/ManifestCommon.h" 10 11 #include <filesystem> 12 #include <map> 13 #include <optional> 14 #include <string> 15 #include <type_traits> 16 #include <variant> 17 #include <vector> 18 19 #include "AppInstallerArchitecture.h" 20 21 using namespace std::chrono_literals; 22 using namespace std::string_view_literals; 23 24 namespace AppInstaller::Settings 25 { 26 // The type of argument. 27 enum class UserSettingsType 28 { 29 // Settings files don't exist. A file is created on the first call to the settings command. 30 Default, 31 // Loaded settings.json 32 Standard, 33 // Loaded settings.json.backup 34 Backup, 35 // Loaded from custom settings content 36 Custom, 37 }; 38 39 // The visual style of the progress bar. 40 enum class VisualStyle 41 { 42 NoVT, 43 Retro, 44 Accent, 45 Rainbow, 46 Sixel, 47 Disabled, 48 }; 49 50 // The download code to use for *installers*. 51 enum class InstallerDownloader 52 { 53 Default, 54 WinInet, 55 DeliveryOptimization, 56 }; 57 58 // Enum of settings. 59 // Must start at 0 to enable direct access to variant in UserSettings. 60 // Max must be last and unused. 61 // How to add a setting 62 // 1 - Add to enum. 63 // 2 - Implement SettingMap specialization via SETTINGMAPPING_SPECIALIZATION 64 // Validate will be called by ValidateAll without any more changes. 65 enum class Setting : size_t 66 { 67 // Visual 68 ProgressBarVisualStyle, 69 AnonymizePathForDisplay, 70 EnableSixelDisplay, 71 // Source 72 AutoUpdateTimeInMinutes, 73 // Experimental 74 EFExperimentalCmd, 75 EFExperimentalArg, 76 EFDirectMSI, 77 EFResume, 78 EFFonts, 79 // Telemetry 80 TelemetryDisable, 81 // Install behavior 82 InstallScopePreference, 83 InstallScopeRequirement, 84 InstallArchitecturePreference, 85 InstallArchitectureRequirement, 86 InstallLocalePreference, 87 InstallLocaleRequirement, 88 InstallerTypePreference, 89 InstallerTypeRequirement, 90 InstallDefaultRoot, 91 InstallSkipDependencies, 92 ArchiveExtractionMethod, 93 DisableInstallNotes, 94 PortablePackageUserRoot, 95 PortablePackageMachineRoot, 96 MaxResumes, 97 // Network 98 NetworkDownloader, 99 NetworkDOProgressTimeoutInSeconds, 100 NetworkWingetAlternateSourceURL, 101 // Logging 102 LoggingLevelPreference, 103 LoggingChannelPreference, 104 // Uninstall behavior 105 UninstallPurgePortablePackage, 106 // Download behavior 107 DownloadDefaultDirectory, 108 // Configure behavior 109 ConfigureDefaultModuleRoot, 110 // Interactivity 111 InteractivityDisable, 112 #ifndef AICLI_DISABLE_TEST_HOOKS 113 // Debug 114 EnableSelfInitiatedMinidump, 115 KeepAllLogFiles, 116 #endif 117 Max 118 }; 119 120 namespace details 121 { 122 template <Setting S> 123 struct SettingMapping 124 { 125 // json_t - type the setting in json. 126 // value_t - the type of this setting. 127 // DefaultValue - the value_t default value when setting is absent or semantically wrong. 128 // Path - json path to the property. See Json::Path in json.h for syntax. So far, this is sufficient 129 // but since is "brief" and "untested" we might implement our own if needed. 130 // Validate - Function that does semantic validation. 131 }; 132 133 #define SETTINGMAPPING_SPECIALIZATION_POLICY(_setting_, _json_, _value_, _default_, _path_, _valuePolicy_) \ 134 template <> \ 135 struct SettingMapping<_setting_> \ 136 { \ 137 using json_t = _json_; \ 138 using value_t = _value_; \ 139 inline static const value_t DefaultValue = _default_; \ 140 static constexpr std::string_view Path = _path_; \ 141 static std::optional<value_t> Validate(const json_t& value); \ 142 static constexpr ValuePolicy Policy = _valuePolicy_; \ 143 using policy_t = GroupPolicy::ValueType<Policy>; \ 144 static_assert(Policy == ValuePolicy::None || std::is_same<json_t, policy_t>::value); \ 145 } 146 147 #define SETTINGMAPPING_SPECIALIZATION(_setting_, _json_, _value_, _default_, _path_) \ 148 SETTINGMAPPING_SPECIALIZATION_POLICY(_setting_, _json_, _value_, _default_, _path_, ValuePolicy::None) 149 150 // Visual 151 SETTINGMAPPING_SPECIALIZATION(Setting::ProgressBarVisualStyle, std::string, VisualStyle, VisualStyle::Accent, ".visual.progressBar"sv); 152 SETTINGMAPPING_SPECIALIZATION(Setting::AnonymizePathForDisplay, bool, bool, true, ".visual.anonymizeDisplayedPaths"sv); 153 SETTINGMAPPING_SPECIALIZATION(Setting::EnableSixelDisplay, bool, bool, false, ".visual.enableSixels"sv); 154 // Source 155 SETTINGMAPPING_SPECIALIZATION_POLICY(Setting::AutoUpdateTimeInMinutes, uint32_t, std::chrono::minutes, 15min, ".source.autoUpdateIntervalInMinutes"sv, ValuePolicy::SourceAutoUpdateIntervalInMinutes); 156 // Experimental 157 SETTINGMAPPING_SPECIALIZATION(Setting::EFExperimentalCmd, bool, bool, false, ".experimentalFeatures.experimentalCmd"sv); 158 SETTINGMAPPING_SPECIALIZATION(Setting::EFExperimentalArg, bool, bool, false, ".experimentalFeatures.experimentalArg"sv); 159 SETTINGMAPPING_SPECIALIZATION(Setting::EFDirectMSI, bool, bool, false, ".experimentalFeatures.directMSI"sv); 160 SETTINGMAPPING_SPECIALIZATION(Setting::EFResume, bool, bool, false, ".experimentalFeatures.resume"sv); 161 SETTINGMAPPING_SPECIALIZATION(Setting::EFFonts, bool, bool, false, ".experimentalFeatures.fonts"sv); 162 // Telemetry 163 SETTINGMAPPING_SPECIALIZATION(Setting::TelemetryDisable, bool, bool, false, ".telemetry.disable"sv); 164 // Install behavior 165 SETTINGMAPPING_SPECIALIZATION(Setting::InstallArchitecturePreference, std::vector<std::string>, std::vector<Utility::Architecture>, {}, ".installBehavior.preferences.architectures"sv); 166 SETTINGMAPPING_SPECIALIZATION(Setting::InstallArchitectureRequirement, std::vector<std::string>, std::vector<Utility::Architecture>, {}, ".installBehavior.requirements.architectures"sv); 167 SETTINGMAPPING_SPECIALIZATION(Setting::InstallScopePreference, std::string, Manifest::ScopeEnum, Manifest::ScopeEnum::User, ".installBehavior.preferences.scope"sv); 168 SETTINGMAPPING_SPECIALIZATION(Setting::InstallScopeRequirement, std::string, Manifest::ScopeEnum, Manifest::ScopeEnum::Unknown, ".installBehavior.requirements.scope"sv); 169 SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocalePreference, std::vector<std::string>, std::vector<std::string>, {}, ".installBehavior.preferences.locale"sv); 170 SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocaleRequirement, std::vector<std::string>, std::vector<std::string>, {}, ".installBehavior.requirements.locale"sv); 171 SETTINGMAPPING_SPECIALIZATION(Setting::InstallerTypePreference, std::vector<std::string>, std::vector<Manifest::InstallerTypeEnum>, {}, ".installBehavior.preferences.installerTypes"sv); 172 SETTINGMAPPING_SPECIALIZATION(Setting::InstallerTypeRequirement, std::vector<std::string>, std::vector<Manifest::InstallerTypeEnum>, {}, ".installBehavior.requirements.installerTypes"sv); 173 SETTINGMAPPING_SPECIALIZATION(Setting::InstallSkipDependencies, bool, bool, false, ".installBehavior.skipDependencies"sv); 174 SETTINGMAPPING_SPECIALIZATION(Setting::ArchiveExtractionMethod, std::string, Archive::ExtractionMethod, Archive::ExtractionMethod::ShellApi, ".installBehavior.archiveExtractionMethod"sv); 175 SETTINGMAPPING_SPECIALIZATION(Setting::DisableInstallNotes, bool, bool, false, ".installBehavior.disableInstallNotes"sv); 176 SETTINGMAPPING_SPECIALIZATION(Setting::PortablePackageUserRoot, std::string, std::filesystem::path, {}, ".installBehavior.portablePackageUserRoot"sv); 177 SETTINGMAPPING_SPECIALIZATION(Setting::PortablePackageMachineRoot, std::string, std::filesystem::path, {}, ".installBehavior.portablePackageMachineRoot"sv); 178 SETTINGMAPPING_SPECIALIZATION(Setting::InstallDefaultRoot, std::string, std::filesystem::path, {}, ".installBehavior.defaultInstallRoot"sv); 179 SETTINGMAPPING_SPECIALIZATION(Setting::MaxResumes, uint32_t, int, 3, ".installBehavior.maxResumes"sv); 180 // Uninstall behavior 181 SETTINGMAPPING_SPECIALIZATION(Setting::UninstallPurgePortablePackage, bool, bool, false, ".uninstallBehavior.purgePortablePackage"sv); 182 // Download behavior 183 SETTINGMAPPING_SPECIALIZATION(Setting::DownloadDefaultDirectory, std::string, std::filesystem::path, {}, ".downloadBehavior.defaultDownloadDirectory"sv); 184 // Configure behavior 185 SETTINGMAPPING_SPECIALIZATION(Setting::ConfigureDefaultModuleRoot, std::string, std::filesystem::path, {}, ".configureBehavior.defaultModuleRoot"sv); 186 187 // Network 188 SETTINGMAPPING_SPECIALIZATION(Setting::NetworkDownloader, std::string, InstallerDownloader, InstallerDownloader::Default, ".network.downloader"sv); 189 SETTINGMAPPING_SPECIALIZATION(Setting::NetworkDOProgressTimeoutInSeconds, uint32_t, std::chrono::seconds, 60s, ".network.doProgressTimeoutInSeconds"sv); 190 SETTINGMAPPING_SPECIALIZATION(Setting::NetworkWingetAlternateSourceURL, bool, bool, true, ".network.enableWingetAlternateSourceURL"sv); 191 #ifndef AICLI_DISABLE_TEST_HOOKS 192 // Debug 193 SETTINGMAPPING_SPECIALIZATION(Setting::EnableSelfInitiatedMinidump, bool, bool, false, ".debugging.enableSelfInitiatedMinidump"sv); 194 SETTINGMAPPING_SPECIALIZATION(Setting::KeepAllLogFiles, bool, bool, false, ".debugging.keepAllLogFiles"sv); 195 #endif 196 // Logging 197 SETTINGMAPPING_SPECIALIZATION(Setting::LoggingLevelPreference, std::string, Logging::Level, Logging::Level::Info, ".logging.level"sv); 198 SETTINGMAPPING_SPECIALIZATION(Setting::LoggingChannelPreference, std::vector<std::string>, Logging::Channel, Logging::Channel::Defaults, ".logging.channels"sv); 199 // Interactivity 200 SETTINGMAPPING_SPECIALIZATION(Setting::InteractivityDisable, bool, bool, false, ".interactivity.disable"sv); 201 202 // Used to deduce the SettingVariant type; making a variant that includes std::monostate and all SettingMapping types. 203 template <size_t... I> 204 inline auto Deduce(std::index_sequence<I...>) { return std::variant<std::monostate, typename SettingMapping<static_cast<Setting>(I)>::value_t...>{}; } 205 206 // Holds data of any type listed in a SettingMapping. 207 using SettingVariant = decltype(Deduce(std::make_index_sequence<static_cast<size_t>(Setting::Max)>())); 208 209 // Gets the index into the variant for the given Setting. 210 constexpr inline size_t SettingIndex(Setting s) { return static_cast<size_t>(s) + 1; } 211 } 212 213 // Representation of the parsed settings file. 214 struct UserSettings 215 { 216 // Jsoncpp doesn't provide line number and column for an individual Json::Value node. 217 struct Warning 218 { 219 Warning(StringResource::StringId message) : Message(message) {} 220 Warning(StringResource::StringId message, std::string_view settingPath) : Message(message), Path(settingPath) {} 221 Warning(StringResource::StringId message, std::string_view settingPath, std::string_view settingValue, bool isField = true) : 222 Message(message), Path(settingPath), Data(settingValue), IsFieldWarning(isField) {} 223 224 StringResource::StringId Message; 225 Utility::LocIndString Path; 226 Utility::LocIndString Data; 227 bool IsFieldWarning = true; 228 }; 229 230 static UserSettings const& Instance(const std::optional<std::string>& content = std::nullopt); 231 232 static std::filesystem::path SettingsFilePath(bool forDisplay = false); 233 234 UserSettings(const UserSettings&) = delete; 235 UserSettings& operator=(const UserSettings&) = delete; 236 237 UserSettings(UserSettings&&) = delete; 238 UserSettings& operator=(UserSettings&&) = delete; 239 240 UserSettingsType GetType() const { return m_type; } 241 std::vector<Warning> const& GetWarnings() const { return m_warnings; } 242 243 void PrepareToShellExecuteFile() const; 244 245 // Gets setting value, if its not in the map it returns the default value. 246 template <Setting S> 247 typename details::SettingMapping<S>::value_t Get() const 248 { 249 auto itr = m_settings.find(S); 250 if (itr == m_settings.end()) 251 { 252 return details::SettingMapping<S>::DefaultValue; 253 } 254 255 return std::get<details::SettingIndex(S)>(itr->second); 256 } 257 258 protected: 259 UserSettingsType m_type = UserSettingsType::Default; 260 std::vector<Warning> m_warnings; 261 std::map<Setting, details::SettingVariant> m_settings; 262 263 UserSettings(const std::optional<std::string>& content = std::nullopt); 264 ~UserSettings() = default; 265 }; 266 267 const UserSettings* TryGetUser(); 268 UserSettings const& User(); 269 bool TryInitializeCustomUserSettings(std::string content); 270 }