Unify the project dependency walks in App and pkg_relations() #118
2 changed files with 111 additions and 79 deletions
|
|
@ -198,7 +198,28 @@ class App(Base):
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __get_project_refs(
|
def read_dep_edges(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
sections: list[str],
|
||||||
|
key: str,
|
||||||
|
) -> list[str]:
|
||||||
|
"""The deduplicated dependency values of name for the given
|
||||||
|
sections and key (flavour), in section and value order.
|
||||||
|
"""
|
||||||
|
ret: list[str] = []
|
||||||
|
for section in sections:
|
||||||
|
vals = self.get_value(name, section, key)
|
||||||
|
log(DEBUG, f'name={name}, section={section}, key={key}, deps={vals}')
|
||||||
|
if not vals:
|
||||||
|
continue
|
||||||
|
for val in vals.split(','):
|
||||||
|
val = val.strip()
|
||||||
|
if (len(val)) and (val not in ret):
|
||||||
|
ret.append(val)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def walk_project_deps(
|
||||||
self,
|
self,
|
||||||
buf: list[str],
|
buf: list[str],
|
||||||
visited: set[str],
|
visited: set[str],
|
||||||
|
|
@ -208,7 +229,21 @@ class App(Base):
|
||||||
add_self: bool,
|
add_self: bool,
|
||||||
scope: Scope,
|
scope: Scope,
|
||||||
names_only: bool,
|
names_only: bool,
|
||||||
|
*,
|
||||||
|
check_installed: bool = True,
|
||||||
|
exclude: set[str] = set(),
|
||||||
|
recurse: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""Walk the dependency edges of sections and key (flavour)
|
||||||
|
starting at spec, appending the visited specs to buf in
|
||||||
|
postorder; buf and visited are updated in place.
|
||||||
|
|
||||||
|
check_installed applies the installed-package check, which
|
||||||
|
skips the dependencies of an installed run package and fails
|
||||||
|
on an unmet dependency. exclude names specs that are neither
|
||||||
|
traversed nor appended. recurse = False stops the walk at the
|
||||||
|
starting spec.
|
||||||
|
"""
|
||||||
dep = Dependency(spec)
|
dep = Dependency(spec)
|
||||||
name = dep.base_name
|
name = dep.base_name
|
||||||
mod = dep.full_name
|
mod = dep.full_name
|
||||||
|
|
@ -216,52 +251,44 @@ class App(Base):
|
||||||
spec = name
|
spec = name
|
||||||
if spec in buf:
|
if spec in buf:
|
||||||
return
|
return
|
||||||
|
if spec in exclude:
|
||||||
|
return
|
||||||
if spec in visited:
|
if spec in visited:
|
||||||
if add_self:
|
if add_self:
|
||||||
buf.append(spec)
|
buf.append(spec)
|
||||||
return
|
return
|
||||||
visited.add(spec)
|
visited.add(spec)
|
||||||
needed_subpackage = 'devel' if mod.endswith(('-dev', '-devel')) else 'run'
|
if check_installed:
|
||||||
if not self.is_installed(name, devel = True):
|
needed_subpackage = 'devel' if mod.endswith(('-dev', '-devel')) else 'run'
|
||||||
if not mod.endswith(('-dev', '-devel')):
|
if not self.is_installed(name, devel = True):
|
||||||
if self.is_installed(name, devel = False):
|
if not mod.endswith(('-dev', '-devel')):
|
||||||
return
|
if self.is_installed(name, devel = False):
|
||||||
raise Exception(
|
return
|
||||||
f'Unmet dependency on {mod}: the -{needed_subpackage} package '
|
raise Exception(
|
||||||
f'of project {name} is not installed'
|
f'Unmet dependency on {mod}: the -{needed_subpackage} package '
|
||||||
)
|
f'of project {name} is not installed'
|
||||||
vals_list: list[str] = []
|
)
|
||||||
for section in sections:
|
vals_list = self.read_dep_edges(name, sections, key)
|
||||||
vals = self.get_value(name, section, key)
|
|
||||||
log(
|
|
||||||
DEBUG,
|
|
||||||
(
|
|
||||||
f'name={name}, section={section}, key={key}, deps={vals}, '
|
|
||||||
f'scope={scope.name}, visited={visited}'
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if not vals:
|
|
||||||
continue
|
|
||||||
for val in vals.split(','):
|
|
||||||
val = val.strip()
|
|
||||||
if (len(val)) and (val not in vals_list):
|
|
||||||
vals_list.append(val)
|
|
||||||
match scope:
|
match scope:
|
||||||
case Scope.Self:
|
case Scope.Self:
|
||||||
buf += vals_list
|
buf += vals_list
|
||||||
case Scope.One | Scope.Subtree:
|
case Scope.One | Scope.Subtree:
|
||||||
subscope = scope.Self if scope == Scope.One else scope
|
if recurse:
|
||||||
for val in vals_list:
|
subscope = scope.Self if scope == Scope.One else scope
|
||||||
self.__get_project_refs(
|
for val in vals_list:
|
||||||
buf,
|
self.walk_project_deps(
|
||||||
visited,
|
buf,
|
||||||
val,
|
visited,
|
||||||
sections,
|
val,
|
||||||
key,
|
sections,
|
||||||
add_self = True,
|
key,
|
||||||
scope = subscope,
|
add_self = True,
|
||||||
names_only = names_only,
|
scope = subscope,
|
||||||
)
|
names_only = names_only,
|
||||||
|
check_installed = check_installed,
|
||||||
|
exclude = exclude,
|
||||||
|
recurse = recurse,
|
||||||
|
)
|
||||||
if add_self:
|
if add_self:
|
||||||
buf.append(spec)
|
buf.append(spec)
|
||||||
|
|
||||||
|
|
@ -567,7 +594,7 @@ class App(Base):
|
||||||
visited: set[str] = set()
|
visited: set[str] = set()
|
||||||
for name in projects:
|
for name in projects:
|
||||||
rr: list[str] = []
|
rr: list[str] = []
|
||||||
self.__get_project_refs(
|
self.walk_project_deps(
|
||||||
rr, visited, name, sections, key, add_self, scope, names_only
|
rr, visited, name, sections, key, add_self, scope, names_only
|
||||||
)
|
)
|
||||||
# TODO: this looks like a performance hogger
|
# TODO: this looks like a performance hogger
|
||||||
|
|
|
||||||
|
|
@ -52,47 +52,52 @@ def pkg_relations(
|
||||||
|
|
||||||
ret: list[str] = []
|
ret: list[str] = []
|
||||||
for flavour in flavours: # build / release / run / devel
|
for flavour in flavours: # build / release / run / devel
|
||||||
cur_pkgs = seed_pkgs.copy()
|
closure: list[str] = []
|
||||||
visited_pkgs: set[str] = set()
|
visited: set[str] = set()
|
||||||
while len(cur_pkgs):
|
for seed in seed_pkgs:
|
||||||
cur_pkg = cur_pkgs.pop(0)
|
app.walk_project_deps(
|
||||||
if cur_pkg in visited_pkgs or cur_pkg in ignore:
|
closure,
|
||||||
continue
|
visited,
|
||||||
|
seed,
|
||||||
|
['pkg.' + rel_type + '.jw'],
|
||||||
|
flavour,
|
||||||
|
add_self = True,
|
||||||
|
scope = Scope.Subtree,
|
||||||
|
names_only = True,
|
||||||
|
check_installed = False,
|
||||||
|
exclude = ignore,
|
||||||
|
recurse = recursive,
|
||||||
|
)
|
||||||
|
for cur_pkg in closure:
|
||||||
for subsec in subsections:
|
for subsec in subsections:
|
||||||
section = 'pkg.' + rel_type + '.' + subsec
|
section = 'pkg.' + rel_type + '.' + subsec
|
||||||
visited_pkgs.add(cur_pkg)
|
for deps_spec in app.read_dep_edges(cur_pkg, [section], flavour):
|
||||||
deps_spec = app.get_value(cur_pkg, section, flavour)
|
for dep in Dependency.parse_deps_spec(
|
||||||
if not deps_spec:
|
deps_spec,
|
||||||
continue
|
lookup_version = app.get_version,
|
||||||
for dep in Dependency.parse_deps_spec(
|
dependent_package = cur_pkg,
|
||||||
deps_spec,
|
):
|
||||||
lookup_version = app.get_version,
|
dep_name = dep.base_name
|
||||||
dependent_package = cur_pkg,
|
if dep_name in ignore or dep.full_name in ignore:
|
||||||
):
|
|
||||||
dep_name = dep.base_name
|
|
||||||
if dep_name in ignore or dep.full_name in ignore:
|
|
||||||
continue
|
|
||||||
if subsec == 'jw':
|
|
||||||
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 and dep_name == 'jw-pkg':
|
|
||||||
continue
|
continue
|
||||||
expand_version_macros = subsec == 'jw'
|
if subsec == 'jw':
|
||||||
if dont_expand_version_macros and dep_name in cur_pkgs:
|
if hide_jw_pkg and dep_name == 'jw-pkg':
|
||||||
expand_version_macros = False
|
continue
|
||||||
if hide_self and dep_name in seed_pkgs:
|
expand_version_macros = subsec == 'jw'
|
||||||
continue
|
if dont_expand_version_macros and dep_name in visited:
|
||||||
dep_str = dep.constraint_str(
|
expand_version_macros = False
|
||||||
untemplated = expand_version_macros,
|
if hide_self and dep_name in seed_pkgs:
|
||||||
include_revision = dont_strip_revision,
|
continue
|
||||||
as_range = expand_semver_revision_range,
|
dep_str = dep.constraint_str(
|
||||||
no_subpackages = no_subpackages,
|
untemplated = expand_version_macros,
|
||||||
syntax = syntax,
|
include_revision = dont_strip_revision,
|
||||||
quote = '"' if quote else None,
|
as_range = expand_semver_revision_range,
|
||||||
)
|
no_subpackages = no_subpackages,
|
||||||
if dep_str in ret:
|
syntax = syntax,
|
||||||
continue
|
quote = '"' if quote else None,
|
||||||
log(DEBUG, f'Appending dependency >{dep_str}<')
|
)
|
||||||
ret.append(dep_str)
|
if dep_str in ret:
|
||||||
|
continue
|
||||||
|
log(DEBUG, f'Appending dependency >{dep_str}<')
|
||||||
|
ret.append(dep_str)
|
||||||
return ret
|
return ret
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue