Compare commits

...
Author SHA1 Message Date
6d60df4497
pkg.sh: Fix broken version macro expansion
Some checks failed
CI / Packaging test (pull_request) Has been cancelled
CI / Packaging - OpenSUSE Tumbleweed (pull_request) Has been cancelled
CI / Packaging - Kali Linux (pull_request) Has been cancelled
pkg-dist.mk queries the package relations with
--dont-expand-version-macros, and build_pkg() expanded the remaining
VERSION and VERSION-REVISION macros with a local sed-based
expand_version_macros(). That substitutes the version of the project being
built for every macro, instead of the version of the dependency the macro
refers to.

Drop --dont-expand-version-macros from the proj_query calls so the macros
resolve to the dependency's own version, and remove expand_version_macros()
from build_pkg(), which passes the PKG_* variables to rpmbuild as they are
queried.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-09-09 15:27:10 +02:00
a805972a3e
lib.version: Add API docstrings
All checks were successful
CI / Packaging - Kali Linux (pull_request) Successful in 3m56s
CI / Packaging - OpenSUSE Tumbleweed (pull_request) Successful in 4m17s
CI / Packaging test (pull_request) Successful in 0s
The lib.version module carries no documentation: the Syntax, Component and
Boundary types, the Version and Dependency classes and their public methods
are bare, and the compatibility tiers the next_* stepping methods implement
are not documented anywhere.

Add docstrings: a line each for the base.py types, the compatibility
tier table in the Version class, and a short description for every
public method, with the three next_* methods citing the tier each one
steps to.

Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.84.2
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-09-09 15:27:10 +02:00
5 changed files with 78 additions and 18 deletions

View file

@ -78,13 +78,13 @@ ifeq ($(CREATE_DEVEL),true)
BINARY_PKG += $(DIST_PCKG_DIR)/$(PKG_DEVEL_X86)
endif
PKG_REQUIRES_BUILD += $(call proj_query, pkg-requires --dont-expand-version-macros $(PROJ_QUERY_PKG_REQUIRES_EXTRA_ARGS) build $(PROJECT))
PKG_REQUIRES_RUN += $(call proj_query, pkg-requires --dont-expand-version-macros $(PROJ_QUERY_PKG_REQUIRES_EXTRA_ARGS) run $(PROJECT))
PKG_REQUIRES_DEVEL += $(call proj_query, pkg-requires --dont-expand-version-macros $(PROJ_QUERY_PKG_REQUIRES_EXTRA_ARGS) devel $(PROJECT))
PKG_CONFLICTS_RUN += $(call proj_query, pkg-conflicts --dont-expand-version-macros $(PROJ_QUERY_PKG_CONFLICTS_EXTRA_ARGS) run $(PROJECT))
PKG_CONFLICTS_DEVEL += $(call proj_query, pkg-conflicts --dont-expand-version-macros $(PROJ_QUERY_PKG_CONFLICTS_EXTRA_ARGS) devel $(PROJECT))
PKG_PROVIDES_RUN += $(call proj_query, pkg-provides --dont-expand-version-macros $(PROJ_QUERY_PKG_PROVIDES_EXTRA_ARGS) run $(PROJECT))
PKG_PROVIDES_DEVEL += $(call proj_query, pkg-provides --dont-expand-version-macros $(PROJ_QUERY_PKG_PROVIDES_EXTRA_ARGS) devel $(PROJECT))
PKG_REQUIRES_BUILD += $(call proj_query, pkg-requires $(PROJ_QUERY_PKG_REQUIRES_EXTRA_ARGS) build $(PROJECT))
PKG_REQUIRES_RUN += $(call proj_query, pkg-requires $(PROJ_QUERY_PKG_REQUIRES_EXTRA_ARGS) run $(PROJECT))
PKG_REQUIRES_DEVEL += $(call proj_query, pkg-requires $(PROJ_QUERY_PKG_REQUIRES_EXTRA_ARGS) devel $(PROJECT))
PKG_CONFLICTS_RUN += $(call proj_query, pkg-conflicts $(PROJ_QUERY_PKG_CONFLICTS_EXTRA_ARGS) run $(PROJECT))
PKG_CONFLICTS_DEVEL += $(call proj_query, pkg-conflicts $(PROJ_QUERY_PKG_CONFLICTS_EXTRA_ARGS) devel $(PROJECT))
PKG_PROVIDES_RUN += $(call proj_query, pkg-provides $(PROJ_QUERY_PKG_PROVIDES_EXTRA_ARGS) run $(PROJECT))
PKG_PROVIDES_DEVEL += $(call proj_query, pkg-provides $(PROJ_QUERY_PKG_PROVIDES_EXTRA_ARGS) devel $(PROJECT))
PKG_UPLOAD_OS_NAME = $(shell echo $(OS_NAME_VERSION) | sed 's/-.*//')
PKG_UPLOAD_OS_VERSION = $(shell echo $(OS_NAME_VERSION) | sed 's/[^-]\+-//')

View file

@ -438,16 +438,12 @@ build_pkg()
local tar_archive_orig=$src_base.orig.tar.bz2
local distribution=`get_os`
expand_version_macros() {
echo "$@" | sed "s/__NEXT_VERSION__/$version/g; s/VERSION-REVISION/$version/g; s/VERSION/$version/g"
}
local rpm_requires_run=`expand_version_macros $PKG_REQUIRES_RUN`
local rpm_requires_devel=`expand_version_macros $PKG_REQUIRES_DEVEL`
local rpm_conflicts_run=`expand_version_macros $PKG_CONFLICTS_RUN`
local rpm_conflicts_devel=`expand_version_macros $PKG_CONFLICTS_DEVEL`
local rpm_provides_run=`expand_version_macros $PKG_PROVIDES_RUN`
local rpm_provides_devel=`expand_version_macros $PKG_PROVIDES_DEVEL`
local rpm_requires_run="$PKG_REQUIRES_RUN"
local rpm_requires_devel="$PKG_REQUIRES_DEVEL"
local rpm_conflicts_run="$PKG_CONFLICTS_RUN"
local rpm_conflicts_devel="$PKG_CONFLICTS_DEVEL"
local rpm_provides_run="$PKG_PROVIDES_RUN"
local rpm_provides_devel="$PKG_PROVIDES_DEVEL"
# --- create source directory tree
create_empty_dir $src_tree "Source files compilation directory"

View file

@ -14,6 +14,10 @@ if TYPE_CHECKING:
from typing import ClassVar
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):
pass
@ -106,6 +110,9 @@ class Dependency: # export
return Version.strip_package_suffix(self.full_name)
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)
def constraint_str(
@ -117,6 +124,16 @@ class Dependency: # export
no_subpackages: bool = False,
quote: str | None = None,
) -> 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:
name = self.base_name if no_subpackages else self.full_name
@ -139,6 +156,7 @@ class Dependency: # export
spec: str,
lookup_version: Lookup | None = None,
) -> Sequence[Dependency]:
"""Split a comma-separated specification into Dependency objects"""
return [
Dependency(spec = spec.strip(), lookup_version = lookup_version)
for spec in spec.split(',')

View file

@ -11,6 +11,17 @@ if TYPE_CHECKING:
from enum import Flag
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):
pass
@ -106,6 +117,7 @@ class Version: # export
@classmethod
def strip_package_suffix(cls, name: str) -> str:
"""Remove the -dev, -devel or -run subpackage suffix"""
return cls.__SUFFIX_RE.sub('', name)
@property
@ -121,11 +133,21 @@ class Version: # export
@property
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':
return True
return bool(self.__FULL_ID_RE.fullmatch(self.__spec))
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':
return self.core(untemplate)
return self.__id(untemplate)
@ -150,6 +172,14 @@ class Version: # export
@property
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)
m = re.match('[0-9]+', rev)
if not m:
@ -162,6 +192,11 @@ class Version: # export
@property
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(
self.__name,
f'{self.major}.{self.minor}.{self.micro + 1}',
@ -170,6 +205,11 @@ class Version: # export
@property
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(
self.__name,
f'{self.major}.{self.minor + 1}.0',

View file

@ -8,11 +8,15 @@ if TYPE_CHECKING:
from .Version import Version
class Syntax(Enum): # export
"""Syntaxes for rendered version constraints"""
DEBIAN = auto()
SEM_VER = auto()
NAMES_ONLY = auto()
class Component(Flag): # export
"""Version components that parts_str() can extract"""
ID = auto()
MAJOR = auto()
MINOR = auto()
@ -21,10 +25,12 @@ class Component(Flag): # export
CORE = MAJOR | MINOR | MICRO
class Boundary(NamedTuple): # export
"""A comparison operator and the Version it bounds"""
op: str
version: Version
"""Syntax-aware formatted version comparion operator"""
def format_op(self, syntax: Syntax) -> str:
if syntax is Syntax.DEBIAN:
match self.op: