InstallerMetadataCollectionContext.h (7806B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 5 #include <AppInstallerVersions.h> 6 #include <winget/Manifest.h> 7 #include <winget/JsonUtil.h> 8 #include <winget/ThreadGlobals.h> 9 #include <winget/ARPCorrelation.h> 10 #include <winget/InstalledFilesCorrelation.h> 11 #include <winget/IconExtraction.h> 12 13 #include <filesystem> 14 #include <map> 15 #include <memory> 16 #include <optional> 17 #include <ostream> 18 #include <string> 19 #include <string_view> 20 21 namespace AppInstaller::Repository::Metadata 22 { 23 // The overall metadata that we collect. 24 struct ProductMetadata 25 { 26 ProductMetadata() = default; 27 28 // Removes all stored data. 29 void Clear(); 30 31 // Load the metadata from an existing JSON blob. 32 void FromJson(const web::json::value& json); 33 34 // Create a JSON value for the metadata using the given schema version. 35 web::json::value ToJson(const Utility::Version& schemaVersion, size_t maximumSizeInBytes); 36 37 // Copies the metadata from the source. If the given submission identifier does not match 38 // the source, it's data is moved to historical. 39 void CopyFrom(const ProductMetadata& source, std::string_view submissionIdentifier); 40 41 // The installer specific metadata that we collect. 42 struct InstallerMetadata 43 { 44 friend ProductMetadata; 45 46 // 1.0 47 std::string SubmissionIdentifier; 48 std::vector<Manifest::AppsAndFeaturesEntry> AppsAndFeaturesEntries; 49 50 // 1.1 51 // If Scope value is empty, the value is not set before. If the value is Unknown, a conflicting value is encountered. 52 std::string Scope; 53 54 // 1.2 55 // If std::nullopt, the value is not set before. If the value is empty(i.e. !HasData()), a conflicting value is encountered. 56 std::optional<Manifest::InstallationMetadataInfo> InstalledFiles; 57 // If std::nullopt, the value is not set before. If the vector is empty, conflicting values are encountered. 58 std::optional<std::vector<Correlation::InstalledStartupLinkFile>> StartupLinkFiles; 59 // Extracted icons 60 std::vector<ExtractedIconInfo> Icons; 61 }; 62 63 // Metadata from previous product revisions. 64 struct HistoricalMetadata 65 { 66 // 1.0 67 Utility::Version ProductVersionMin; 68 Utility::Version ProductVersionMax; 69 std::set<std::string> Names; 70 std::set<std::string> Publishers; 71 std::set<std::string> ProductCodes; 72 std::set<std::string> UpgradeCodes; 73 }; 74 75 // 1.0 76 Utility::Version SchemaVersion; 77 Utility::Version ProductVersionMin; 78 Utility::Version ProductVersionMax; 79 // Map from installer hash to metadata 80 std::map<std::string, InstallerMetadata> InstallerMetadataMap; 81 std::vector<HistoricalMetadata> HistoricalMetadataList; 82 83 private: 84 void FromJson_1_N(const web::json::value& json); 85 web::json::value ToJson_1_N(); 86 87 // Removes the historical data with the oldest version. 88 // Returns true if something was removed; false it not. 89 bool DropOldestHistoricalData(); 90 }; 91 92 // Contains the functions and data used for collecting metadata from installers. 93 struct InstallerMetadataCollectionContext 94 { 95 InstallerMetadataCollectionContext(); 96 InstallerMetadataCollectionContext( 97 std::unique_ptr<Correlation::ARPCorrelationData> correlationData, 98 std::unique_ptr<Correlation::InstalledFilesCorrelation> installedFilesCorrelation, 99 const std::wstring& json); 100 101 InstallerMetadataCollectionContext(const InstallerMetadataCollectionContext&) = delete; 102 InstallerMetadataCollectionContext& operator=(const InstallerMetadataCollectionContext&) = delete; 103 104 InstallerMetadataCollectionContext(InstallerMetadataCollectionContext&&) = default; 105 InstallerMetadataCollectionContext& operator=(InstallerMetadataCollectionContext&&) = default; 106 107 // Create from various forms of JSON input to prevent type collisions on constructor. 108 static std::unique_ptr<InstallerMetadataCollectionContext> FromFile(const std::filesystem::path& file, const std::filesystem::path& logFile); 109 static std::unique_ptr<InstallerMetadataCollectionContext> FromURI(std::wstring_view uri, const std::filesystem::path& logFile); 110 static std::unique_ptr<InstallerMetadataCollectionContext> FromJSON(const std::wstring& json, const std::filesystem::path& logFile); 111 112 // Completes the collection, writing to the given location. 113 void Complete(const std::filesystem::path& output); 114 115 // Completes the collection, writing to the given location. 116 void Complete(std::ostream& output); 117 118 static std::wstring Merge(const std::wstring& json, size_t maximumSizeInBytes, const std::filesystem::path& logFile); 119 120 private: 121 // Initializes the context runtime, including the log file if provided. 122 static std::unique_ptr<ThreadLocalStorage::PreviousThreadGlobals> InitializeLogging(ThreadLocalStorage::WingetThreadGlobals& threadGlobals, const std::filesystem::path& logFile); 123 std::unique_ptr<ThreadLocalStorage::PreviousThreadGlobals> InitializeLogging(const std::filesystem::path& logFile); 124 125 // Sets the collection context input and the preinstall state. 126 void InitializePreinstallState(const std::wstring& json); 127 128 // Creates the output ProductMetadata and diagnostics objects for output 129 void ComputeOutputData(); 130 131 // Callers should set the thread globals before calling this. 132 void CompleteWithThreadGlobalsSet(std::ostream& output); 133 134 // Parse version 1.0 of input JSON 135 void ParseInputJson_1_0(web::json::value& input); 136 137 // Create version 1.0 of output JSON 138 web::json::value CreateOutputJson_1_0(); 139 140 // Determines whether an error has occurred in the context. 141 bool ContainsError() const; 142 143 // Collects information from the exception for error reporting. 144 void CollectErrorDataFromException(std::exception_ptr exception); 145 146 // Create version 1.0 of error JSON 147 web::json::value CreateErrorJson_1_0(); 148 149 // Merge using merge input version 1.0 150 static web::json::value Merge_1_0(web::json::value& input, size_t maximumSizeInBytes); 151 152 ThreadLocalStorage::WingetThreadGlobals m_threadGlobals; 153 154 // Parsed input 155 Utility::Version m_inputVersion; 156 Utility::Version m_supportedMetadataVersion; 157 ProductMetadata m_currentMetadata; 158 web::json::value m_submissionData; 159 std::string m_submissionIdentifier; 160 std::string m_installerHash; 161 Manifest::Manifest m_incomingManifest; 162 163 std::unique_ptr<Correlation::ARPCorrelationData> m_correlationData; 164 std::unique_ptr<Correlation::InstalledFilesCorrelation> m_installedFilesCorrelation; 165 166 // Output data 167 enum class OutputStatus 168 { 169 // Version 1.0 status values 170 Unknown, 171 Success, 172 Error, 173 LowConfidence, 174 }; 175 176 // Convert status to a JSON string value 177 static utility::string_t ToString(OutputStatus status); 178 179 OutputStatus m_outputStatus = OutputStatus::Unknown; 180 ProductMetadata m_outputMetadata; 181 web::json::value m_outputDiagnostics; 182 183 // Error data storage 184 HRESULT m_errorHR = S_OK; 185 std::string m_errorText; 186 }; 187 }