winget-cli

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

AppInstallerVersions.h (12158B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #pragma once
      4 #include <string>
      5 #include <string_view>
      6 #include <vector>
      7 
      8 namespace AppInstaller::Utility
      9 {
     10     using namespace std::string_view_literals;
     11 
     12     // Creates a comparable version object from a string.
     13     // Versions are parsed by:
     14     //  1. Parse approximate comparator sign if applicable
     15     //  2. Splitting the string based on the given splitChars (or DefaultSplitChars)
     16     //  3. Parsing a leading, positive integer from each split part
     17     //  4. Saving any remaining, non-digits as a supplemental value
     18     //
     19     // Versions are compared by:
     20     //  for each part in each version
     21     //      if one side has no more parts, perform the remaining comparisons against an empty part
     22     //      if integers not equal, return comparison of integers
     23     //      else if only one side has a non-empty string part, it is less
     24     //      else if string parts not equal, return comparison of strings
     25     //  if each part has been compared, use approximate comparator if applicable
     26     //
     27     //  Note: approximate to another approximate version is invalid.
     28     //        approximate to Unknown is invalid.
     29     struct Version
     30     {
     31         // Used in approximate version to indicate the relation to the base version.
     32         enum class ApproximateComparator
     33         {
     34             None,
     35             LessThan,
     36             GreaterThan,
     37         };
     38 
     39         // The default characters to split a version string on.
     40         constexpr static std::string_view DefaultSplitChars = "."sv;
     41 
     42         Version() = default;
     43 
     44         Version(const std::string& version, std::string_view splitChars = DefaultSplitChars) :
     45             Version(std::string(version), splitChars) {}
     46         Version(std::string&& version, std::string_view splitChars = DefaultSplitChars);
     47 
     48         // Constructing an approximate version from a base version.
     49         Version(Version baseVersion, ApproximateComparator approximateComparator);
     50 
     51         // Resets the version's value to the input.
     52         virtual void Assign(std::string version, std::string_view splitChars = DefaultSplitChars);
     53 
     54         // Gets the full version string used to construct the Version.
     55         const std::string& ToString() const { return m_version; }
     56 
     57         bool operator<(const Version& other) const;
     58         bool operator>(const Version& other) const;
     59         bool operator<=(const Version& other) const;
     60         bool operator>=(const Version& other) const;
     61         bool operator==(const Version& other) const;
     62         bool operator!=(const Version& other) const;
     63 
     64         // Determines if this version is the sentinel value defining the 'Latest' version
     65         bool IsLatest() const;
     66 
     67         // Returns a Version that will return true for IsLatest
     68         static Version CreateLatest();
     69 
     70         // Determines if this version is the sentinel value defining an 'Unknown' version
     71         bool IsUnknown() const;
     72 
     73         // Returns a Version that will return true for IsUnknown
     74         static Version CreateUnknown();
     75 
     76         // Gets a bool indicating whether the full version string is empty.
     77         // Does not indicate that Parts is empty; for instance when "0.0" is given,
     78         // this will be false while GetParts().empty() would be true.
     79         bool IsEmpty() const { return m_version.empty(); }
     80 
     81         // An individual version part in between split characters.
     82         struct Part
     83         {
     84             Part() = default;
     85             Part(uint64_t integer) : Integer(integer) {}
     86             Part(const std::string& part);
     87             Part(uint64_t integer, std::string other);
     88 
     89             bool operator<(const Part& other) const;
     90             bool operator==(const Part& other) const;
     91             bool operator!=(const Part& other) const;
     92 
     93             uint64_t Integer = 0;
     94             std::string Other;
     95 
     96         private:
     97             std::string m_foldedOther;
     98         };
     99 
    100         // Gets the part breakdown for a given version.
    101         const std::vector<Part>& GetParts() const { return m_parts; }
    102 
    103         // Gets the part at the given index; or the implied zero part if past the end.
    104         const Part& PartAt(size_t index) const;
    105         
    106         // Returns if the version is an approximate version.
    107         bool IsApproximate() const { return m_approximateComparator != ApproximateComparator::None; }
    108 
    109         // Get the base version from approximate version, or return a copy if the version is not approximate.
    110         Version GetBaseVersion() const;
    111 
    112     protected:
    113 
    114         bool IsBaseVersionLatest() const;
    115         bool IsBaseVersionUnknown() const;
    116         // Called by overloaded less than operator implementation when base version already compared and equal, less than determined by approximate comparator.
    117         bool ApproximateCompareLessThan(const Version& other) const;
    118 
    119         std::string m_version;
    120         std::vector<Part> m_parts;
    121         bool m_trimPrefix = true;
    122         ApproximateComparator m_approximateComparator = ApproximateComparator::None;
    123 
    124       // Remove trailing empty parts (0 or empty)
    125         void Trim();
    126     };
    127 
    128     // Version that does not have leading non-digit characters trimmed
    129     struct RawVersion : protected Version
    130     {
    131         RawVersion() { m_trimPrefix = false; }
    132         RawVersion(std::string version, std::string_view splitChars = DefaultSplitChars);
    133 
    134         using Version::GetParts;
    135     };
    136 
    137     // Four parts version number: 16-bits.16-bits.16-bits.16-bits
    138     struct UInt64Version : public Version
    139     {
    140         UInt64Version() = default;
    141         UInt64Version(UINT64 version);
    142         UInt64Version(uint16_t major, uint16_t minor, uint16_t build, uint16_t revision);
    143         UInt64Version(std::string&& version, std::string_view splitChars = DefaultSplitChars);
    144         UInt64Version(const std::string& version, std::string_view splitChars = DefaultSplitChars) :
    145             UInt64Version(std::string(version), splitChars) {}
    146 
    147         void Assign(std::string version, std::string_view splitChars = DefaultSplitChars) override;
    148         void Assign(UINT64 version);
    149         void Assign(uint16_t major, uint16_t minor, uint16_t build, uint16_t revision);
    150 
    151         UINT64 Major() const { return m_parts.size() > 0 ? m_parts[0].Integer : 0; }
    152         UINT64 Minor() const { return m_parts.size() > 1 ? m_parts[1].Integer : 0; }
    153         UINT64 Build() const { return m_parts.size() > 2 ? m_parts[2].Integer : 0; }
    154         UINT64 Revision() const { return m_parts.size() > 3 ? m_parts[3].Integer : 0; }
    155     };
    156 
    157     // A semantic version as defined by semver.org
    158     // This is currently fairly loose in its restrictions on a version, and is largely to separate out the prelease and build metadata portions.
    159     struct SemanticVersion : public Version
    160     {
    161         SemanticVersion() = default;
    162         SemanticVersion(std::string&& version);
    163         SemanticVersion(const std::string& version) :
    164             SemanticVersion(std::string(version)) {}
    165 
    166         void Assign(std::string version, std::string_view splitChars = DefaultSplitChars) override;
    167 
    168         // Indicates that the version is pre-release
    169         bool IsPrerelease() const;
    170         // The pre-release version
    171         const Version& PrereleaseVersion() const;
    172 
    173         // Indicates that the version has build metadata
    174         bool HasBuildMetadata() const;
    175         // The build metadata version
    176         const Version& BuildMetadata() const;
    177 
    178     private:
    179         Version m_prerelease;
    180         Version m_buildMetadata;
    181     };
    182 
    183     // Version range represented by a min version and max version, both inclusive.
    184     struct VersionRange
    185     {
    186         VersionRange() { m_isEmpty = true; };
    187         VersionRange(Version minVersion, Version maxVersion);
    188 
    189         bool IsEmpty() const { return m_isEmpty; }
    190 
    191         // Checks if version ranges overlap. Empty version range does not overlap with any version range.
    192         bool Overlaps(const VersionRange& other) const;
    193 
    194         // Checks if the version range is effectively the same as a single version.
    195         bool IsSameAsSingleVersion(const Version& version) const;
    196 
    197         // Checks if a version is within the version range
    198         bool ContainsVersion(const Version& version) const;
    199 
    200         // < operator will thow if compared with an empty range or an overlapped range
    201         bool operator<(const VersionRange& other) const;
    202 
    203         const Version& GetMinVersion() const;
    204         const Version& GetMaxVersion() const;
    205 
    206     private:
    207         Version m_minVersion;
    208         Version m_maxVersion;
    209         bool m_isEmpty = false;
    210     };
    211 
    212     // A range of versions indicated by a version and optionally a wildcard at the end.
    213     struct GatedVersion
    214     {
    215         GatedVersion() {}
    216         GatedVersion(Version&& version) : m_version(std::move(version)) {}
    217         GatedVersion(const Version& version) : m_version(version) {}
    218         GatedVersion(std::string_view versionString) : m_version(std::string{ versionString }) {}
    219         GatedVersion(const std::string& versionString) : m_version(versionString) {}
    220 
    221         // Determines whether a given version falls within this Gated version.
    222         // I.e., whether it matches up to the wildcard
    223         bool IsValidVersion(Version version) const;
    224 
    225         bool operator==(const GatedVersion& other) const { return m_version == other.m_version; }
    226         const std::string& ToString() const { return m_version.ToString(); }
    227 
    228     private:
    229         // Hold the version string as a Version object that makes it easy to access each of
    230         // the version's parts. The real magic is in IsValidVersion()
    231         Version m_version;
    232     };
    233 
    234     // A channel string; existing solely to give a type.
    235     //
    236     // Compared lexicographically.
    237     struct Channel
    238     {
    239         Channel() = default;
    240         Channel(const std::string& channel) : m_channel(channel) {}
    241         Channel(std::string&& channel) : m_channel(std::move(channel)) {}
    242 
    243         const std::string& ToString() const { return m_channel; }
    244 
    245         bool operator<(const Channel& other) const;
    246 
    247     private:
    248         std::string m_channel;
    249     };
    250 
    251     // Contains a version and channel.
    252     // These are compared by:
    253     //  if channel not equal, return compare channel
    254     //  else return !compare version
    255     //
    256     // The implication of this is that the default less sort will be:
    257     //  2.0, ""
    258     //  1.0, ""
    259     //  3.0, "alpha"
    260     //  2.0, "alpha"
    261     struct VersionAndChannel
    262     {
    263         VersionAndChannel() = default;
    264         VersionAndChannel(Version&& version, Channel&& channel);
    265 
    266         const Version& GetVersion() const { return m_version; }
    267         const Channel& GetChannel() const { return m_channel; }
    268 
    269         std::string ToString() const;
    270 
    271         bool operator<(const VersionAndChannel& other) const;
    272 
    273         // A convenience function to make more semantic sense at call sites over the somewhat awkward less than ordering.
    274         bool IsUpdatedBy(const VersionAndChannel& other) const;
    275 
    276     private:
    277         Version m_version;
    278         Channel m_channel;
    279     };
    280 
    281     // Checks if there are overlaps within the list of version ranges
    282     bool HasOverlapInVersionRanges(const std::vector<VersionRange>& ranges);
    283 
    284     // The OpenType font version.
    285     // The format of this version type is 'Version 1.234 ;567'
    286     // The only part that is of importance is the 'Major.Minor' parts.
    287     // The 'Version' string is typically found at the beginning of the version string.
    288     // Any value after a digit that is not a '.' represents some other meaning.
    289     struct OpenTypeFontVersion : Version
    290     {
    291         OpenTypeFontVersion() = default;
    292 
    293         OpenTypeFontVersion(std::string&& version);
    294         OpenTypeFontVersion(const std::string& version) :
    295             OpenTypeFontVersion(std::string(version)) {}
    296 
    297         void Assign(std::string version, std::string_view splitChars = DefaultSplitChars) override;
    298     };
    299 }