diff --git a/src/python/jw/pkg/App.py b/src/python/jw/pkg/App.py index 07f23d2d..fe93c585 100644 --- a/src/python/jw/pkg/App.py +++ b/src/python/jw/pkg/App.py @@ -11,10 +11,11 @@ from enum import Enum, auto from functools import cache from typing import TYPE_CHECKING, override -from .lib.ExecApp import ExecApp as Base from .lib.Distro import Distro +from .lib.ExecApp import ExecApp as Base from .lib.log import DEBUG, ERR, log from .lib.ProjectConf import ProjectConf +from .lib.version.Dependency import Dependency if TYPE_CHECKING: import argparse @@ -435,7 +436,7 @@ class App(Base): return self.find_dir(name, ['/tmpl'], ['/opt/' + name + '/share/tmpl']) def strip_module_from_spec(self, mod: str) -> str: - return re.sub(r'-dev$|-devel$|-run$', '', re.split('([=><]+)', mod)[0].strip()) + return Dependency(mod).base_name @cache def get_value(self, project: str, section: str, key: str) -> str | None: diff --git a/src/python/jw/pkg/cmds/projects/BaseCmdPkgRelations.py b/src/python/jw/pkg/cmds/projects/BaseCmdPkgRelations.py index 66004f96..98c42c27 100644 --- a/src/python/jw/pkg/cmds/projects/BaseCmdPkgRelations.py +++ b/src/python/jw/pkg/cmds/projects/BaseCmdPkgRelations.py @@ -4,8 +4,8 @@ import re from typing import TYPE_CHECKING, cast, override +from ...lib.version.base import Syntax from .Cmd import Cmd, Parent -from .lib.pkg_relations import VersionSyntax from .lib.pkg_relations import pkg_relations as pkg_relations_list if TYPE_CHECKING: @@ -30,7 +30,11 @@ class BaseCmdPkgRelations(Cmd): no_subpackages = args.no_subpackages, dont_strip_revision = args.dont_strip_revision, expand_semver_revision_range = args.expand_semver_revision_range, - syntax = VersionSyntax[args.syntax.replace('-', '_')], + syntax = { + 'semver': Syntax.SEM_VER, + 'debian': Syntax.DEBIAN, + 'names-only': Syntax.NAMES_ONLY, + }[args.syntax], recursive = args.recursive, dont_expand_version_macros = args.dont_expand_version_macros, ignore = set(re.split(self.arg_sep, args.ignore)), diff --git a/src/python/jw/pkg/cmds/projects/CmdCreateFile.py b/src/python/jw/pkg/cmds/projects/CmdCreateFile.py index b852ac80..dfe5b95f 100644 --- a/src/python/jw/pkg/cmds/projects/CmdCreateFile.py +++ b/src/python/jw/pkg/cmds/projects/CmdCreateFile.py @@ -3,8 +3,9 @@ from enum import Enum, auto from typing import override from ...lib.log import WARNING, log +from ...lib.version.base import Syntax from .Cmd import Cmd, Parent -from .lib.pkg_relations import VersionSyntax, pkg_relations +from .lib.pkg_relations import pkg_relations from .lib.templates import ListDict, RenderValues, tmpl_render def key_value(s: str) -> tuple[str, str]: @@ -36,7 +37,7 @@ class CmdCreateFile(Cmd): # export flavours = ['run'], subsections = ['jw'], seed_pkgs = [module], - syntax = VersionSyntax.names_only, + syntax = Syntax.NAMES_ONLY, no_subpackages = True, recursive = True, quote = False, diff --git a/src/python/jw/pkg/cmds/projects/lib/pkg_relations.py b/src/python/jw/pkg/cmds/projects/lib/pkg_relations.py index 2b470d79..9a14fbe9 100644 --- a/src/python/jw/pkg/cmds/projects/lib/pkg_relations.py +++ b/src/python/jw/pkg/cmds/projects/lib/pkg_relations.py @@ -1,14 +1,7 @@ -import re - -from enum import Enum, auto - from ....App import App, Scope from ....lib.log import DEBUG, log - -class VersionSyntax(Enum): - semver = auto() - debian = auto() - names_only = auto() +from ....lib.version.base import Syntax +from ....lib.version.Dependency import Dependency def pkg_relations( app: App, @@ -20,7 +13,7 @@ def pkg_relations( no_subpackages: bool = False, dont_strip_revision: bool = False, expand_semver_revision_range: bool = False, - syntax: VersionSyntax = VersionSyntax.semver, + syntax: Syntax = Syntax.SEM_VER, recursive: bool = False, dont_expand_version_macros: bool = False, ignore: set[str] = set(), @@ -34,8 +27,7 @@ def pkg_relations( subsections = app.distro.os_cascade subsections.append('jw') - expand_semver_revision_range = expand_semver_revision_range - if syntax == VersionSyntax.debian: + if syntax == Syntax.DEBIAN: expand_semver_revision_range = True if skip_excluded: @@ -58,113 +50,48 @@ def pkg_relations( ), ) - version_pattern = re.compile('[0-9-.]*') ret: list[str] = [] for flavour in flavours: # build / release / run / devel cur_pkgs = seed_pkgs.copy() - visited = set() + visited_pkgs: set[str] = set() while len(cur_pkgs): cur_pkg = cur_pkgs.pop(0) - if cur_pkg in visited or cur_pkg in ignore: + if cur_pkg in visited_pkgs or cur_pkg in ignore: continue for subsec in subsections: - version: str | None = None section = 'pkg.' + rel_type + '.' + subsec - visited.add(cur_pkg) - value = app.get_value(cur_pkg, section, flavour) - if not value: + visited_pkgs.add(cur_pkg) + deps_spec = app.get_value(cur_pkg, section, flavour) + if not deps_spec: continue - deps = value.split(',') - for spec in deps: - dep = re.split('([=><]+)', spec) - if syntax == VersionSyntax.names_only: - dep = dep[:1] - dep = list(map(str.strip, dep)) - dep_name = re.sub('-dev$|-devel$|-run$', '', dep[0]) - if dep_name in ignore or dep[0] in ignore: + for dep in Dependency.parse_deps_spec( + deps_spec, + lookup_version = app.get_version, + ): + dep_name = dep.base_name + if dep_name in ignore or dep.full_name in ignore: continue - if no_subpackages: - dep[0] = dep_name - for i, item in enumerate(dep): - dep[i] = item.strip() if subsec == 'jw': - if (recursive and dep_name not in visited + if (recursive and dep_name not in visited_pkgs and dep_name not in cur_pkgs): cur_pkgs.append(dep_name) - if hide_jw_pkg: + if hide_jw_pkg and dep_name == 'jw-pkg': continue - if len(dep) == 3: - if dont_expand_version_macros and dep_name in cur_pkgs: - version = dep[2] - else: - version = app.get_version(dep_name) - if dep[2] == 'VERSION': - if dont_strip_revision: - dep[2] = version - else: - dep[2] = version.split('-')[0] - elif dep[2] == 'VERSION-REVISION': - dep[2] = version - elif version_pattern.match(dep[2]): - # dep[2] = dep[2] - pass - else: - raise Exception('Unknown version specifier in ' + spec) - if len(dep) != 3 or not expand_semver_revision_range: - expanded_deps = [dep] - else: - assert version is not None - expanded_deps = [] - semver = re.split(r'[.-]', version) - if len(semver) != 4: - expanded_deps = [dep] - else: - release = int(semver[2]) - major_minor = f'{semver[0]}.{semver[1]}' - match dep[1]: - case '>' | '>=': - expanded_deps.append([dep[0], dep[1], dep[2]]) - expanded_deps.append( - [dep[0], '<', f'{major_minor}.{release + 1}'] - ) - case '<' | '<=': - expanded_deps.append([dep[0], dep[1], dep[2]]) - case '=': - expanded_deps.append( - [dep[0], '>=', f'{major_minor}.{release}'] - ) - expanded_deps.append( - [dep[0], '<', f'{major_minor}.{release + 1}'] - ) - case _: - raise NotImplementedError( - ( - 'Expanding SemVer range ' - f'"{dep[0]} {dep[1]} {dep[3]}" ' - 'is not yet implemented' - ) - ) - for expanded_dep in expanded_deps: - if hide_self and dep_name in seed_pkgs: - continue - match syntax: - case VersionSyntax.semver: - pass - case VersionSyntax.names_only: - pass - case VersionSyntax.debian: - if len(expanded_dep) == 3: - match expanded_dep[1]: - case '<': - expanded_dep[1] = '<<' - case '>': - expanded_dep[1] = '>>' - case _: - pass - dep_str = ' '.join(expanded_dep) - if quote: - dep_str = '"' + dep_str + '"' - if dep_str not in ret: - log(DEBUG, f'Appending dependency >{dep_str}<') - ret.append(dep_str) + expand_version_macros = subsec == 'jw' + if dont_expand_version_macros and dep_name in cur_pkgs: + expand_version_macros = False + if hide_self and dep_name in seed_pkgs: + continue + dep_str = dep.constraint_str( + untemplated = expand_version_macros, + include_revision = dont_strip_revision, + as_range = expand_semver_revision_range, + no_subpackages = no_subpackages, + syntax = syntax, + quote = '"' if quote else None, + ) + if dep_str in ret: + continue + log(DEBUG, f'Appending dependency >{dep_str}<') + ret.append(dep_str) return ret