Skip to content

Commit

Permalink
oci: fix handling of symlink subdirs (canonical#211)
Browse files Browse the repository at this point in the history
When Rockcraft creates the tar archive from the priming area, subdirs
symlinks are skipped from archive.

Solution is to add subdirs when they are symlinks.

Fix canonical#208

---------
Co-authored-by: Tiago Nobrega <[email protected]>
  • Loading branch information
gboutry authored and cjdcordeiro committed Mar 31, 2023
1 parent 091bf76 commit 0df68f1
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
9 changes: 9 additions & 0 deletions rockcraft/oci.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down Expand Up @@ -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


Expand Down
24 changes: 24 additions & 0 deletions tests/unit/test_oci.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit 0df68f1

Please sign in to comment.