diff --git a/swh/model/from_disk.py b/swh/model/from_disk.py --- a/swh/model/from_disk.py +++ b/swh/model/from_disk.py @@ -12,7 +12,7 @@ from .hashutil import MultiHash, HASH_BLOCK_SIZE from .merkle import MerkleLeaf, MerkleNode from .identifiers import ( - directory_identifier, + directory_entry_sort_key, directory_identifier, identifier_to_bytes as id_to_bytes, identifier_to_str as id_to_str, ) @@ -325,11 +325,13 @@ @property def entries(self): + """Child nodes, sorted by name in the same way `directory_identifier` + does.""" if self.__entries is None: - self.__entries = [ + self.__entries = sorted(( self.child_to_directory_entry(name, child) for name, child in self.items() - ] + ), key=directory_entry_sort_key) return self.__entries diff --git a/swh/model/identifiers.py b/swh/model/identifiers.py --- a/swh/model/identifiers.py +++ b/swh/model/identifiers.py @@ -114,7 +114,7 @@ return MultiHash.from_data(content['data']).digest() -def _sort_key(entry): +def directory_entry_sort_key(entry): """The sorting key for tree entries""" if entry['type'] == 'dir': return entry['name'] + b'/' @@ -182,7 +182,7 @@ components = [] - for entry in sorted(directory['entries'], key=_sort_key): + for entry in sorted(directory['entries'], key=directory_entry_sort_key): components.extend([ _perms_to_bytes(entry['perms']), b'\x20', diff --git a/swh/model/tests/test_from_disk.py b/swh/model/tests/test_from_disk.py --- a/swh/model/tests/test_from_disk.py +++ b/swh/model/tests/test_from_disk.py @@ -449,7 +449,7 @@ if isinstance(right, Directory): right = right.get_data() - return self.assertCountEqual(left.entries, right['entries']) + assert left.entries == right['entries'] def make_contents(self, directory): for filename, content in self.contents.items(): @@ -579,6 +579,7 @@ check_path=True) +@pytest.mark.fs class DirectoryToObjects(DataMixin, unittest.TestCase): def setUp(self): super().setUp() @@ -729,6 +730,18 @@ len(self.contents) + 1) + def test_directory_entry_order(self): + with tempfile.TemporaryDirectory() as dirname: + dirname = os.fsencode(dirname) + open(os.path.join(dirname, b'foo.'), 'a') + open(os.path.join(dirname, b'foo0'), 'a') + os.mkdir(os.path.join(dirname, b'foo')) + + directory = Directory.from_disk(path=dirname) + + assert [entry['name'] for entry in directory.entries] \ + == [b'foo.', b'foo', b'foo0'] + @pytest.mark.fs class TarballTest(DataMixin, unittest.TestCase):