Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
01a0c40647 |
3 changed files with 64 additions and 0 deletions
|
|
@ -14,6 +14,10 @@ if TYPE_CHECKING:
|
||||||
from typing import ClassVar
|
from typing import ClassVar
|
||||||
|
|
||||||
class Dependency: # export
|
class Dependency: # export
|
||||||
|
"""A single package dependency: a package name and an optional
|
||||||
|
version boundary, parsed from a specification such as
|
||||||
|
'foo-devel >= 1.2.3-4'. Rendering happens in constraint_str().
|
||||||
|
"""
|
||||||
|
|
||||||
class Error(ValueError):
|
class Error(ValueError):
|
||||||
pass
|
pass
|
||||||
|
|
@ -106,6 +110,9 @@ class Dependency: # export
|
||||||
return Version.strip_package_suffix(self.full_name)
|
return Version.strip_package_suffix(self.full_name)
|
||||||
|
|
||||||
def version_boundaries(self, expanded: bool = False) -> Sequence[Boundary]:
|
def version_boundaries(self, expanded: bool = False) -> Sequence[Boundary]:
|
||||||
|
"""The parsed version boundary, or the range it spans when
|
||||||
|
expanded is True and it pins a full version.
|
||||||
|
"""
|
||||||
return self.__version_boundaries(expanded)
|
return self.__version_boundaries(expanded)
|
||||||
|
|
||||||
def constraint_str(
|
def constraint_str(
|
||||||
|
|
@ -117,6 +124,16 @@ class Dependency: # export
|
||||||
no_subpackages: bool = False,
|
no_subpackages: bool = False,
|
||||||
quote: str | None = None,
|
quote: str | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
|
"""Render the dependency as a version constraint string.
|
||||||
|
|
||||||
|
NAMES_ONLY renders the name alone. untemplated keeps the
|
||||||
|
VERSION, VERSION-REVISION and REVISION macros as written instead
|
||||||
|
of the resolved versions. include_revision = False drops the
|
||||||
|
revision of VERSION specs. as_range expands a boundary that
|
||||||
|
pins a full version into the range it spans. no_subpackages
|
||||||
|
renders the base name, quote wraps the result in the given
|
||||||
|
string.
|
||||||
|
"""
|
||||||
|
|
||||||
def __str() -> str:
|
def __str() -> str:
|
||||||
name = self.base_name if no_subpackages else self.full_name
|
name = self.base_name if no_subpackages else self.full_name
|
||||||
|
|
@ -139,6 +156,7 @@ class Dependency: # export
|
||||||
spec: str,
|
spec: str,
|
||||||
lookup_version: Lookup | None = None,
|
lookup_version: Lookup | None = None,
|
||||||
) -> Sequence[Dependency]:
|
) -> Sequence[Dependency]:
|
||||||
|
"""Split a comma-separated specification into Dependency objects"""
|
||||||
return [
|
return [
|
||||||
Dependency(spec = spec.strip(), lookup_version = lookup_version)
|
Dependency(spec = spec.strip(), lookup_version = lookup_version)
|
||||||
for spec in spec.split(',')
|
for spec in spec.split(',')
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,17 @@ if TYPE_CHECKING:
|
||||||
from enum import Flag
|
from enum import Flag
|
||||||
|
|
||||||
class Version: # export
|
class Version: # export
|
||||||
|
"""A version spec: a literal such as '1.2.3-4', or one of the macros
|
||||||
|
VERSION, VERSION-REVISION and REVISION, which resolve against the
|
||||||
|
version of the project the name refers to, through the lookup
|
||||||
|
callback.
|
||||||
|
|
||||||
|
Versions step through compatibility tiers: a different revision is
|
||||||
|
a binary-compatible change, a different micro is source-compatible,
|
||||||
|
a different minor carries no major incompatibilities but downstream
|
||||||
|
packages should expect trivial fixes, and a different major gives
|
||||||
|
no compatibility guarantees at all.
|
||||||
|
"""
|
||||||
|
|
||||||
class Error(ValueError):
|
class Error(ValueError):
|
||||||
pass
|
pass
|
||||||
|
|
@ -106,6 +117,7 @@ class Version: # export
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def strip_package_suffix(cls, name: str) -> str:
|
def strip_package_suffix(cls, name: str) -> str:
|
||||||
|
"""Remove the -dev, -devel or -run subpackage suffix"""
|
||||||
return cls.__SUFFIX_RE.sub('', name)
|
return cls.__SUFFIX_RE.sub('', name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
@ -121,11 +133,21 @@ class Version: # export
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_full(self) -> bool:
|
def is_full(self) -> bool:
|
||||||
|
"""True if the spec pins a complete version: the
|
||||||
|
VERSION-REVISION macro, or a literal of the form
|
||||||
|
MAJOR.MINOR.MICRO-REVISION. Only full versions have the
|
||||||
|
exclusive upper bound (next_binary_incompatible) that range
|
||||||
|
expansion relies on.
|
||||||
|
"""
|
||||||
if self.__spec == 'VERSION-REVISION':
|
if self.__spec == 'VERSION-REVISION':
|
||||||
return True
|
return True
|
||||||
return bool(self.__FULL_ID_RE.fullmatch(self.__spec))
|
return bool(self.__FULL_ID_RE.fullmatch(self.__spec))
|
||||||
|
|
||||||
def id(self, untemplate: bool, include_revision: bool = True) -> str:
|
def id(self, untemplate: bool, include_revision: bool = True) -> str:
|
||||||
|
"""Return the version id: the raw spec if untemplate is False,
|
||||||
|
else the resolved version. With include_revision = False a
|
||||||
|
VERSION spec yields the core version.
|
||||||
|
"""
|
||||||
if not include_revision and self.__spec == 'VERSION':
|
if not include_revision and self.__spec == 'VERSION':
|
||||||
return self.core(untemplate)
|
return self.core(untemplate)
|
||||||
return self.__id(untemplate)
|
return self.__id(untemplate)
|
||||||
|
|
@ -150,6 +172,14 @@ class Version: # export
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def next_binary_compatible(self) -> Version:
|
def next_binary_compatible(self) -> Version:
|
||||||
|
"""The next version within the binary tier: the same core with
|
||||||
|
the revision incremented. A different revision is a
|
||||||
|
binary-compatible change, so binaries built against the current
|
||||||
|
version keep working. Only the revision's leading digits count:
|
||||||
|
a suffixed revision such as '4blah' steps to '5', which sits
|
||||||
|
strictly above every variant of the current revision. A
|
||||||
|
revision without leading digits raises Version.Error.
|
||||||
|
"""
|
||||||
rev = self.revision(True)
|
rev = self.revision(True)
|
||||||
m = re.match('[0-9]+', rev)
|
m = re.match('[0-9]+', rev)
|
||||||
if not m:
|
if not m:
|
||||||
|
|
@ -162,6 +192,11 @@ class Version: # export
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def next_binary_incompatible(self) -> Version:
|
def next_binary_incompatible(self) -> Version:
|
||||||
|
"""The next version out of the binary tier: the micro
|
||||||
|
incremented, the revision dropped. A different micro is
|
||||||
|
source-compatible, so this is the first version binaries of the
|
||||||
|
current version are not guaranteed to run against.
|
||||||
|
"""
|
||||||
return Version(
|
return Version(
|
||||||
self.__name,
|
self.__name,
|
||||||
f'{self.major}.{self.minor}.{self.micro + 1}',
|
f'{self.major}.{self.minor}.{self.micro + 1}',
|
||||||
|
|
@ -170,6 +205,11 @@ class Version: # export
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def next_source_incompatible(self) -> Version:
|
def next_source_incompatible(self) -> Version:
|
||||||
|
"""The next version out of the source tier: the minor
|
||||||
|
incremented, micro and revision reset. A different minor carries
|
||||||
|
no major incompatibilities, but downstream packages should
|
||||||
|
expect to need trivial fixes.
|
||||||
|
"""
|
||||||
return Version(
|
return Version(
|
||||||
self.__name,
|
self.__name,
|
||||||
f'{self.major}.{self.minor + 1}.0',
|
f'{self.major}.{self.minor + 1}.0',
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,15 @@ if TYPE_CHECKING:
|
||||||
from .Version import Version
|
from .Version import Version
|
||||||
|
|
||||||
class Syntax(Enum): # export
|
class Syntax(Enum): # export
|
||||||
|
"""Syntaxes for rendered version constraints"""
|
||||||
|
|
||||||
DEBIAN = auto()
|
DEBIAN = auto()
|
||||||
SEM_VER = auto()
|
SEM_VER = auto()
|
||||||
NAMES_ONLY = auto()
|
NAMES_ONLY = auto()
|
||||||
|
|
||||||
class Component(Flag): # export
|
class Component(Flag): # export
|
||||||
|
"""Version components that parts_str() can extract"""
|
||||||
|
|
||||||
ID = auto()
|
ID = auto()
|
||||||
MAJOR = auto()
|
MAJOR = auto()
|
||||||
MINOR = auto()
|
MINOR = auto()
|
||||||
|
|
@ -21,6 +25,8 @@ class Component(Flag): # export
|
||||||
CORE = MAJOR | MINOR | MICRO
|
CORE = MAJOR | MINOR | MICRO
|
||||||
|
|
||||||
class Boundary(NamedTuple): # export
|
class Boundary(NamedTuple): # export
|
||||||
|
"""A comparison operator and the Version it bounds"""
|
||||||
|
|
||||||
op: str
|
op: str
|
||||||
version: Version
|
version: Version
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue