From b8b51604886c242602568a888cd32cc46c7e4478 Mon Sep 17 00:00:00 2001 From: guerler Date: Sat, 9 Nov 2024 13:19:01 +0300 Subject: [PATCH 1/4] Add link only option to posix file source --- lib/galaxy/files/sources/posix.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/galaxy/files/sources/posix.py b/lib/galaxy/files/sources/posix.py index 8768b5b5ca9c..1461f63a32b5 100644 --- a/lib/galaxy/files/sources/posix.py +++ b/lib/galaxy/files/sources/posix.py @@ -26,6 +26,7 @@ DEFAULT_ENFORCE_SYMLINK_SECURITY = True DEFAULT_DELETE_ON_REALIZE = False DEFAULT_ALLOW_SUBDIR_CREATION = True +DEFAULT_LINK_ONLY = False class PosixFilesSourceProperties(FilesSourceProperties, total=False): @@ -33,6 +34,7 @@ class PosixFilesSourceProperties(FilesSourceProperties, total=False): enforce_symlink_security: bool delete_on_realize: bool allow_subdir_creation: bool + link_only: bool class PosixFilesSource(BaseFilesSource): @@ -50,6 +52,7 @@ def __init__(self, **kwd: Unpack[PosixFilesSourceProperties]): self.root = props.get("root") if not self.root: self.writable = False + self.link_only = props.get("link_only", DEFAULT_LINK_ONLY) self.enforce_symlink_security = props.get("enforce_symlink_security", DEFAULT_ENFORCE_SYMLINK_SECURITY) self.delete_on_realize = props.get("delete_on_realize", DEFAULT_DELETE_ON_REALIZE) self.allow_subdir_creation = props.get("allow_subdir_creation", DEFAULT_ALLOW_SUBDIR_CREATION) From 503e69b2bd94dd648632d95bad8c83db684cc40b Mon Sep 17 00:00:00 2001 From: guerler Date: Sat, 9 Nov 2024 13:20:48 +0300 Subject: [PATCH 2/4] Add symlink operation to posix file source --- lib/galaxy/files/sources/posix.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/files/sources/posix.py b/lib/galaxy/files/sources/posix.py index 1461f63a32b5..7cb6dc2e301d 100644 --- a/lib/galaxy/files/sources/posix.py +++ b/lib/galaxy/files/sources/posix.py @@ -106,7 +106,9 @@ def _realize_to( source_native_path = os.path.normpath(source_native_path) assert source_native_path.startswith(os.path.normpath(effective_root)) - if not self.delete_on_realize: + if self.link_only: + os.symlink(source_native_path, native_path) + elif not self.delete_on_realize: shutil.copyfile(source_native_path, native_path) else: shutil.move(source_native_path, native_path) From 5052b21810bf77ee23a3f5a94c59ce31bc8d72e2 Mon Sep 17 00:00:00 2001 From: guerler Date: Sat, 9 Nov 2024 13:38:21 +0300 Subject: [PATCH 3/4] Add link_only to serializer --- lib/galaxy/files/sources/posix.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/galaxy/files/sources/posix.py b/lib/galaxy/files/sources/posix.py index 7cb6dc2e301d..e27c0bfa9c2a 100644 --- a/lib/galaxy/files/sources/posix.py +++ b/lib/galaxy/files/sources/posix.py @@ -187,6 +187,7 @@ def _serialization_props(self, user_context: OptionalUserContext = None) -> Posi "enforce_symlink_security": self.enforce_symlink_security, "delete_on_realize": self.delete_on_realize, "allow_subdir_creation": self.allow_subdir_creation, + "link_only": self.link_only, } @property From e105703eeeaed919e2284b2242705f31c0e32d35 Mon Sep 17 00:00:00 2001 From: guerler Date: Sat, 9 Nov 2024 16:01:18 +0300 Subject: [PATCH 4/4] Naive attempt to force symlink --- lib/galaxy/files/sources/posix.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/files/sources/posix.py b/lib/galaxy/files/sources/posix.py index e27c0bfa9c2a..6c9d744c682d 100644 --- a/lib/galaxy/files/sources/posix.py +++ b/lib/galaxy/files/sources/posix.py @@ -107,6 +107,8 @@ def _realize_to( assert source_native_path.startswith(os.path.normpath(effective_root)) if self.link_only: + if os.path.exists(native_path) or os.path.islink(native_path): + os.remove(native_path) os.symlink(source_native_path, native_path) elif not self.delete_on_realize: shutil.copyfile(source_native_path, native_path) @@ -138,9 +140,14 @@ def _write_from( # Use a temporary name while writing so anything that consumes written files can detect when they've completed, # and identify interrupted writes - target_native_path_part = os.path.join(target_native_path_parent, f"_{target_native_path_name}.part") - shutil.copyfile(native_path, target_native_path_part) - os.rename(target_native_path_part, target_native_path) + if self.link_only: + if os.path.exists(native_path) or os.path.islink(native_path): + os.remove(native_path) + os.symlink(target_native_path, native_path) + else: + target_native_path_part = os.path.join(target_native_path_parent, f"_{target_native_path_name}.part") + shutil.copyfile(native_path, target_native_path_part) + os.rename(target_native_path_part, target_native_path) def _to_native_path(self, source_path: str, user_context: OptionalUserContext = None): source_path = os.path.normpath(source_path)