From c309f53ac9dc2330241a2f643f0be225d542d0e3 Mon Sep 17 00:00:00 2001 From: Max Beutelspacher Date: Tue, 25 Feb 2025 21:16:32 +0100 Subject: [PATCH] feat: add the option to store sha256 cache in a file cache is also used for per package source checkouts and - is used as a key --- README.md | 7 ++++++- ros2nix/ros2nix.py | 33 +++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5ec9406..bddd2cd 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,8 @@ usage: ros2nix [-h] [--output-dir OUTPUT_DIR] [--fetch] [--use-per-package-src] [--patches | --no-patches] [--distro DISTRO] [--src-param SRC_PARAM] [--source-root SOURCE_ROOT] - [--do-check] [--extra-build-inputs DEP1,DEP2,...] + [--cache-file CACHE_FILE] [--do-check] + [--extra-build-inputs DEP1,DEP2,...] [--extra-propagated-build-inputs DEP1,DEP2,...] [--extra-check-inputs DEP1,DEP2,...] [--extra-native-build-inputs DEP1,DEP2,...] [--flake] @@ -172,6 +173,10 @@ options: Set sourceRoot attribute value in the generated Nix expression. Substring '{package_name}' gets replaced with the package name. (default: None) + --cache-file CACHE_FILE + Path to a json-file to store sha265 hashes of + checkouts persistently to cache them across generation + runs. (default: None) --do-check Set doCheck attribute to true (default: False) --extra-build-inputs DEP1,DEP2,... Additional dependencies to add to the generated Nix diff --git a/ros2nix/ros2nix.py b/ros2nix/ros2nix.py index 8bf2190..64a757e 100755 --- a/ros2nix/ros2nix.py +++ b/ros2nix/ros2nix.py @@ -14,6 +14,7 @@ import os import re import subprocess import sys +import json from contextlib import contextmanager from textwrap import dedent, indent from typing import Iterable, Set, List @@ -280,6 +281,9 @@ def ros2nix(args): help="Set sourceRoot attribute value in the generated Nix expression. " "Substring '{package_name}' gets replaced with the package name.", ) + parser.add_argument( + "--cache-file", help="Path to a json-file to store sha265 hashes of checkouts persistently to cache them across generation runs." + ) parser.add_argument( "--do-check", action="store_true", @@ -357,6 +361,9 @@ def ros2nix(args): expressions: dict[str, str] = {} git_cache = {} + if args.cache_file is not None and os.path.exists(args.cache_file): + with open(args.cache_file) as f: + git_cache = json.load(f) patch_filenames = set() for source in args.source: @@ -418,15 +425,21 @@ def ros2nix(args): merge_base = merge_base_to_upstream(head) head = check_output(f"git rev-list {merge_base} -1 -- .".split()) - if not args.use_per_package_src and toplevel in git_cache: # only use cache if not using separate checkout per package - info = git_cache[toplevel] + def cache_key(prefix, rev): + if args.use_per_package_src: + return f"{prefix}-{rev}" + return rev + + + # Latest commit present in the upstream repo. If + # the local repository doesn't have additional + # commits, it is the same as HEAD. Should work + # even with detached HEAD. + upstream_rev = merge_base_to_upstream(head) + if cache_key(prefix, upstream_rev) in git_cache: + info = git_cache[cache_key(prefix, upstream_rev)] upstream_rev = info["rev"] else: - # Latest commit present in the upstream repo. If - # the local repository doesn't have additional - # commits, it is the same as HEAD. Should work - # even with detached HEAD. - upstream_rev = merge_base_to_upstream(head) info = json.loads( subprocess.check_output( ["nix-prefetch-git", "--quiet"] @@ -438,7 +451,7 @@ def ros2nix(args): + [toplevel, upstream_rev], ).decode() ) - git_cache[toplevel] = info + git_cache[cache_key(prefix, upstream_rev)] = {k : info[k] for k in ["rev", "sha256"]} match = re.match("https://github.com/(?P[^/]*)/(?P.*?)(.git|/.*)?$", url) sparse_checkout = f"""sparseCheckout = ["{prefix}"]; @@ -568,6 +581,10 @@ def ros2nix(args): generate_default(args) # TODO generate also release.nix (for testing/CI)? + if args.cache_file is not None: + with open(args.cache_file, "w") as f: + json.dump(git_cache, f) + if args.compare and compare_failed: err("Some files are not up-to-date") return 2