Skip to content

Commit 4f7c3b4

Browse files
authored
Added bindings to support link rerouting. (#1)
1 parent d12fab5 commit 4f7c3b4

7 files changed

+87
-1
lines changed

src/pygobbler/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@
4343
from .reject_probation import reject_probation
4444
from .set_permissions import set_permissions
4545
from .unpack_path import unpack_path
46+
from .reroute_links import reroute_links

src/pygobbler/remove_asset.py

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
def remove_asset(project: str, asset: str, staging: str, url: str, force: bool = False):
55
"""
66
Remove an asset of a project from the registry.
7+
This should only be performed by Gobbler instance administrators.
8+
Consider running :py:func:`~pygobbler.reroute_links.reroute_links` beforehand to avoid dangling references to files in this asset.
79
810
Args:
911
project:

src/pygobbler/remove_project.py

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
def remove_project(project: str, staging: str, url: str):
55
"""
66
Remove a project from the registry.
7+
This should only be performed by Gobbler instance administrators.
8+
Consider running :py:func:`~pygobbler.reroute_links.reroute_links` beforehand to avoid dangling references to files in this project.
79
810
Args:
911
project:

src/pygobbler/remove_version.py

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
def remove_version(project: str, asset: str, version: str, staging: str, url: str, force: bool = False):
55
"""
66
Remove a version of a project asset from the registry.
7+
This should only be performed by Gobbler instance administrators.
8+
Consider running :py:func:`~pygobbler.reroute_links.reroute_links` beforehand to avoid dangling references to files in this version.
79
810
Args:
911
project:

src/pygobbler/reroute_links.py

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from typing import List
2+
from ._utils import dump_request
3+
4+
5+
def reroute_links(to_delete: List, staging: str, url: str, dry_run: bool = False) -> List:
6+
"""Reroute symbolic links to files in directories that are to be deleted, e.g., by :py:func:`~pygobbler.remove_project.remove_project`.
7+
This preserves the validity of links within the Gobbler registry.
8+
9+
Note that rerouting does not actually delete the directories specified in ``to_delete``.
10+
Deletion requires separate invocations of :py:func:`~pygobbler.remove_project.remove_project` and friends - preferably after the user has verified that rerouting was successful!
11+
12+
Rerouting is not necessary if ``to_delete`` consists only of probational versions, or projects/assets containing only probational versions.
13+
The Gobbler should never create links to files in probational version directories.
14+
15+
Args:
16+
to_delete:
17+
List of projects, assets or versions to be deleted.
18+
Each entry should be a dicionary containing at least the ``project`` name.
19+
When deleting an asset, the inner list should contain an additional ``asset`` name.
20+
When deleting a version, the inner list should contain additional ``asset`` and ``version`` names.
21+
Different inner lists may specify different projects, assets or versions.
22+
23+
staging:
24+
Path to the staging directory.
25+
26+
url:
27+
URL for the Gobbler REST API.
28+
29+
dry_run:
30+
Whether to perform a dry run of the rerouting.
31+
32+
Returns:
33+
List of dictionaries.
34+
Each dictionary represents a rerouting action and contains the following fields.
35+
36+
- ``path``, string containing the path to a symbolic link in the registry that was changed by rerouting.
37+
- ``copy``, boolean indicating whether the link at ``path`` was replaced by a copy of its target file.
38+
If ``False``, the link was merely updated to refer to a new target file.
39+
- ``source``, the path to the target file that caused rerouting of ``path``.
40+
Specifically, this is a file in one of the to-be-deleted directories specified in ``to_delete``.
41+
If ``copy = TRUE``, this is the original linked-to file that was copied to ``path``.
42+
43+
If ``dry_run = False``, the registry is modified as described by the rerouting actions.
44+
Otherwise, no modifications are performed to the registry.
45+
"""
46+
out = dump_request(staging, url, "reroute_links", { "to_delete": to_delete, "dry_run": dry_run })
47+
return out["changes"]

src/pygobbler/start_gobbler.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def start_gobbler(
1414
registry: Optional[str] = None,
1515
port: Optional[int] = None,
1616
wait: float = 1,
17-
version: str = "0.3.9",
17+
version: str = "0.3.10",
1818
overwrite: bool = False) -> Tuple[bool, str, str, str]:
1919
"""
2020
Start a test Gobbler service.

tests/test_reroute_links.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import pygobbler as pyg
2+
import os
3+
4+
5+
def test_reroute_links():
6+
_, staging, registry, url = pyg.start_gobbler()
7+
8+
pyg.remove_project("test-reroute", staging=staging, url=url)
9+
pyg.create_project("test-reroute", staging=staging, url=url)
10+
11+
src = pyg.allocate_upload_directory(staging)
12+
with open(os.path.join(src, "foo"), "w") as handle:
13+
handle.write("BAR")
14+
15+
pyg.upload_directory("test-reroute", "simple", "v1", src, staging=staging, url=url)
16+
pyg.upload_directory("test-reroute", "simple", "v2", src, staging=staging, url=url)
17+
pyg.upload_directory("test-reroute", "simple", "v3", src, staging=staging, url=url)
18+
19+
actions = pyg.reroute_links([{"project":"test-reroute", "asset":"simple", "version":"v1"}], staging=staging, url=url, dry_run=True)
20+
print(actions)
21+
assert all([x["source"] == "test-reroute/simple/v1/foo" for x in actions])
22+
all_paths = [x["path"] for x in actions]
23+
assert "test-reroute/simple/v2/foo" in all_paths
24+
assert "test-reroute/simple/v3/foo" in all_paths
25+
all_copy = [x["copy"] for x in actions]
26+
assert all_copy[all_paths.index("test-reroute/simple/v2/foo")]
27+
assert not all_copy[all_paths.index("test-reroute/simple/v3/foo")]
28+
assert os.path.islink(os.path.join(registry, "test-reroute/simple/v2/foo"))
29+
30+
actions2 = pyg.reroute_links([{"project":"test-reroute", "asset":"simple", "version":"v1"}], staging=staging, url=url)
31+
assert actions == actions2
32+
assert not os.path.islink(os.path.join(registry, "test-reroute/simple/v2/foo"))

0 commit comments

Comments
 (0)