winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

RepositorySearch.h (17440B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #pragma once
      4 #include <AppInstallerErrors.h>
      5 #include <AppInstallerStrings.h>
      6 #include <AppInstallerVersions.h>
      7 #include <winget/LocIndependent.h>
      8 #include <winget/Manifest.h>
      9 
     10 #include <map>
     11 #include <memory>
     12 #include <optional>
     13 #include <string>
     14 #include <string_view>
     15 #include <vector>
     16 
     17 
     18 namespace AppInstaller::Repository
     19 {
     20     struct Source;
     21 
     22     // The type of matching to perform during a search.
     23     // The values must be declared in order of preference in search results.
     24     enum class MatchType
     25     {
     26         Exact = 0,
     27         CaseInsensitive,
     28         StartsWith,
     29         Fuzzy,
     30         Substring,
     31         FuzzySubstring,
     32         Wildcard,
     33     };
     34 
     35     // Convert a MatchType to a string.
     36     std::string_view ToString(MatchType type);
     37 
     38     // The field to match on.
     39     // The values must be declared in order of preference in search results.
     40     enum class PackageMatchField
     41     {
     42         Id = 0,
     43         Name,
     44         Moniker,
     45         Command,
     46         Tag,
     47         PackageFamilyName,
     48         ProductCode,
     49         UpgradeCode,
     50         NormalizedNameAndPublisher,
     51         Market,
     52         Unknown = 9999
     53     };
     54 
     55     // Convert a PackageMatchField to a string.
     56     std::string_view ToString(PackageMatchField matchField);
     57 
     58     // Parse a string to PackageMatchField.
     59     PackageMatchField StringToPackageMatchField(std::string_view field);
     60 
     61     // A single match to be performed during a search.
     62     struct RequestMatch
     63     {
     64         MatchType Type;
     65         Utility::NormalizedString Value;
     66         std::optional<Utility::NormalizedString> Additional;
     67 
     68         RequestMatch(MatchType t) : Type(t) {}
     69         RequestMatch(MatchType t, Utility::NormalizedString& v) : Type(t), Value(v) {}
     70         RequestMatch(MatchType t, const Utility::NormalizedString& v) : Type(t), Value(v) {}
     71         RequestMatch(MatchType t, Utility::NormalizedString&& v) : Type(t), Value(std::move(v)) {}
     72         RequestMatch(MatchType t, std::string_view v1, std::string_view v2) : Type(t), Value(v1), Additional(Utility::NormalizedString{ v2 }) {}
     73     };
     74 
     75     // A match on a specific field to be performed during a search.
     76     struct PackageMatchFilter : public RequestMatch
     77     {
     78         PackageMatchField Field;
     79 
     80         PackageMatchFilter(PackageMatchField f, MatchType t) : RequestMatch(t), Field(f) { EnsureRequiredValues(); }
     81         PackageMatchFilter(PackageMatchField f, MatchType t, Utility::NormalizedString& v) : RequestMatch(t, v), Field(f) { EnsureRequiredValues(); }
     82         PackageMatchFilter(PackageMatchField f, MatchType t, const Utility::NormalizedString& v) : RequestMatch(t, v), Field(f) { EnsureRequiredValues(); }
     83         PackageMatchFilter(PackageMatchField f, MatchType t, Utility::NormalizedString&& v) : RequestMatch(t, std::move(v)), Field(f) { EnsureRequiredValues(); }
     84         PackageMatchFilter(PackageMatchField f, MatchType t, std::string_view v1, std::string_view v2) : RequestMatch(t, v1, v2), Field(f) { EnsureRequiredValues(); }
     85 
     86     protected:
     87         void EnsureRequiredValues()
     88         {
     89             // Ensure that the second value always exists when it should
     90             if (Field == PackageMatchField::NormalizedNameAndPublisher && !Additional)
     91             {
     92                 Additional = Utility::NormalizedString{};
     93             }
     94         }
     95     };
     96 
     97     // The search purpose of the search request.
     98     enum class SearchPurpose
     99     {
    100         // Default search purpose.
    101         Default,
    102         // The result is used for correlation to an installed package.
    103         CorrelationToInstalled,
    104         // The result is used for correlation to an available package.
    105         CorrelationToAvailable,
    106     };
    107 
    108     // Container for data used to filter the available manifests in a source.
    109     // It can be thought of as:
    110     //  (Query || Inclusions...) && Filters...
    111     // If Query and Inclusions are both empty, the starting data set will be the entire database.
    112     //  Everything && Filters...
    113     struct SearchRequest
    114     {
    115         // The generic query matches against a source defined set of fields.
    116         std::optional<RequestMatch> Query;
    117 
    118         // Specific fields used to include more data.
    119         // If Query is defined, this can add more rows afterward.
    120         // If Query is not defined, this is the only set of data included.
    121         std::vector<PackageMatchFilter> Inclusions;
    122 
    123         // Specific fields used to filter the data further.
    124         std::vector<PackageMatchFilter> Filters;
    125 
    126         // The search purpose of the search request.
    127         SearchPurpose Purpose = SearchPurpose::Default;
    128 
    129         // The maximum number of results to return.
    130         // The default of 0 will place no limit.
    131         size_t MaximumResults{};
    132 
    133         // Returns a value indicating whether this request is for all available data.
    134         bool IsForEverything() const;
    135 
    136         // Returns a string summarizing the search request.
    137         std::string ToString() const;
    138     };
    139 
    140     // A property of a package version.
    141     enum class PackageVersionProperty
    142     {
    143         Id,
    144         Name,
    145         SourceIdentifier,
    146         SourceName,
    147         Version,
    148         Channel,
    149         RelativePath,
    150         // Returned in hexadecimal format
    151         ManifestSHA256Hash,
    152         Publisher,
    153         ArpMinVersion,
    154         ArpMaxVersion,
    155         Moniker,
    156     };
    157 
    158     // A property of a package version that can have multiple values.
    159     enum class PackageVersionMultiProperty
    160     {
    161         // The package family names (PFN) associated with the package version
    162         PackageFamilyName,
    163         // The product codes associated with the package version.
    164         ProductCode,
    165         // The upgrade codes associated with the package version.
    166         UpgradeCode,
    167         // TODO: Fully implement these 3; the data is not yet in the index source (name and publisher are hacks and locale is not present)
    168         //       For future usage of these, be aware of the limitations.
    169         // The package names for the version; ideally these would match in number and order with both Publisher and Locale.
    170         Name,
    171         // The publisher values for the version; ideally these would match in number and order with both Name and Locale.
    172         Publisher,
    173         // The locale of the matching Name and Publisher values; ideally these would match in number and order with both Name and Publisher.
    174         // May be empty if there is only a single value for Name and Publisher.
    175         Locale,
    176         // The tags associated with a package version.
    177         Tag,
    178         // The commands associated with a package version.
    179         Command,
    180     };
    181 
    182     // A metadata item of a package version. These values are persisted and cannot be changed.
    183     enum class PackageVersionMetadata : int32_t
    184     {
    185         // The InstallerType of an installed package
    186         InstalledType,
    187         // The Scope of an installed package
    188         InstalledScope,
    189         // The system path where the package is installed
    190         InstalledLocation,
    191         // The standard uninstall command; which may be interactive
    192         StandardUninstallCommand,
    193         // An uninstall command that should be non-interactive
    194         SilentUninstallCommand,
    195         // The publisher of the package
    196         Publisher,
    197         // The locale of the package
    198         InstalledLocale,
    199         // The write time for the given version
    200         TrackingWriteTime,
    201         // The Architecture of an installed package
    202         InstalledArchitecture,
    203         // The pinned state of the installed package
    204         // As a package can have multiple pins for multiple sources, this is the strictest pin
    205         PinnedState,
    206         // The Architecture of user intent
    207         UserIntentArchitecture,
    208         // The locale of user intent
    209         UserIntentLocale,
    210         // The standard modify command; which may be interactive
    211         StandardModifyCommand,
    212         // No Modify flag
    213         NoModify,
    214         // No Repair flag
    215         NoRepair,
    216     };
    217 
    218     // Convert a PackageVersionMetadata to a string.
    219     std::string_view ToString(PackageVersionMetadata pvm);
    220 
    221     // A single package version.
    222     struct IPackageVersion
    223     {
    224         using Metadata = std::map<PackageVersionMetadata, std::string>;
    225 
    226         virtual ~IPackageVersion() = default;
    227 
    228         // Gets a property of this package version.
    229         virtual Utility::LocIndString GetProperty(PackageVersionProperty property) const = 0;
    230 
    231         // Gets a property of this package version that can have multiple values.
    232         virtual std::vector<Utility::LocIndString> GetMultiProperty(PackageVersionMultiProperty property) const = 0;
    233 
    234         // Gets the manifest of this package version.
    235         virtual Manifest::Manifest GetManifest() = 0;
    236 
    237         // Gets the source where this package version is from.
    238         virtual Source GetSource() const = 0;
    239 
    240         // Gets any metadata associated with this package version.
    241         // Primarily stores data on installed packages.
    242         virtual Metadata GetMetadata() const = 0;
    243     };
    244 
    245     // A key to identify a package version within a package.
    246     struct PackageVersionKey
    247     {
    248         PackageVersionKey() = default;
    249 
    250         PackageVersionKey(std::string sourceId, Utility::NormalizedString version, Utility::NormalizedString channel) :
    251             SourceId(std::move(sourceId)), Version(std::move(version)), Channel(std::move(channel)) {}
    252 
    253         // The source id that this version came from.
    254         std::string SourceId;
    255 
    256         // The version.
    257         Utility::NormalizedString Version;
    258 
    259         // The channel.
    260         Utility::NormalizedString Channel;
    261 
    262         bool operator<(const PackageVersionKey& other) const
    263         {
    264             // Sort using only the version and channel.
    265             // The order for the sources depends on the context.
    266             return Utility::VersionAndChannel({ Version }, { Channel }) < Utility::VersionAndChannel({ other.Version }, { other.Channel });
    267         }
    268 
    269         // Determines if a well defined key (this one) is matched by the provided key.
    270         // The provided key may use empty values to indicate no specific matching requirements.
    271         bool IsMatch(const PackageVersionKey& other) const;
    272 
    273         // Determines if this version is the simple "latest" targeting version (version and channel are both empty).
    274         bool IsDefaultLatest() const;
    275     };
    276 
    277     // A property of a package.
    278     enum class PackageProperty
    279     {
    280         Id,
    281         Name,
    282     };
    283 
    284     // A property of a package that can have multiple values.
    285     enum class PackageMultiProperty
    286     {
    287         // The package family names (PFN) associated with the package.
    288         PackageFamilyName,
    289         // The product codes associated with the package.
    290         ProductCode,
    291         // The upgrade codes associated with the package.
    292         UpgradeCode,
    293         // The normalized names for the package.
    294         NormalizedName,
    295         // The normalized publisher names for the package.
    296         NormalizedPublisher,
    297         // The tags associated with the package.
    298         Tag,
    299         // The commands associated with the package.
    300         Command,
    301     };
    302 
    303     // Maps the package multi-property value to its package version multi-property value for internal use.
    304     PackageVersionMultiProperty PackageMultiPropertyToPackageVersionMultiProperty(PackageMultiProperty property);
    305 
    306     // To allow for runtime casting from IPackage to the specific types, this enum contains all of the IPackage implementations.
    307     enum class IPackageType
    308     {
    309         TestPackage,
    310         RestPackage,
    311         SQLitePackage1,
    312         SQLitePackage2,
    313         PinnablePackage,
    314         CompositeInstalledPackage,
    315     };
    316 
    317     // Contains a collection of package versions.
    318     struct IPackageVersionCollection
    319     {
    320         virtual ~IPackageVersionCollection() = default;
    321 
    322         // Gets all versions of this package.
    323         // The versions will be returned in sorted, descending order.
    324         //  Ex. { 4, 3, 2, 1 }
    325         virtual std::vector<PackageVersionKey> GetVersionKeys() const = 0;
    326 
    327         // Gets a specific version of this package.
    328         virtual std::shared_ptr<IPackageVersion> GetVersion(const PackageVersionKey& versionKey) const = 0;
    329 
    330         // A convenience method to effectively call `GetVersion(GetVersionKeys[0])`.
    331         virtual std::shared_ptr<IPackageVersion> GetLatestVersion() const = 0;
    332     };
    333 
    334     // Contains information about a package and its versions from a single source.
    335     struct IPackage : public IPackageVersionCollection
    336     {
    337         virtual ~IPackage() = default;
    338 
    339         // Gets a property of this package.
    340         virtual Utility::LocIndString GetProperty(PackageProperty property) const = 0;
    341 
    342         // Gets a property of this package that can have multiple values.
    343         virtual std::vector<Utility::LocIndString> GetMultiProperty(PackageMultiProperty property) const = 0;
    344 
    345         // Gets the source that this package is from.
    346         virtual Source GetSource() const = 0;
    347 
    348         // Determines if the given IPackage refers to the same package as this one.
    349         virtual bool IsSame(const IPackage*) const = 0;
    350 
    351         // Gets this object as the requested type, or null if it is not the requested type.
    352         virtual const void* CastTo(IPackageType type) const = 0;
    353     };
    354 
    355     // Contains information about the graph of packages related to a search.
    356     struct ICompositePackage
    357     {
    358         virtual ~ICompositePackage() = default;
    359 
    360         // Gets a property of this package result.
    361         virtual Utility::LocIndString GetProperty(PackageProperty property) const = 0;
    362 
    363         // Gets the installed package information.
    364         virtual std::shared_ptr<IPackage> GetInstalled() = 0;
    365 
    366         // Gets all of the available packages for this result.
    367         // There will be at most one package per source in this list.
    368         virtual std::vector<std::shared_ptr<IPackage>> GetAvailable() = 0;
    369     };
    370 
    371     // Does the equivalent of a dynamic_cast, but without it to allow RTTI to be disabled.
    372     // Example usage:
    373     //  bool IsSame(const IPackage* other) const override
    374     //  {
    375     //      const MyPackage* otherAsMyType = PackageCast<const MyPackage*>(other);
    376     //      ...
    377     //  }
    378     template <typename PackageType>
    379     PackageType PackageCast(const IPackage* package)
    380     {
    381         static_assert(std::is_pointer_v<PackageType>, "The target type of the PackageCast must be a pointer; use the same type as if this were a dynamic_cast.");
    382         if (!package)
    383         {
    384             return nullptr;
    385         }
    386         using ActualPackageType = std::remove_pointer_t<std::remove_cv_t<PackageType>>;
    387         return reinterpret_cast<PackageType>(package->CastTo(ActualPackageType::PackageType));
    388     }
    389 
    390     // A single result from the search.
    391     struct ResultMatch
    392     {
    393         // The package found by the search request.
    394         std::shared_ptr<ICompositePackage> Package;
    395 
    396         // The highest order field on which the package matched the search.
    397         PackageMatchFilter MatchCriteria;
    398 
    399         ResultMatch(std::shared_ptr<ICompositePackage> p, PackageMatchFilter f) : Package(std::move(p)), MatchCriteria(std::move(f)) {}
    400     };
    401 
    402     // Search result data.
    403     struct SearchResult
    404     {
    405         // Contains a failure from the Search.
    406         struct Failure
    407         {
    408             std::string SourceName;
    409             std::exception_ptr Exception;
    410         };
    411 
    412         // The full set of results from the search.
    413         std::vector<ResultMatch> Matches;
    414 
    415         // If true, the results were truncated by the given SearchRequest::MaximumResults.
    416         bool Truncated = false;
    417 
    418         // Present if the Search was against a composite source and one failed, but not limited to that scenario.
    419         std::vector<Failure> Failures;
    420     };
    421 
    422     struct UnsupportedRequestException : public wil::ResultException
    423     {
    424         UnsupportedRequestException() : wil::ResultException(APPINSTALLER_CLI_ERROR_UNSUPPORTED_SOURCE_REQUEST) {}
    425 
    426         UnsupportedRequestException(
    427             std::vector<std::string> unsupportedPackageMatchFields,
    428             std::vector<std::string> requiredPackageMatchFields,
    429             std::vector<std::string> unsupportedQueryParameters,
    430             std::vector<std::string> requiredQueryParameters) :
    431             wil::ResultException(APPINSTALLER_CLI_ERROR_UNSUPPORTED_SOURCE_REQUEST),
    432             UnsupportedPackageMatchFields(std::move(unsupportedPackageMatchFields)), RequiredPackageMatchFields(std::move(requiredPackageMatchFields)),
    433             UnsupportedQueryParameters(std::move(unsupportedQueryParameters)), RequiredQueryParameters(std::move(requiredQueryParameters)) {}
    434 
    435         std::vector<std::string> UnsupportedPackageMatchFields;
    436         std::vector<std::string> RequiredPackageMatchFields;
    437         std::vector<std::string> UnsupportedQueryParameters;
    438         std::vector<std::string> RequiredQueryParameters;
    439 
    440         const char* what() const noexcept override;
    441 
    442     private:
    443         mutable std::string m_whatMessage;
    444     };
    445 }