diff --git a/docs/design.md b/docs/design.md --- a/docs/design.md +++ b/docs/design.md @@ -102,6 +102,10 @@ - `parent` (note the singular): present if and only if the current commit has a single parent commit (which is the most common case). When present it is a symlink pointing into `archive/` to the SWHID for the sole parent commit +- `history`: a virtual directory containing all the parents commit until the +root commit. Entries are listed as symlinks with the SWHID as directory name, +pointing into `archive/SWHID`, and are returned in a topological ordering +similar to `git log` ordering. - `meta.json`: metadata for the current node, as a symlink pointing to the relevant `meta/.json` file @@ -219,3 +223,13 @@ happen. For instance, when first opening a rev virtual directory a recursive listing of all its ancestor can be retrieved from the remote backend and used to recursively populate the parents cache for all ancestors. + + +### History cache + + rev SWHID → ancestor SWHIDs + +The history cache map SWHIDs of type `rev` to a list of `rev` SWHIDs +corresponding to all its revision ancestors, sorted in reverse topological +order. As the parents cache, the history cache is lazily populated and can be +prefetched. diff --git a/swh/fuse/cache.py b/swh/fuse/cache.py --- a/swh/fuse/cache.py +++ b/swh/fuse/cache.py @@ -5,11 +5,13 @@ from abc import ABC import json +import logging from pathlib import Path -from typing import Any, AsyncGenerator, Dict, Optional +from typing import Any, AsyncGenerator, Dict, List, Optional import aiosqlite +from swh.model.exceptions import ValidationError from swh.model.identifiers import SWHID, parse_swhid from swh.web.client.client import typify_json @@ -38,13 +40,16 @@ async def __aenter__(self): self.metadata = MetadataCache(self.cache_conf["metadata"]) self.blob = BlobCache(self.cache_conf["blob"]) + self.history = HistoryCache(self.cache_conf["history"]) await self.metadata.__aenter__() await self.blob.__aenter__() + await self.history.__aenter__() return self async def __aexit__(self, type=None, val=None, tb=None) -> None: await self.metadata.__aexit__() await self.blob.__aexit__() + await self.history.__aexit__() async def get_cached_swhids(self) -> AsyncGenerator[SWHID, None]: """ Return a list of all previously cached SWHID """ @@ -139,3 +144,37 @@ await self.conn.execute( "insert into blob_cache values (?, ?)", (str(swhid), blob) ) + + +class HistoryCache(AbstractCache): + """ The history cache map SWHIDs of type `rev` to a list of all their parent + commits (until root commit). """ + + async def __aenter__(self): + await super().__aenter__() + await self.conn.execute( + "create table if not exists history_cache (swhid, history)" + ) + return self + + async def get(self, swhid: SWHID) -> Optional[List[SWHID]]: + cursor = await self.conn.execute( + "select history from history_cache where swhid=?", (str(swhid),) + ) + cache = await cursor.fetchone() + if not cache: + return None + + history = [] + for parent in cache[0].split("\n"): + try: + history.append(parse_swhid(parent)) + except ValidationError: + logging.warning(f"Cannot parse object from history cache: {parent}") + return history + + async def set(self, swhid: SWHID, history: str) -> None: + history = history.strip() + await self.conn.execute( + "insert into history_cache values (?, ?)", (str(swhid), history) + ) diff --git a/swh/fuse/cli.py b/swh/fuse/cli.py --- a/swh/fuse/cli.py +++ b/swh/fuse/cli.py @@ -30,6 +30,7 @@ "cache": { "metadata": {"path": CACHE_HOME_DIR / "swh/fuse/metadata.sqlite"}, "blob": {"path": CACHE_HOME_DIR / "swh/fuse/blob.sqlite"}, + "history": {"path": CACHE_HOME_DIR / "swh/fuse/history.sqlite"}, }, "web-api": { "url": "https://archive.softwareheritage.org/api/1", @@ -194,5 +195,5 @@ pass conf = ctx.obj["config"] - for cache_name in ["blob", "metadata"]: + for cache_name in ["blob", "metadata", "history"]: rm_cache(conf, cache_name) diff --git a/swh/fuse/fs/artifact.py b/swh/fuse/fs/artifact.py --- a/swh/fuse/fs/artifact.py +++ b/swh/fuse/fs/artifact.py @@ -139,6 +139,7 @@ - `parent` (note the singular): present if and only if the current commit has at least one parent commit (which is the most common case). When present it is a symlink pointing into `parents/1/` + - TODO: history - `meta.json`: metadata for the current node, as a symlink pointing to the relevant `meta/.json` file """ @@ -173,6 +174,13 @@ FuseSymlinkEntry, name="parent", target="parents/1/", ) + yield self.create_child( + RevisionHistory, + name="history", + mode=int(EntryMode.RDONLY_DIR), + swhid=self.swhid, + ) + @dataclass class RevisionParents(FuseDirEntry): @@ -190,6 +198,26 @@ ) +@dataclass +class RevisionHistory(FuseDirEntry): + """ Revision virtual `history/` directory """ + + swhid: SWHID + history: List[SWHID] = None + + async def __aiter__(self) -> AsyncIterator[FuseEntry]: + if not self.history: + self.history = await self.fuse.get_history(self.swhid) + + root_path = self.get_relative_root_path() + for swhid in self.history: + yield self.create_child( + FuseSymlinkEntry, + name=str(swhid), + target=Path(root_path, f"archive/{swhid}"), + ) + + @dataclass class Release(FuseDirEntry): """ Software Heritage release artifact. diff --git a/swh/fuse/fuse.py b/swh/fuse/fuse.py --- a/swh/fuse/fuse.py +++ b/swh/fuse/fuse.py @@ -18,7 +18,7 @@ from swh.fuse.cache import FuseCache from swh.fuse.fs.entry import FuseDirEntry, FuseEntry, FuseFileEntry, FuseSymlinkEntry from swh.fuse.fs.mountpoint import Root -from swh.model.identifiers import CONTENT, SWHID +from swh.model.identifiers import CONTENT, REVISION, SWHID from swh.web.client.client import WebAPIClient @@ -76,7 +76,6 @@ return cache try: - # TODO: swh-graph API typify = False # Get the raw JSON from the API # TODO: async web API loop = asyncio.get_event_loop() @@ -112,6 +111,30 @@ logging.error(f"Cannot fetch blob for object {swhid}: {err}") raise + async def get_history(self, swhid: SWHID) -> List[SWHID]: + if swhid.object_type != REVISION: + raise pyfuse3.FUSEError(errno.EINVAL) + + cache = await self.cache.history.get(swhid) + if cache: + return cache + + try: + # Use the swh-graph API to retrieve the full history very fast + call = f"graph/visit/nodes/{swhid}?edges=rev:rev" + loop = asyncio.get_event_loop() + history = await loop.run_in_executor(None, self.web_api._call, call) + await self.cache.history.set(swhid, history.text) + # Retrieve it from cache so it is correctly typed + return await self.cache.history.get(swhid) + except requests.HTTPError as err: + logging.error(f"Cannot fetch history for object {swhid}: {err}") + # Ignore exception since swh-graph does not necessarily contain the + # most recent artifacts from the archive. Computing the full history + # from the Web API is too computationally intensive so simply return + # an empty list. + return [] + async def get_attrs(self, entry: FuseEntry) -> pyfuse3.EntryAttributes: """ Return entry attributes """ diff --git a/swh/fuse/tests/api_url.py b/swh/fuse/tests/api_url.py new file mode 100644 --- /dev/null +++ b/swh/fuse/tests/api_url.py @@ -0,0 +1,50 @@ +# Copyright (C) 2020 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 enum import Enum +from typing import Union + +from swh.model.identifiers import ( + CONTENT, + DIRECTORY, + RELEASE, + REVISION, + SNAPSHOT, + SWHID, + parse_swhid, +) + +GRAPH_API_REQUEST = Enum("GRAPH_API_REQUEST", "HISTORY") + + +def swhid_to_web_url(swhid: Union[SWHID, str], raw: bool = False) -> str: + if isinstance(swhid, str): + swhid = parse_swhid(swhid) + + prefix = { + CONTENT: "content/sha1_git:", + DIRECTORY: "directory/", + REVISION: "revision/", + RELEASE: "release/", + SNAPSHOT: "snapshot/", + } + + url = f"{prefix[swhid.object_type]}{swhid.object_id}/" + if raw: + url += "raw/" + return url + + +def swhid_to_graph_url( + swhid: Union[SWHID, str], request_type: GRAPH_API_REQUEST +) -> str: + if isinstance(swhid, str): + swhid = parse_swhid(swhid) + + prefix = { + GRAPH_API_REQUEST.HISTORY: "graph/visit/nodes/", + } + + return f"{prefix[request_type]}{swhid}" diff --git a/swh/fuse/tests/common.py b/swh/fuse/tests/common.py --- a/swh/fuse/tests/common.py +++ b/swh/fuse/tests/common.py @@ -7,13 +7,16 @@ from pathlib import Path from typing import Any, List -from swh.fuse.tests.data.api_data import MOCK_ARCHIVE, SWHID2URL +from swh.fuse.tests.api_url import ( + GRAPH_API_REQUEST, + swhid_to_graph_url, + swhid_to_web_url, +) +from swh.fuse.tests.data.api_data import MOCK_ARCHIVE -def get_data_from_archive(swhid: str, raw: bool = False) -> Any: - url = SWHID2URL[swhid] - if raw: - url += "raw/" +def get_data_from_web_archive(swhid: str, raw: bool = False) -> Any: + url = swhid_to_web_url(swhid, raw) # Special case: snapshots Web API and Web Client API differ a bit in format if url.startswith("snapshot"): @@ -22,8 +25,13 @@ return MOCK_ARCHIVE[url] +def get_data_from_graph_archive(swhid: str, request_type: GRAPH_API_REQUEST) -> Any: + url = swhid_to_graph_url(swhid, request_type) + return MOCK_ARCHIVE[url] + + def get_dir_name_entries(swhid: str) -> List[str]: - dir_meta = get_data_from_archive(swhid) + dir_meta = get_data_from_web_archive(swhid) return [x["name"] for x in dir_meta] diff --git a/swh/fuse/tests/conftest.py b/swh/fuse/tests/conftest.py --- a/swh/fuse/tests/conftest.py +++ b/swh/fuse/tests/conftest.py @@ -23,7 +23,7 @@ def web_api_mock(requests_mock): for api_call, data in MOCK_ARCHIVE.items(): # Convert Python dict JSON into a string (only for non-raw API call) - if not api_call.endswith("raw/"): + if not api_call.endswith("raw/") and not api_call.startswith("graph/"): data = json.dumps(data) requests_mock.get(f"{API_URL}/{api_call}", text=data) return requests_mock @@ -35,7 +35,11 @@ tmpfile = NamedTemporaryFile(suffix=".swh-fuse-test.yml") config = { - "cache": {"metadata": {"in-memory": True}, "blob": {"in-memory": True}}, + "cache": { + "metadata": {"in-memory": True}, + "blob": {"in-memory": True}, + "history": {"in-memory": True}, + }, "web-api": {"url": API_URL, "auth-token": None}, } diff --git a/swh/fuse/tests/data/api_data.py b/swh/fuse/tests/data/api_data.py --- a/swh/fuse/tests/data/api_data.py +++ b/swh/fuse/tests/data/api_data.py @@ -5,35 +5,14 @@ API_URL = "https://invalid-test-only.archive.softwareheritage.org/api/1" -SWHID2URL: Dict[str, str] = { - "swh:1:cnt:61d3c9e1157203f0c4ed5165608d92294eaca808": "content/sha1_git:61d3c9e1157203f0c4ed5165608d92294eaca808/", - "swh:1:dir:c6dcbe9711ea6d5a31429a833a3d0c59cbbb2578": "directory/c6dcbe9711ea6d5a31429a833a3d0c59cbbb2578/", - "swh:1:dir:80ae84abc6122c47aae597fde99645f8663d1aba": "directory/80ae84abc6122c47aae597fde99645f8663d1aba/", - "swh:1:rev:b8cedc00407a4c56a3bda1ed605c6fc166655447": "revision/b8cedc00407a4c56a3bda1ed605c6fc166655447/", - "swh:1:rev:87dd6843678575f8dda962f239d14ef4be14b352": "revision/87dd6843678575f8dda962f239d14ef4be14b352/", - "swh:1:rev:1a2390247ad6d08160e0dd74f40a01a9578659c2": "revision/1a2390247ad6d08160e0dd74f40a01a9578659c2/", - "swh:1:rev:4d78994915af1bde9a95c04a8c27d8dca066232a": "revision/4d78994915af1bde9a95c04a8c27d8dca066232a/", - "swh:1:rev:3e6e1001dc6e095dbd5c88005e80969f60e384e1": "revision/3e6e1001dc6e095dbd5c88005e80969f60e384e1/", - "swh:1:rev:11e893fc1357bc688418ddf1087c2b7aa25d154d": "revision/11e893fc1357bc688418ddf1087c2b7aa25d154d/", - "swh:1:rev:1c2bd024d13f8011307e13386cf1fea2180352b5": "revision/1c2bd024d13f8011307e13386cf1fea2180352b5/", - "swh:1:rev:92baf7293dd2d418d2ac4b141b0faa822075d9f7": "revision/92baf7293dd2d418d2ac4b141b0faa822075d9f7/", - "swh:1:rel:874f7cbe352033cac5a8bc889847da2fe1d13e9f": "release/874f7cbe352033cac5a8bc889847da2fe1d13e9f/", - "swh:1:rel:da5f9898d6248ab26277116f54aca855338401d2": "release/da5f9898d6248ab26277116f54aca855338401d2/", - "swh:1:cnt:be5effea679c057aec2bb020f0241b1d1d660840": "content/sha1_git:be5effea679c057aec2bb020f0241b1d1d660840/", - "swh:1:rel:3a7b2dfffed2945d2933ba4ebc063adba35ddb2e": "release/3a7b2dfffed2945d2933ba4ebc063adba35ddb2e/", - "swh:1:dir:b24d39c928b9c3f440f8e2ec06c78f43d28d87d6": "directory/b24d39c928b9c3f440f8e2ec06c78f43d28d87d6/", - "swh:1:snp:02db117fef22434f1658b833a756775ca6effed0": "snapshot/02db117fef22434f1658b833a756775ca6effed0/", - "swh:1:rev:430a9fd4c797c50cea26157141b2408073b2ed91": "revision/430a9fd4c797c50cea26157141b2408073b2ed91/", -} - MOCK_ARCHIVE: Dict[str, Any] = { "content/sha1_git:61d3c9e1157203f0c4ed5165608d92294eaca808/": { "length": 10084, "status": "visible", "checksums": { - "sha256": "7152be0097b003d148f773ce0be0a695219c636f4f20073993335758c810166c", - "sha1": "0d84ad5f5167010347a13cf0be95f47a3cb99dfa", "blake2s256": "fe43b0ad08a9bf943a912f67b5e7d98e58fbd4ff318dcd9a1edaceceefe9ebca", + "sha1": "0d84ad5f5167010347a13cf0be95f47a3cb99dfa", + "sha256": "7152be0097b003d148f773ce0be0a695219c636f4f20073993335758c810166c", "sha1_git": "61d3c9e1157203f0c4ed5165608d92294eaca808", }, "data_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:61d3c9e1157203f0c4ed5165608d92294eaca808/raw/", @@ -52,8 +31,8 @@ "status": "visible", "length": 357, "checksums": { - "sha256": "59a397e1ac39dd858750476ebd621ad0b468e511c3bea56fb8b507849409bdde", "sha1": "ce9cce2dad1505a8d35c229943925046d3a4cbc8", + "sha256": "59a397e1ac39dd858750476ebd621ad0b468e511c3bea56fb8b507849409bdde", "sha1_git": "a7de7ce85593c140267bd3bafa3812859d8f259f", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:a7de7ce85593c140267bd3bafa3812859d8f259f/", @@ -67,8 +46,8 @@ "status": "visible", "length": 1054, "checksums": { - "sha256": "d0d262bc2f18bda49a434222ff508f8fe43da72b31b06138cb81b9d8fc6c471a", "sha1": "874e94541299f36e7d45d5e60252cc360421d921", + "sha256": "d0d262bc2f18bda49a434222ff508f8fe43da72b31b06138cb81b9d8fc6c471a", "sha1_git": "d9761ce40927ce92d29daa23b4496e04b9e97e4f", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:d9761ce40927ce92d29daa23b4496e04b9e97e4f/", @@ -82,8 +61,8 @@ "status": "visible", "length": 1638, "checksums": { - "sha256": "429734af1b42ca1d4e7b8112a9fbcb0d13ec8a89cc92864bddd6a4036a68ead9", "sha1": "2728096a9234a05c2e246dbf437cc99969a7ed73", + "sha256": "429734af1b42ca1d4e7b8112a9fbcb0d13ec8a89cc92864bddd6a4036a68ead9", "sha1_git": "003e50d0788e4c6efb0d4315556a8c1ce0cf73ef", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:003e50d0788e4c6efb0d4315556a8c1ce0cf73ef/", @@ -97,8 +76,8 @@ "status": "visible", "length": 16168, "checksums": { - "sha256": "8b0443f512c8540b2942bfad7b2057bf05d3718c8d00e4e04099575a1b3cba1d", "sha1": "272e26eb45fbe4d57d2b3ef771b728aa37d45f04", + "sha256": "8b0443f512c8540b2942bfad7b2057bf05d3718c8d00e4e04099575a1b3cba1d", "sha1_git": "6ab6be26cf101388162fbec2a942d5352ecea49a", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:6ab6be26cf101388162fbec2a942d5352ecea49a/", @@ -112,8 +91,8 @@ "status": "visible", "length": 131, "checksums": { - "sha256": "3c4d1c4de2e6991695f5dc495f7530ecb188dfafdb1f47a1323ce7159987accd", "sha1": "8242335087079c2fafb18c1f6f89bcdb8f6ba647", + "sha256": "3c4d1c4de2e6991695f5dc495f7530ecb188dfafdb1f47a1323ce7159987accd", "sha1_git": "e3708bc485399fd42b32c6a1c24491771afa1a04", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:e3708bc485399fd42b32c6a1c24491771afa1a04/", @@ -127,8 +106,8 @@ "status": "visible", "length": 21302, "checksums": { - "sha256": "0ce1302f56e93ac9cee754253690d5400f907e80d63d175e603ef26a537c5131", "sha1": "3439b8ccdf39af7b95a646c6ae3fa18fe86e6420", + "sha256": "0ce1302f56e93ac9cee754253690d5400f907e80d63d175e603ef26a537c5131", "sha1_git": "fc8ca5d07b21280c575477457b8e4e3e953b26b4", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:fc8ca5d07b21280c575477457b8e4e3e953b26b4/", @@ -142,8 +121,8 @@ "status": "visible", "length": 9322, "checksums": { - "sha256": "401266ab45019fe25d501eb10f11b85140ecf54a739fc1e3d26800ed276f899a", "sha1": "9fa123623c5ecf1fa171c3a211c41dc1b4767fe8", + "sha256": "401266ab45019fe25d501eb10f11b85140ecf54a739fc1e3d26800ed276f899a", "sha1_git": "dc9abf84b8e5a4d3b6ab5472883f0997fa0454cc", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:dc9abf84b8e5a4d3b6ab5472883f0997fa0454cc/", @@ -157,8 +136,8 @@ "status": "visible", "length": 116575, "checksums": { - "sha256": "8a0f9f9557435540a797032ae005fa40cae933cf906730bf95cf1d12e850e0a0", "sha1": "cb30c3049af7a34291af1fff80ecb91f8728879a", + "sha256": "8a0f9f9557435540a797032ae005fa40cae933cf906730bf95cf1d12e850e0a0", "sha1_git": "80c90243e5db7130efa10f96e19fb65a9cbcf140", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:80c90243e5db7130efa10f96e19fb65a9cbcf140/", @@ -172,8 +151,8 @@ "status": "visible", "length": 2436, "checksums": { - "sha256": "5eefbe2e4fad05f80b63450a764b646dd3c691376cbe8aaf7ef68b9911ea5704", "sha1": "037cc780fa9836ec344fe02b47ab5c3642fe26b1", + "sha256": "5eefbe2e4fad05f80b63450a764b646dd3c691376cbe8aaf7ef68b9911ea5704", "sha1_git": "9d5c27b96df5d435daaded1ece44d1c8b6b613c1", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:9d5c27b96df5d435daaded1ece44d1c8b6b613c1/", @@ -187,8 +166,8 @@ "status": "visible", "length": 9723, "checksums": { - "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", "sha1": "6e5c4711bcae04967d7f5b5e01cf56ae03bebe7a", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", "sha1_git": "1b5ec8b78e237b5c3b3d812a7c0a6589d0f7161d", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:1b5ec8b78e237b5c3b3d812a7c0a6589d0f7161d/", @@ -202,8 +181,8 @@ "status": "visible", "length": 1023, "checksums": { - "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", "sha1": "ce3a2603094e799f42ce99c40941544dfcc5c4a5", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", "sha1_git": "31aa79387f27e730e33d871925e152e35e428031", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:31aa79387f27e730e33d871925e152e35e428031/", @@ -217,8 +196,8 @@ "status": "visible", "length": 10084, "checksums": { - "sha256": "7152be0097b003d148f773ce0be0a695219c636f4f20073993335758c810166c", "sha1": "0d84ad5f5167010347a13cf0be95f47a3cb99dfa", + "sha256": "7152be0097b003d148f773ce0be0a695219c636f4f20073993335758c810166c", "sha1_git": "61d3c9e1157203f0c4ed5165608d92294eaca808", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:61d3c9e1157203f0c4ed5165608d92294eaca808/", @@ -232,8 +211,8 @@ "status": "visible", "length": 436110, "checksums": { - "sha256": "9efd0b82142e37f24948d185a359c84d57c8894ef32480a98e963c5076400f7f", "sha1": "971916d3e574a3b1caa332e144d3cd85d396aa39", + "sha256": "9efd0b82142e37f24948d185a359c84d57c8894ef32480a98e963c5076400f7f", "sha1_git": "77d0bbe57912bed5a90c2f1d3628eb7bdcab0dd8", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:77d0bbe57912bed5a90c2f1d3628eb7bdcab0dd8/", @@ -247,8 +226,8 @@ "status": "visible", "length": 22148, "checksums": { - "sha256": "f77840688189e2a3fb1f7921886e763382d7c65b7b044bb4d92f21957c7773e2", "sha1": "604c62c6a08002c18795f0e3c70bdc454ad8889c", + "sha256": "f77840688189e2a3fb1f7921886e763382d7c65b7b044bb4d92f21957c7773e2", "sha1_git": "c9e17337ee23f801857093ec1237bbb833ae17b3", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:c9e17337ee23f801857093ec1237bbb833ae17b3/", @@ -262,8 +241,8 @@ "status": "visible", "length": 275, "checksums": { - "sha256": "5f6e26a0f2993b96749fce11791631e8b0085f344f8c135b710e182c4d6dd420", "sha1": "f6a766df481855359c1dac80c0262a5e6c3f3aab", + "sha256": "5f6e26a0f2993b96749fce11791631e8b0085f344f8c135b710e182c4d6dd420", "sha1_git": "eeb8d081d34549f5ca2b19f703bbb4e547264e46", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:eeb8d081d34549f5ca2b19f703bbb4e547264e46/", @@ -277,8 +256,8 @@ "status": "visible", "length": 1014, "checksums": { - "sha256": "37bcf3d674319038e17f9d607a5df81b93ea2b96408db43ba9920c6bbafad47a", "sha1": "b778b5d9c139074d0eba57486419d2513af537ec", + "sha256": "37bcf3d674319038e17f9d607a5df81b93ea2b96408db43ba9920c6bbafad47a", "sha1_git": "73f8cc1ff68c68bbbbfe6216f4b0f00626701672", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:73f8cc1ff68c68bbbbfe6216f4b0f00626701672/", @@ -301,8 +280,8 @@ "status": "visible", "length": 971, "checksums": { - "sha256": "f405f6325384e99729cc883ff871512f1be4829259059d2d59a7b47e3062ef90", "sha1": "07d3df8565a55d2ddf1502b7fb0b173d128e3fda", + "sha256": "f405f6325384e99729cc883ff871512f1be4829259059d2d59a7b47e3062ef90", "sha1_git": "7ece7f977ce2a39b76c002105aacb1598885a36a", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:7ece7f977ce2a39b76c002105aacb1598885a36a/", @@ -316,8 +295,8 @@ "status": "visible", "length": 270, "checksums": { - "sha256": "3573a0e5a4def372ad5800b3f76aa4163b60bce4596fac892de737e409380baf", "sha1": "6eb663ee7ac8d3849139dca2e60c00f2935915eb", + "sha256": "3573a0e5a4def372ad5800b3f76aa4163b60bce4596fac892de737e409380baf", "sha1_git": "7973730ef177cd600aaf4baebe1b40a81ed1b085", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:7973730ef177cd600aaf4baebe1b40a81ed1b085/", @@ -342,8 +321,8 @@ "status": "visible", "length": 92, "checksums": { - "sha256": "3cfb6483c2ff498754aa2cf9ef41347cc5fe41c7753bc74c1db5f3160d07d0b4", "sha1": "a5f982a0831d5c563610de8d3f82ab3a574e6f97", + "sha256": "3cfb6483c2ff498754aa2cf9ef41347cc5fe41c7753bc74c1db5f3160d07d0b4", "sha1_git": "f4898dc676530356e86b287c42018a2ad4cd5699", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:f4898dc676530356e86b287c42018a2ad4cd5699/", @@ -357,8 +336,8 @@ "status": "visible", "length": 94, "checksums": { - "sha256": "10e8220d761c9ff87954417effad9c6c381739732e12e7975129c845beda6721", "sha1": "609a26fbd8a91083d7fb551d5e1096ed7e95987d", + "sha256": "10e8220d761c9ff87954417effad9c6c381739732e12e7975129c845beda6721", "sha1_git": "920c6edc389fe8aafdd17f582df8af6aed80cf2e", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:920c6edc389fe8aafdd17f582df8af6aed80cf2e/", @@ -372,8 +351,8 @@ "status": "visible", "length": 93, "checksums": { - "sha256": "0d402aa08c59e2f134f0bc6696c4d81cbda379772a8b4a4f959270ef1713ed42", "sha1": "dd14bfdaf0b97f433c6a107942b4bfb3f9080a86", + "sha256": "0d402aa08c59e2f134f0bc6696c4d81cbda379772a8b4a4f959270ef1713ed42", "sha1_git": "b44de8e2cb32d3cd72213bcb4228870f1edcf0dc", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:b44de8e2cb32d3cd72213bcb4228870f1edcf0dc/", @@ -405,8 +384,8 @@ "status": "visible", "length": 72, "checksums": { - "sha256": "6ce1630d627e002c01e21bb1c14994cf814ebe00fab6ca6e97d4c051a9fccc83", "sha1": "f054d111eeef94a0337a06e2d2b81b9a276cdab3", + "sha256": "6ce1630d627e002c01e21bb1c14994cf814ebe00fab6ca6e97d4c051a9fccc83", "sha1_git": "8f881657bdc1a1965140ab4941436a06bee2f3ba", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:8f881657bdc1a1965140ab4941436a06bee2f3ba/", @@ -420,8 +399,8 @@ "status": "visible", "length": 362, "checksums": { - "sha256": "93aa2c5f3a3a890581870a66d6233b5fdb181901694c8f95c8155ed621ada30c", "sha1": "c255bb1015b2da689f615cd4b8dd0a8c04eab4fd", + "sha256": "93aa2c5f3a3a890581870a66d6233b5fdb181901694c8f95c8155ed621ada30c", "sha1_git": "77e151235e822d4281d365d6908d13bf8073a231", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:77e151235e822d4281d365d6908d13bf8073a231/", @@ -435,8 +414,8 @@ "status": "visible", "length": 265, "checksums": { - "sha256": "7fea658f27efcb8eea07748e98b2fbc80523ff5c2aadd39556f65c7ccd9da4bc", "sha1": "1e450161ad277053fe76c03a209de22b59a4b534", + "sha256": "7fea658f27efcb8eea07748e98b2fbc80523ff5c2aadd39556f65c7ccd9da4bc", "sha1_git": "604a65dc8a9b98cd797e6555d1802a49c6067cef", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:604a65dc8a9b98cd797e6555d1802a49c6067cef/", @@ -450,8 +429,8 @@ "status": "visible", "length": 267, "checksums": { - "sha256": "da97f73a003c3a658500547e8a97be80b0481c5aa753681f8391e9fd24a28349", "sha1": "26b33551387b7defe83d0ec2f69e70bc2df5a4df", + "sha256": "da97f73a003c3a658500547e8a97be80b0481c5aa753681f8391e9fd24a28349", "sha1_git": "4501d74073e900846f0bcf13196bfca39f6e9484", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:4501d74073e900846f0bcf13196bfca39f6e9484/", @@ -465,8 +444,8 @@ "status": "visible", "length": 139, "checksums": { - "sha256": "5aa7054e3c2238dc093c46547604beece9b91e186364b1fe2bd5029a9676643b", "sha1": "a5481e1cb75eed8d90663e33d3ac6d9c4ac47c56", + "sha256": "5aa7054e3c2238dc093c46547604beece9b91e186364b1fe2bd5029a9676643b", "sha1_git": "85badc11d64f03de8b2fd9262b1fb2cf0470cbcb", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:85badc11d64f03de8b2fd9262b1fb2cf0470cbcb/", @@ -480,8 +459,8 @@ "status": "visible", "length": 126, "checksums": { - "sha256": "17b521b83aef7183c2c22841ebf2ac1e2f5a42712de7467e859dc4c7b752fbb1", "sha1": "0212ebfaed13a7847a49588c6197d02f7198efcc", + "sha256": "17b521b83aef7183c2c22841ebf2ac1e2f5a42712de7467e859dc4c7b752fbb1", "sha1_git": "fd71d3e3c8e79e1030039dc17f587cda6018df3a", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:fd71d3e3c8e79e1030039dc17f587cda6018df3a/", @@ -495,8 +474,8 @@ "status": "visible", "length": 132, "checksums": { - "sha256": "aade247c7f69aba4248450f5f1a8be77ae87c94fc73e597d1edfe134df911214", "sha1": "88e47f1c32dd2df8d338ccfa378e056ac5979dfd", + "sha256": "aade247c7f69aba4248450f5f1a8be77ae87c94fc73e597d1edfe134df911214", "sha1_git": "1130a10bd1c5540c1f3f5be2a0da56fda1acb444", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:1130a10bd1c5540c1f3f5be2a0da56fda1acb444/", @@ -510,8 +489,8 @@ "status": "visible", "length": 115, "checksums": { - "sha256": "194a44f13a9806027e6f39fdd3cf2d32cea9591ebf8eed88eac76bfd70a76c17", "sha1": "9ba9912b177cb33b2a42651780fdb597e1ded091", + "sha256": "194a44f13a9806027e6f39fdd3cf2d32cea9591ebf8eed88eac76bfd70a76c17", "sha1_git": "228cb3c624f8958abc5526886745f03dbf912fac", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:228cb3c624f8958abc5526886745f03dbf912fac/", @@ -525,8 +504,8 @@ "status": "visible", "length": 143, "checksums": { - "sha256": "df1ea1cff3fe6082222840754dbb440980cd9cf04d85e5287d9f23d5db5ea863", "sha1": "3c1ec7447489a516cd4d9e1389073e1862d5ff22", + "sha256": "df1ea1cff3fe6082222840754dbb440980cd9cf04d85e5287d9f23d5db5ea863", "sha1_git": "767dafc5baf9208e3927680947fe3da83c493201", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:767dafc5baf9208e3927680947fe3da83c493201/", @@ -540,8 +519,8 @@ "status": "visible", "length": 135, "checksums": { - "sha256": "b8b132edf8d80694638dbb85f84ca8a098103618fc92ca1a2c2f06f45cdbd955", "sha1": "7a5ecf2d63691280e4fb433ed6dc2c9335d3b917", + "sha256": "b8b132edf8d80694638dbb85f84ca8a098103618fc92ca1a2c2f06f45cdbd955", "sha1_git": "6c511548789b73656a9303f5dbf153274d62f4de", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:6c511548789b73656a9303f5dbf153274d62f4de/", @@ -555,8 +534,8 @@ "status": "visible", "length": 293, "checksums": { - "sha256": "9eb9ba201ac0a4c1347db17e89cdbdfdf7e682cf9ecb26dc5aa7d86454facfd2", "sha1": "6abd35d1edcb1569ce8fa82c87b71ecef5ba49e2", + "sha256": "9eb9ba201ac0a4c1347db17e89cdbdfdf7e682cf9ecb26dc5aa7d86454facfd2", "sha1_git": "bafdb2fe0bbc3790867d1e8a117226f033c298ae", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:bafdb2fe0bbc3790867d1e8a117226f033c298ae/", @@ -570,8 +549,8 @@ "status": "visible", "length": 120, "checksums": { - "sha256": "4a9a99fe8de30d497d3995b2767ded900449a56153da144bc5d78eec30262d79", "sha1": "d70b2391cc30674d1b0d32f69a02f87ce59d961f", + "sha256": "4a9a99fe8de30d497d3995b2767ded900449a56153da144bc5d78eec30262d79", "sha1_git": "d030614489bccfd3ad87f3619003fe43ed65a7f6", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:d030614489bccfd3ad87f3619003fe43ed65a7f6/", @@ -585,8 +564,8 @@ "status": "visible", "length": 139, "checksums": { - "sha256": "cacfb85fcf58614e40a91b112ae7e6d7a3132a4d5d43c24d2163a03a183b7eb1", "sha1": "0c649ef00ae61445fde8f6509b82b1b3998e14cf", + "sha256": "cacfb85fcf58614e40a91b112ae7e6d7a3132a4d5d43c24d2163a03a183b7eb1", "sha1_git": "21217bf54d7693e50a4777601536f2fca935edc0", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:21217bf54d7693e50a4777601536f2fca935edc0/", @@ -600,8 +579,8 @@ "status": "visible", "length": 125, "checksums": { - "sha256": "61af0dc860ae011b5a4e8eba990d3bc581ace146736247b8e450f4c663f664cd", "sha1": "d85d294a9ed8d11d31e2e25b6272e8e6e3058e00", + "sha256": "61af0dc860ae011b5a4e8eba990d3bc581ace146736247b8e450f4c663f664cd", "sha1_git": "28d9fb48b73e74485f6a8b930428a7fbb6db81ef", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:28d9fb48b73e74485f6a8b930428a7fbb6db81ef/", @@ -615,8 +594,8 @@ "status": "visible", "length": 134, "checksums": { - "sha256": "4a5e663d343fcbd8fb69bbbd4a1b0566862cea079c7517cafdb261b775e6195a", "sha1": "5122f12a66652ebc5d2357a25695590eb6a60b4f", + "sha256": "4a5e663d343fcbd8fb69bbbd4a1b0566862cea079c7517cafdb261b775e6195a", "sha1_git": "3c1a82d0174494f9c276eca6c20801fc2fdb1a6b", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:3c1a82d0174494f9c276eca6c20801fc2fdb1a6b/", @@ -630,8 +609,8 @@ "status": "visible", "length": 108, "checksums": { - "sha256": "b25c83b21ca63b3c896ba37452d5b1f1b6d159b4458ec53f72972d56ab19de3f", "sha1": "cb4ff4bf5f73aabeb72b51fae345a355d047381c", + "sha256": "b25c83b21ca63b3c896ba37452d5b1f1b6d159b4458ec53f72972d56ab19de3f", "sha1_git": "b9e70e7cfd7e06f27160657e9bb509011b5bf89a", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:b9e70e7cfd7e06f27160657e9bb509011b5bf89a/", @@ -645,8 +624,8 @@ "status": "visible", "length": 4366, "checksums": { - "sha256": "353459533ed0b76facfb75b57f690d754360b9cd8d7bce8195191d3e5d40ac1b", "sha1": "cede6ea0203a41976e3a729426e94c769d8af9ea", + "sha256": "353459533ed0b76facfb75b57f690d754360b9cd8d7bce8195191d3e5d40ac1b", "sha1_git": "0a2a80e8fd6e2b4d62dcf9a93f2dc5983b0da249", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:0a2a80e8fd6e2b4d62dcf9a93f2dc5983b0da249/", @@ -660,8 +639,8 @@ "status": "visible", "length": 150, "checksums": { - "sha256": "0d48afe88e4ff6e88b7b09b35f02f368ca29a80a8a823be9051746e8dc279059", "sha1": "e51eb22fb0afc96a6cda88204bd37ef363518d4c", + "sha256": "0d48afe88e4ff6e88b7b09b35f02f368ca29a80a8a823be9051746e8dc279059", "sha1_git": "48712d8d49b55f3f70c5134247dfc54ce46744e2", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:48712d8d49b55f3f70c5134247dfc54ce46744e2/", @@ -693,8 +672,8 @@ "status": "visible", "length": 2639, "checksums": { - "sha256": "3e12811e42249800a98e69e31d1b9ed7941749981f77f618f97c707a5c24b7e8", "sha1": "9656218548d47dda0b43ad16f617914a283ae804", + "sha256": "3e12811e42249800a98e69e31d1b9ed7941749981f77f618f97c707a5c24b7e8", "sha1_git": "d26fcfc0168d7676138a74ac2ef336b115268b30", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:d26fcfc0168d7676138a74ac2ef336b115268b30/", @@ -708,8 +687,8 @@ "status": "visible", "length": 118, "checksums": { - "sha256": "254be837de875bb8bf0e650ad1c94090eebf52c754e174e9c3fade6867263a88", "sha1": "05a24674274e70062bdc0088a31f3126a0f898fc", + "sha256": "254be837de875bb8bf0e650ad1c94090eebf52c754e174e9c3fade6867263a88", "sha1_git": "33e3860c2a4340ba428e789a980bafeeb7982b02", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:33e3860c2a4340ba428e789a980bafeeb7982b02/", @@ -732,8 +711,8 @@ "status": "visible", "length": 137, "checksums": { - "sha256": "f7e15476ea21caf0a81e74a7e2389e88eaa8e177268924b04b7619dc9ef92f0f", "sha1": "4b7736799c39dc3636fe0c8d4494bfef774f8e79", + "sha256": "f7e15476ea21caf0a81e74a7e2389e88eaa8e177268924b04b7619dc9ef92f0f", "sha1_git": "fdeea17ed1124bde8b8453bd4c6b0a6035079074", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:fdeea17ed1124bde8b8453bd4c6b0a6035079074/", @@ -747,8 +726,8 @@ "status": "visible", "length": 762, "checksums": { - "sha256": "1d5fc8b3d3dc393ba1e67b4b0b267ec4b14357fb6c3990ace2e0f03c4aa7c719", "sha1": "0590cfcec734441c5d9f1ea46f445c80becd27c6", + "sha256": "1d5fc8b3d3dc393ba1e67b4b0b267ec4b14357fb6c3990ace2e0f03c4aa7c719", "sha1_git": "61ee12739fb37426603b65e857060f03aefb3434", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:61ee12739fb37426603b65e857060f03aefb3434/", @@ -771,8 +750,8 @@ "status": "visible", "length": 7604, "checksums": { - "sha256": "029da15998da9bf0bd9c6ea190cdfbf3a3563ae18bfe50674efd99eca62a3a85", "sha1": "6e86ec1077ef0c268a373b42ecf173de45e4891f", + "sha256": "029da15998da9bf0bd9c6ea190cdfbf3a3563ae18bfe50674efd99eca62a3a85", "sha1_git": "a92d4ff54db837a6e64dd260d66b3bc5e2e60f43", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:a92d4ff54db837a6e64dd260d66b3bc5e2e60f43/", @@ -786,8 +765,8 @@ "status": "visible", "length": 108, "checksums": { - "sha256": "c474313aabfbc668f205eaf146c31bc47470fb322d1fd96008ac8ddbb585273f", "sha1": "014d60b4041b6135c2e2c6a2c47d99334de473f6", + "sha256": "c474313aabfbc668f205eaf146c31bc47470fb322d1fd96008ac8ddbb585273f", "sha1_git": "5008b228c5c85fe04df289f4180a83fd4f5ce7b9", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:5008b228c5c85fe04df289f4180a83fd4f5ce7b9/", @@ -819,8 +798,8 @@ "status": "visible", "length": 5192, "checksums": { - "sha256": "0898345d1f94b6b15f324a1c9afa4df85fc45fb05960879ac61e9a9ac0b47835", "sha1": "e584054db3a809e089d84b1680d78cadb7eacb1f", + "sha256": "0898345d1f94b6b15f324a1c9afa4df85fc45fb05960879ac61e9a9ac0b47835", "sha1_git": "dfd8e9db3c5c9cacb236c7d1cacc84791649920f", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:dfd8e9db3c5c9cacb236c7d1cacc84791649920f/", @@ -843,8 +822,8 @@ "status": "visible", "length": 84, "checksums": { - "sha256": "5d5ebec01e6606b7f0f8ff2fac793a8b870847b715d069c1ff88b81ddb1ecdc1", "sha1": "85f5f5a92b0904bcfcf0eb4b54dae893b2b17d52", + "sha256": "5d5ebec01e6606b7f0f8ff2fac793a8b870847b715d069c1ff88b81ddb1ecdc1", "sha1_git": "d4a25efec17f6895baeed32178ca69baad319159", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:d4a25efec17f6895baeed32178ca69baad319159/", @@ -858,8 +837,8 @@ "status": "visible", "length": 177, "checksums": { - "sha256": "6d2a400c36e46a97acadeecac8103ef603cd1bf5533df453cf519d4a4a769193", "sha1": "98bbf3d1c8e78e1ab161de9a5385499668d516f1", + "sha256": "6d2a400c36e46a97acadeecac8103ef603cd1bf5533df453cf519d4a4a769193", "sha1_git": "320283f31b51feb3e3fd24a632195fcb42a5181a", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:320283f31b51feb3e3fd24a632195fcb42a5181a/", @@ -882,8 +861,8 @@ "status": "visible", "length": 342, "checksums": { - "sha256": "5c43d83bf45d7a0e8e10f2f66730d8e8a737c77668e1f7a522444d46e613efcf", "sha1": "4b4cfe57c5e1aab39eac235699a14dded2c565b0", + "sha256": "5c43d83bf45d7a0e8e10f2f66730d8e8a737c77668e1f7a522444d46e613efcf", "sha1_git": "7215e4f13c9bb4d914032eda4192430e69c51a41", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:7215e4f13c9bb4d914032eda4192430e69c51a41/", @@ -924,6 +903,7 @@ "history_url": "https://archive.softwareheritage.org/api/1/revision/b8cedc00407a4c56a3bda1ed605c6fc166655447/log/", "directory_url": "https://archive.softwareheritage.org/api/1/directory/c6dcbe9711ea6d5a31429a833a3d0c59cbbb2578/", }, + "graph/visit/nodes/swh:1:rev:b8cedc00407a4c56a3bda1ed605c6fc166655447": "", "revision/87dd6843678575f8dda962f239d14ef4be14b352/": { "message": "Fix listing numbers (#2227)\n\nFix listing numbers", "author": { @@ -964,6 +944,7 @@ "history_url": "https://archive.softwareheritage.org/api/1/revision/87dd6843678575f8dda962f239d14ef4be14b352/log/", "directory_url": "https://archive.softwareheritage.org/api/1/directory/4c1b991bc9997e885308de8a87b05bbd9956a4fb/", }, + "graph/visit/nodes/swh:1:rev:87dd6843678575f8dda962f239d14ef4be14b352": "", "revision/1a2390247ad6d08160e0dd74f40a01a9578659c2/": { "message": "Merge pull request #194 from zakaluka/rustup2148\n\nUpdated install and uninstall instructions", "author": { @@ -1004,6 +985,7 @@ "history_url": "https://archive.softwareheritage.org/api/1/revision/1a2390247ad6d08160e0dd74f40a01a9578659c2/log/", "directory_url": "https://archive.softwareheritage.org/api/1/directory/5f461af28f89e3de5fa7aadbe8e601e61e0318de/", }, + "graph/visit/nodes/swh:1:rev:1a2390247ad6d08160e0dd74f40a01a9578659c2": "", "revision/4d78994915af1bde9a95c04a8c27d8dca066232a/": { "message": "Merge #221\n\n221: Update .gitattributes r=therealprof a=jethrogb\n\nSee https://github.com/rust-lang/rust/pull/57858\n\nCo-authored-by: jethrogb \n", "author": { @@ -1044,6 +1026,7 @@ "history_url": "https://archive.softwareheritage.org/api/1/revision/4d78994915af1bde9a95c04a8c27d8dca066232a/log/", "directory_url": "https://archive.softwareheritage.org/api/1/directory/aedfd5f87a2bb6f48d748a3d6e11ce755a5fc531/", }, + "graph/visit/nodes/swh:1:rev:4d78994915af1bde9a95c04a8c27d8dca066232a": "", "revision/3e6e1001dc6e095dbd5c88005e80969f60e384e1/": { "message": "Merge pull request #177 from petertodd/2019-12-long-live-contravariance\n\nRemove mention of contravariance possibly getting scrapped", "author": { @@ -1084,6 +1067,7 @@ "history_url": "https://archive.softwareheritage.org/api/1/revision/3e6e1001dc6e095dbd5c88005e80969f60e384e1/log/", "directory_url": "https://archive.softwareheritage.org/api/1/directory/2c4e09410c52ffd98d771d370948037d192f6178/", }, + "graph/visit/nodes/swh:1:rev:3e6e1001dc6e095dbd5c88005e80969f60e384e1": "", "revision/11e893fc1357bc688418ddf1087c2b7aa25d154d/": { "message": "Merge pull request #726 from phansch/small_pointer_improvement\n\nSmall improvements to types/pointer.md", "author": { @@ -1124,6 +1108,7 @@ "history_url": "https://archive.softwareheritage.org/api/1/revision/11e893fc1357bc688418ddf1087c2b7aa25d154d/log/", "directory_url": "https://archive.softwareheritage.org/api/1/directory/2892c88f2d5fc8c16adef8dd7e7c649bc194b672/", }, + "graph/visit/nodes/swh:1:rev:11e893fc1357bc688418ddf1087c2b7aa25d154d": "", "revision/1c2bd024d13f8011307e13386cf1fea2180352b5/": { "message": "Merge pull request #1302 from Cawibo/patch-1\n\nCamelCase -> UpperCamelCase", "author": { @@ -1164,6 +1149,7 @@ "history_url": "https://archive.softwareheritage.org/api/1/revision/1c2bd024d13f8011307e13386cf1fea2180352b5/log/", "directory_url": "https://archive.softwareheritage.org/api/1/directory/07720bc1cae5641b300fadc2aa076b9a5de71d2b/", }, + "graph/visit/nodes/swh:1:rev:1c2bd024d13f8011307e13386cf1fea2180352b5": "", "revision/92baf7293dd2d418d2ac4b141b0faa822075d9f7/": { "message": "Fix link\n", "author": { @@ -1195,6 +1181,39 @@ "history_url": "https://archive.softwareheritage.org/api/1/revision/92baf7293dd2d418d2ac4b141b0faa822075d9f7/log/", "directory_url": "https://archive.softwareheritage.org/api/1/directory/d5b7e02dd66666e7f16066162d3cc9bbc3a2c3d3/", }, + "graph/visit/nodes/swh:1:rev:92baf7293dd2d418d2ac4b141b0faa822075d9f7": "", + "revision/37426e42cf78a43779312d780eecb21a64006d99/": { + "message": "Add sever-glue, for missing first stage of sweep.\n", + "author": { + "fullname": "Graydon Hoare ", + "name": "Graydon Hoare", + "email": "graydon@mozilla.com", + }, + "committer": { + "fullname": "Graydon Hoare ", + "name": "Graydon Hoare", + "email": "graydon@mozilla.com", + }, + "date": "2010-06-25T21:57:46-07:00", + "committer_date": "2010-06-25T21:57:46-07:00", + "type": "git", + "directory": "6eb0b5a43bf0672e2d272f78ef9b939333af47fc", + "synthetic": False, + "metadata": {}, + "parents": [ + { + "id": "0cf3c2ad935be699281ed20fb3d2f29554e6229b", + "url": "https://archive.softwareheritage.org/api/1/revision/0cf3c2ad935be699281ed20fb3d2f29554e6229b/", + } + ], + "id": "37426e42cf78a43779312d780eecb21a64006d99", + "extra_headers": [], + "merge": False, + "url": "https://archive.softwareheritage.org/api/1/revision/37426e42cf78a43779312d780eecb21a64006d99/", + "history_url": "https://archive.softwareheritage.org/api/1/revision/37426e42cf78a43779312d780eecb21a64006d99/log/", + "directory_url": "https://archive.softwareheritage.org/api/1/directory/6eb0b5a43bf0672e2d272f78ef9b939333af47fc/", + }, + "graph/visit/nodes/swh:1:rev:37426e42cf78a43779312d780eecb21a64006d99": "swh:1:rev:37426e42cf78a43779312d780eecb21a64006d99\nswh:1:rev:0cf3c2ad935be699281ed20fb3d2f29554e6229b\nswh:1:rev:37180552769b316e7239d047008f187127e630e6\nswh:1:rev:dd2716f56c7cf55f2904fbbf4dfabaab1afbcd88\nswh:1:rev:968ec145278d3d6562e4b5ec4006af97dc0da563\nswh:1:rev:34dc7053ebfd440648f49dc83d2538ab5e7ceda5\nswh:1:rev:c56a729ff1d9467d612bf522614519ac7b97f798\nswh:1:rev:eb7807c4fe7a2c2ad3c074705fb70de5eae5abe3\nswh:1:rev:d601b357ecbb1fa33dc10c177bb557868be07deb\nswh:1:rev:2a2474d497ae19472b4366f6d8d62e9a516787c3\nswh:1:rev:eed5c0aa249f3e17bbabeeba1650ab699e3dff5a\nswh:1:rev:67d1f0a9aafaa7dcd63b86032127ab660e630c46\nswh:1:rev:2e3fa5bd68677762c619d83dfdf1a83ba7f0e749\nswh:1:rev:a9c639ec8af3a4099108788c1db0176c7fea5799\nswh:1:rev:c06ea8f9445dbb5eda99ac8730d7fb2177df6816\nswh:1:rev:422b8a6be4aab120685f450db0a520fcb5a8aa6b\nswh:1:rev:e8759934711c70c50b5d616be22104e649abff58\nswh:1:rev:63b5e18207c7f8a261c1f7f50fd8c7bbf9a21bda\nswh:1:rev:5dfe101e5197d6854aa1d8c9907ac7851468d468\nswh:1:rev:287d69ddacba3f5945b70695fb721b2f055d3ee6\nswh:1:rev:85a701c8f668fc03e6340682956e7ca7d9cf54bc\nswh:1:rev:241305caab232b04666704dc6853c41312cd283a\nswh:1:rev:0d9565a4c144c07dab052161eb5fa3815dcd7f06\nswh:1:rev:72c6c60d80cdfe63af5046a1a98549f0515734f2\nswh:1:rev:c483808e0ff9836bc1cda0ce95d77c8b7d3be91c\nswh:1:rev:1c60be2f32f70f9181a261ae2c2b4efe353d0f85\nswh:1:rev:bcf29b882acdf477be412fdb401b0fc2a6c819aa\nswh:1:rev:261d543920e1c66049c469773ca989aaf9ce480e\nswh:1:rev:24d5ff75c3abfe7b327c48468ed9a39f0d8a0427\nswh:1:rev:d3c0762ff85ff7d29668d1f5d2361df03978bbea\nswh:1:rev:af44ec2856603b8a978a1f2582c285c7c0065403\nswh:1:rev:69a34503f4d51b639855501f1b6d6ce2da4e16c7\nswh:1:rev:0364a801bb29211d4731f3f910c7629286b51c45\nswh:1:rev:25eb1fd3c9d997e460dff3e03d87e398e616c726\nswh:1:rev:4a1f86ccd7e823f63d12208baef79b1e74479203\nswh:1:rev:0016473117e4bc3c8959bf2fd49368844847d74c\nswh:1:rev:935442babcf4f8ae52c1a13bb9ce07270a302886\nswh:1:rev:1f3cff91f6762b0f47f41025b5e2c5ac942479ba\nswh:1:rev:bc286c7f2ceb5c3d2e06ec72f78d28842f94ef65\nswh:1:rev:f038f4d533f897a29f9422510d1b3f0caac97388\nswh:1:rev:d6b7c96c3eb29b9244ece0c046d3f372ff432d04\nswh:1:rev:c01efc669f09508b55eced32d3c88702578a7c3e", "release/874f7cbe352033cac5a8bc889847da2fe1d13e9f/": { "name": "1.42.0", "message": "1.42.0 release\n", @@ -1229,9 +1248,9 @@ "length": 5279, "status": "visible", "checksums": { - "sha256": "d3923bc07a944321af5eb781c1ae7b86b1f8c07385dce3adad1eee052f2cda47", - "sha1": "c640e23feb6f93b02878de5b02d70e87388a2bd2", "blake2s256": "6f515bb07318b5730f7c2d0aa4dbe24fe1b65ed4f38cf3500a8ffbdbb1ea3cfe", + "sha1": "c640e23feb6f93b02878de5b02d70e87388a2bd2", + "sha256": "d3923bc07a944321af5eb781c1ae7b86b1f8c07385dce3adad1eee052f2cda47", "sha1_git": "be5effea679c057aec2bb020f0241b1d1d660840", }, "data_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:be5effea679c057aec2bb020f0241b1d1d660840/raw/", @@ -1274,8 +1293,8 @@ "status": "visible", "length": 27, "checksums": { - "sha256": "28d6e007e8ba8de537247c2e4dce5ea081919da9eabd2a1cd580afd02425275b", "sha1": "e757103bdac5b2be6e8f28b47595862dd3d36b2b", + "sha256": "28d6e007e8ba8de537247c2e4dce5ea081919da9eabd2a1cd580afd02425275b", "sha1_git": "53ea710b37aef348b3e09478b18e2bfd180efb43", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:53ea710b37aef348b3e09478b18e2bfd180efb43/", @@ -1298,8 +1317,8 @@ "status": "visible", "length": 1216, "checksums": { - "sha256": "e6ab5dc18e4ca7612439c28a991d5a5c09ed2006a5efa2e9034ced6ee995cf1e", "sha1": "37a14e4c123ae1d5006665ef867f84bc23ca2fe8", + "sha256": "e6ab5dc18e4ca7612439c28a991d5a5c09ed2006a5efa2e9034ced6ee995cf1e", "sha1_git": "5ddf82d3f5330bad8c830ac6b21bab2e912bee6e", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:5ddf82d3f5330bad8c830ac6b21bab2e912bee6e/", @@ -1313,8 +1332,8 @@ "status": "visible", "length": 915, "checksums": { - "sha256": "c63c6cbe41d8fc6fcc3401f0d4d993e42a7ae873dd97fda9dc4cfc2132d61c03", "sha1": "bf83eda0827a970c3cccc9d3ba681c497b1108e9", + "sha256": "c63c6cbe41d8fc6fcc3401f0d4d993e42a7ae873dd97fda9dc4cfc2132d61c03", "sha1_git": "d8d2804032211fec42ec197827b049d5dea40ea7", }, "target_url": "https://archive.softwareheritage.org/api/1/content/sha1_git:d8d2804032211fec42ec197827b049d5dea40ea7/", @@ -1531,4 +1550,5 @@ "history_url": "https://archive.softwareheritage.org/api/1/revision/430a9fd4c797c50cea26157141b2408073b2ed91/log/", "directory_url": "https://archive.softwareheritage.org/api/1/directory/1ac29db0e7280af41064676569a96d1f88ccfa96/", }, + "graph/visit/nodes/swh:1:rev:430a9fd4c797c50cea26157141b2408073b2ed91": "", } diff --git a/swh/fuse/tests/data/config.py b/swh/fuse/tests/data/config.py --- a/swh/fuse/tests/data/config.py +++ b/swh/fuse/tests/data/config.py @@ -21,6 +21,7 @@ "swh:1:rev:1c2bd024d13f8011307e13386cf1fea2180352b5", "swh:1:rev:92baf7293dd2d418d2ac4b141b0faa822075d9f7", ] +REV_SMALL_HISTORY = "swh:1:rev:37426e42cf78a43779312d780eecb21a64006d99" # Release ROOT_REL = "swh:1:rel:874f7cbe352033cac5a8bc889847da2fe1d13e9f" # Snapshot @@ -44,6 +45,7 @@ DIR_WITH_SUBMODULES, ROOT_REV, *SUBMODULES, + REV_SMALL_HISTORY, ROOT_REL, REL_TARGET_CNT, REL_TARGET_DIR, diff --git a/swh/fuse/tests/data/gen-api-data.py b/swh/fuse/tests/data/gen-api-data.py --- a/swh/fuse/tests/data/gen-api-data.py +++ b/swh/fuse/tests/data/gen-api-data.py @@ -11,7 +11,12 @@ import requests -from swh.fuse.tests.data.config import ALL_ENTRIES +from swh.fuse.tests.api_url import ( + GRAPH_API_REQUEST, + swhid_to_graph_url, + swhid_to_web_url, +) +from swh.fuse.tests.data.config import ALL_ENTRIES, REV_SMALL_HISTORY from swh.model.identifiers import ( CONTENT, DIRECTORY, @@ -25,24 +30,11 @@ API_URL_real = "https://archive.softwareheritage.org/api/1" API_URL_test = "https://invalid-test-only.archive.softwareheritage.org/api/1" -SWHID2URL: Dict[str, str] = {} MOCK_ARCHIVE: Dict[str, Any] = {} # Temporary map (swhid -> metadata) to ease data generation METADATA: Dict[SWHID, Any] = {} -def swhid2url(swhid: SWHID) -> str: - prefix = { - CONTENT: "content/sha1_git:", - DIRECTORY: "directory/", - REVISION: "revision/", - RELEASE: "release/", - SNAPSHOT: "snapshot/", - } - - return f"{prefix[swhid.object_type]}{swhid.object_id}/" - - def get_short_type(object_type: str) -> str: short_type = { CONTENT: "cnt", @@ -54,18 +46,16 @@ return short_type[object_type] -def generate_archive_data( +def generate_archive_web_api( swhid: SWHID, raw: bool = False, recursive: bool = False ) -> None: # Already in mock archive if swhid in METADATA and not raw: return - url = swhid2url(swhid) - SWHID2URL[str(swhid)] = url + url = swhid_to_web_url(swhid, raw) if raw: - url += "raw/" data = requests.get(f"{API_URL_real}/{url}").text else: data = requests.get(f"{API_URL_real}/{url}").text @@ -78,17 +68,71 @@ # blob data, release target, etc.) if recursive: if swhid.object_type == CONTENT: - generate_archive_data(swhid, raw=True) + generate_archive_web_api(swhid, raw=True) elif swhid.object_type == RELEASE: target_type = METADATA[swhid]["target_type"] target_id = METADATA[swhid]["target"] target = parse_swhid(f"swh:1:{get_short_type(target_type)}:{target_id}") - generate_archive_data(target, recursive=True) + generate_archive_web_api(target, recursive=True) + + +def generate_archive_graph_api(swhid: SWHID) -> None: + if swhid.object_type == REVISION: + # Empty history for all revisions (except REV_SMALL_HISTORY used in tests) + url = swhid_to_graph_url(swhid, GRAPH_API_REQUEST.HISTORY) + MOCK_ARCHIVE[url] = "" + if str(swhid) == REV_SMALL_HISTORY: + # TODO: temporary fix, retrieve from the graph API once it is public + MOCK_ARCHIVE[ + url + ] = """swh:1:rev:37426e42cf78a43779312d780eecb21a64006d99 +swh:1:rev:0cf3c2ad935be699281ed20fb3d2f29554e6229b +swh:1:rev:37180552769b316e7239d047008f187127e630e6 +swh:1:rev:dd2716f56c7cf55f2904fbbf4dfabaab1afbcd88 +swh:1:rev:968ec145278d3d6562e4b5ec4006af97dc0da563 +swh:1:rev:34dc7053ebfd440648f49dc83d2538ab5e7ceda5 +swh:1:rev:c56a729ff1d9467d612bf522614519ac7b97f798 +swh:1:rev:eb7807c4fe7a2c2ad3c074705fb70de5eae5abe3 +swh:1:rev:d601b357ecbb1fa33dc10c177bb557868be07deb +swh:1:rev:2a2474d497ae19472b4366f6d8d62e9a516787c3 +swh:1:rev:eed5c0aa249f3e17bbabeeba1650ab699e3dff5a +swh:1:rev:67d1f0a9aafaa7dcd63b86032127ab660e630c46 +swh:1:rev:2e3fa5bd68677762c619d83dfdf1a83ba7f0e749 +swh:1:rev:a9c639ec8af3a4099108788c1db0176c7fea5799 +swh:1:rev:c06ea8f9445dbb5eda99ac8730d7fb2177df6816 +swh:1:rev:422b8a6be4aab120685f450db0a520fcb5a8aa6b +swh:1:rev:e8759934711c70c50b5d616be22104e649abff58 +swh:1:rev:63b5e18207c7f8a261c1f7f50fd8c7bbf9a21bda +swh:1:rev:5dfe101e5197d6854aa1d8c9907ac7851468d468 +swh:1:rev:287d69ddacba3f5945b70695fb721b2f055d3ee6 +swh:1:rev:85a701c8f668fc03e6340682956e7ca7d9cf54bc +swh:1:rev:241305caab232b04666704dc6853c41312cd283a +swh:1:rev:0d9565a4c144c07dab052161eb5fa3815dcd7f06 +swh:1:rev:72c6c60d80cdfe63af5046a1a98549f0515734f2 +swh:1:rev:c483808e0ff9836bc1cda0ce95d77c8b7d3be91c +swh:1:rev:1c60be2f32f70f9181a261ae2c2b4efe353d0f85 +swh:1:rev:bcf29b882acdf477be412fdb401b0fc2a6c819aa +swh:1:rev:261d543920e1c66049c469773ca989aaf9ce480e +swh:1:rev:24d5ff75c3abfe7b327c48468ed9a39f0d8a0427 +swh:1:rev:d3c0762ff85ff7d29668d1f5d2361df03978bbea +swh:1:rev:af44ec2856603b8a978a1f2582c285c7c0065403 +swh:1:rev:69a34503f4d51b639855501f1b6d6ce2da4e16c7 +swh:1:rev:0364a801bb29211d4731f3f910c7629286b51c45 +swh:1:rev:25eb1fd3c9d997e460dff3e03d87e398e616c726 +swh:1:rev:4a1f86ccd7e823f63d12208baef79b1e74479203 +swh:1:rev:0016473117e4bc3c8959bf2fd49368844847d74c +swh:1:rev:935442babcf4f8ae52c1a13bb9ce07270a302886 +swh:1:rev:1f3cff91f6762b0f47f41025b5e2c5ac942479ba +swh:1:rev:bc286c7f2ceb5c3d2e06ec72f78d28842f94ef65 +swh:1:rev:f038f4d533f897a29f9422510d1b3f0caac97388 +swh:1:rev:d6b7c96c3eb29b9244ece0c046d3f372ff432d04 +swh:1:rev:c01efc669f09508b55eced32d3c88702578a7c3e""" for entry in ALL_ENTRIES: swhid = parse_swhid(entry) - generate_archive_data(swhid, recursive=True) + generate_archive_web_api(swhid, recursive=True) + generate_archive_graph_api(swhid) print("# GENERATED FILE, DO NOT EDIT.") print("# Run './gen-api-data.py > api_data.py' instead.") @@ -96,5 +140,4 @@ print("from typing import Any, Dict") print("") print(f"API_URL = '{API_URL_test}'\n") -print(f"SWHID2URL: Dict[str, str] = {SWHID2URL}\n") print(f"MOCK_ARCHIVE: Dict[str, Any] = {MOCK_ARCHIVE}") diff --git a/swh/fuse/tests/test_content.py b/swh/fuse/tests/test_content.py --- a/swh/fuse/tests/test_content.py +++ b/swh/fuse/tests/test_content.py @@ -1,4 +1,4 @@ -from swh.fuse.tests.common import get_data_from_archive +from swh.fuse.tests.common import get_data_from_web_archive from swh.fuse.tests.data.config import REGULAR_FILE @@ -9,5 +9,5 @@ def test_cat_file(fuse_mntdir): file_path = fuse_mntdir / "archive" / REGULAR_FILE - expected = get_data_from_archive(REGULAR_FILE, raw=True) + expected = get_data_from_web_archive(REGULAR_FILE, raw=True) assert file_path.read_text() == expected diff --git a/swh/fuse/tests/test_meta.py b/swh/fuse/tests/test_meta.py --- a/swh/fuse/tests/test_meta.py +++ b/swh/fuse/tests/test_meta.py @@ -1,6 +1,6 @@ import json -from swh.fuse.tests.common import get_data_from_archive +from swh.fuse.tests.common import get_data_from_web_archive from swh.fuse.tests.data.config import ALL_ENTRIES @@ -12,5 +12,5 @@ file_path_meta = fuse_mntdir / f"meta/{swhid}.json" assert file_path_meta.exists() - expected = json.dumps(get_data_from_archive(swhid)) + expected = json.dumps(get_data_from_web_archive(swhid)) assert file_path_meta.read_text() == expected diff --git a/swh/fuse/tests/test_release.py b/swh/fuse/tests/test_release.py --- a/swh/fuse/tests/test_release.py +++ b/swh/fuse/tests/test_release.py @@ -1,7 +1,7 @@ import json import os -from swh.fuse.tests.common import check_dir_name_entries, get_data_from_archive +from swh.fuse.tests.common import check_dir_name_entries, get_data_from_web_archive from swh.fuse.tests.data.config import ( REL_TARGET_CNT, REL_TARGET_DIR, @@ -14,15 +14,15 @@ def test_access_meta(fuse_mntdir): file_path = fuse_mntdir / "archive" / ROOT_REL / "meta.json" - expected = json.dumps(get_data_from_archive(ROOT_REL)) + expected = json.dumps(get_data_from_web_archive(ROOT_REL)) assert file_path.read_text() == expected def test_access_rev_target(fuse_mntdir): target_path = fuse_mntdir / "archive" / ROOT_REL / "target" - expected = ["meta.json", "root", "parent", "parents"] - actual = os.listdir(target_path) - assert set(actual) == set(expected) + expected = set(["meta.json", "root", "parent", "parents", "history"]) + actual = set(os.listdir(target_path)) + assert expected.issubset(actual) def test_access_dir_target(fuse_mntdir): @@ -32,7 +32,7 @@ def test_access_cnt_target(fuse_mntdir): target_path = fuse_mntdir / "archive" / REL_TARGET_CNT / "target" - expected = get_data_from_archive(TARGET_CNT, raw=True) + expected = get_data_from_web_archive(TARGET_CNT, raw=True) assert target_path.read_text() == expected diff --git a/swh/fuse/tests/test_revision.py b/swh/fuse/tests/test_revision.py --- a/swh/fuse/tests/test_revision.py +++ b/swh/fuse/tests/test_revision.py @@ -1,13 +1,18 @@ import json import os -from swh.fuse.tests.common import check_dir_name_entries, get_data_from_archive -from swh.fuse.tests.data.config import ROOT_DIR, ROOT_REV +from swh.fuse.tests.api_url import GRAPH_API_REQUEST +from swh.fuse.tests.common import ( + check_dir_name_entries, + get_data_from_graph_archive, + get_data_from_web_archive, +) +from swh.fuse.tests.data.config import REV_SMALL_HISTORY, ROOT_DIR, ROOT_REV def test_access_meta(fuse_mntdir): file_path = fuse_mntdir / "archive" / ROOT_REV / "meta.json" - expected = json.dumps(get_data_from_archive(ROOT_REV)) + expected = json.dumps(get_data_from_web_archive(ROOT_REV)) assert file_path.read_text() == expected @@ -17,7 +22,7 @@ def test_list_parents(fuse_mntdir): - rev_meta = get_data_from_archive(ROOT_REV) + rev_meta = get_data_from_web_archive(ROOT_REV) dir_path = fuse_mntdir / "archive" / ROOT_REV / "parents" for i, parent in enumerate(rev_meta["parents"]): parent_path = dir_path / str(i + 1) @@ -30,3 +35,13 @@ file_path = fuse_mntdir / "archive" / ROOT_REV / "parent" assert file_path.is_symlink() assert os.readlink(file_path) == "parents/1/" + + +def test_list_history(fuse_mntdir): + dir_path = fuse_mntdir / "archive" / REV_SMALL_HISTORY / "history" + history_meta = get_data_from_graph_archive( + REV_SMALL_HISTORY, GRAPH_API_REQUEST.HISTORY + ) + expected = history_meta.split("\n") + actual = os.listdir(dir_path) + assert set(actual) == set(expected) diff --git a/swh/fuse/tests/test_snapshot.py b/swh/fuse/tests/test_snapshot.py --- a/swh/fuse/tests/test_snapshot.py +++ b/swh/fuse/tests/test_snapshot.py @@ -1,12 +1,12 @@ import os import urllib.parse -from swh.fuse.tests.common import get_data_from_archive +from swh.fuse.tests.common import get_data_from_web_archive from swh.fuse.tests.data.config import ROOT_SNP def test_list_branches(fuse_mntdir): - snp_meta = get_data_from_archive(ROOT_SNP) + snp_meta = get_data_from_web_archive(ROOT_SNP) expected = snp_meta.keys() # Mangle branch name to create a valid UNIX filename expected = [urllib.parse.quote_plus(x) for x in expected] @@ -17,6 +17,6 @@ def test_access_rev_target(fuse_mntdir): branch_name = urllib.parse.quote_plus("refs/heads/master") dir_path = fuse_mntdir / "archive" / ROOT_SNP / branch_name - expected = ["meta.json", "root", "parent", "parents"] - actual = os.listdir(dir_path) - assert set(actual) == set(expected) + expected = set(["meta.json", "root", "parent", "parents", "history"]) + actual = set(os.listdir(dir_path)) + assert expected.issubset(actual)