YamlWriter.cpp (33709B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "AppInstallerStrings.h" 5 #include "AppInstallerSHA256.h" 6 #include "winget/Yaml.h" 7 #include "winget/ManifestYamlWriter.h" 8 9 namespace AppInstaller::Manifest::YamlWriter 10 { 11 using namespace Utility::literals; 12 13 namespace 14 { 15 constexpr std::string_view PackageIdentifier = "PackageIdentifier"sv; 16 constexpr std::string_view PackageFamilyName = "PackageFamilyName"sv; 17 constexpr std::string_view ProductCode = "ProductCode"sv; 18 constexpr std::string_view Versions = "Versions"sv; 19 constexpr std::string_view PackageVersion = "PackageVersion"sv; 20 constexpr std::string_view Channel = "Channel"sv; 21 constexpr std::string_view ManifestVersion = "ManifestVersion"sv; 22 constexpr std::string_view ManifestType = "ManifestType"sv; 23 24 // Installer 25 constexpr std::string_view Installers = "Installers"sv; 26 constexpr std::string_view InstallerIdentifier = "InstallerIdentifier"sv; 27 constexpr std::string_view InstallerSha256 = "InstallerSha256"sv; 28 constexpr std::string_view InstallerUrl = "InstallerUrl"sv; 29 constexpr std::string_view Architecture = "Architecture"sv; 30 constexpr std::string_view InstallerLocale = "InstallerLocale"sv; 31 constexpr std::string_view Platform = "Platform"sv; 32 constexpr std::string_view InstallerType = "InstallerType"sv; 33 constexpr std::string_view Scope = "Scope"sv; 34 constexpr std::string_view SignatureSha256 = "SignatureSha256"sv; 35 constexpr std::string_view InstallModes = "InstallModes"sv; 36 constexpr std::string_view MSStoreProductIdentifier = "MSStoreProductIdentifier"sv; 37 constexpr std::string_view ReleaseDate = "ReleaseDate"sv; 38 constexpr std::string_view InstallerAbortsTerminal = "InstallerAbortsTerminal"sv; 39 constexpr std::string_view InstallLocationRequired = "InstallLocationRequired"sv; 40 constexpr std::string_view RequireExplicitUpgrade = "RequireExplicitUpgrade"sv; 41 constexpr std::string_view UnsupportedOSArchitectures = "UnsupportedOSArchitectures"sv; 42 constexpr std::string_view AppsAndFeaturesEntries = "AppsAndFeaturesEntries"sv; 43 constexpr std::string_view DisplayVersion = "DisplayVersion"sv; 44 constexpr std::string_view UpgradeCode = "UpgradeCode"sv; 45 constexpr std::string_view Markets = "Markets"sv; 46 constexpr std::string_view AllowedMarkets = "AllowedMarkets"sv; 47 constexpr std::string_view ExcludedMarkets = "ExcludedMarkets"sv; 48 constexpr std::string_view ElevationRequirement = "ElevationRequirement"sv; 49 constexpr std::string_view ExpectedReturnCodes = "ExpectedReturnCodes"sv; 50 constexpr std::string_view InstallerReturnCode = "InstallerReturnCode"sv; 51 constexpr std::string_view ReturnResponse = "ReturnResponse"sv; 52 constexpr std::string_view ReturnResponseUrl = "ReturnResponseUrl"sv; 53 constexpr std::string_view NestedInstallerType = "NestedInstallerType"sv; 54 constexpr std::string_view DisplayInstallWarnings = "DisplayInstallWarnings"sv; 55 constexpr std::string_view UnsupportedArguments = "UnsupportedArguments"sv; 56 constexpr std::string_view NestedInstallerFiles = "NestedInstallerFiles"sv; 57 constexpr std::string_view NestedInstallerFileRelativeFilePath = "RelativeFilePath"sv; 58 constexpr std::string_view PortableCommandAlias = "PortableCommandAlias"sv; 59 constexpr std::string_view InstallationMetadata = "InstallationMetadata"sv; 60 constexpr std::string_view DefaultInstallLocation = "DefaultInstallLocation"sv; 61 constexpr std::string_view InstallationMetadataFiles = "Files"sv; 62 constexpr std::string_view InstallationMetadataRelativeFilePath = "RelativeFilePath"sv; 63 constexpr std::string_view FileSha256 = "FileSha256"sv; 64 constexpr std::string_view FileType = "FileType"sv; 65 constexpr std::string_view InvocationParameter = "InvocationParameter"sv; 66 constexpr std::string_view DisplayName = "DisplayName"sv; 67 constexpr std::string_view MinimumOSVersion = "MinimumOSVersion"sv; 68 constexpr std::string_view DownloadCommandProhibited = "DownloadCommandProhibited"sv; 69 constexpr std::string_view RepairBehavior = "RepairBehavior"sv; 70 constexpr std::string_view ArchiveBinariesDependOnPath = "ArchiveBinariesDependOnPath"sv; 71 constexpr std::string_view Authentication = "Authentication"sv; 72 constexpr std::string_view AuthenticationType = "AuthenticationType"sv; 73 constexpr std::string_view MicrosoftEntraIdAuthenticationInfo = "MicrosoftEntraIdAuthenticationInfo"sv; 74 constexpr std::string_view MicrosoftEntraIdResource = "Resource"sv; 75 constexpr std::string_view MicrosoftEntraIdScope = "Scope"sv; 76 77 // Installer switches 78 constexpr std::string_view InstallerSwitches = "InstallerSwitches"sv; 79 constexpr std::string_view Silent = "Silent"sv; 80 constexpr std::string_view SilentWithProgress = "SilentWithProgress"sv; 81 constexpr std::string_view Interactive = "Interactive"sv; 82 constexpr std::string_view InstallLocation = "InstallLocation"sv; 83 constexpr std::string_view Log = "Log"sv; 84 constexpr std::string_view Upgrade = "Upgrade"sv; 85 constexpr std::string_view Custom = "Custom"sv; 86 constexpr std::string_view Repair = "Repair"sv; 87 88 constexpr std::string_view InstallerSuccessCodes = "InstallerSuccessCodes"sv; 89 constexpr std::string_view UpgradeBehavior = "UpgradeBehavior"sv; 90 constexpr std::string_view Commands = "Commands"sv; 91 constexpr std::string_view Protocols = "Protocols"sv; 92 constexpr std::string_view FileExtensions = "FileExtensions"sv; 93 94 // Dependencies 95 constexpr std::string_view Dependencies = "Dependencies"sv; 96 constexpr std::string_view WindowsFeatures = "WindowsFeatures"sv; 97 constexpr std::string_view WindowsLibraries = "WindowsLibraries"sv; 98 constexpr std::string_view PackageDependencies = "PackageDependencies"sv; 99 constexpr std::string_view MinimumVersion = "MinimumVersion"sv; 100 constexpr std::string_view ExternalDependencies = "ExternalDependencies"sv; 101 constexpr std::string_view Capabilities = "Capabilities"sv; 102 constexpr std::string_view RestrictedCapabilities = "RestrictedCapabilities"sv; 103 104 // Locale 105 constexpr std::string_view Localization = "Localization"sv; 106 constexpr std::string_view InstallationNotes = "InstallationNotes"sv; 107 constexpr std::string_view PurchaseUrl = "PurchaseUrl"sv; 108 constexpr std::string_view Documentations = "Documentations"sv; 109 constexpr std::string_view DocumentLabel = "DocumentLabel"sv; 110 constexpr std::string_view DocumentUrl = "DocumentUrl"sv; 111 constexpr std::string_view Icons = "Icons"sv; 112 constexpr std::string_view IconUrl = "IconUrl"sv; 113 constexpr std::string_view IconFileType = "IconFileType"sv; 114 constexpr std::string_view IconResolution = "IconResolution"sv; 115 constexpr std::string_view IconTheme = "IconTheme"sv; 116 constexpr std::string_view IconSha256 = "IconSha256"sv; 117 constexpr std::string_view ReleaseNotes = "ReleaseNotes"sv; 118 constexpr std::string_view ReleaseNotesUrl = "ReleaseNotesUrl"sv; 119 constexpr std::string_view Agreements = "Agreements"sv; 120 constexpr std::string_view AgreementLabel = "AgreementLabel"sv; 121 constexpr std::string_view Agreement = "Agreement"sv; 122 constexpr std::string_view AgreementUrl = "AgreementUrl"sv; 123 constexpr std::string_view DefaultLocale = "DefaultLocale"sv; 124 constexpr std::string_view Locales = "Locales"sv; 125 constexpr std::string_view PackageLocale = "PackageLocale"sv; 126 constexpr std::string_view Publisher = "Publisher"sv; 127 constexpr std::string_view PublisherUrl = "PublisherUrl"sv; 128 constexpr std::string_view PublisherSupportUrl = "PublisherSupportUrl"sv; 129 constexpr std::string_view PrivacyUrl = "PrivacyUrl"sv; 130 constexpr std::string_view Author = "Author"sv; 131 constexpr std::string_view PackageName = "PackageName"sv; 132 constexpr std::string_view PackageUrl = "PackageUrl"sv; 133 constexpr std::string_view License = "License"sv; 134 constexpr std::string_view LicenseUrl = "LicenseUrl"sv; 135 constexpr std::string_view Copyright = "Copyright"sv; 136 constexpr std::string_view CopyrightUrl = "CopyrightUrl"sv; 137 constexpr std::string_view ShortDescription = "ShortDescription"sv; 138 constexpr std::string_view Description = "Description"sv; 139 constexpr std::string_view Tags = "Tags"sv; 140 constexpr std::string_view Moniker = "Moniker"sv; 141 142 #define WRITE_PROPERTY(emitter, key, value) \ 143 { \ 144 emitter << YAML::Key << key << YAML::Value << value; \ 145 } 146 147 #define WRITE_BOOL_PROPERTY(emitter, key, value) \ 148 { \ 149 emitter << YAML::Key << key << YAML::Value << Utility::ConvertBoolToString(value); \ 150 } 151 152 #define WRITE_PROPERTY_IF_EXISTS(emitter, key, value) \ 153 { \ 154 if (!value.empty()) \ 155 { \ 156 WRITE_PROPERTY(emitter, key, value) \ 157 } \ 158 } 159 160 #define WRITE_SHA256_PROPERTY_IF_NOT_EMPTY(emitter, key, field) \ 161 { \ 162 if (!field.empty()) \ 163 { \ 164 WRITE_PROPERTY(emitter, key, Utility::SHA256::ConvertToString(field)) \ 165 } \ 166 } 167 168 #define WRITE_ENUM_PROPERTY_IF_NOT_UNKNOWN(emitter, key, value, enumField, enumType) \ 169 { \ 170 if (enumField != enumType::Unknown) \ 171 { \ 172 WRITE_PROPERTY(emitter, key, value) \ 173 } \ 174 } 175 176 void ProcessAgreements(YAML::Emitter& out, const std::vector<AppInstaller::Manifest::Agreement>& agreements) 177 { 178 if (agreements.empty()) 179 { 180 return; 181 } 182 183 out << YAML::Key << Agreements; 184 out << YAML::BeginSeq; 185 for (const auto& agreement : agreements) 186 { 187 out << YAML::BeginMap; 188 WRITE_PROPERTY_IF_EXISTS(out, AgreementLabel, agreement.Label); 189 WRITE_PROPERTY_IF_EXISTS(out, AgreementUrl, agreement.AgreementUrl); 190 WRITE_PROPERTY_IF_EXISTS(out, Agreement, agreement.AgreementText); 191 out << YAML::EndMap; 192 } 193 out << YAML::EndSeq; 194 } 195 196 void ProcessDocumentations(YAML::Emitter& out, const std::vector<AppInstaller::Manifest::Documentation>& documentations) 197 { 198 if (documentations.empty()) 199 { 200 return; 201 } 202 203 out << YAML::Key << Documentations; 204 out << YAML::BeginSeq; 205 for (const auto& document : documentations) 206 { 207 out << YAML::BeginMap; 208 WRITE_PROPERTY_IF_EXISTS(out, DocumentLabel, document.DocumentLabel); 209 WRITE_PROPERTY_IF_EXISTS(out, DocumentUrl, document.DocumentUrl); 210 out << YAML::EndMap; 211 } 212 out << YAML::EndSeq; 213 } 214 215 void ProcessIcons(YAML::Emitter& out, std::vector<AppInstaller::Manifest::Icon> icons) 216 { 217 if (icons.empty()) 218 { 219 return; 220 } 221 222 out << YAML::Key << Icons; 223 out << YAML::BeginSeq; 224 for (const auto& icon : icons) 225 { 226 out << YAML::BeginMap; 227 WRITE_PROPERTY(out, IconUrl, icon.Url); 228 WRITE_PROPERTY(out, IconFileType, IconFileTypeToString(icon.FileType)); 229 WRITE_ENUM_PROPERTY_IF_NOT_UNKNOWN(out, IconResolution, IconResolutionToString(icon.Resolution), icon.Resolution, IconResolutionEnum); 230 WRITE_ENUM_PROPERTY_IF_NOT_UNKNOWN(out, IconTheme, IconThemeToString(icon.Theme), icon.Theme, IconThemeEnum); 231 WRITE_SHA256_PROPERTY_IF_NOT_EMPTY(out, IconSha256, icon.Sha256); 232 out << YAML::EndMap; 233 } 234 out << YAML::EndSeq; 235 } 236 237 // Generic method for handling a list of strings (i.e. tags) 238 void ProcessStringSequence(YAML::Emitter& out, std::string_view name, std::vector<AppInstaller::Manifest::string_t> items) 239 { 240 if (items.empty()) 241 { 242 return; 243 } 244 245 out << YAML::Key << name; 246 out << YAML::BeginSeq; 247 for (const auto& item : items) 248 { 249 if (!item.empty()) 250 { 251 out << item; 252 } 253 } 254 out << YAML::EndSeq; 255 } 256 257 void ProcessLocaleFields(YAML::Emitter& out, const ManifestLocalization& manifest) 258 { 259 ProcessAgreements(out, manifest.Get<Localization::Agreements>()); 260 ProcessDocumentations(out, manifest.Get<Localization::Documentations>()); 261 ProcessIcons(out, manifest.Get<Localization::Icons>()); 262 ProcessStringSequence(out, Tags, manifest.Get<Localization::Tags>()); 263 264 WRITE_PROPERTY(out, PackageLocale, manifest.Locale); 265 WRITE_PROPERTY_IF_EXISTS(out, Author, manifest.Get<Localization::Author>()); 266 WRITE_PROPERTY_IF_EXISTS(out, Copyright, manifest.Get<Localization::Copyright>()); 267 WRITE_PROPERTY_IF_EXISTS(out, CopyrightUrl, manifest.Get<Localization::CopyrightUrl>()); 268 WRITE_PROPERTY_IF_EXISTS(out, Description, manifest.Get<Localization::Description>()); 269 WRITE_PROPERTY_IF_EXISTS(out, ShortDescription, manifest.Get<Localization::ShortDescription>()); 270 WRITE_PROPERTY_IF_EXISTS(out, License, manifest.Get<Localization::License>()); 271 WRITE_PROPERTY_IF_EXISTS(out, LicenseUrl, manifest.Get<Localization::LicenseUrl>()); 272 WRITE_PROPERTY_IF_EXISTS(out, PackageName, manifest.Get<Localization::PackageName>()); 273 WRITE_PROPERTY_IF_EXISTS(out, PackageUrl, manifest.Get<Localization::PackageUrl>()); 274 WRITE_PROPERTY_IF_EXISTS(out, PrivacyUrl, manifest.Get<Localization::PrivacyUrl>()); 275 WRITE_PROPERTY_IF_EXISTS(out, Publisher, manifest.Get<Localization::Publisher>()); 276 WRITE_PROPERTY_IF_EXISTS(out, PublisherSupportUrl, manifest.Get<Localization::PublisherSupportUrl>()); 277 WRITE_PROPERTY_IF_EXISTS(out, PublisherUrl, manifest.Get<Localization::PublisherUrl>()); 278 WRITE_PROPERTY_IF_EXISTS(out, PurchaseUrl, manifest.Get<Localization::PurchaseUrl>()); 279 WRITE_PROPERTY_IF_EXISTS(out, ReleaseNotes, manifest.Get<Localization::ReleaseNotes>()); 280 WRITE_PROPERTY_IF_EXISTS(out, ReleaseNotesUrl, manifest.Get<Localization::ReleaseNotesUrl>()); 281 WRITE_PROPERTY_IF_EXISTS(out, InstallationNotes, manifest.Get<Localization::InstallationNotes>()); 282 } 283 284 void ProcessAppsAndFeaturesEntries(YAML::Emitter& out, const std::vector<AppsAndFeaturesEntry>& appsAndFeaturesEntries) 285 { 286 if (appsAndFeaturesEntries.empty()) 287 { 288 return; 289 } 290 291 out << YAML::Key << AppsAndFeaturesEntries; 292 out << YAML::BeginSeq; 293 for (const auto& appsAndFeatureEntry : appsAndFeaturesEntries) 294 { 295 out << YAML::BeginMap; 296 WRITE_PROPERTY_IF_EXISTS(out, DisplayName, appsAndFeatureEntry.DisplayName); 297 WRITE_PROPERTY_IF_EXISTS(out, DisplayVersion, appsAndFeatureEntry.DisplayVersion); 298 WRITE_ENUM_PROPERTY_IF_NOT_UNKNOWN(out, InstallerType, InstallerTypeToString(appsAndFeatureEntry.InstallerType), appsAndFeatureEntry.InstallerType, InstallerTypeEnum); 299 WRITE_PROPERTY_IF_EXISTS(out, ProductCode, appsAndFeatureEntry.ProductCode); 300 WRITE_PROPERTY_IF_EXISTS(out, Publisher, appsAndFeatureEntry.Publisher); 301 WRITE_PROPERTY_IF_EXISTS(out, UpgradeCode, appsAndFeatureEntry.UpgradeCode); 302 out << YAML::EndMap; 303 } 304 out << YAML::EndSeq; 305 } 306 307 void ProcessInstallerSwitches(YAML::Emitter& out, const std::map<InstallerSwitchType, string_t>& installerSwitches) 308 { 309 if (installerSwitches.empty()) 310 { 311 return; 312 } 313 314 out << YAML::Key << InstallerSwitches; 315 out << YAML::BeginMap; 316 for (auto const& [type, value] : installerSwitches) 317 { 318 WRITE_PROPERTY_IF_EXISTS(out, InstallerSwitchTypeToString(type), value); 319 } 320 out << YAML::EndMap; 321 } 322 323 void ProcessExpectedReturnCodes(YAML::Emitter& out, const std::map<DWORD, ManifestInstaller::ExpectedReturnCodeInfo>& expectedReturnCodes) 324 { 325 if (expectedReturnCodes.empty()) 326 { 327 return; 328 } 329 330 out << YAML::Key << ExpectedReturnCodes; 331 out << YAML::BeginSeq; 332 for (const auto& expectedReturnCode : expectedReturnCodes) 333 { 334 out << YAML::BeginMap; 335 WRITE_PROPERTY(out, InstallerReturnCode, std::to_string(expectedReturnCode.first)); 336 WRITE_PROPERTY(out, ReturnResponse, ExpectedReturnCodeToString(expectedReturnCode.second.ReturnResponseEnum)); 337 WRITE_PROPERTY_IF_EXISTS(out, ReturnResponseUrl, expectedReturnCode.second.ReturnResponseUrl); 338 out << YAML::EndMap; 339 } 340 out << YAML::EndSeq; 341 } 342 343 void ProcessUnsupportedArguments(YAML::Emitter& out, const std::vector<UnsupportedArgumentEnum>& unsupportedArguments) 344 { 345 if (unsupportedArguments.empty()) 346 { 347 return; 348 } 349 350 out << YAML::Key << UnsupportedArguments; 351 out << YAML::BeginSeq; 352 for (auto const& unsupportedArg : unsupportedArguments) 353 { 354 if (unsupportedArg != UnsupportedArgumentEnum::Unknown) 355 { 356 out << UnsupportedArgumentToString(unsupportedArg); 357 } 358 } 359 out << YAML::EndSeq; 360 } 361 362 void ProcessUnsupportedOSArchitecture(YAML::Emitter& out, const std::vector<AppInstaller::Utility::Architecture>& architectures) 363 { 364 if (architectures.empty()) 365 { 366 return; 367 } 368 369 out << YAML::Key << UnsupportedOSArchitectures; 370 out << YAML::BeginSeq; 371 for (auto const& architecture : architectures) 372 { 373 if (architecture != AppInstaller::Utility::Architecture::Unknown) 374 { 375 out << Utility::ToLower(ToString(architecture)); 376 } 377 } 378 out << YAML::EndSeq; 379 } 380 381 void ProcessInstallModes(YAML::Emitter& out, const std::vector<InstallModeEnum>& installModes) 382 { 383 if (installModes.empty()) 384 { 385 return; 386 } 387 388 out << YAML::Key << InstallModes; 389 out << YAML::BeginSeq; 390 for (auto const& installMode : installModes) 391 { 392 if (installMode != InstallModeEnum::Unknown) 393 { 394 out << InstallModeToString(installMode); 395 } 396 } 397 out << YAML::EndSeq; 398 } 399 400 void ProcessPlatforms(YAML::Emitter& out, const std::vector<PlatformEnum>& platforms) 401 { 402 if (platforms.empty()) 403 { 404 return; 405 } 406 out << YAML::Key << Platform; 407 out << YAML::BeginSeq; 408 for (auto const& platform : platforms) 409 { 410 if (platform != PlatformEnum::Unknown) 411 { 412 out << PlatformToString(platform); 413 } 414 } 415 out << YAML::EndSeq; 416 } 417 418 void ProcessInstallerSuccessCodes(YAML::Emitter& out, const std::vector<DWORD>& installerSuccessCodes) 419 { 420 if (installerSuccessCodes.empty()) 421 { 422 return; 423 } 424 425 out << YAML::Key << InstallerSuccessCodes; 426 out << YAML::BeginSeq; 427 for (auto const& installerSuccessCode : installerSuccessCodes) 428 { 429 out << std::to_string(installerSuccessCode); 430 } 431 out << YAML::EndSeq; 432 } 433 434 void ProcessMarkets(YAML::Emitter& out, const MarketsInfo& marketsInfo) 435 { 436 if (marketsInfo.AllowedMarkets.empty() && marketsInfo.ExcludedMarkets.empty()) 437 { 438 return; 439 } 440 441 out << YAML::Key << Markets; 442 out << YAML::BeginMap; 443 ProcessStringSequence(out, AllowedMarkets, marketsInfo.AllowedMarkets); 444 ProcessStringSequence(out, ExcludedMarkets, marketsInfo.ExcludedMarkets); 445 out << YAML::EndMap; 446 } 447 448 void ProcessNestedInstallerFiles(YAML::Emitter& out, const std::vector<NestedInstallerFile>& nestedInstallerFiles) 449 { 450 if (nestedInstallerFiles.empty()) 451 { 452 return; 453 } 454 455 out << YAML::Key << NestedInstallerFiles; 456 out << YAML::BeginSeq; 457 for (const auto& nestedInstallerFile : nestedInstallerFiles) 458 { 459 out << YAML::BeginMap; 460 WRITE_PROPERTY(out, NestedInstallerFileRelativeFilePath, nestedInstallerFile.RelativeFilePath); 461 WRITE_PROPERTY_IF_EXISTS(out, PortableCommandAlias, nestedInstallerFile.PortableCommandAlias); 462 out << YAML::EndMap; 463 } 464 out << YAML::EndSeq; 465 } 466 467 void ProcessInstallationMetadataInstalledFiles(YAML::Emitter& out, const std::vector<InstalledFile>& installedFiles) 468 { 469 if (installedFiles.empty()) 470 { 471 return; 472 } 473 474 out << YAML::Key << InstallationMetadataFiles; 475 out << YAML::BeginSeq; 476 for (const auto& installedFile : installedFiles) 477 { 478 out << YAML::BeginMap; 479 WRITE_PROPERTY(out, InstallationMetadataRelativeFilePath, installedFile.RelativeFilePath); 480 WRITE_SHA256_PROPERTY_IF_NOT_EMPTY(out, FileSha256, installedFile.FileSha256); 481 WRITE_ENUM_PROPERTY_IF_NOT_UNKNOWN(out, FileType, InstalledFileTypeToString(installedFile.FileType), installedFile.FileType, InstalledFileTypeEnum); 482 WRITE_PROPERTY_IF_EXISTS(out, InvocationParameter, installedFile.InvocationParameter); 483 WRITE_PROPERTY_IF_EXISTS(out, DisplayName, installedFile.DisplayName); 484 485 out << YAML::EndMap; 486 } 487 out << YAML::EndSeq; 488 } 489 490 void ProcessInstallationMetadata(YAML::Emitter& out, const InstallationMetadataInfo& installationMetadata) 491 { 492 if (installationMetadata.DefaultInstallLocation.empty() && installationMetadata.Files.empty()) 493 { 494 return; 495 } 496 497 out << YAML::Key << InstallationMetadata; 498 out << YAML::BeginMap; 499 WRITE_PROPERTY_IF_EXISTS(out, DefaultInstallLocation, installationMetadata.DefaultInstallLocation); 500 ProcessInstallationMetadataInstalledFiles(out, installationMetadata.Files); 501 out << YAML::EndMap; 502 } 503 504 void ProcessAuthentication(YAML::Emitter& out, const Authentication::AuthenticationInfo& authInfo) 505 { 506 if (authInfo.Type == Authentication::AuthenticationType::None) 507 { 508 return; 509 } 510 511 out << YAML::Key << Authentication; 512 out << YAML::BeginMap; 513 WRITE_PROPERTY(out, AuthenticationType, Authentication::AuthenticationTypeToString(authInfo.Type)); 514 if (authInfo.MicrosoftEntraIdInfo) 515 { 516 out << YAML::Key << MicrosoftEntraIdAuthenticationInfo; 517 out << YAML::BeginMap; 518 WRITE_PROPERTY_IF_EXISTS(out, MicrosoftEntraIdResource, authInfo.MicrosoftEntraIdInfo->Resource); 519 WRITE_PROPERTY_IF_EXISTS(out, MicrosoftEntraIdScope, authInfo.MicrosoftEntraIdInfo->Scope); 520 out << YAML::EndMap; 521 } 522 out << YAML::EndMap; 523 } 524 525 void ProcessDependencies(YAML::Emitter& out, const DependencyList& dependencies) 526 { 527 if (!dependencies.HasAny()) 528 { 529 return; 530 } 531 532 out << YAML::Key << Dependencies; 533 out << YAML::BeginMap; 534 535 if (dependencies.HasAnyOf(DependencyType::WindowsFeature)) 536 { 537 out << YAML::Key << WindowsFeatures; 538 out << YAML::BeginSeq; 539 dependencies.ApplyToType(DependencyType::WindowsFeature, [&out](Dependency dependency) 540 { 541 out << dependency.Id(); 542 }); 543 out << YAML::EndSeq; 544 } 545 546 if (dependencies.HasAnyOf(DependencyType::WindowsLibrary)) 547 { 548 out << YAML::Key << WindowsLibraries; 549 out << YAML::BeginSeq; 550 dependencies.ApplyToType(DependencyType::WindowsLibrary, [&out](Dependency dependency) 551 { 552 out << dependency.Id(); 553 }); 554 out << YAML::EndSeq; 555 } 556 557 if (dependencies.HasAnyOf(DependencyType::Package)) 558 { 559 out << YAML::Key << PackageDependencies; 560 out << YAML::BeginSeq; 561 dependencies.ApplyToType(DependencyType::Package, [&out](Dependency dependency) 562 { 563 out << YAML::BeginMap; 564 WRITE_PROPERTY(out, PackageIdentifier, dependency.Id()); 565 566 if (dependency.MinVersion.has_value()) 567 { 568 WRITE_PROPERTY_IF_EXISTS(out, MinimumVersion, dependency.MinVersion.value().ToString()); 569 } 570 571 out << YAML::EndMap; 572 }); 573 out << YAML::EndSeq; 574 } 575 576 if (dependencies.HasAnyOf(DependencyType::External)) 577 { 578 out << YAML::Key << ExternalDependencies; 579 out << YAML::BeginSeq; 580 dependencies.ApplyToType(DependencyType::External, [&out](Dependency dependency) 581 { 582 out << dependency.Id(); 583 }); 584 out << YAML::EndSeq; 585 } 586 587 out << YAML::EndMap; 588 } 589 590 void ProcessInstallerFields(YAML::Emitter& out, const ManifestInstaller& installer) 591 { 592 WRITE_PROPERTY(out, Architecture, Utility::ToLower(ToString(installer.Arch))); 593 WRITE_PROPERTY(out, InstallerType, InstallerTypeToString(installer.BaseInstallerType)); 594 WRITE_ENUM_PROPERTY_IF_NOT_UNKNOWN(out, NestedInstallerType, InstallerTypeToString(installer.NestedInstallerType), installer.NestedInstallerType, InstallerTypeEnum); 595 WRITE_SHA256_PROPERTY_IF_NOT_EMPTY(out, InstallerSha256, installer.Sha256); 596 WRITE_SHA256_PROPERTY_IF_NOT_EMPTY(out, SignatureSha256, installer.SignatureSha256); 597 WRITE_PROPERTY_IF_EXISTS(out, InstallerUrl, installer.Url); 598 WRITE_PROPERTY_IF_EXISTS(out, MSStoreProductIdentifier, installer.ProductId); 599 600 WRITE_ENUM_PROPERTY_IF_NOT_UNKNOWN(out, Scope, Utility::ToLower(ScopeToString(installer.Scope)), installer.Scope, ScopeEnum); 601 WRITE_PROPERTY_IF_EXISTS(out, InstallerLocale, installer.Locale); 602 WRITE_ENUM_PROPERTY_IF_NOT_UNKNOWN(out, ElevationRequirement, ElevationRequirementToString(installer.ElevationRequirement), installer.ElevationRequirement, ElevationRequirementEnum); 603 WRITE_PROPERTY_IF_EXISTS(out, PackageFamilyName, installer.PackageFamilyName); 604 WRITE_PROPERTY_IF_EXISTS(out, ReleaseDate, installer.ReleaseDate); 605 WRITE_BOOL_PROPERTY(out, InstallerAbortsTerminal, installer.InstallerAbortsTerminal); 606 WRITE_BOOL_PROPERTY(out, InstallLocationRequired, installer.InstallLocationRequired); 607 WRITE_BOOL_PROPERTY(out, RequireExplicitUpgrade, installer.RequireExplicitUpgrade); 608 WRITE_BOOL_PROPERTY(out, DisplayInstallWarnings, installer.DisplayInstallWarnings); 609 WRITE_BOOL_PROPERTY(out, DownloadCommandProhibited, installer.DownloadCommandProhibited); 610 WRITE_BOOL_PROPERTY(out, ArchiveBinariesDependOnPath, installer.ArchiveBinariesDependOnPath); 611 WRITE_PROPERTY_IF_EXISTS(out, MinimumOSVersion, installer.MinOSVersion); 612 WRITE_PROPERTY_IF_EXISTS(out, ProductCode, installer.ProductCode); 613 WRITE_ENUM_PROPERTY_IF_NOT_UNKNOWN(out, UpgradeBehavior, UpdateBehaviorToString(installer.UpdateBehavior), installer.UpdateBehavior, UpdateBehaviorEnum); 614 WRITE_ENUM_PROPERTY_IF_NOT_UNKNOWN(out, RepairBehavior, RepairBehaviorToString(installer.RepairBehavior), installer.RepairBehavior, RepairBehaviorEnum); 615 616 ProcessStringSequence(out, Capabilities, installer.Capabilities); 617 ProcessStringSequence(out, Commands, installer.Commands); 618 ProcessStringSequence(out, FileExtensions, installer.FileExtensions); 619 ProcessStringSequence(out, Protocols, installer.Protocols); 620 ProcessStringSequence(out, RestrictedCapabilities, installer.RestrictedCapabilities); 621 622 ProcessAppsAndFeaturesEntries(out, installer.AppsAndFeaturesEntries); 623 ProcessDependencies(out, installer.Dependencies); 624 ProcessExpectedReturnCodes(out, installer.ExpectedReturnCodes); 625 ProcessInstallerSwitches(out, installer.Switches); 626 ProcessInstallationMetadata(out, installer.InstallationMetadata); 627 ProcessInstallerSuccessCodes(out, installer.InstallerSuccessCodes); 628 ProcessInstallModes(out, installer.InstallModes); 629 ProcessMarkets(out, installer.Markets); 630 ProcessNestedInstallerFiles(out, installer.NestedInstallerFiles); 631 ProcessPlatforms(out, installer.Platform); 632 ProcessUnsupportedArguments(out, installer.UnsupportedArguments); 633 ProcessUnsupportedOSArchitecture(out, installer.UnsupportedOSArchitectures); 634 ProcessAuthentication(out, installer.AuthInfo); 635 } 636 637 void ProcessInstaller(YAML::Emitter& out, const ManifestInstaller& installer) 638 { 639 out << YAML::Key << Installers; 640 out << YAML::BeginSeq; 641 out << YAML::BeginMap; 642 ProcessInstallerFields(out, installer); 643 out << YAML::EndMap; 644 out << YAML::EndSeq; 645 } 646 647 void ProcessLocalizations(YAML::Emitter& out, const std::vector<ManifestLocalization>& localizations) 648 { 649 if (!localizations.empty()) 650 { 651 out << YAML::Key << Localization; 652 out << YAML::BeginSeq; 653 654 for (const auto& localization : localizations) 655 { 656 out << YAML::BeginMap; 657 ProcessLocaleFields(out, localization); 658 out << YAML::EndMap; 659 } 660 661 out << YAML::EndSeq; 662 } 663 } 664 665 void PopulateManifestYamlEmitter(YAML::Emitter& out, const Manifest& manifest, const ManifestInstaller& installer) 666 { 667 // Currently, exporting the yaml only supports outputting a single installer. 668 // TODO: If no single installer is provided, output all installers. 669 out << YAML::BeginMap; 670 WRITE_PROPERTY(out, PackageIdentifier, manifest.Id); 671 WRITE_PROPERTY(out, PackageVersion, manifest.Version); 672 WRITE_PROPERTY_IF_EXISTS(out, Channel, manifest.Channel); 673 WRITE_PROPERTY_IF_EXISTS(out, Moniker, manifest.Moniker); 674 ProcessLocaleFields(out, manifest.DefaultLocalization); 675 ProcessLocalizations(out, manifest.Localizations); 676 ProcessInstaller(out, installer); 677 WRITE_PROPERTY(out, ManifestVersion, manifest.ManifestVersion.ToString()); 678 679 ManifestTypeEnum manifestType = ManifestTypeEnum::Merged; 680 WRITE_PROPERTY(out, ManifestType, ManifestTypeToString(manifestType)); 681 out << YAML::EndMap; 682 } 683 } 684 685 std::string YamlWriter::ManifestToYamlString(const Manifest& manifest, const ManifestInstaller& installer) 686 { 687 YAML::Emitter out; 688 PopulateManifestYamlEmitter(out, manifest, installer); 689 return out.str(); 690 } 691 692 void YamlWriter::OutputYamlFile(const Manifest& manifest, const ManifestInstaller& installer, const std::filesystem::path& out) 693 { 694 const std::filesystem::path& parentDirectory = out.parent_path(); 695 696 if (!std::filesystem::exists(parentDirectory)) 697 { 698 std::filesystem::create_directories(parentDirectory); 699 } 700 else 701 { 702 THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE), !std::filesystem::is_directory(parentDirectory)); 703 } 704 705 YAML::Emitter emitter; 706 PopulateManifestYamlEmitter(emitter, manifest, installer); 707 708 std::ofstream outFileStream(out); 709 emitter.Emit(outFileStream); 710 outFileStream.close(); 711 } 712 }