Skip to content

Commit

Permalink
ypkg-install-deps: add --dry-run and --json
Browse files Browse the repository at this point in the history
The JSON dump has the following format:
```json
[
{
    "name": "<package-name>",
    "version": "<version>",
    "release": "<relno>",
    "packageHash": "<hash-of-eopkg>",
}
]
```

This not only dumps every single (including transitive) dependencies, but also
dumps the **currently installed** packages on the system. If we run this
inside the `solbuild` chroot and run `sudo eopkg up` prior to running `ypkg-
install-deps --dry-run --json package.yml`, we should get a (mostly)
reproducible JSON of packages that the root is comprised of. If we cache this
root identified by the hash of this JSON dump, we should be able to re-use
this cached root in `solbuild`, eliminating most if not all the time needed
for dependencies to install given that no dependency is changed.

Signed-off-by: Gavin Zhao <[email protected]>
  • Loading branch information
GZGavinZhao committed Jan 15, 2024
1 parent e676667 commit 9b34216
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 26 deletions.
68 changes: 60 additions & 8 deletions ypkg-install-deps
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import sys
import os
import subprocess
import argparse

import Queue
import json

def main():
spec = YpkgSpec()
Expand All @@ -37,6 +38,10 @@ def main():
"i.e. no prompt", action="store_true")
parser.add_argument("-D", "--output-dir", type=str,
help="Ignored in ypkg-install-deps")
parser.add_argument("--dry-run", help="Don't install anyting",
action="store_true")
parser.add_argument("--json", help="Dump json info of all packages that should be "
"installed when building package", action="store_true")
# Main file
parser.add_argument("filename", help="Path to the ypkg YAML file")

Expand All @@ -47,6 +52,9 @@ def main():
# Show version
if args.version:
show_version()
# Disallow logging if outputting json
if args.json:
console_ui.quiet = True

# Grab filename
if not args.filename:
Expand All @@ -61,6 +69,7 @@ def main():
pc32deps = set()
pcdeps = set()
ndeps = set()
full_deps = set()

idb = InstallDB()
pdb = PackageDB()
Expand All @@ -80,6 +89,7 @@ def main():
if em:
pcdeps.add(em.group(1))
continue
full_deps.add(dep)
if not idb.has_package(dep):
ndeps.add(dep)

Expand All @@ -93,6 +103,7 @@ def main():
if em:
pcdeps.add(em.group(1))
continue
full_deps.add(dep)
if not idb.has_package(dep):
ndeps.add(dep)

Expand Down Expand Up @@ -127,6 +138,7 @@ def main():
console_ui.emit_error("BuildDep", "pkgconfig32({}) build dep "
"doesn't exist in the repository.".format(i))
sys.exit(1)

if not idb.has_package(pkg.name):
ndeps.add(pkg.name)

Expand All @@ -148,6 +160,8 @@ def main():
" does not exist in the repository.".
format(i))
sys.exit(1)

full_deps.add(pkg.name)
if not idb.has_package(pkg.name):
ndeps.add(pkg.name)

Expand All @@ -172,13 +186,51 @@ def main():
format(" ".join(invalid)))
sys.exit(1)

console_ui.emit_info("BuildDep", "Requesting installation of: {}".
format(", ".join(ndeps)))
try:
subprocess.check_call(cmd, shell=True)
except Exception as e:
console_ui.emit_error("BuildDep", "Failed to install build deps")
sys.exit(1)
if not args.dry_run:
console_ui.emit_info("BuildDep", "Requesting installation of: {}".
format(", ".join(ndeps)))
try:
subprocess.check_call(cmd, shell=True)
except Exception as e:
console_ui.emit_error("BuildDep", "Failed to install build deps")
sys.exit(1)
elif args.json:
json_pkgs = []
queue = Queue.Queue()
for dep in full_deps:
queue.put(dep)

while not queue.empty():
dep = queue.get()
dpkg = pdb.get_package(dep)
if not dpkg:
console_ui.emit_error("JSON", "Unknown build dep: {}".format(dep))
sys.exit(1)

json_pkgs.append({key: getattr(dpkg, key) for key in ["name", "version", "release", "packageHash"]})
for ddep in dpkg.runtimeDependencies():
if not ddep.satisfied_by_repo():
console_ui.emit_error("JSON",
"%s depends on %s but latter is not satisfied" % (dep, ddep.name()))
sys.exit(1)

if ddep.name() in full_deps:
continue
queue.put(ddep.name())
full_deps.add(ddep.name())

for ipkg in idb.list_installed():
if ipkg in full_deps:
continue

pkg = pdb.get_package(ipkg)
if not pkg:
console_ui.emit_error("JSON", "why is %s installed but doesn't exist in package db?" % ipkg)
sys.exit(1)
json_pkgs.append({key: getattr(pkg, key) for key in ["name", "version", "release", "packageHash"]})

print(json.dumps(json_pkgs, indent=2))


sys.exit(0)

Expand Down
41 changes: 23 additions & 18 deletions ypkg2/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class YpkgUI:

""" We must allow toggling of colors in the UI """
allow_colors = False
""" Don't emit anything except errors """
quiet = False

def __init__(self):
self.allow_colors = True
Expand All @@ -68,28 +70,31 @@ def emit_error(self, key, error):
AnsiColors.RESET, AnsiColors.BOLD, error, AnsiColors.RESET))

def emit_warning(self, key, warn):
""" Report a warning to the user """
if not self.allow_colors:
print("[{}] {}".format(key, warn))
else:
print("{}[{}]{} {}{}{}".format(AnsiColors.YELLOW, key,
AnsiColors.RESET, AnsiColors.BOLD, warn, AnsiColors.RESET))
if not self.quiet:
""" Report a warning to the user """
if not self.allow_colors:
print("[{}] {}".format(key, warn))
else:
print("{}[{}]{} {}{}{}".format(AnsiColors.YELLOW, key,
AnsiColors.RESET, AnsiColors.BOLD, warn, AnsiColors.RESET))

def emit_info(self, key, info):
""" Report information to the user """
if not self.allow_colors:
print("[{}] {}".format(key, info))
else:
print("{}[{}]{} {}".format(AnsiColors.BLUE, key,
AnsiColors.RESET, info))
if not self.quiet:
""" Report information to the user """
if not self.allow_colors:
print("[{}] {}".format(key, info))
else:
print("{}[{}]{} {}".format(AnsiColors.BLUE, key,
AnsiColors.RESET, info))

def emit_success(self, key, success):
""" Report success to the user """
if not self.allow_colors:
print("[{}] {}".format(key, success))
else:
print("{}[{}]{} {}".format(AnsiColors.GREEN, key,
AnsiColors.RESET, success))
if not self.quiet:
""" Report success to the user """
if not self.allow_colors:
print("[{}] {}".format(key, success))
else:
print("{}[{}]{} {}".format(AnsiColors.GREEN, key,
AnsiColors.RESET, success))


suffixes = ["B", "KB", "MB", "GB", "TB", "PB"]
Expand Down

0 comments on commit 9b34216

Please sign in to comment.