From 36bb5ba31efa049704f33d1c73d58024be61b149 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Wed, 17 Apr 2024 08:29:01 +0200 Subject: [PATCH] giteapc: improve install plan logic (#5) --- giteapc/repo.py | 50 +++++++++++++++++++++++++++++------------------- giteapc/repos.py | 5 +++++ 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/giteapc/repo.py b/giteapc/repo.py index d203150..9284675 100644 --- a/giteapc/repo.py +++ b/giteapc/repo.py @@ -121,6 +121,9 @@ class Spec: self.repo = resolve(self.name, local_only, remote_only) return self.repo + def is_blank(self): + return self.version is None and self.config is None + def str(self, pretty=False): if self.repo and pretty: name = pretty_repo(self.repo) @@ -133,6 +136,9 @@ class Spec: config = f":{self.config}" if self.config else "" return name + version + config + def same_version_config_as(self, other): + return self.version == other.version and self.config == other.config + def __str__(self): return self.str(pretty=False) def __repr__(self): @@ -335,32 +341,36 @@ def install(*args, use_https=False, use_ssh=False, update=False, yes=False, args = [ r.fullname for r in LocalRepo.all() ] # Fetch every repository and determine its dependencies to form a basic - # plan of what to build in what order + # plan of what repo to build in what order, but without version/config info - basic_plan = [] - search_dependencies(args, set(), basic_plan, use_https=use_https, + dep_order = [] + search_dependencies(args, set(), dep_order, use_https=use_https, use_ssh=use_ssh, update=update) - # Sanitize the build plan by checking occurrences of the same repository - # are consistent and eliminating duplicates - - # Build plan organized by name - named = dict() - # Final plan - plan = [] - - for s in basic_plan: - r = s.repo - if r.fullname not in named: - named[r.fullname] = s - plan.append(s) + # Apply configurations on everyone and make sure they are no contradictions + # and all configs exist + spec_by_repo = { spec.repo.fullname: spec for spec in dep_order } + for arg in args: + s = Spec(arg) + if s.is_blank(): continue - s2 = named[r.fullname] - if not s2.compatible_with(s): - return fatal(f"repo install: cannot install both {s} and {s2}") + r = s.resolve(local_only=True) + + name = s.repo.fullname + if not s.same_version_config_as(spec_by_repo[name]): + return fatal(f"repo install: multiple specs for {name}: {s}, " + + f"{spec_by_repo[name]}") + + if s.config not in ["", None] and s.config not in r.configs(): + return fatal(f"repo install: no config {s.config} for {name}" + + " (configs: " + ", ".join(r.configs()) + ")") + + spec_by_repo[name] = s + + # Final plan + plan = [ spec_by_repo[s.repo.fullname] for s in dep_order ] # Plan review and confirmation - msg("Will install:", ", ".join(s.pretty_str() for s in plan)) if dry_run: diff --git a/giteapc/repos.py b/giteapc/repos.py index cafe0d3..5665d09 100644 --- a/giteapc/repos.py +++ b/giteapc/repos.py @@ -161,6 +161,11 @@ class LocalRepo: with ChangeDirectory(self.folder): return run([command, "-f", "giteapc.make", target], env=env) + def configs(self): + RE_NAME = re.compile(r'giteapc-config-(.*)\.make') + files = glob.glob(self.folder + "/giteapc-config-*.make") + return sorted(RE_NAME.match(os.path.basename(x))[1] for x in files) + def set_config(self, config): source = self.folder + f"/giteapc-config.make" target = self.folder + f"/giteapc-config-{config}.make"