ManifestYamlPopulator.cpp (77427B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "AppInstallerSHA256.h" 5 #include "winget/ManifestYamlPopulator.h" 6 7 namespace AppInstaller::Manifest 8 { 9 using ValidationErrors = std::vector<ValidationError>; 10 using ExpectedReturnCodeInfo = AppInstaller::Manifest::ManifestInstaller::ExpectedReturnCodeInfo; 11 12 namespace 13 { 14 template <typename Ptr> 15 Ptr* variant_ptr(const VariantManifestPtr& v) { return std::get<Ptr*>(v); } 16 17 ManifestInstaller* GetManifestInstallerPtrFromManifest(const VariantManifestPtr& v) { return &(variant_ptr<Manifest>(v)->DefaultInstallerInfo); } 18 19 ManifestLocalization* GetManifestLocalizationPtrFromManifest(const VariantManifestPtr& v) { return &(variant_ptr<Manifest>(v)->DefaultLocalization); } 20 21 ManifestInstaller* GetManifestInstallerPtr(const VariantManifestPtr& v) 22 { 23 if (auto installer = std::get_if<ManifestInstaller*>(&v)) 24 { 25 return *installer; 26 } 27 28 return GetManifestInstallerPtrFromManifest(v); 29 } 30 31 ManifestLocalization* GetManifestLocalizationPtr(const VariantManifestPtr& v) 32 { 33 if (auto localization = std::get_if<ManifestLocalization*>(&v)) 34 { 35 return *localization; 36 } 37 38 return GetManifestLocalizationPtrFromManifest(v); 39 } 40 41 // Only used in preview manifest 42 std::vector<Manifest::string_t> SplitMultiValueField(const std::string& input) 43 { 44 if (input.empty()) 45 { 46 return {}; 47 } 48 49 std::vector<Manifest::string_t> result; 50 size_t currentPos = 0; 51 while (currentPos < input.size()) 52 { 53 size_t splitPos = input.find(',', currentPos); 54 if (splitPos == std::string::npos) 55 { 56 splitPos = input.size(); 57 } 58 59 std::string splitVal = input.substr(currentPos, splitPos - currentPos); 60 Utility::Trim(splitVal); 61 if (!splitVal.empty()) 62 { 63 result.emplace_back(std::move(splitVal)); 64 } 65 currentPos = splitPos + 1; 66 } 67 68 return result; 69 } 70 71 std::vector<Manifest::string_t> ProcessStringSequenceNode(const YAML::Node& node, bool trim = true) 72 { 73 THROW_HR_IF(E_INVALIDARG, !node.IsSequence()); 74 75 std::vector<Manifest::string_t> result; 76 77 for (auto const& entry : node.Sequence()) 78 { 79 std::string value = entry.as<std::string>(); 80 if (trim) 81 { 82 Utility::Trim(value); 83 } 84 85 result.emplace_back(std::move(value)); 86 } 87 88 return result; 89 } 90 91 std::vector<DWORD> ProcessInstallerSuccessCodeSequenceNode(const YAML::Node& node) 92 { 93 THROW_HR_IF(E_INVALIDARG, !node.IsSequence()); 94 95 std::vector<DWORD> result; 96 97 for (auto const& entry : node.Sequence()) 98 { 99 result.emplace_back(static_cast<DWORD>(entry.as<int>())); 100 } 101 102 return result; 103 } 104 105 std::vector<PlatformEnum> ProcessPlatformSequenceNode(const YAML::Node& node) 106 { 107 THROW_HR_IF(E_INVALIDARG, !node.IsSequence()); 108 109 std::vector<PlatformEnum> result; 110 111 for (auto const& entry : node.Sequence()) 112 { 113 result.emplace_back(ConvertToPlatformEnum(entry.as<std::string>())); 114 } 115 116 return result; 117 } 118 119 std::vector<InstallModeEnum> ProcessInstallModeSequenceNode(const YAML::Node& node) 120 { 121 THROW_HR_IF(E_INVALIDARG, !node.IsSequence()); 122 123 std::vector<InstallModeEnum> result; 124 125 for (auto const& entry : node.Sequence()) 126 { 127 result.emplace_back(ConvertToInstallModeEnum(entry.as<std::string>())); 128 } 129 130 return result; 131 } 132 133 std::vector<AppInstaller::Utility::Architecture> ProcessArchitectureSequenceNode(const YAML::Node& node) 134 { 135 THROW_HR_IF(E_INVALIDARG, !node.IsSequence()); 136 137 std::vector<AppInstaller::Utility::Architecture> result; 138 139 for (auto const& entry : node.Sequence()) 140 { 141 result.emplace_back(Utility::ConvertToArchitectureEnum(entry.as<std::string>())); 142 } 143 144 return result; 145 } 146 147 std::vector<UnsupportedArgumentEnum> ProcessUnsupportedArgumentsSequenceNode(const YAML::Node& node) 148 { 149 THROW_HR_IF(E_INVALIDARG, !node.IsSequence()); 150 151 std::vector<UnsupportedArgumentEnum> result; 152 153 for (auto const& entry : node.Sequence()) 154 { 155 result.emplace_back(ConvertToUnsupportedArgumentEnum(entry.as<std::string>())); 156 } 157 158 return result; 159 } 160 161 void ProcessDependenciesNode(DependencyType type, const YAML::Node& node, DependencyList* dependencyList) 162 { 163 const auto& ids = ProcessStringSequenceNode(node); 164 for (auto id : ids) 165 { 166 dependencyList->Add(Dependency(type, id)); 167 } 168 } 169 } 170 171 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetRootFieldProcessInfo() 172 { 173 // Common fields across versions 174 std::vector<FieldProcessInfo> result = 175 { 176 { "ManifestVersion", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { /* ManifestVersion already populated. Field listed here for duplicate and PascalCase check */ return {}; } }, 177 { "Installers", [this](const YAML::Node& value, const VariantManifestPtr&)->ValidationErrors { m_p_installersNode = &value; return {}; } }, 178 { "Localization", [this](const YAML::Node& value, const VariantManifestPtr&)->ValidationErrors { m_p_localizationsNode = &value; return {}; } }, 179 { "Channel", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Channel = Utility::Trim(value.as<std::string>()); return {}; } }, 180 }; 181 182 // Additional version specific fields 183 if (m_manifestVersion.get().Major() == 0) 184 { 185 std::vector<FieldProcessInfo> previewRootFields 186 { 187 { "Id", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Id = Utility::Trim(value.as<std::string>()); return {}; } }, 188 { "Version", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Version = Utility::Trim(value.as<std::string>()); return {}; } }, 189 { "AppMoniker", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Moniker = Utility::Trim(value.as<std::string>()); return {}; } }, 190 }; 191 192 193 std::move(previewRootFields.begin(), previewRootFields.end(), std::inserter(result, result.end())); 194 } 195 else if (m_manifestVersion.get().Major() == 1) 196 { 197 // Starting v1, we should be only adding new fields for each minor version increase 198 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1 }) 199 { 200 std::vector<FieldProcessInfo> v1RootFields 201 { 202 { "PackageIdentifier", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Id = Utility::Trim(value.as<std::string>()); return {}; } }, 203 { "PackageVersion", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Version = Utility::Trim(value.as<std::string>()); return {}; } }, 204 { "Moniker", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Moniker = Utility::Trim(value.as<std::string>()); return {}; } }, 205 { "ManifestType", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { /* ManifestType already checked. Field listed here for duplicate and PascalCase check */ return {}; } }, 206 }; 207 208 std::move(v1RootFields.begin(), v1RootFields.end(), std::inserter(result, result.end())); 209 } 210 } 211 212 // Root fields mapped as Installer and Localization values 213 auto rootInstallerFields = GetInstallerFieldProcessInfo(true); 214 std::move(rootInstallerFields.begin(), rootInstallerFields.end(), std::inserter(result, result.end())); 215 216 auto rootLocalizationFields = GetLocalizationFieldProcessInfo(true); 217 std::move(rootLocalizationFields.begin(), rootLocalizationFields.end(), std::inserter(result, result.end())); 218 219 return result; 220 } 221 222 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetInstallerFieldProcessInfo(bool forRootFields) 223 { 224 // Common fields across versions 225 std::vector<FieldProcessInfo> result = 226 { 227 { "InstallerType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->BaseInstallerType = ConvertToInstallerTypeEnum(value.as<std::string>()); return {}; } }, 228 { "PackageFamilyName", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->PackageFamilyName = value.as<std::string>(); return {}; } }, 229 { "ProductCode", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->ProductCode = value.as<std::string>(); return {}; } }, 230 }; 231 232 // Additional version specific fields 233 if (m_manifestVersion.get().Major() == 0) 234 { 235 // Root level and Localization node level 236 std::vector<FieldProcessInfo> previewCommonFields = 237 { 238 { "UpdateBehavior", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->UpdateBehavior = ConvertToUpdateBehaviorEnum(value.as<std::string>()); return {}; } }, 239 { "Switches", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ValidateAndProcessFields(value, SwitchesFieldInfos, VariantManifestPtr(&(GetManifestInstallerPtr(v)->Switches))); }}, 240 }; 241 242 std::move(previewCommonFields.begin(), previewCommonFields.end(), std::inserter(result, result.end())); 243 244 if (!forRootFields) 245 { 246 // Installer node only 247 std::vector<FieldProcessInfo> installerOnlyFields = 248 { 249 { "Arch", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Arch = Utility::ConvertToArchitectureEnum(value.as<std::string>()); return {}; } }, 250 { "Url", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Url = value.as<std::string>(); return {}; } }, 251 { "Sha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Sha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } }, 252 { "SignatureSha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->SignatureSha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } }, 253 { "Language", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Locale = value.as<std::string>(); return {}; } }, 254 { "Scope", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Scope = ConvertToScopeEnum(value.as<std::string>()); return {}; } }, 255 }; 256 257 if (m_manifestVersion.get().HasExtension(s_MSStoreExtension)) 258 { 259 installerOnlyFields.emplace_back("ProductId", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->ProductId = value.as<std::string>(); return {}; }); 260 } 261 262 std::move(installerOnlyFields.begin(), installerOnlyFields.end(), std::inserter(result, result.end())); 263 } 264 else 265 { 266 // Root node only 267 std::vector<FieldProcessInfo> rootOnlyFields = 268 { 269 { "MinOSVersion", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtrFromManifest(v)->MinOSVersion = value.as<std::string>(); return {}; } }, 270 { "Commands", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtrFromManifest(v)->Commands = SplitMultiValueField(value.as<std::string>()); return {}; } }, 271 { "Protocols", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtrFromManifest(v)->Protocols = SplitMultiValueField(value.as<std::string>()); return {}; } }, 272 { "FileExtensions", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtrFromManifest(v)->FileExtensions = SplitMultiValueField(value.as<std::string>()); return {}; } }, 273 }; 274 275 std::move(rootOnlyFields.begin(), rootOnlyFields.end(), std::inserter(result, result.end())); 276 } 277 } 278 else if (m_manifestVersion.get().Major() == 1) 279 { 280 // Starting v1, we should be only adding new fields for each minor version increase 281 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1 }) 282 { 283 // Root level and Installer node level 284 std::vector<FieldProcessInfo> v1CommonFields = 285 { 286 { "InstallerLocale", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Locale = value.as<std::string>(); return {}; } }, 287 { "Platform", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Platform = ProcessPlatformSequenceNode(value); return {}; } }, 288 { "MinimumOSVersion", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->MinOSVersion = value.as<std::string>(); return {}; } }, 289 { "Scope", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Scope = ConvertToScopeEnum(value.as<std::string>()); return {}; } }, 290 { "InstallModes", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->InstallModes = ProcessInstallModeSequenceNode(value); return {}; } }, 291 { "InstallerSwitches", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ValidateAndProcessFields(value, SwitchesFieldInfos, VariantManifestPtr(&(GetManifestInstallerPtr(v)->Switches))); }}, 292 { "InstallerSuccessCodes", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->InstallerSuccessCodes = ProcessInstallerSuccessCodeSequenceNode(value); return {}; } }, 293 { "UpgradeBehavior", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->UpdateBehavior = ConvertToUpdateBehaviorEnum(value.as<std::string>()); return {}; } }, 294 { "Commands", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Commands = ProcessStringSequenceNode(value); return {}; } }, 295 { "Protocols", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Protocols = ProcessStringSequenceNode(value); return {}; } }, 296 { "FileExtensions", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->FileExtensions = ProcessStringSequenceNode(value); return {}; } }, 297 { "Dependencies", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ValidateAndProcessFields(value, DependenciesFieldInfos, VariantManifestPtr(&(GetManifestInstallerPtr(v)->Dependencies))); }}, 298 { "Capabilities", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Capabilities = ProcessStringSequenceNode(value); return {}; } }, 299 { "RestrictedCapabilities", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->RestrictedCapabilities = ProcessStringSequenceNode(value); return {}; } }, 300 }; 301 302 std::move(v1CommonFields.begin(), v1CommonFields.end(), std::inserter(result, result.end())); 303 304 if (!forRootFields) 305 { 306 // Installer level only fields 307 std::vector<FieldProcessInfo> v1InstallerFields = 308 { 309 { "Architecture", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Arch = Utility::ConvertToArchitectureEnum(value.as<std::string>()); return {}; } }, 310 { "InstallerUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Url = value.as<std::string>(); return {}; } }, 311 { "InstallerSha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Sha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } }, 312 { "SignatureSha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->SignatureSha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } }, 313 // No custom validation needed at field populating time since we have semantic validation later to block msstore and productId from community repo. 314 { "MSStoreProductIdentifier", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->ProductId = value.as<std::string>(); return {}; } }, 315 }; 316 317 std::move(v1InstallerFields.begin(), v1InstallerFields.end(), std::inserter(result, result.end())); 318 } 319 } 320 321 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 }) 322 { 323 std::vector<FieldProcessInfo> fields_v1_1 = 324 { 325 { "InstallerAbortsTerminal", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->InstallerAbortsTerminal = value.as<bool>(); return {}; } }, 326 { "InstallLocationRequired", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->InstallLocationRequired = value.as<bool>(); return {}; } }, 327 { "RequireExplicitUpgrade", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->RequireExplicitUpgrade = value.as<bool>(); return {}; } }, 328 { "ReleaseDate", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->ReleaseDate = Utility::Trim(value.as<std::string>()); return {}; } }, 329 { "UnsupportedOSArchitectures", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->UnsupportedOSArchitectures = ProcessArchitectureSequenceNode(value); return {}; } }, 330 { "ElevationRequirement", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->ElevationRequirement = ConvertToElevationRequirementEnum(value.as<std::string>()); return {}; } }, 331 { "Markets", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessMarketsNode(value, GetManifestInstallerPtr(v)); } }, 332 { "AppsAndFeaturesEntries", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessAppsAndFeaturesEntriesNode(value, GetManifestInstallerPtr(v)); } }, 333 { "ExpectedReturnCodes", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessExpectedReturnCodesNode(value, GetManifestInstallerPtr(v)); } }, 334 }; 335 336 std::move(fields_v1_1.begin(), fields_v1_1.end(), std::inserter(result, result.end())); 337 } 338 339 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_2 }) 340 { 341 std::vector<FieldProcessInfo> fields_v1_2 = 342 { 343 { "UnsupportedArguments", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->UnsupportedArguments = ProcessUnsupportedArgumentsSequenceNode(value); return {}; } }, 344 { "DisplayInstallWarnings", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->DisplayInstallWarnings = value.as<bool>(); return {}; } }, 345 }; 346 347 std::move(fields_v1_2.begin(), fields_v1_2.end(), std::inserter(result, result.end())); 348 } 349 350 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_4 }) 351 { 352 std::vector<FieldProcessInfo> fields_v1_4 = 353 { 354 { "NestedInstallerType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->NestedInstallerType = ConvertToInstallerTypeEnum(value.as<std::string>()); return {}; } }, 355 { "NestedInstallerFiles", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessNestedInstallerFilesNode(value, GetManifestInstallerPtr(v)); } }, 356 { "InstallationMetadata", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ValidateAndProcessFields(value, InstallationMetadataFieldInfos, VariantManifestPtr(&(GetManifestInstallerPtr(v)->InstallationMetadata))); }}, 357 }; 358 359 std::move(fields_v1_4.begin(), fields_v1_4.end(), std::inserter(result, result.end())); 360 } 361 362 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_6 }) 363 { 364 std::vector<FieldProcessInfo> fields_v1_6 = 365 { 366 { "DownloadCommandProhibited", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->DownloadCommandProhibited = value.as<bool>(); return {}; }, true }, 367 }; 368 369 std::move(fields_v1_6.begin(), fields_v1_6.end(), std::inserter(result, result.end())); 370 } 371 372 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_7 }) 373 { 374 std::vector<FieldProcessInfo> fields_v1_7 = 375 { 376 { "RepairBehavior", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->RepairBehavior = ConvertToRepairBehaviorEnum(value.as<std::string>()); return {}; } }, 377 }; 378 379 std::move(fields_v1_7.begin(), fields_v1_7.end(), std::inserter(result, result.end())); 380 } 381 382 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_9 }) 383 { 384 std::vector<FieldProcessInfo> fields_v1_9 = 385 { 386 { "ArchiveBinariesDependOnPath", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->ArchiveBinariesDependOnPath = value.as<bool>(); return {}; } }, 387 }; 388 389 std::move(fields_v1_9.begin(), fields_v1_9.end(), std::inserter(result, result.end())); 390 } 391 392 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_10 }) 393 { 394 std::vector<FieldProcessInfo> fields_v1_10 = 395 { 396 { "Authentication", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->AuthInfo = {}; auto errors = ValidateAndProcessFields(value, AuthenticationFieldInfos, VariantManifestPtr(&(GetManifestInstallerPtr(v)->AuthInfo))); GetManifestInstallerPtr(v)->AuthInfo.UpdateRequiredFieldsIfNecessary(); return errors; }, true}, 397 }; 398 399 std::move(fields_v1_10.begin(), fields_v1_10.end(), std::inserter(result, result.end())); 400 } 401 } 402 403 return result; 404 } 405 406 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetSwitchesFieldProcessInfo() 407 { 408 // Common fields across versions 409 std::vector<FieldProcessInfo> result = 410 { 411 { "Custom", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Custom] = value.as<std::string>(); return{}; } }, 412 { "Silent", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Silent] = value.as<std::string>(); return{}; } }, 413 { "SilentWithProgress", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::SilentWithProgress] = value.as<std::string>(); return{}; } }, 414 { "Interactive", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Interactive] = value.as<std::string>(); return{}; } }, 415 { "Log", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Log] = value.as<std::string>(); return{}; } }, 416 { "InstallLocation", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::InstallLocation] = value.as<std::string>(); return{}; } }, 417 }; 418 419 // Additional version specific fields 420 if (m_manifestVersion.get().Major() == 0) 421 { 422 // Language only exists in preview manifests. Though we don't use it in our code yet, keep it here to be consistent with schema. 423 result.emplace_back("Language", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Language] = value.as<std::string>(); return{}; }); 424 result.emplace_back("Update", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Update] = value.as<std::string>(); return{}; }); 425 } 426 else if (m_manifestVersion.get().Major() == 1) 427 { 428 result.emplace_back("Upgrade", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Update] = value.as<std::string>(); return{}; }); 429 430 if (m_manifestVersion.get() >= ManifestVer{s_ManifestVersionV1_7}) 431 { 432 result.emplace_back("Repair", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Repair] = value.as<std::string>(); return{}; }); 433 }; 434 } 435 436 return result; 437 } 438 439 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetExpectedReturnCodesFieldProcessInfo() 440 { 441 std::vector<FieldProcessInfo> result = {}; 442 443 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 }) 444 { 445 result.emplace_back("InstallerReturnCode", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ExpectedReturnCode>(v)->InstallerReturnCode = static_cast<int>(value.as<int>()); return {}; }); 446 result.emplace_back("ReturnResponse", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ExpectedReturnCode>(v)->ReturnResponse = ConvertToExpectedReturnCodeEnum(value.as<std::string>()); return {}; }); 447 } 448 449 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_2 }) 450 { 451 result.emplace_back("ReturnResponseUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ExpectedReturnCode>(v)->ReturnResponseUrl = value.as<std::string>(); return {}; }); 452 } 453 454 return result; 455 } 456 457 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetLocalizationFieldProcessInfo(bool forRootFields) 458 { 459 // Common fields across versions 460 std::vector<FieldProcessInfo> result = 461 { 462 { "Description", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::Description>(Utility::Trim(value.as<std::string>())); return {}; } }, 463 { "LicenseUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::LicenseUrl>(value.as<std::string>()); return {}; } }, 464 }; 465 466 // Additional version specific fields 467 if (m_manifestVersion.get().Major() == 0) 468 { 469 // Root level and Localization node level 470 result.emplace_back("Homepage", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PackageUrl>(value.as<std::string>()); return {}; }); 471 472 if (!forRootFields) 473 { 474 // Localization node only 475 result.emplace_back("Language", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestLocalization>(v)->Locale = value.as<std::string>(); return {}; }); 476 } 477 else 478 { 479 // Root node only 480 std::vector<FieldProcessInfo> rootOnlyFields = 481 { 482 { "Name", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtrFromManifest(v)->Add<Localization::PackageName>(Utility::Trim(value.as<std::string>())); return {}; } }, 483 { "Publisher", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtrFromManifest(v)->Add<Localization::Publisher>(value.as<std::string>()); return {}; } }, 484 { "Author", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtrFromManifest(v)->Add<Localization::Author>(value.as<std::string>()); return {}; } }, 485 { "License", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtrFromManifest(v)->Add<Localization::License>(value.as<std::string>()); return {}; } }, 486 { "Tags", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtrFromManifest(v)->Add<Localization::Tags>(SplitMultiValueField(value.as<std::string>())); return {}; } }, 487 }; 488 489 std::move(rootOnlyFields.begin(), rootOnlyFields.end(), std::inserter(result, result.end())); 490 } 491 } 492 else if (m_manifestVersion.get().Major() == 1) 493 { 494 // Starting v1, we should be only adding new fields for each minor version increase 495 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1 }) 496 { 497 // Root level and Localization node level 498 std::vector<FieldProcessInfo> v1CommonFields = 499 { 500 { "PackageLocale", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Locale = value.as<std::string>(); return {}; } }, 501 { "Publisher", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::Publisher>(value.as<std::string>()); return {}; } }, 502 { "PublisherUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PublisherUrl>(value.as<std::string>()); return {}; } }, 503 { "PublisherSupportUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PublisherSupportUrl>(value.as<std::string>()); return {}; } }, 504 { "PrivacyUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PrivacyUrl>(value.as<std::string>()); return {}; } }, 505 { "Author", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::Author>(value.as<std::string>()); return {}; } }, 506 { "PackageName", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PackageName>(Utility::Trim(value.as<std::string>())); return {}; } }, 507 { "PackageUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PackageUrl>(value.as<std::string>()); return {}; } }, 508 { "License", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::License>(value.as<std::string>()); return {}; } }, 509 { "Copyright", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::Copyright>(value.as<std::string>()); return {}; } }, 510 { "CopyrightUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::CopyrightUrl>(value.as<std::string>()); return {}; } }, 511 { "ShortDescription", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::ShortDescription>(Utility::Trim(value.as<std::string>())); return {}; } }, 512 { "Tags", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::Tags>(ProcessStringSequenceNode(value)); return {}; } }, 513 }; 514 515 std::move(v1CommonFields.begin(), v1CommonFields.end(), std::inserter(result, result.end())); 516 } 517 518 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 }) 519 { 520 std::vector<FieldProcessInfo> fields_v1_1 = 521 { 522 { "Agreements", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessAgreementsNode(value, GetManifestLocalizationPtr(v)); } }, 523 { "ReleaseNotes", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::ReleaseNotes>(value.as<std::string>()); return {}; } }, 524 { "ReleaseNotesUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::ReleaseNotesUrl>(value.as<std::string>()); return {}; } }, 525 }; 526 527 std::move(fields_v1_1.begin(), fields_v1_1.end(), std::inserter(result, result.end())); 528 } 529 530 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_2 }) 531 { 532 std::vector<FieldProcessInfo> fields_v1_2 = 533 { 534 { "PurchaseUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PurchaseUrl>(value.as<std::string>()); return {}; } }, 535 { "InstallationNotes", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::InstallationNotes>(value.as<std::string>()); return {}; } }, 536 { "Documentations", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessDocumentationsNode(value, GetManifestLocalizationPtr(v)); } }, 537 }; 538 539 std::move(fields_v1_2.begin(), fields_v1_2.end(), std::inserter(result, result.end())); 540 } 541 542 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_5 }) 543 { 544 std::vector<FieldProcessInfo> fields_v1_5 = 545 { 546 { "Icons", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessIconsNode(value, GetManifestLocalizationPtr(v)); }, true }, 547 }; 548 549 std::move(fields_v1_5.begin(), fields_v1_5.end(), std::inserter(result, result.end())); 550 } 551 } 552 553 return result; 554 } 555 556 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetDependenciesFieldProcessInfo() 557 { 558 std::vector<FieldProcessInfo> result = {}; 559 560 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1 }) 561 { 562 result = 563 { 564 { "WindowsFeatures", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { ProcessDependenciesNode(DependencyType::WindowsFeature, value, variant_ptr<DependencyList>(v)); return {}; } }, 565 { "WindowsLibraries", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { ProcessDependenciesNode(DependencyType::WindowsLibrary, value, variant_ptr<DependencyList>(v)); return {}; } }, 566 { "PackageDependencies", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { ProcessPackageDependenciesNode(value, variant_ptr<DependencyList>(v)); return {}; } }, 567 { "ExternalDependencies", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { ProcessDependenciesNode(DependencyType::External, value, variant_ptr<DependencyList>(v)); return {}; } }, 568 }; 569 } 570 571 return result; 572 } 573 574 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetPackageDependenciesFieldProcessInfo() 575 { 576 std::vector<FieldProcessInfo> result = {}; 577 578 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1 }) 579 { 580 result = 581 { 582 { "PackageIdentifier", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Dependency>(v)->SetId(Utility::Trim(value.as<std::string>())); return {}; } }, 583 { "MinimumVersion", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Dependency>(v)->MinVersion = Utility::Version(Utility::Trim(value.as<std::string>())); return {}; } }, 584 }; 585 } 586 587 return result; 588 } 589 590 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetAgreementFieldProcessInfo() 591 { 592 std::vector<FieldProcessInfo> result = {}; 593 594 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 }) 595 { 596 result = 597 { 598 { "AgreementLabel", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Agreement>(v)->Label = Utility::Trim(value.as<std::string>()); return {}; } }, 599 { "Agreement", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Agreement>(v)->AgreementText = Utility::Trim(value.as<std::string>()); return {}; }, true }, 600 { "AgreementUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Agreement>(v)->AgreementUrl = Utility::Trim(value.as<std::string>()); return {}; } }, 601 }; 602 } 603 604 return result; 605 } 606 607 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetMarketsFieldProcessInfo() 608 { 609 std::vector<FieldProcessInfo> result = {}; 610 611 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 }) 612 { 613 result = 614 { 615 { "AllowedMarkets", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<MarketsInfo>(v)->AllowedMarkets = ProcessStringSequenceNode(value); return {}; } }, 616 { "ExcludedMarkets", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<MarketsInfo>(v)->ExcludedMarkets = ProcessStringSequenceNode(value); return {}; } }, 617 }; 618 } 619 620 return result; 621 } 622 623 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetAppsAndFeaturesEntryFieldProcessInfo() 624 { 625 std::vector<FieldProcessInfo> result = {}; 626 627 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 }) 628 { 629 result = 630 { 631 { "DisplayName", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->DisplayName = Utility::Trim(value.as<std::string>()); return {}; } }, 632 { "Publisher", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->Publisher = Utility::Trim(value.as<std::string>()); return {}; } }, 633 { "DisplayVersion", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->DisplayVersion = Utility::Trim(value.as<std::string>()); return {}; } }, 634 { "ProductCode", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->ProductCode = Utility::Trim(value.as<std::string>()); return {}; } }, 635 { "UpgradeCode", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->UpgradeCode = Utility::Trim(value.as<std::string>()); return {}; } }, 636 { "InstallerType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->InstallerType = ConvertToInstallerTypeEnum(value.as<std::string>()); return {}; } }, 637 }; 638 } 639 640 return result; 641 } 642 643 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetDocumentationFieldProcessInfo() 644 { 645 std::vector<FieldProcessInfo> result = {}; 646 647 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_2 }) 648 { 649 result = 650 { 651 { "DocumentLabel", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Documentation>(v)->DocumentLabel = Utility::Trim(value.as<std::string>()); return {}; } }, 652 { "DocumentUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Documentation>(v)->DocumentUrl = Utility::Trim(value.as<std::string>()); return {}; } }, 653 }; 654 } 655 656 return result; 657 } 658 659 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetIconFieldProcessInfo() 660 { 661 std::vector<FieldProcessInfo> result = {}; 662 663 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_5 }) 664 { 665 result = 666 { 667 { "IconUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Icon>(v)->Url = Utility::Trim(value.as<std::string>()); return {}; } }, 668 { "IconFileType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Icon>(v)->FileType = ConvertToIconFileTypeEnum(value.as<std::string>()); return {}; } }, 669 { "IconResolution", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Icon>(v)->Resolution = ConvertToIconResolutionEnum(value.as<std::string>()); return {}; } }, 670 { "IconTheme", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Icon>(v)->Theme = ConvertToIconThemeEnum(value.as<std::string>()); return {}; } }, 671 { "IconSha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Icon>(v)->Sha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } }, 672 }; 673 } 674 675 return result; 676 } 677 678 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetNestedInstallerFileFieldProcessInfo() 679 { 680 std::vector<FieldProcessInfo> result = {}; 681 682 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_4 }) 683 { 684 result = 685 { 686 { "RelativeFilePath", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<NestedInstallerFile>(v)->RelativeFilePath = Utility::Trim(value.as<std::string>()); return {}; } }, 687 { "PortableCommandAlias", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<NestedInstallerFile>(v)->PortableCommandAlias = Utility::Trim(value.as<std::string>()); return {}; } }, 688 }; 689 } 690 691 return result; 692 } 693 694 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetInstallationMetadataFieldProcessInfo() 695 { 696 std::vector<FieldProcessInfo> result = {}; 697 698 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_4 }) 699 { 700 result = 701 { 702 { "DefaultInstallLocation", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstallationMetadataInfo>(v)->DefaultInstallLocation = Utility::Trim(value.as<std::string>()); return {}; } }, 703 { "Files", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessInstallationMetadataFilesNode(value, variant_ptr<InstallationMetadataInfo>(v)); } }, 704 }; 705 } 706 707 return result; 708 } 709 710 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetInstallationMetadataFilesFieldProcessInfo() 711 { 712 std::vector<FieldProcessInfo> result = {}; 713 714 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_4 }) 715 { 716 result = 717 { 718 { "RelativeFilePath", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstalledFile>(v)->RelativeFilePath = Utility::Trim(value.as<std::string>()); return {}; } }, 719 { "FileSha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstalledFile>(v)->FileSha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } }, 720 { "FileType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstalledFile>(v)->FileType = ConvertToInstalledFileTypeEnum(value.as<std::string>()); return {}; } }, 721 { "InvocationParameter", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstalledFile>(v)->InvocationParameter = Utility::Trim(value.as<std::string>()); return {}; } }, 722 { "DisplayName", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstalledFile>(v)->DisplayName = Utility::Trim(value.as<std::string>()); return {}; } }, 723 }; 724 } 725 726 return result; 727 } 728 729 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetAuthenticationFieldInfos() 730 { 731 std::vector<FieldProcessInfo> result = {}; 732 733 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_10 }) 734 { 735 result = 736 { 737 { "AuthenticationType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Authentication::AuthenticationInfo>(v)->Type = Authentication::ConvertToAuthenticationType(value.as<std::string>()); return {}; } }, 738 { "MicrosoftEntraIdAuthenticationInfo", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Authentication::AuthenticationInfo>(v)->MicrosoftEntraIdInfo.emplace(); return ValidateAndProcessFields(value, MicrosoftEntraIdAuthenticationInfoFieldInfos, VariantManifestPtr(&(variant_ptr<Authentication::AuthenticationInfo>(v)->MicrosoftEntraIdInfo.value()))); }}, 739 }; 740 } 741 742 return result; 743 } 744 745 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetMicrosoftEntraIdAuthenticationInfoFieldInfos() 746 { 747 std::vector<FieldProcessInfo> result = {}; 748 749 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_10 }) 750 { 751 result = 752 { 753 { "Resource", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Authentication::MicrosoftEntraIdAuthenticationInfo>(v)->Resource = Utility::Trim(value.as<std::string>()); return {}; } }, 754 { "Scope", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Authentication::MicrosoftEntraIdAuthenticationInfo>(v)->Scope = Utility::Trim(value.as<std::string>()); return {}; } }, 755 }; 756 } 757 758 return result; 759 } 760 761 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetShadowRootFieldProcessInfo() 762 { 763 std::vector<FieldProcessInfo> result; 764 765 if (m_manifestVersion.get().Major() == 1) 766 { 767 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_5 }) 768 { 769 std::vector<FieldProcessInfo> fields_v1_5 = 770 { 771 { 772 { "Localization", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessShadowLocalizationNode(value, variant_ptr<Manifest>(v)); } }, 773 { "ManifestType", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { return {}; } }, 774 { "PackageIdentifier", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { return {}; } }, 775 { "PackageVersion", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { return {}; } }, 776 { "ManifestVersion", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { return {}; } }, 777 }, 778 }; 779 780 std::move(fields_v1_5.begin(), fields_v1_5.end(), std::inserter(result, result.end())); 781 } 782 } 783 784 auto rootLocalizationFields = GetShadowLocalizationFieldProcessInfo(); 785 std::move(rootLocalizationFields.begin(), rootLocalizationFields.end(), std::inserter(result, result.end())); 786 787 return result; 788 } 789 790 std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetShadowLocalizationFieldProcessInfo() 791 { 792 std::vector<FieldProcessInfo> result; 793 794 if (m_manifestVersion.get().Major() == 1) 795 { 796 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_5 }) 797 { 798 std::vector<FieldProcessInfo> fields_v1_5 = 799 { 800 { "PackageLocale", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Locale = value.as<std::string>(); return {}; } }, 801 { "Icons", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessIconsNode(value, GetManifestLocalizationPtr(v)); } }, 802 }; 803 804 std::move(fields_v1_5.begin(), fields_v1_5.end(), std::inserter(result, result.end())); 805 } 806 } 807 808 return result; 809 } 810 811 ValidationErrors ManifestYamlPopulator::ValidateAndProcessFields( 812 const YAML::Node& rootNode, 813 const std::vector<FieldProcessInfo>& fieldInfos, 814 const VariantManifestPtr& v) 815 { 816 ValidationErrors resultErrors; 817 818 if (!rootNode.IsMap() || rootNode.size() == 0) 819 { 820 resultErrors.emplace_back(ManifestError::InvalidRootNode, "", "", m_isMergedManifest ? 0 : rootNode.Mark().line, m_isMergedManifest ? 0 : rootNode.Mark().column); 821 return resultErrors; 822 } 823 824 // Keeps track of already processed fields. Used to check duplicate fields. 825 std::set<std::string> processedFields; 826 827 for (auto const& keyValuePair : rootNode.Mapping()) 828 { 829 std::string key = keyValuePair.first.as<std::string>(); 830 const YAML::Node& valueNode = keyValuePair.second; 831 832 // We'll do case-insensitive search first and validate correct case later. 833 auto fieldIter = std::find_if(fieldInfos.begin(), fieldInfos.end(), 834 [&](auto const& s) 835 { 836 return Utility::CaseInsensitiveEquals(s.Name, key); 837 }); 838 839 if (fieldIter != fieldInfos.end()) 840 { 841 const FieldProcessInfo& fieldInfo = *fieldIter; 842 843 // Make sure the found key is in Pascal Case 844 if (key != fieldInfo.Name) 845 { 846 resultErrors.emplace_back(ManifestError::FieldIsNotPascalCase, key, "", m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column); 847 } 848 849 // Make sure it's not a duplicate key 850 if (!processedFields.insert(fieldInfo.Name).second) 851 { 852 resultErrors.emplace_back(ManifestError::FieldDuplicate, fieldInfo.Name, "", m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column); 853 } 854 855 if (fieldInfo.RequireVerifiedPublisher) 856 { 857 resultErrors.emplace_back(ManifestError::FieldRequireVerifiedPublisher, fieldInfo.Name, "", 858 m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column, 859 m_validateOption.ErrorOnVerifiedPublisherFields ? ValidationError::Level::Error : ValidationError::Level::Warning); 860 } 861 862 if (!valueNode.IsNull()) 863 { 864 try 865 { 866 auto errors = fieldInfo.ProcessFunc(valueNode, v); 867 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 868 } 869 catch (const std::exception&) 870 { 871 resultErrors.emplace_back(ManifestError::FieldFailedToProcess, fieldInfo.Name); 872 } 873 } 874 } 875 else 876 { 877 // For full validation, also reports unrecognized fields as warning 878 if (m_validateOption.FullValidation) 879 { 880 resultErrors.emplace_back(ManifestError::FieldUnknown, key, "", m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column, ValidationError::Level::Warning); 881 } 882 } 883 } 884 885 return resultErrors; 886 } 887 888 ValidationErrors ManifestYamlPopulator::ProcessPackageDependenciesNode(const YAML::Node& rootNode, DependencyList* dependencyList) 889 { 890 ValidationErrors resultErrors; 891 892 for (auto const& entry : rootNode.Sequence()) 893 { 894 Dependency packageDependency = Dependency(DependencyType::Package); 895 auto errors = ValidateAndProcessFields(entry, PackageDependenciesFieldInfos, VariantManifestPtr(&packageDependency)); 896 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 897 dependencyList->Add(std::move(packageDependency)); 898 } 899 900 return resultErrors; 901 } 902 903 ValidationErrors ManifestYamlPopulator::ProcessAgreementsNode(const YAML::Node& agreementsNode, ManifestLocalization* localization) 904 { 905 THROW_HR_IF(E_INVALIDARG, !agreementsNode.IsSequence()); 906 907 ValidationErrors resultErrors; 908 std::vector<Agreement> agreements; 909 910 for (auto const& entry : agreementsNode.Sequence()) 911 { 912 Agreement agreement; 913 auto errors = ValidateAndProcessFields(entry, AgreementFieldInfos, VariantManifestPtr(&agreement)); 914 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 915 agreements.emplace_back(std::move(agreement)); 916 } 917 918 if (!agreements.empty()) 919 { 920 localization->Add<Localization::Agreements>(std::move(agreements)); 921 } 922 923 return resultErrors; 924 } 925 926 std::vector<ValidationError> ManifestYamlPopulator::ProcessMarketsNode(const YAML::Node& marketsNode, ManifestInstaller* installer) 927 { 928 MarketsInfo markets; 929 auto errors = ValidateAndProcessFields(marketsNode, MarketsFieldInfos, VariantManifestPtr(&markets)); 930 installer->Markets = markets; 931 return errors; 932 } 933 934 std::vector<ValidationError> ManifestYamlPopulator::ProcessAppsAndFeaturesEntriesNode(const YAML::Node& appsAndFeaturesEntriesNode, ManifestInstaller* installer) 935 { 936 THROW_HR_IF(E_INVALIDARG, !appsAndFeaturesEntriesNode.IsSequence()); 937 938 ValidationErrors resultErrors; 939 std::vector<AppsAndFeaturesEntry> appsAndFeaturesEntries; 940 941 for (auto const& entry : appsAndFeaturesEntriesNode.Sequence()) 942 { 943 AppsAndFeaturesEntry appsAndFeaturesEntry; 944 auto errors = ValidateAndProcessFields(entry, AppsAndFeaturesEntryFieldInfos, VariantManifestPtr(&appsAndFeaturesEntry)); 945 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 946 appsAndFeaturesEntries.emplace_back(std::move(appsAndFeaturesEntry)); 947 } 948 949 installer->AppsAndFeaturesEntries = appsAndFeaturesEntries; 950 951 return resultErrors; 952 } 953 954 ValidationErrors ManifestYamlPopulator::ProcessExpectedReturnCodesNode(const YAML::Node& returnCodesNode, ManifestInstaller* installer) 955 { 956 THROW_HR_IF(E_INVALIDARG, !returnCodesNode.IsSequence()); 957 958 ValidationErrors resultErrors; 959 std::map<DWORD, ExpectedReturnCodeInfo> returnCodes; 960 961 for (auto const& entry : returnCodesNode.Sequence()) 962 { 963 ExpectedReturnCode returnCode; 964 auto errors = ValidateAndProcessFields(entry, ExpectedReturnCodesFieldInfos, VariantManifestPtr(&returnCode)); 965 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 966 if (!returnCodes.insert({ returnCode.InstallerReturnCode, {returnCode.ReturnResponse, returnCode.ReturnResponseUrl} }).second) 967 { 968 resultErrors.emplace_back(ManifestError::DuplicateReturnCodeEntry); 969 } 970 } 971 972 installer->ExpectedReturnCodes = returnCodes; 973 974 return resultErrors; 975 } 976 977 ValidationErrors ManifestYamlPopulator::ProcessDocumentationsNode(const YAML::Node& documentationsNode, ManifestLocalization* localization) 978 { 979 THROW_HR_IF(E_INVALIDARG, !documentationsNode.IsSequence()); 980 981 ValidationErrors resultErrors; 982 std::vector<Documentation> documentations; 983 984 for (auto const& entry : documentationsNode.Sequence()) 985 { 986 Documentation documentation; 987 auto errors = ValidateAndProcessFields(entry, DocumentationFieldInfos, VariantManifestPtr(&documentation)); 988 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 989 documentations.emplace_back(std::move(documentation)); 990 } 991 992 if (!documentations.empty()) 993 { 994 localization->Add<Localization::Documentations>(std::move(documentations)); 995 } 996 997 return resultErrors; 998 } 999 1000 std::vector<ValidationError> ManifestYamlPopulator::ProcessIconsNode(const YAML::Node& iconsNode, ManifestLocalization* localization) 1001 { 1002 THROW_HR_IF(E_INVALIDARG, !iconsNode.IsSequence()); 1003 1004 ValidationErrors resultErrors; 1005 std::vector<Icon> icons; 1006 1007 for (auto const& entry : iconsNode.Sequence()) 1008 { 1009 Icon icon; 1010 auto errors = ValidateAndProcessFields(entry, IconFieldInfos, VariantManifestPtr(&icon)); 1011 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 1012 icons.emplace_back(std::move(icon)); 1013 } 1014 1015 if (!icons.empty()) 1016 { 1017 localization->Add<Localization::Icons>(std::move(icons)); 1018 } 1019 1020 return resultErrors; 1021 } 1022 1023 ValidationErrors ManifestYamlPopulator::ProcessNestedInstallerFilesNode(const YAML::Node& nestedInstallerFilesNode, ManifestInstaller* installer) 1024 { 1025 THROW_HR_IF(E_INVALIDARG, !nestedInstallerFilesNode.IsSequence()); 1026 1027 ValidationErrors resultErrors; 1028 std::vector<NestedInstallerFile> nestedInstallerFiles; 1029 1030 for (auto const& entry : nestedInstallerFilesNode.Sequence()) 1031 { 1032 NestedInstallerFile nestedInstallerFile; 1033 auto errors = ValidateAndProcessFields(entry, NestedInstallerFileFieldInfos, VariantManifestPtr(&nestedInstallerFile)); 1034 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 1035 nestedInstallerFiles.emplace_back(std::move(nestedInstallerFile)); 1036 } 1037 1038 if (!nestedInstallerFiles.empty()) 1039 { 1040 installer->NestedInstallerFiles = nestedInstallerFiles; 1041 } 1042 1043 return resultErrors; 1044 } 1045 1046 std::vector<ValidationError> ManifestYamlPopulator::ProcessInstallationMetadataFilesNode(const YAML::Node& installedFilesNode, InstallationMetadataInfo* installationMetadata) 1047 { 1048 THROW_HR_IF(E_INVALIDARG, !installedFilesNode.IsSequence()); 1049 1050 ValidationErrors resultErrors; 1051 std::vector<InstalledFile> installedFiles; 1052 1053 for (auto const& entry : installedFilesNode.Sequence()) 1054 { 1055 InstalledFile installedFile; 1056 auto errors = ValidateAndProcessFields(entry, InstallationMetadataFilesFieldInfos, VariantManifestPtr(&installedFile)); 1057 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 1058 installedFiles.emplace_back(std::move(installedFile)); 1059 } 1060 1061 if (!installedFiles.empty()) 1062 { 1063 installationMetadata->Files = installedFiles; 1064 } 1065 1066 return resultErrors; 1067 } 1068 1069 std::vector<ValidationError> ManifestYamlPopulator::ProcessShadowLocalizationNode(const YAML::Node& localizationNode, Manifest* manifest) 1070 { 1071 THROW_HR_IF(E_INVALIDARG, !localizationNode.IsSequence()); 1072 1073 ValidationErrors resultErrors; 1074 auto shadowLocalizationFields = GetShadowLocalizationFieldProcessInfo(); 1075 1076 for (auto const& entry : localizationNode.Sequence()) 1077 { 1078 ManifestLocalization localization; 1079 auto errors = ValidateAndProcessFields(entry, shadowLocalizationFields, VariantManifestPtr(&localization)); 1080 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 1081 manifest->Localizations.emplace_back(std::move(std::move(localization))); 1082 } 1083 1084 return resultErrors; 1085 } 1086 1087 ManifestYamlPopulator::ManifestYamlPopulator(YAML::Node& rootNode, Manifest& manifest, const ManifestVer& manifestVersion, ManifestValidateOption validateOption) : 1088 m_rootNode(rootNode), m_manifest(manifest), m_manifestVersion(manifestVersion), m_validateOption(validateOption) 1089 { 1090 m_isMergedManifest = !m_rootNode.get()["ManifestType"sv].IsNull() && m_rootNode.get()["ManifestType"sv].as<std::string>() == "merged"; 1091 m_manifest.get().ManifestVersion = m_manifestVersion; 1092 } 1093 1094 ValidationErrors ManifestYamlPopulator::PopulateManifestInternal() 1095 { 1096 const YAML::Node& rootNode = m_rootNode; 1097 ValidationErrors resultErrors; 1098 1099 // Prepare field infos 1100 RootFieldInfos = GetRootFieldProcessInfo(); 1101 InstallerFieldInfos = GetInstallerFieldProcessInfo(); 1102 SwitchesFieldInfos = GetSwitchesFieldProcessInfo(); 1103 ExpectedReturnCodesFieldInfos = GetExpectedReturnCodesFieldProcessInfo(); 1104 DependenciesFieldInfos = GetDependenciesFieldProcessInfo(); 1105 PackageDependenciesFieldInfos = GetPackageDependenciesFieldProcessInfo(); 1106 LocalizationFieldInfos = GetLocalizationFieldProcessInfo(); 1107 AgreementFieldInfos = GetAgreementFieldProcessInfo(); 1108 MarketsFieldInfos = GetMarketsFieldProcessInfo(); 1109 AppsAndFeaturesEntryFieldInfos = GetAppsAndFeaturesEntryFieldProcessInfo(); 1110 DocumentationFieldInfos = GetDocumentationFieldProcessInfo(); 1111 IconFieldInfos = GetIconFieldProcessInfo(); 1112 NestedInstallerFileFieldInfos = GetNestedInstallerFileFieldProcessInfo(); 1113 InstallationMetadataFieldInfos = GetInstallationMetadataFieldProcessInfo(); 1114 InstallationMetadataFilesFieldInfos = GetInstallationMetadataFilesFieldProcessInfo(); 1115 AuthenticationFieldInfos = GetAuthenticationFieldInfos(); 1116 MicrosoftEntraIdAuthenticationInfoFieldInfos = GetMicrosoftEntraIdAuthenticationInfoFieldInfos(); 1117 1118 resultErrors = ValidateAndProcessFields(rootNode, RootFieldInfos, VariantManifestPtr(&(m_manifest.get()))); 1119 1120 if (!m_p_installersNode) 1121 { 1122 return resultErrors; 1123 } 1124 1125 // Populate installers 1126 for (auto const& entry : m_p_installersNode->Sequence()) 1127 { 1128 ManifestInstaller installer = m_manifest.get().DefaultInstallerInfo; 1129 1130 // Clear these defaults as PackageFamilyName, ProductCode, AppsAndFeaturesEntries need to be copied based on InstallerType 1131 installer.PackageFamilyName.clear(); 1132 installer.ProductCode.clear(); 1133 installer.AppsAndFeaturesEntries.clear(); 1134 // Clear dependencies as installer overrides root dependencies 1135 installer.Dependencies.Clear(); 1136 // Clear nested installers as it should only be copied for zip installerType. 1137 installer.NestedInstallerType = InstallerTypeEnum::Unknown; 1138 installer.NestedInstallerFiles.clear(); 1139 1140 auto errors = ValidateAndProcessFields(entry, InstallerFieldInfos, VariantManifestPtr(&installer)); 1141 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 1142 1143 // Copy in system reference strings from the root if not set in the installer and appropriate 1144 if (installer.PackageFamilyName.empty() && DoesInstallerTypeUsePackageFamilyName(installer.EffectiveInstallerType())) 1145 { 1146 installer.PackageFamilyName = m_manifest.get().DefaultInstallerInfo.PackageFamilyName; 1147 } 1148 1149 if (installer.ProductCode.empty() && DoesInstallerTypeUseProductCode(installer.EffectiveInstallerType())) 1150 { 1151 installer.ProductCode = m_manifest.get().DefaultInstallerInfo.ProductCode; 1152 } 1153 1154 if (installer.AppsAndFeaturesEntries.empty() && DoesInstallerTypeWriteAppsAndFeaturesEntry(installer.EffectiveInstallerType())) 1155 { 1156 installer.AppsAndFeaturesEntries = m_manifest.get().DefaultInstallerInfo.AppsAndFeaturesEntries; 1157 } 1158 1159 if (IsArchiveType(installer.BaseInstallerType)) 1160 { 1161 if (installer.NestedInstallerFiles.empty()) 1162 { 1163 installer.NestedInstallerFiles = m_manifest.get().DefaultInstallerInfo.NestedInstallerFiles; 1164 } 1165 1166 if (installer.NestedInstallerType == InstallerTypeEnum::Unknown) 1167 { 1168 installer.NestedInstallerType = m_manifest.get().DefaultInstallerInfo.NestedInstallerType; 1169 } 1170 } 1171 1172 // If there are no dependencies on installer use default ones 1173 if (!installer.Dependencies.HasAny()) 1174 { 1175 installer.Dependencies = m_manifest.get().DefaultInstallerInfo.Dependencies; 1176 } 1177 1178 // Populate installer default switches if not exists 1179 auto defaultSwitches = GetDefaultKnownSwitches(installer.EffectiveInstallerType()); 1180 for (auto const& defaultSwitch : defaultSwitches) 1181 { 1182 if (installer.Switches.find(defaultSwitch.first) == installer.Switches.end()) 1183 { 1184 installer.Switches[defaultSwitch.first] = defaultSwitch.second; 1185 } 1186 } 1187 1188 // Populate installer default return codes if not present in ExpectedReturnCodes and InstallerSuccessCodes 1189 auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.EffectiveInstallerType()); 1190 for (auto const& defaultReturnCode : defaultReturnCodes) 1191 { 1192 if (installer.ExpectedReturnCodes.find(defaultReturnCode.first) == installer.ExpectedReturnCodes.end() && 1193 std::find(installer.InstallerSuccessCodes.begin(), installer.InstallerSuccessCodes.end(), defaultReturnCode.first) == installer.InstallerSuccessCodes.end()) 1194 { 1195 installer.ExpectedReturnCodes[defaultReturnCode.first].ReturnResponseEnum = defaultReturnCode.second; 1196 } 1197 } 1198 1199 m_manifest.get().Installers.emplace_back(std::move(installer)); 1200 } 1201 1202 // Populate additional localizations 1203 if (m_p_localizationsNode && m_p_localizationsNode->IsSequence()) 1204 { 1205 for (auto const& entry : m_p_localizationsNode->Sequence()) 1206 { 1207 ManifestLocalization localization; 1208 auto errors = ValidateAndProcessFields(entry, LocalizationFieldInfos, VariantManifestPtr(&localization)); 1209 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); 1210 m_manifest.get().Localizations.emplace_back(std::move(std::move(localization))); 1211 } 1212 } 1213 1214 return resultErrors; 1215 } 1216 1217 ValidationErrors ManifestYamlPopulator::InsertShadow(const YAML::Node& shadowNode) 1218 { 1219 Manifest shadowManifest; 1220 1221 // Process shadow node. 1222 auto resultErrors = ValidateAndProcessFields(shadowNode, GetShadowRootFieldProcessInfo(), VariantManifestPtr(&shadowManifest)); 1223 1224 // Merge. 1225 if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_5 }) 1226 { 1227 // Default localization 1228 if (Utility::ICUCaseInsensitiveEquals(m_manifest.get().DefaultLocalization.Locale, shadowManifest.DefaultLocalization.Locale)) 1229 { 1230 // Icons 1231 if (!m_manifest.get().DefaultLocalization.Contains(Localization::Icons) && 1232 shadowManifest.DefaultLocalization.Contains(Localization::Icons)) 1233 { 1234 m_manifest.get().DefaultLocalization.Add<Localization::Icons>(std::move(shadowManifest.DefaultLocalization.Get<Localization::Icons>())); 1235 1236 YAML::Node key{ YAML::Node::Type::Scalar, "", YAML::Mark() }; 1237 key.SetScalar("Icons"); 1238 YAML::Node value = shadowNode.GetChildNode("Icons"); 1239 m_rootNode.get().AddMappingNode(std::move(key), std::move(value)); 1240 } 1241 } 1242 1243 // Localizations 1244 if (!shadowManifest.Localizations.empty()) 1245 { 1246 // Merge manifest object 1247 for (auto const& shadowLocalization : shadowManifest.Localizations) 1248 { 1249 // Manifest 1250 if (auto iter = std::find_if(m_manifest.get().Localizations.begin(), m_manifest.get().Localizations.end(), [&](auto const& l) { return Utility::ICUCaseInsensitiveEquals(l.Locale, shadowLocalization.Locale); }); iter != m_manifest.get().Localizations.end()) 1251 { 1252 if (!(*iter).Contains(Localization::Icons) && 1253 shadowLocalization.Contains(Localization::Icons)) 1254 { 1255 (*iter).Add<Localization::Icons>(std::move(shadowLocalization.Get<Localization::Icons>())); 1256 } 1257 } 1258 else 1259 { 1260 ManifestLocalization localization = shadowLocalization; 1261 m_manifest.get().Localizations.emplace_back(std::move(std::move(localization))); 1262 } 1263 } 1264 1265 // Merge yaml 1266 auto shadowLocalizationsNode = shadowNode.GetChildNode("Localization"); 1267 if (m_p_localizationsNode) 1268 { 1269 m_rootNode.get().GetChildNode("Localization").MergeSequenceNode(shadowLocalizationsNode, "PackageLocale", true); 1270 } 1271 else 1272 { 1273 YAML::Node key{ YAML::Node::Type::Scalar, "", YAML::Mark() }; 1274 key.SetScalar("Localization"); 1275 m_rootNode.get().AddMappingNode(std::move(key), std::move(shadowLocalizationsNode)); 1276 } 1277 } 1278 } 1279 1280 return resultErrors; 1281 } 1282 1283 ValidationErrors ManifestYamlPopulator::PopulateManifest( 1284 YAML::Node& rootNode, 1285 Manifest& manifest, 1286 const ManifestVer& manifestVersion, 1287 ManifestValidateOption validateOption, 1288 const std::optional<YAML::Node>& shadowNode) 1289 { 1290 ManifestYamlPopulator manifestPopulator(rootNode, manifest, manifestVersion, validateOption); 1291 auto errors = manifestPopulator.PopulateManifestInternal(); 1292 1293 if (shadowNode.has_value()) 1294 { 1295 auto shadowErrors = manifestPopulator.InsertShadow(shadowNode.value()); 1296 std::move(shadowErrors.begin(), shadowErrors.end(), std::inserter(errors, errors.end())); 1297 } 1298 1299 return errors; 1300 } 1301 }