feat: add the option to store sha256 cache in a file

cache is also used for per package source checkouts and
<git-rev>-<package-prefix> is used as a key
This commit is contained in:
Max Beutelspacher 2025-02-25 21:16:32 +01:00
parent c35b0dc7aa
commit c309f53ac9
2 changed files with 31 additions and 9 deletions

View file

@ -116,7 +116,8 @@ usage: ros2nix [-h]
[--output-dir OUTPUT_DIR] [--fetch] [--use-per-package-src] [--output-dir OUTPUT_DIR] [--fetch] [--use-per-package-src]
[--patches | --no-patches] [--distro DISTRO] [--patches | --no-patches] [--distro DISTRO]
[--src-param SRC_PARAM] [--source-root SOURCE_ROOT] [--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-propagated-build-inputs DEP1,DEP2,...]
[--extra-check-inputs DEP1,DEP2,...] [--extra-check-inputs DEP1,DEP2,...]
[--extra-native-build-inputs DEP1,DEP2,...] [--flake] [--extra-native-build-inputs DEP1,DEP2,...] [--flake]
@ -172,6 +173,10 @@ options:
Set sourceRoot attribute value in the generated Nix Set sourceRoot attribute value in the generated Nix
expression. Substring '{package_name}' gets replaced expression. Substring '{package_name}' gets replaced
with the package name. (default: None) 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) --do-check Set doCheck attribute to true (default: False)
--extra-build-inputs DEP1,DEP2,... --extra-build-inputs DEP1,DEP2,...
Additional dependencies to add to the generated Nix Additional dependencies to add to the generated Nix

View file

@ -14,6 +14,7 @@ import os
import re import re
import subprocess import subprocess
import sys import sys
import json
from contextlib import contextmanager from contextlib import contextmanager
from textwrap import dedent, indent from textwrap import dedent, indent
from typing import Iterable, Set, List from typing import Iterable, Set, List
@ -280,6 +281,9 @@ def ros2nix(args):
help="Set sourceRoot attribute value in the generated Nix expression. " help="Set sourceRoot attribute value in the generated Nix expression. "
"Substring '{package_name}' gets replaced with the package name.", "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( parser.add_argument(
"--do-check", "--do-check",
action="store_true", action="store_true",
@ -357,6 +361,9 @@ def ros2nix(args):
expressions: dict[str, str] = {} expressions: dict[str, str] = {}
git_cache = {} 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() patch_filenames = set()
for source in args.source: for source in args.source:
@ -418,15 +425,21 @@ def ros2nix(args):
merge_base = merge_base_to_upstream(head) merge_base = merge_base_to_upstream(head)
head = check_output(f"git rev-list {merge_base} -1 -- .".split()) 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 def cache_key(prefix, rev):
info = git_cache[toplevel] if args.use_per_package_src:
upstream_rev = info["rev"] return f"{prefix}-{rev}"
else: return rev
# Latest commit present in the upstream repo. If # Latest commit present in the upstream repo. If
# the local repository doesn't have additional # the local repository doesn't have additional
# commits, it is the same as HEAD. Should work # commits, it is the same as HEAD. Should work
# even with detached HEAD. # even with detached HEAD.
upstream_rev = merge_base_to_upstream(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:
info = json.loads( info = json.loads(
subprocess.check_output( subprocess.check_output(
["nix-prefetch-git", "--quiet"] ["nix-prefetch-git", "--quiet"]
@ -438,7 +451,7 @@ def ros2nix(args):
+ [toplevel, upstream_rev], + [toplevel, upstream_rev],
).decode() ).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<owner>[^/]*)/(?P<repo>.*?)(.git|/.*)?$", url) match = re.match("https://github.com/(?P<owner>[^/]*)/(?P<repo>.*?)(.git|/.*)?$", url)
sparse_checkout = f"""sparseCheckout = ["{prefix}"]; sparse_checkout = f"""sparseCheckout = ["{prefix}"];
@ -568,6 +581,10 @@ def ros2nix(args):
generate_default(args) generate_default(args)
# TODO generate also release.nix (for testing/CI)? # 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: if args.compare and compare_failed:
err("Some files are not up-to-date") err("Some files are not up-to-date")
return 2 return 2