Skip to content

Commit fe03157

Browse files
feat: support XRootD as a default remote provider (snakemake#1017)
* Add the remote provider XRootD to the list of allowed default remote providers. * see what happens if we set supports_default = True for XRootD * make sure non-relative path is supplied to xrootd * ensure paths are always non-relative * missing slash * snakemake expects copying to overwrite the destination file if it already exists * Formatting. * Remove extraneous forward-slashes Co-authored-by: Johannes Köster <[email protected]>
1 parent 8892bf2 commit fe03157

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

snakemake/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,6 +1931,7 @@ def get_argument_parser(profile=None):
19311931
"gridftp",
19321932
"iRODS",
19331933
"AzBlob",
1934+
"XRootD",
19341935
],
19351936
help="Specify default remote provider to be used for "
19361937
"all input and output files that don't yet specify "

snakemake/remote/XRootD.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222

2323
class RemoteProvider(AbstractRemoteProvider):
24+
supports_default = True
25+
2426
def __init__(
2527
self, *args, keep_local=False, stay_on_remote=False, is_default=False, **kwargs
2628
):
@@ -29,7 +31,7 @@ def __init__(
2931
keep_local=keep_local,
3032
stay_on_remote=stay_on_remote,
3133
is_default=is_default,
32-
**kwargs
34+
**kwargs,
3335
)
3436

3537
self._xrd = XRootDHelper()
@@ -59,7 +61,7 @@ def __init__(
5961
keep_local=keep_local,
6062
stay_on_remote=stay_on_remote,
6163
provider=provider,
62-
**kwargs
64+
**kwargs,
6365
)
6466

6567
if provider:
@@ -131,6 +133,12 @@ def _parse_url(self, url):
131133
dirname, filename = os.path.split(match.group("path"))
132134
# We need a trailing / to keep XRootD happy
133135
dirname += "/"
136+
137+
# and also make sure we supply a non-relative path
138+
# (snakemake removes double-slash // characters)
139+
if not dirname.startswith("/"):
140+
dirname = "/" + dirname
141+
134142
return domain, dirname, filename
135143

136144
def exists(self, url):
@@ -188,18 +196,24 @@ def copy(self, source, destination):
188196
# Prepare the source path for XRootD
189197
if not self._parse_url(source):
190198
source = abspath(source)
199+
else:
200+
domain, dirname, filename = self._parse_url(source)
201+
source = f"{domain}/{dirname}/{filename}"
202+
191203
# Prepare the destination path for XRootD
192204
assert os.path.basename(source) == os.path.basename(destination)
193205
if self._parse_url(destination):
194206
domain, dirname, filename = self._parse_url(destination)
207+
destination = f"{domain}/{dirname}/{filename}"
195208
self.makedirs(domain, dirname)
196209
else:
197210
destination = abspath(destination)
198211
if not os.path.isdir(os.path.dirname(destination)):
199212
os.makedirs(os.path.dirname(destination))
213+
200214
# Perform the copy operation
201215
process = client.CopyProcess()
202-
process.add_job(source, destination)
216+
process.add_job(source, destination, force=True)
203217
process.prepare()
204218
status, returns = process.run()
205219
if not status.ok or not returns[0]["status"].ok:

0 commit comments

Comments
 (0)