diff --git a/rockcraft/oci.py b/rockcraft/oci.py index 7a51983cc..2c22bdca9 100644 --- a/rockcraft/oci.py +++ b/rockcraft/oci.py @@ -441,6 +441,7 @@ def _gather_layer_paths( A dict where the value is a path (file or dir) in ``new_layer_dir`` and the key is the name that this path should have in the tarball for the layer. """ + # pylint: disable=too-many-locals class LayerLinker: """Helper to keep track of paths between the upper and lower layer.""" @@ -512,6 +513,14 @@ def get_target_path(self, path: Path) -> Path: archive_path = layer_linker.get_target_path(relative_path / name) result[f"{archive_path}"].append(upper_subpath / name) + # Add each subdir in the directory if it's a symlink, because the os.walk() + # call will not enter them. + for subdir in subdirs: + upper_subdir_path = upper_subpath / subdir + if upper_subdir_path.is_symlink(): + archive_path = layer_linker.get_target_path(relative_path / subdir) + result[f"{archive_path}"].append(upper_subdir_path) + return result diff --git a/tests/unit/test_oci.py b/tests/unit/test_oci.py index 7e59a8aee..6cda06dcc 100644 --- a/tests/unit/test_oci.py +++ b/tests/unit/test_oci.py @@ -283,6 +283,30 @@ def test_add_layer_directories(self, tmp_path, temp_tar_contents): ] assert temp_tar_contents == expected_tar_contents + def test_add_layer_symlinks(self, tmp_path, temp_tar_contents): + """ + Test creating a new layer with symlinks (both file and dir). + """ + dest_dir = tmp_path / "dest" + dest_dir.mkdir() + + layer_dir = tmp_path / "layer_dir" + layer_dir.mkdir() + + (layer_dir / "first_dir").mkdir() + (layer_dir / "first_file").touch() + + (layer_dir / "second_dir").symlink_to("first_dir", target_is_directory=True) + (layer_dir / "second_file").symlink_to("first_file", target_is_directory=False) + + image = oci.Image("a:b", dest_dir) + + assert len(temp_tar_contents) == 0 + image.add_layer("tag", layer_dir) + + expected_tar_contents = ["first_dir", "first_file", "second_dir", "second_file"] + assert temp_tar_contents == expected_tar_contents + def test_add_layer_with_base_layer_dir(self, tmp_path, temp_tar_contents): """Test creating a layer with a base layer dir for reference.""" dest_dir = tmp_path / "dest"