Something went wrong. Try again.
Manifests and a static winget source for jcollie's Windows programs, built and signed on Linux.
Something went wrong. Try again.
4.0 kB · 112 lines
Python
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113# SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us># SPDX-License-Identifier: MIT
"""winget's version ordering.
A port of `Utility::Version` from winget-cli's`src/AppInstallerSharedLib/Versions.cpp`, enough to order versions the waythe client does. The index needs it for the ARP version range of a manifest,the lowest and highest `DisplayVersion` among its Apps & Features entries."""
import functoolsimport re
from .strings import fold_case
_SPACE_CHARS = " \f\n\r\t\v"_LESS_THAN = "< "_GREATER_THAN = "> "_LEADING_DIGITS = re.compile(r"[0-9]+")
class _Part: def __init__(self, text: str): text = text.strip(_SPACE_CHARS) match = _LEADING_DIGITS.match(text) self.integer = int(match.group(0)) if match else 0 self.other = text[match.end() :] if match else text if self.integer >= 2**64: # strtoull overflows; winget keeps the whole part as text. self.integer = 0 self.other = text self.folded_other = fold_case(self.other)
def __eq__(self, other: "_Part") -> bool: return self.integer == other.integer and self.folded_other == other.folded_other
def __lt__(self, other: "_Part") -> bool: if self.integer != other.integer: return self.integer < other.integer if not self.other: return False if not other.other: return True return self.folded_other < other.folded_other
_EMPTY_PART = _Part("")
@functools.total_orderingclass Version: def __init__(self, version: str): self.text = version.strip(_SPACE_CHARS) self.approximate = None base = self.text if base.lower().startswith(_LESS_THAN): self.approximate = "<" base = base[len(_LESS_THAN) :] elif base.lower().startswith(_GREATER_THAN): self.approximate = ">" base = base[len(_GREATER_THAN) :]
# If there is a digit before the first '.', or no '.' at all, drop # everything before the first digit ("v1.2" is 1.2). digit = next((i for i, c in enumerate(base) if c.isascii() and c.isdigit()), None) split = base.find(".") if digit is not None and (split == -1 or digit < split): base = base[digit:]
self.parts = [_Part(p) for p in base.split(".")] if base else [] while self.parts and self.parts[-1].integer == 0 and not self.parts[-1].other: self.parts.pop()
def __str__(self) -> str: return self.text
def _is(self, word: str) -> bool: return len(self.parts) == 1 and self.parts[0].integer == 0 and self.parts[0].folded_other == fold_case(word)
def _approximate_less_than(self, other: "Version") -> bool: return (self.approximate == "<" and other.approximate != "<") or ( self.approximate is None and other.approximate == ">" )
def __eq__(self, other: object) -> bool: if not isinstance(other, Version): return NotImplemented return not (self < other) and not (other < self)
def __lt__(self, other: "Version") -> bool: latest, other_latest = self._is("Latest"), other._is("Latest") if latest and other_latest: return self._approximate_less_than(other) if latest or other_latest: return other_latest and not latest
unknown, other_unknown = self._is("Unknown"), other._is("Unknown") if unknown and other_unknown: return self._approximate_less_than(other) if unknown or other_unknown: return unknown and not other_unknown
for i in range(max(len(self.parts), len(other.parts))): a = self.parts[i] if i < len(self.parts) else _EMPTY_PART b = other.parts[i] if i < len(other.parts) else _EMPTY_PART if a < b: return True if b < a: return False
return self._approximate_less_than(other)