giteapc: improve install plan logic (#5)

This commit is contained in:
Lephenixnoir 2024-04-17 08:29:01 +02:00
parent b946986ca9
commit 36bb5ba31e
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
2 changed files with 35 additions and 20 deletions

View File

@ -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:

View File

@ -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"