mirror of
https://github.com/wentasah/ros2nix.git
synced 2025-06-09 15:52:23 +03:00
Add experimental option --patches
This generates Nix expressions which include local patches (additional commits in local git repositories).
This commit is contained in:
parent
9193811bfc
commit
dc3de1f289
3 changed files with 92 additions and 3 deletions
|
@ -25,7 +25,7 @@
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
from textwrap import dedent, indent
|
from textwrap import dedent, indent
|
||||||
from time import gmtime, strftime
|
from time import gmtime, strftime
|
||||||
from typing import Iterable, Set, Optional
|
from typing import Iterable, Set, Optional, List
|
||||||
|
|
||||||
from superflore.utils import get_license
|
from superflore.utils import get_license
|
||||||
|
|
||||||
|
@ -95,11 +95,13 @@ class NixExpression:
|
||||||
src_param: Optional[str] = None,
|
src_param: Optional[str] = None,
|
||||||
source_root: Optional[str] = None,
|
source_root: Optional[str] = None,
|
||||||
do_check: Optional[bool] = None,
|
do_check: Optional[bool] = None,
|
||||||
|
patches: Optional[List[str]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.version = version
|
self.version = version
|
||||||
self.src_param = src_param
|
self.src_param = src_param
|
||||||
self.src_expr = src_expr
|
self.src_expr = src_expr
|
||||||
|
self.patches = patches
|
||||||
self.source_root = source_root
|
self.source_root = source_root
|
||||||
self.do_check = do_check
|
self.do_check = do_check
|
||||||
|
|
||||||
|
@ -168,6 +170,8 @@ class NixExpression:
|
||||||
version=self.version,
|
version=self.version,
|
||||||
src=src,
|
src=src,
|
||||||
build_type=self.build_type)
|
build_type=self.build_type)
|
||||||
|
if self.patches:
|
||||||
|
ret += f""" patches = [\n {"\n ".join(self.patches)}\n ];\n"""
|
||||||
|
|
||||||
if self.source_root:
|
if self.source_root:
|
||||||
ret += f' sourceRoot = "{self.source_root}";\n'
|
ret += f' sourceRoot = "{self.source_root}";\n'
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
# Copyright 2019-2024 Ben Wolsieffer <benwolsieffer@gmail.com>
|
# Copyright 2019-2024 Ben Wolsieffer <benwolsieffer@gmail.com>
|
||||||
# Copyright 2024 Michal Sojka <michal.sojka@cvut.cz>
|
# Copyright 2024 Michal Sojka <michal.sojka@cvut.cz>
|
||||||
|
|
||||||
|
from os.path import dirname
|
||||||
import argcomplete, argparse
|
import argcomplete, argparse
|
||||||
import difflib
|
import difflib
|
||||||
import io
|
import io
|
||||||
|
@ -246,6 +247,13 @@ def ros2nix(args):
|
||||||
"The fetch function and its parameters are determined from the local git work tree. "
|
"The fetch function and its parameters are determined from the local git work tree. "
|
||||||
"sourceRoot attribute is set if needed and not overridden by --source-root.",
|
"sourceRoot attribute is set if needed and not overridden by --source-root.",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--patches",
|
||||||
|
action=argparse.BooleanOptionalAction,
|
||||||
|
help="""Add git commits not present in git remote named "origin" as patches in the """
|
||||||
|
"""generated Nix expression. Only allowed with --fetch. This option is experimental """
|
||||||
|
"""and may be changed in the future.""",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--distro",
|
"--distro",
|
||||||
default="rolling",
|
default="rolling",
|
||||||
|
@ -333,8 +341,13 @@ def ros2nix(args):
|
||||||
if args.output_dir is None and (args.output_as_nix_pkg_name or args.output_as_ros_pkg_name):
|
if args.output_dir is None and (args.output_as_nix_pkg_name or args.output_as_ros_pkg_name):
|
||||||
args.output_dir = "."
|
args.output_dir = "."
|
||||||
|
|
||||||
|
if args.patches and not args.fetch:
|
||||||
|
err("--patches cannot be used without --fetch")
|
||||||
|
return 1
|
||||||
|
|
||||||
expressions: dict[str, str] = {}
|
expressions: dict[str, str] = {}
|
||||||
git_cache = {}
|
git_cache = {}
|
||||||
|
patch_filenames = set()
|
||||||
|
|
||||||
for source in args.source:
|
for source in args.source:
|
||||||
try:
|
try:
|
||||||
|
@ -370,6 +383,7 @@ def ros2nix(args):
|
||||||
buildtool_deps | buildtool_export_deps)
|
buildtool_deps | buildtool_export_deps)
|
||||||
|
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
patches = []
|
||||||
|
|
||||||
if args.src_param:
|
if args.src_param:
|
||||||
kwargs["src_param"] = args.src_param
|
kwargs["src_param"] = args.src_param
|
||||||
|
@ -388,12 +402,25 @@ def ros2nix(args):
|
||||||
"git rev-parse --show-toplevel".split(), cwd=srcdir
|
"git rev-parse --show-toplevel".split(), cwd=srcdir
|
||||||
).decode().strip()
|
).decode().strip()
|
||||||
|
|
||||||
|
head = subprocess.check_output(
|
||||||
|
"git rev-parse HEAD".split(), cwd=srcdir
|
||||||
|
).decode().strip()
|
||||||
|
|
||||||
if toplevel in git_cache:
|
if toplevel in git_cache:
|
||||||
info = git_cache[toplevel]
|
info = git_cache[toplevel]
|
||||||
|
upstream_rev = info["rev"]
|
||||||
else:
|
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 = subprocess.check_output(
|
||||||
|
"git merge-base HEAD $(git for-each-ref refs/remotes/origin --format='%(objectname)')",
|
||||||
|
shell=True, cwd=srcdir
|
||||||
|
).decode().strip()
|
||||||
info = json.loads(
|
info = json.loads(
|
||||||
subprocess.check_output(
|
subprocess.check_output(
|
||||||
["nix-prefetch-git", "--quiet", toplevel],
|
["nix-prefetch-git", "--quiet", toplevel, upstream_rev],
|
||||||
).decode()
|
).decode()
|
||||||
)
|
)
|
||||||
git_cache[toplevel] = info
|
git_cache[toplevel] = info
|
||||||
|
@ -421,6 +448,14 @@ def ros2nix(args):
|
||||||
# kwargs["src_expr"] = f'''let fullSrc = {kwargs["src_expr"]}; in "${{fullSrc}}/{prefix}"'''
|
# kwargs["src_expr"] = f'''let fullSrc = {kwargs["src_expr"]}; in "${{fullSrc}}/{prefix}"'''
|
||||||
kwargs["source_root"] = f"${{src.name}}/{prefix}"
|
kwargs["source_root"] = f"${{src.name}}/{prefix}"
|
||||||
|
|
||||||
|
if args.patches:
|
||||||
|
patches = subprocess.check_output(
|
||||||
|
f"if ! git diff --quiet {upstream_rev}..HEAD -- .; then git format-patch --relative {upstream_rev}..HEAD; fi",
|
||||||
|
shell=True, cwd=srcdir,
|
||||||
|
).decode().strip().splitlines()
|
||||||
|
elif head != upstream_rev:
|
||||||
|
warn(f"{toplevel} contains commits not available upstream. Consider using --patches")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if args.output_dir is None:
|
if args.output_dir is None:
|
||||||
kwargs["src_expr"] = "./."
|
kwargs["src_expr"] = "./."
|
||||||
|
@ -444,6 +479,7 @@ def ros2nix(args):
|
||||||
propagated_build_inputs=propagated_build_inputs | set(args.extra_propagated_build_inputs),
|
propagated_build_inputs=propagated_build_inputs | set(args.extra_propagated_build_inputs),
|
||||||
check_inputs=check_inputs | set(args.extra_check_inputs),
|
check_inputs=check_inputs | set(args.extra_check_inputs),
|
||||||
native_build_inputs=native_build_inputs | set(args.extra_native_build_inputs),
|
native_build_inputs=native_build_inputs | set(args.extra_native_build_inputs),
|
||||||
|
patches=[f"./{p}" for p in patches],
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -478,6 +514,20 @@ def ros2nix(args):
|
||||||
output_file_name = get_output_file_name(source, pkg, args)
|
output_file_name = get_output_file_name(source, pkg, args)
|
||||||
with file_writer(output_file_name, args.compare) as recipe_file:
|
with file_writer(output_file_name, args.compare) as recipe_file:
|
||||||
recipe_file.write(derivation_text)
|
recipe_file.write(derivation_text)
|
||||||
|
for patch in patches:
|
||||||
|
patch_filename = os.path.join(dirname(output_file_name), patch)
|
||||||
|
if not patch_filename in patch_filenames:
|
||||||
|
patch_filenames.add(patch_filename)
|
||||||
|
else:
|
||||||
|
# TODO Allow better handling of patch name collisions (e.g. by
|
||||||
|
# having them in per-package directories, perhaps via
|
||||||
|
# --output_subdir_as_nix_pkg_name)
|
||||||
|
msg = f"Patch {patch_filename} already exists"
|
||||||
|
err(msg)
|
||||||
|
raise Exception(msg)
|
||||||
|
with file_writer(patch_filename, args.compare) as patch_dest, \
|
||||||
|
open(os.path.join(os.path.dirname(source), patch), "r") as patch_src:
|
||||||
|
patch_dest.write(patch_src.read())
|
||||||
if not args.compare:
|
if not args.compare:
|
||||||
ok(f"Successfully generated derivation for package '{pkg.name}' as '{output_file_name}'.")
|
ok(f"Successfully generated derivation for package '{pkg.name}' as '{output_file_name}'.")
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,41 @@ load common.bash
|
||||||
@test "--fetch from github over https" {
|
@test "--fetch from github over https" {
|
||||||
git clone https://github.com/wentasah/ros2nix
|
git clone https://github.com/wentasah/ros2nix
|
||||||
ros2nix --output-as-nix-pkg-name --fetch $(find "ros2nix/test/ws/src" -name package.xml)
|
ros2nix --output-as-nix-pkg-name --fetch $(find "ros2nix/test/ws/src" -name package.xml)
|
||||||
cat ros-node.nix
|
|
||||||
nix-build -A rosPackages.jazzy.ros-node
|
nix-build -A rosPackages.jazzy.ros-node
|
||||||
|
run ./result/lib/ros_node/node
|
||||||
|
assert_success
|
||||||
|
assert_line --partial "hello world"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "--patches without --fetch" {
|
||||||
|
run ! ros2nix --patches $(find ws/src -name package.xml)
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "--fetch --patches" {
|
||||||
|
git clone https://github.com/wentasah/ros2nix
|
||||||
|
pushd ros2nix
|
||||||
|
sed -i -e 's/hello world/hello patch/' test/ws/src/ros_node/src/node.cpp
|
||||||
|
git commit -m 'test patch' -- test/ws/src/ros_node/src/node.cpp
|
||||||
|
popd
|
||||||
|
ros2nix --output-as-nix-pkg-name --fetch --patches $(find "ros2nix/test/ws/src" -name package.xml)
|
||||||
|
# remove original (abd patched) sources
|
||||||
|
rm -rf ros2nix
|
||||||
|
nix-build -A rosPackages.jazzy.ros-node
|
||||||
|
# validate that we get patched binary
|
||||||
|
run ./result/lib/ros_node/node
|
||||||
|
assert_success
|
||||||
|
assert_line --partial "hello patch"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "--fetch --patches with colliding changes" {
|
||||||
|
git clone https://github.com/wentasah/ros2nix
|
||||||
|
pushd ros2nix
|
||||||
|
sed -i -e 's/hello world/hello patch/' test/ws/src/ros_node/src/node.cpp
|
||||||
|
git commit -m 'test patch' -- test/ws/src/ros_node/src/node.cpp
|
||||||
|
sed -i -e '1a// comment' test/ws/src/library/src/library.cpp
|
||||||
|
git commit -m 'test patch' -- test/ws/src/library/src/library.cpp
|
||||||
|
popd
|
||||||
|
run ros2nix --output-as-nix-pkg-name --fetch --patches $(find "ros2nix/test/ws/src" -name package.xml)
|
||||||
|
assert_failure
|
||||||
|
assert_line --partial "Patch ./0001-test-patch.patch already exists"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue