ShowFlow.cpp (14535B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 4 #include "pch.h" 5 #include "ShowFlow.h" 6 #include <winget/ManifestComparator.h> 7 #include "TableOutput.h" 8 9 using namespace AppInstaller::Repository; 10 using namespace AppInstaller::CLI; 11 using namespace AppInstaller::Utility; 12 using namespace AppInstaller::Utility::literals; 13 14 namespace { 15 16 template <typename String> 17 void ShowSingleLineField(Execution::OutputStream outputStream, AppInstaller::StringResource::StringId label, const String& value, bool indent = false) 18 { 19 if (value.empty()) 20 { 21 return; 22 } 23 if (indent) 24 { 25 outputStream << " "_liv; 26 } 27 outputStream << Execution::ManifestInfoEmphasis << label << ' ' << value << std::endl; 28 } 29 30 template <typename String> 31 void ShowMultiLineField(Execution::OutputStream outputStream, AppInstaller::StringResource::StringId label, const String& value) 32 { 33 if (value.empty()) 34 { 35 return; 36 } 37 /* 38 We need to be able to find and replace within the string.However, we don't want to own the original string 39 Therefore, a copy is created here so we can manipulate it. The memory should be freed again once this method 40 returns and the string is no longer in scope. 41 */ 42 std::string shownValue = value; 43 bool isMultiLine = FindAndReplace(shownValue, "\n", "\n "); 44 outputStream << Execution::ManifestInfoEmphasis << label; 45 if (isMultiLine) 46 { 47 outputStream << std::endl << " "_liv << shownValue << std::endl; 48 } 49 else 50 { 51 outputStream << ' ' << shownValue << std::endl; 52 } 53 } 54 55 template <typename Enumerable> 56 void ShowMultiValueField(Execution::OutputStream outputStream, AppInstaller::StringResource::StringId label, const Enumerable& values) 57 { 58 if (values.empty()) 59 { 60 return; 61 } 62 outputStream << Execution::ManifestInfoEmphasis << label << std::endl; 63 for (const auto& value : values) 64 { 65 outputStream << " "_liv << value << std::endl; 66 } 67 } 68 69 void ShowAgreements(Execution::OutputStream outputStream, const std::vector<AppInstaller::Manifest::Agreement>& agreements) { 70 71 if (agreements.empty()) { 72 return; 73 } 74 75 outputStream << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelAgreements << std::endl; 76 for (const auto& agreement : agreements) { 77 78 if (!agreement.Label.empty()) 79 { 80 outputStream << " "_liv << Execution::ManifestInfoEmphasis << agreement.Label << ": "_liv; 81 } 82 83 if (!agreement.AgreementText.empty()) 84 { 85 outputStream << agreement.AgreementText << std::endl; 86 } 87 88 if (!agreement.AgreementUrl.empty()) 89 { 90 outputStream << agreement.AgreementUrl << std::endl; 91 } 92 } 93 } 94 } 95 96 namespace AppInstaller::CLI::Workflow 97 { 98 void ShowAgreementsInfo(Execution::Context& context) 99 { 100 const auto& manifest = context.Get<Execution::Data::Manifest>(); 101 auto info = context.Reporter.Info(); 102 103 ShowSingleLineField(info, Resource::String::ShowLabelVersion, manifest.Version); 104 ShowSingleLineField(info, Resource::String::ShowLabelPublisher, manifest.CurrentLocalization.Get<Manifest::Localization::Publisher>()); 105 ShowSingleLineField(info, Resource::String::ShowLabelPublisherUrl, manifest.CurrentLocalization.Get<Manifest::Localization::PublisherUrl>()); 106 ShowSingleLineField(info, Resource::String::ShowLabelPublisherSupportUrl, manifest.CurrentLocalization.Get<Manifest::Localization::PublisherSupportUrl>()); 107 ShowSingleLineField(info, Resource::String::ShowLabelAuthor, manifest.CurrentLocalization.Get<Manifest::Localization::Author>()); 108 ShowSingleLineField(info, Resource::String::ShowLabelPackageUrl, manifest.CurrentLocalization.Get<Manifest::Localization::PackageUrl>()); 109 ShowSingleLineField(info, Resource::String::ShowLabelLicense, manifest.CurrentLocalization.Get<Manifest::Localization::License>()); 110 ShowSingleLineField(info, Resource::String::ShowLabelLicenseUrl, manifest.CurrentLocalization.Get<Manifest::Localization::LicenseUrl>()); 111 ShowSingleLineField(info, Resource::String::ShowLabelPrivacyUrl, manifest.CurrentLocalization.Get<Manifest::Localization::PrivacyUrl>()); 112 ShowSingleLineField(info, Resource::String::ShowLabelCopyright, manifest.CurrentLocalization.Get<Manifest::Localization::Copyright>()); 113 ShowSingleLineField(info, Resource::String::ShowLabelCopyrightUrl, manifest.CurrentLocalization.Get<Manifest::Localization::CopyrightUrl>()); 114 ShowSingleLineField(info, Resource::String::ShowLabelPurchaseUrl, manifest.CurrentLocalization.Get<Manifest::Localization::PurchaseUrl>()); 115 ShowAgreements(info, manifest.CurrentLocalization.Get<Manifest::Localization::Agreements>()); 116 117 } 118 119 void ShowManifestInfo(Execution::Context& context) 120 { 121 context << ShowPackageInfo << ShowInstallerInfo; 122 } 123 124 void ShowPackageInfo(Execution::Context& context) 125 { 126 const auto& manifest = context.Get<Execution::Data::Manifest>(); 127 auto info = context.Reporter.Info(); 128 // Get description from manifest so we can see if it is empty later 129 auto description = manifest.CurrentLocalization.Get<Manifest::Localization::Description>(); 130 131 // TODO: Come up with a prettier format 132 ShowSingleLineField(info, Resource::String::ShowLabelVersion, manifest.Version); 133 ShowSingleLineField(info, Resource::String::ShowLabelPublisher, manifest.CurrentLocalization.Get<Manifest::Localization::Publisher>()); 134 ShowSingleLineField(info, Resource::String::ShowLabelPublisherUrl, manifest.CurrentLocalization.Get<Manifest::Localization::PublisherUrl>()); 135 ShowSingleLineField(info, Resource::String::ShowLabelPublisherSupportUrl, manifest.CurrentLocalization.Get<Manifest::Localization::PublisherSupportUrl>()); 136 ShowSingleLineField(info, Resource::String::ShowLabelAuthor, manifest.CurrentLocalization.Get<Manifest::Localization::Author>()); 137 ShowSingleLineField(info, Resource::String::ShowLabelMoniker, manifest.Moniker); 138 ShowMultiLineField(info, Resource::String::ShowLabelDescription, description.empty() ? manifest.CurrentLocalization.Get<Manifest::Localization::ShortDescription>() : description); 139 ShowSingleLineField(info, Resource::String::ShowLabelPackageUrl, manifest.CurrentLocalization.Get<Manifest::Localization::PackageUrl>()); 140 ShowSingleLineField(info, Resource::String::ShowLabelLicense, manifest.CurrentLocalization.Get<Manifest::Localization::License>()); 141 ShowSingleLineField(info, Resource::String::ShowLabelLicenseUrl, manifest.CurrentLocalization.Get<Manifest::Localization::LicenseUrl>()); 142 ShowSingleLineField(info, Resource::String::ShowLabelPrivacyUrl, manifest.CurrentLocalization.Get<Manifest::Localization::PrivacyUrl>()); 143 ShowSingleLineField(info, Resource::String::ShowLabelCopyright, manifest.CurrentLocalization.Get<Manifest::Localization::Copyright>()); 144 ShowSingleLineField(info, Resource::String::ShowLabelCopyrightUrl, manifest.CurrentLocalization.Get<Manifest::Localization::CopyrightUrl>()); 145 ShowMultiLineField(info, Resource::String::ShowLabelReleaseNotes, manifest.CurrentLocalization.Get<Manifest::Localization::ReleaseNotes>()); 146 ShowSingleLineField(info, Resource::String::ShowLabelReleaseNotesUrl, manifest.CurrentLocalization.Get<Manifest::Localization::ReleaseNotesUrl>()); 147 ShowSingleLineField(info, Resource::String::ShowLabelPurchaseUrl, manifest.CurrentLocalization.Get<Manifest::Localization::PurchaseUrl>()); 148 ShowMultiLineField(info, Resource::String::ShowLabelInstallationNotes, manifest.CurrentLocalization.Get<Manifest::Localization::InstallationNotes>()); 149 const auto& documentations = manifest.CurrentLocalization.Get<Manifest::Localization::Documentations>(); 150 if (!documentations.empty()) 151 { 152 context.Reporter.Info() << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelDocumentation << std::endl; 153 for (const auto& documentation : documentations) 154 { 155 if (!documentation.DocumentUrl.empty()) 156 { 157 info << " "_liv; 158 if (!documentation.DocumentLabel.empty()) 159 { 160 info << Execution::ManifestInfoEmphasis << documentation.DocumentLabel << ": "_liv; 161 } 162 163 info << documentation.DocumentUrl << std::endl; 164 } 165 } 166 } 167 ShowMultiValueField(info, Resource::String::ShowLabelTags, manifest.CurrentLocalization.Get<Manifest::Localization::Tags>()); 168 ShowAgreements(info, manifest.CurrentLocalization.Get<Manifest::Localization::Agreements>()); 169 } 170 171 void ShowInstallerInfo(Execution::Context& context) 172 { 173 const auto& installer = context.Get<Execution::Data::Installer>(); 174 auto info = context.Reporter.Info(); 175 176 info << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstaller << std::endl; 177 if (installer) 178 { 179 Manifest::InstallerTypeEnum effectiveInstallerType = installer->EffectiveInstallerType(); 180 Manifest::InstallerTypeEnum baseInstallerType = installer->BaseInstallerType; 181 std::string shownInstallerType; 182 shownInstallerType = Manifest::InstallerTypeToString(effectiveInstallerType); 183 if (effectiveInstallerType != baseInstallerType) 184 { 185 shownInstallerType += " ("_liv; 186 shownInstallerType += Manifest::InstallerTypeToString(baseInstallerType); 187 shownInstallerType += ')'; 188 } 189 ShowSingleLineField(info, Resource::String::ShowLabelInstallerType, shownInstallerType, true); 190 ShowSingleLineField(info, Resource::String::ShowLabelInstallerLocale, installer->Locale, true); 191 ShowSingleLineField(info, Resource::String::ShowLabelInstallerUrl, installer->Url, true); 192 ShowSingleLineField(info, Resource::String::ShowLabelInstallerSha256, (installer->Sha256.empty()) ? "" : Utility::SHA256::ConvertToString(installer->Sha256), true); 193 ShowSingleLineField(info, Resource::String::ShowLabelInstallerProductId, installer->ProductId, true); 194 ShowSingleLineField(info, Resource::String::ShowLabelInstallerReleaseDate, installer->ReleaseDate, true); 195 ShowSingleLineField(info, Resource::String::ShowLabelInstallerOfflineDistributionSupported, Utility::ConvertBoolToString(!installer->DownloadCommandProhibited), true); 196 197 const auto& dependencies = installer->Dependencies; 198 199 if (dependencies.HasAny()) 200 { 201 info << Execution::ManifestInfoEmphasis << " "_liv << Resource::String::ShowLabelDependencies << ' ' << std::endl; 202 203 if (dependencies.HasAnyOf(Manifest::DependencyType::WindowsFeature)) 204 { 205 info << " - "_liv << Resource::String::ShowLabelWindowsFeaturesDependencies << ' ' << std::endl; 206 dependencies.ApplyToType(Manifest::DependencyType::WindowsFeature, [&info](Manifest::Dependency dependency) {info << " "_liv << dependency.Id() << std::endl; }); 207 } 208 209 if (dependencies.HasAnyOf(Manifest::DependencyType::WindowsLibrary)) 210 { 211 info << " - "_liv << Resource::String::ShowLabelWindowsLibrariesDependencies << ' ' << std::endl; 212 dependencies.ApplyToType(Manifest::DependencyType::WindowsLibrary, [&info](Manifest::Dependency dependency) {info << " "_liv << dependency.Id() << std::endl; }); 213 } 214 215 if (dependencies.HasAnyOf(Manifest::DependencyType::Package)) 216 { 217 info << " - "_liv << Resource::String::ShowLabelPackageDependencies << ' ' << std::endl; 218 dependencies.ApplyToType(Manifest::DependencyType::Package, [&info](Manifest::Dependency dependency) 219 { 220 info << " "_liv << dependency.Id(); 221 if (dependency.MinVersion) 222 { 223 info << " [>= " << dependency.MinVersion.value().ToString() << "]"; 224 } 225 info << std::endl; 226 }); 227 } 228 229 if (dependencies.HasAnyOf(Manifest::DependencyType::External)) 230 { 231 info << " - "_liv << Resource::String::ShowLabelExternalDependencies << ' ' << std::endl; 232 dependencies.ApplyToType(Manifest::DependencyType::External, [&info](Manifest::Dependency dependency) {info << " "_liv << dependency.Id() << std::endl; }); 233 } 234 } 235 } 236 else 237 { 238 context.Reporter.Warn() << " "_liv << Resource::String::NoApplicableInstallers << std::endl; 239 } 240 } 241 242 void ShowManifestVersion(Execution::Context& context) 243 { 244 const auto& manifest = context.Get<Execution::Data::Manifest>(); 245 Execution::TableOutput<2> table(context.Reporter, { Resource::String::ShowVersion, Resource::String::ShowChannel }); 246 table.OutputLine({ manifest.Version, manifest.Channel }); 247 table.Complete(); 248 } 249 250 void GetManifest::operator()(Execution::Context& context) const 251 { 252 if (context.Args.Contains(Execution::Args::Type::Manifest)) 253 { 254 context << 255 GetManifestFromArg; 256 } 257 else 258 { 259 context << 260 OpenSource() << 261 SearchSourceForSingle << 262 HandleSearchResultFailures << 263 EnsureOneMatchFromSearchResult(OperationType::Show) << 264 GetManifestFromPackage(m_considerPins); 265 } 266 } 267 }