diff --git a/swh/storage/algos/directory.py b/swh/storage/algos/directory.py new file mode 100644 --- /dev/null +++ b/swh/storage/algos/directory.py @@ -0,0 +1,34 @@ +# Copyright (C) 2022 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + +from typing import Iterable, Optional + +from swh.core.api.classes import stream_results_optional +from swh.model.model import Directory, DirectoryEntry, Sha1Git +from swh.storage.interface import StorageInterface + + +def directory_get( + storage: StorageInterface, directory_id: Sha1Git +) -> Optional[Directory]: + """Get all the entries for a given directory + + Args: + storage (swh.storage.interface.StorageInterface): the storage instance + directory_id (bytes): the directory's identifier + Returns: + The directory if it could be properly put back together. + """ + entries: Optional[Iterable[DirectoryEntry]] = stream_results_optional( + storage.directory_get_entries, + directory_id=directory_id, + ) + if entries is None: + return None + return Directory( + id=directory_id, + entries=tuple(entries), + raw_manifest=storage.directory_get_raw_manifest([directory_id])[directory_id], + ) diff --git a/swh/storage/tests/algos/test_directory.py b/swh/storage/tests/algos/test_directory.py new file mode 100644 --- /dev/null +++ b/swh/storage/tests/algos/test_directory.py @@ -0,0 +1,44 @@ +# Copyright (C) 2022 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + +import pytest + +from swh.model.model import Directory, DirectoryEntry +from swh.storage.algos.directory import directory_get + +from ..storage_data import StorageData + + +@pytest.mark.parametrize("directory_id", [d.id for d in StorageData.directories]) +def test_directory_small(swh_storage, directory_id): + swh_storage.directory_add(StorageData.directories) + + (expected_directory,) = [d for d in StorageData.directories if d.id == directory_id] + returned_directory = directory_get(swh_storage, directory_id) + assert returned_directory.id == expected_directory.id + assert set(returned_directory.entries) == set(expected_directory.entries) + assert returned_directory.raw_manifest == expected_directory.raw_manifest + + +def test_directory_large(swh_storage): + expected_directory = Directory( + entries=tuple( + DirectoryEntry( + name=f"entry{i:04}".encode(), + type="file", + target=b"\x00" * 20, + perms=0o000664, + ) + for i in range(10) + ) + ) + + swh_storage.directory_add([expected_directory]) + + returned_directory = directory_get(swh_storage, expected_directory.id) + + assert returned_directory.id == expected_directory.id + assert set(returned_directory.entries) == set(expected_directory.entries) + assert returned_directory.raw_manifest == expected_directory.raw_manifest diff --git a/swh/storage/tests/storage_data.py b/swh/storage/tests/storage_data.py --- a/swh/storage/tests/storage_data.py +++ b/swh/storage/tests/storage_data.py @@ -185,12 +185,39 @@ ], ), ) + + directory6 = Directory( + id=hash_to_bytes("afa0105cfcaa14fdbacee344e96659170bb1bda5"), + entries=tuple( + [ + DirectoryEntry( + name=b"foo", + type="file", + target=b"\x00" * 20, + perms=from_disk.DentryPerms.content, + ), + DirectoryEntry( + name=b"bar", + type="dir", + target=b"\x01" * 20, + perms=from_disk.DentryPerms.directory, + ), + ], + ), + raw_manifest=( + b"tree 61\x00" + b"100644 foo\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # noqa + b"40000 bar\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" # noqa + ), + ) + directories: Tuple[Directory, ...] = ( directory2, directory, directory3, directory4, directory5, + directory6, ) revision = Revision(