lib.pkg_relations(): Beautify exceptions #93
3 changed files with 44 additions and 31 deletions
|
|
@ -67,6 +67,7 @@ def pkg_relations(
|
||||||
for dep in Dependency.parse_deps_spec(
|
for dep in Dependency.parse_deps_spec(
|
||||||
deps_spec,
|
deps_spec,
|
||||||
lookup_version = app.get_version,
|
lookup_version = app.get_version,
|
||||||
|
dependent_package = cur_pkg,
|
||||||
):
|
):
|
||||||
dep_name = dep.base_name
|
dep_name = dep.base_name
|
||||||
if dep_name in ignore or dep.full_name in ignore:
|
if dep_name in ignore or dep.full_name in ignore:
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@ import re
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import TYPE_CHECKING, override
|
from typing import TYPE_CHECKING, override
|
||||||
|
|
||||||
from ..log import WARNING, log
|
from ..log import get_caller_pos
|
||||||
from .base import Boundary, Lookup, Syntax
|
from .base import Boundary, Lookup, Syntax
|
||||||
from .Version import Version
|
from .Version import Version
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from typing import ClassVar
|
from typing import ClassVar, Never
|
||||||
|
|
||||||
class Dependency: # export
|
class Dependency: # export
|
||||||
"""A single package dependency: a package name and an optional
|
"""A single package dependency: a package name and an optional
|
||||||
|
|
@ -24,30 +24,38 @@ class Dependency: # export
|
||||||
|
|
||||||
__SPLIT_RE: ClassVar[re.Pattern[str]] = re.compile('([=><]+)')
|
__SPLIT_RE: ClassVar[re.Pattern[str]] = re.compile('([=><]+)')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def __target_prefix(self) -> str:
|
||||||
|
if self.__dependent_package is None:
|
||||||
|
return ''
|
||||||
|
return f' Package "{self.__dependent_package}"'
|
||||||
|
|
||||||
|
def __raise(self, msg: str, cls: type[Exception] = Error) -> Never:
|
||||||
|
mod, file, line = get_caller_pos()
|
||||||
|
raise cls(f'[{file}:{line}]{self.__target_prefix}: {msg}')
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def __parsed_spec(self) -> tuple[str, Boundary | None]:
|
def __parsed_spec(self) -> tuple[str, Boundary | None]:
|
||||||
parts = [part.strip() for part in self.__SPLIT_RE.split(self.__spec)]
|
parts = [part.strip() for part in self.__SPLIT_RE.split(self.__spec)]
|
||||||
match len(parts):
|
match len(parts):
|
||||||
case 1:
|
case 1:
|
||||||
if not parts[0]:
|
if not parts[0]:
|
||||||
raise Dependency.Error(f'Invalid dependency spec "{self.__spec}"')
|
self.__raise(f'Invalid dependency spec "{self.__spec}"')
|
||||||
return parts[0], None
|
return parts[0], None
|
||||||
case 3:
|
case 3:
|
||||||
if not parts[0] or not parts[2]:
|
if not parts[0] or not parts[2]:
|
||||||
raise Dependency.Error(f'Invalid dependency spec "{self.__spec}"')
|
self.__raise(f'Invalid dependency spec "{self.__spec}"')
|
||||||
if parts[2] == 'REVISION':
|
if parts[2] == 'REVISION':
|
||||||
log(
|
self.__raise(
|
||||||
WARNING,
|
f'Spec "{self.__spec}": a bare REVISION renders as a '
|
||||||
f'Spec "{self.__spec}": a bare REVISION renders as a bare '
|
'bare number, which is likely not what the user intended'
|
||||||
'number, which RPM reads as a version constraint, not a '
|
|
||||||
'release constraint'
|
|
||||||
)
|
)
|
||||||
return parts[0], Boundary(
|
return parts[0], Boundary(
|
||||||
op = parts[1],
|
op=parts[1],
|
||||||
version = Version(parts[0], parts[2], self.__lookup_version),
|
version=Version(parts[0], parts[2], self.__lookup_version),
|
||||||
)
|
)
|
||||||
case _:
|
case _:
|
||||||
raise Dependency.Error(f'Invalid dependency spec "{self.__spec}"')
|
self.__raise(f'Invalid dependency spec "{self.__spec}"')
|
||||||
|
|
||||||
def __version_boundaries(
|
def __version_boundaries(
|
||||||
self,
|
self,
|
||||||
|
|
@ -69,12 +77,13 @@ class Dependency: # export
|
||||||
case '<' | '<=':
|
case '<' | '<=':
|
||||||
ret.append(specified)
|
ret.append(specified)
|
||||||
case _:
|
case _:
|
||||||
raise NotImplementedError(
|
self.__raise(
|
||||||
(
|
(
|
||||||
'Expanding version boundary '
|
'Expanding version boundary '
|
||||||
f'"{self.full_name} {specified.op} {specified.version}" '
|
f'"{self.full_name} {specified.op} {specified.version}" '
|
||||||
'is not yet implemented'
|
'is not yet implemented'
|
||||||
)
|
),
|
||||||
|
cls = NotImplementedError,
|
||||||
)
|
)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
@ -84,18 +93,24 @@ class Dependency: # export
|
||||||
self,
|
self,
|
||||||
spec: str,
|
spec: str,
|
||||||
lookup_version: Lookup | None = None,
|
lookup_version: Lookup | None = None,
|
||||||
|
dependent_package: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.__spec = spec
|
self.__spec = spec
|
||||||
self.__lookup_version = lookup_version
|
self.__lookup_version = lookup_version
|
||||||
|
self.__dependent_package = dependent_package
|
||||||
|
|
||||||
@override
|
@override
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.__spec
|
return self.__spec
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dependent_package(self) -> str | None:
|
||||||
|
return self.__dependent_package
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def current_version(self) -> str:
|
def current_version(self) -> str:
|
||||||
if not self.__lookup_version:
|
if not self.__lookup_version:
|
||||||
raise Dependency.Error(
|
self.__raise(
|
||||||
f'Tried to look up "{self.__spec}" for package '
|
f'Tried to look up "{self.__spec}" for package '
|
||||||
f'"{self.base_name}" without lookup function'
|
f'"{self.base_name}" without lookup function'
|
||||||
)
|
)
|
||||||
|
|
@ -155,9 +170,13 @@ class Dependency: # export
|
||||||
cls,
|
cls,
|
||||||
spec: str,
|
spec: str,
|
||||||
lookup_version: Lookup | None = None,
|
lookup_version: Lookup | None = None,
|
||||||
|
dependent_package: str | None = None,
|
||||||
) -> Sequence[Dependency]:
|
) -> Sequence[Dependency]:
|
||||||
"""Split a comma-separated specification into Dependency objects"""
|
"""Split a comma-separated specification into Dependency objects"""
|
||||||
return [
|
return [
|
||||||
Dependency(spec = spec.strip(), lookup_version = lookup_version)
|
Dependency(
|
||||||
for spec in spec.split(',')
|
spec = spec.strip(),
|
||||||
|
lookup_version = lookup_version,
|
||||||
|
dependent_package = dependent_package,
|
||||||
|
) for spec in spec.split(',')
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
import io
|
|
||||||
|
|
||||||
from jw.pkg.lib.log import add_capture_stream, rm_capture_stream
|
|
||||||
from jw.pkg.lib.version import Component, Dependency, Syntax, Version
|
from jw.pkg.lib.version import Component, Dependency, Syntax, Version
|
||||||
|
|
||||||
class FakeApp:
|
class FakeApp:
|
||||||
|
|
@ -82,17 +79,13 @@ assert d.constraint_str(untemplated=False, include_revision=False) == \
|
||||||
# untemplated=False keeps the specifiers as written
|
# untemplated=False keeps the specifiers as written
|
||||||
d = Dependency('foo = VERSION', app.get_version)
|
d = Dependency('foo = VERSION', app.get_version)
|
||||||
assert d.constraint_str(untemplated = False) == 'foo = VERSION'
|
assert d.constraint_str(untemplated = False) == 'foo = VERSION'
|
||||||
# REVISION resolves to the revision part
|
# A bare REVISION is rejected on the grounds that is assumed that
|
||||||
d = Dependency('foo = REVISION', app.get_version)
|
# the user wanted VERSION instead
|
||||||
assert d.constraint_str() == 'foo = 45'
|
try:
|
||||||
assert d.constraint_str(untemplated = False) == 'foo = REVISION'
|
Dependency('foo = REVISION', app.get_version).constraint_str()
|
||||||
# A bare REVISION warns: RPM reads a bare number as a version
|
assert False, 'Should have raised'
|
||||||
buf = io.StringIO()
|
except Dependency.Error:
|
||||||
sd = add_capture_stream(buf)
|
pass
|
||||||
d = Dependency('foo = REVISION', app.get_version)
|
|
||||||
assert d.constraint_str() == 'foo = 45'
|
|
||||||
assert 'not a release constraint' in buf.getvalue()
|
|
||||||
rm_capture_stream(sd)
|
|
||||||
|
|
||||||
# The lookup uses the base name, not the subpackage name
|
# The lookup uses the base name, not the subpackage name
|
||||||
d = Dependency('foo-devel = VERSION', app.get_version)
|
d = Dependency('foo-devel = VERSION', app.get_version)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue