rda-python-miscs 3.0.2__tar.gz → 3.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rda_python_miscs-3.0.2/src/rda_python_miscs.egg-info → rda_python_miscs-3.0.4}/PKG-INFO +1 -1
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/pyproject.toml +1 -1
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexcp.py +152 -9
- rda_python_miscs-3.0.4/src/rda_python_miscs/gdexcp.usg +145 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/pg_rst.py +128 -25
- rda_python_miscs-3.0.4/src/rda_python_miscs/rst_templates/appendix.rst.temp +19 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4/src/rda_python_miscs.egg-info}/PKG-INFO +1 -1
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs.egg-info/SOURCES.txt +1 -0
- rda_python_miscs-3.0.2/src/rda_python_miscs/gdexcp.usg +0 -77
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/LICENSE +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/MANIFEST.in +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/README.md +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/setup.cfg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/__init__.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/bash_qsub.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/bashqsub.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/bashqsub.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdex_ls.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexkill.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexkill.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexls.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexls.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexls_standalone.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexmod.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexmod.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexown.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexown.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexps.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexps.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexsub.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexsub.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexzip.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/gdexzip.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/pg_docs.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/pg_rst.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/pg_wget.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/pgwget.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/pgwget.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rda_cp.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rda_kill.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rda_mod.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rda_own.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rda_ps.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rda_sub.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rda_zip.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rdals.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rdals.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rst_templates/index.rst.temp +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rst_templates/section.rst.temp +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/tcsh_qsub.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/tcshqsub.py +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/tcshqsub.usg +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs.egg-info/dependency_links.txt +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs.egg-info/entry_points.txt +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs.egg-info/requires.txt +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs.egg-info/top_level.txt +0 -0
- {rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/tests/test_miscs.py +0 -0
|
@@ -33,15 +33,21 @@ class GdexCp(PgFile):
|
|
|
33
33
|
'fp': None, # from Globus endpoint
|
|
34
34
|
'tp': None, # to Globus endpoint
|
|
35
35
|
'f': [], # from file names
|
|
36
|
+
'i': None, # input file holding a list of from file names, one per line
|
|
36
37
|
't': None, # to file name
|
|
37
38
|
'r': 0, # 1 if recursive all
|
|
38
39
|
'R': 0, # > 0 to set recursive limit
|
|
40
|
+
'o': 0, # 1 to force a downloaded file owned by COMMONUSER; needs -fp
|
|
41
|
+
'O': 0, # 1 to override an existing target file of the same size
|
|
42
|
+
'm': 1, # number of multiple processes to copy files in parallel
|
|
43
|
+
'd': 0, # 1 to add a dscheck record for delayed PBS batch process
|
|
39
44
|
'F': 0o664, # to file mode, default to 664
|
|
40
45
|
'D': 0o775, # to directory mode, default to 775
|
|
41
46
|
}
|
|
42
47
|
self.CINFO = {
|
|
43
48
|
'tcnt': 0,
|
|
44
49
|
'htcnt': 0,
|
|
50
|
+
'pcnt': 0, # count of dispatched child processes for option -m
|
|
45
51
|
'cpflag': 0, # 1 file only, 2 directory only, 3 both
|
|
46
52
|
'cpstr': ['', 'Files', 'Directories', 'Files/Directories'],
|
|
47
53
|
'fpath': None,
|
|
@@ -75,8 +81,8 @@ class GdexCp(PgFile):
|
|
|
75
81
|
if ms:
|
|
76
82
|
option = ms.group(1)
|
|
77
83
|
if option not in self.RDACP: self.pglog(arg + ": Unknown Option", self.LGEREX)
|
|
78
|
-
if option
|
|
79
|
-
self.RDACP[
|
|
84
|
+
if option in ('r', 'o', 'd', 'O'):
|
|
85
|
+
self.RDACP[option] = 1
|
|
80
86
|
option = None
|
|
81
87
|
continue
|
|
82
88
|
if not option: self.pglog(arg + ": Value provided without option", self.LGEREX)
|
|
@@ -84,7 +90,7 @@ class GdexCp(PgFile):
|
|
|
84
90
|
self.RDACP['f'].append(arg)
|
|
85
91
|
defopt = None
|
|
86
92
|
else:
|
|
87
|
-
if option
|
|
93
|
+
if option in ('R', 'm'):
|
|
88
94
|
self.RDACP[option] = int(arg)
|
|
89
95
|
elif option in 'FD':
|
|
90
96
|
self.RDACP[option] = self.base2int(arg, 8)
|
|
@@ -95,8 +101,29 @@ class GdexCp(PgFile):
|
|
|
95
101
|
elif option == 'fh':
|
|
96
102
|
self.CINFO['fhost'] = arg + '-'
|
|
97
103
|
option = defopt
|
|
104
|
+
if self.RDACP['i']: self.add_input_files(self.RDACP['i'])
|
|
98
105
|
if dohelp or not self.RDACP['f']: self.show_usage("gdexcp")
|
|
99
|
-
|
|
106
|
+
|
|
107
|
+
# read source paths from an input file and append them to the -f list
|
|
108
|
+
def add_input_files(self, infile):
|
|
109
|
+
"""Append source paths read from an input file to the -f source list.
|
|
110
|
+
|
|
111
|
+
Each non-empty line in the input file is treated as one source path;
|
|
112
|
+
leading/trailing whitespace is stripped and lines starting with '#' are
|
|
113
|
+
ignored as comments.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
infile (str): Path to the input file holding one source path per line.
|
|
117
|
+
"""
|
|
118
|
+
finfo = self.check_local_file(infile, 0, self.LGWNEX)
|
|
119
|
+
if not finfo: self.pglog("{}: Input file of -i not found".format(infile), self.LGEREX)
|
|
120
|
+
fd = open(infile, 'r')
|
|
121
|
+
for line in fd:
|
|
122
|
+
line = line.strip()
|
|
123
|
+
if not line or line[0] == '#': continue
|
|
124
|
+
self.RDACP['f'].append(line)
|
|
125
|
+
fd.close()
|
|
126
|
+
|
|
100
127
|
# function to start actions
|
|
101
128
|
def start_actions(self):
|
|
102
129
|
"""Validate copy targets, configure host/bucket/endpoint context, and dispatch copies.
|
|
@@ -132,7 +159,23 @@ class GdexCp(PgFile):
|
|
|
132
159
|
self.PGLOG['BACKUPEP'] = self.RDACP['fp']
|
|
133
160
|
elif self.RDACP['tp']:
|
|
134
161
|
self.PGLOG['BACKUPEP'] = self.RDACP['tp']
|
|
162
|
+
if self.RDACP['o']:
|
|
163
|
+
if not self.RDACP['fp']:
|
|
164
|
+
self.pglog("-o: works only when source Globus endpoint -fp is provided", self.LGEREX)
|
|
165
|
+
if self.RDACP['th'] or self.RDACP['tp'] or self.RDACP['tb']:
|
|
166
|
+
self.pglog("-o: works only for downloading to local files (no -th/-tp/-tb)", self.LGEREX)
|
|
167
|
+
if self.RDACP['m'] < 1: self.RDACP['m'] = 1
|
|
168
|
+
if self.RDACP['m'] > 16:
|
|
169
|
+
self.pglog("-m {}: process count too large, capped at 16".format(self.RDACP['m']), self.LOGWRN)
|
|
170
|
+
self.RDACP['m'] = 16
|
|
171
|
+
if self.RDACP['d']:
|
|
172
|
+
self.add_delayed_check()
|
|
173
|
+
self.cmdlog()
|
|
174
|
+
return
|
|
175
|
+
if self.RDACP['m'] > 1:
|
|
176
|
+
self.start_none_daemon('gdexcp', '', self.PGLOG['CURUID'], self.RDACP['m'], 120)
|
|
135
177
|
self.copy_top_list(self.RDACP['f'])
|
|
178
|
+
if self.RDACP['m'] > 1: self.check_child(None, 0, self.LOGWRN, 1)
|
|
136
179
|
hinfo = ''
|
|
137
180
|
if self.RDACP['fh']: hinfo += " From " + self.RDACP['fh']
|
|
138
181
|
if self.RDACP['th']: hinfo += " To " + self.RDACP['th']
|
|
@@ -175,7 +218,7 @@ class GdexCp(PgFile):
|
|
|
175
218
|
if not re.match(r'^/', file): file = self.join_paths(self.CINFO['curdir'], file)
|
|
176
219
|
self.CINFO['fpath'] = (file if dosub else op.dirname(file)) + "/"
|
|
177
220
|
if info['isfile']:
|
|
178
|
-
self.CINFO['tcnt'] += self.
|
|
221
|
+
self.CINFO['tcnt'] += self.dispatch_copy(file, info)
|
|
179
222
|
elif dosub or self.RDACP['R']:
|
|
180
223
|
flist = self.gdex_glob(file, self.RDACP['fh'], 0, self.LGWNEX)
|
|
181
224
|
if flist: self.copy_list(flist, 1, file)
|
|
@@ -197,7 +240,7 @@ class GdexCp(PgFile):
|
|
|
197
240
|
fcnt = 0
|
|
198
241
|
for file in tlist:
|
|
199
242
|
if tlist[file]['isfile']:
|
|
200
|
-
fcnt += self.
|
|
243
|
+
fcnt += self.dispatch_copy(file, tlist[file])
|
|
201
244
|
self.CINFO['cpflag'] |= (1 if tlist[file]['isfile'] else 2)
|
|
202
245
|
elif level < self.RDACP['R']:
|
|
203
246
|
flist = self.gdex_glob(file, self.RDACP['fh'], 0, self.LGWNEX)
|
|
@@ -206,20 +249,50 @@ class GdexCp(PgFile):
|
|
|
206
249
|
self.pglog("{}{}: {} {} copied from directory".format(self.CINFO['fhost'], cdir, fcnt, self.CINFO['cpstr'][self.CINFO['cpflag']]), self.LOGWRN)
|
|
207
250
|
self.CINFO['tcnt'] += fcnt
|
|
208
251
|
|
|
252
|
+
# copy one file, forking a child process when running with option -m
|
|
253
|
+
def dispatch_copy(self, fromfile, finfo):
|
|
254
|
+
"""Copy one file, dispatching the copy to a child process when -m > 1.
|
|
255
|
+
|
|
256
|
+
With a single process (-m 1) the file is copied in line. With multiple
|
|
257
|
+
processes the copy is forked to a child via the PgSIG process pool (up to
|
|
258
|
+
RDACP['m'] children run concurrently); the parent records one dispatched
|
|
259
|
+
file and continues traversing, while each child performs the copy, logs
|
|
260
|
+
its own result, and exits.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
fromfile (str): Absolute source file path.
|
|
264
|
+
finfo (dict): Source file-info dict (with 'isfile' and 'data_size').
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
int: 1 if the file was copied (single process) or dispatched to a
|
|
268
|
+
child process (-m > 1), 0 otherwise.
|
|
269
|
+
"""
|
|
270
|
+
if self.RDACP['m'] < 2: return self.copy_file(fromfile, finfo)
|
|
271
|
+
stat = self.start_child("gdexcp_{}".format(self.CINFO['pcnt']), self.LOGWRN, 1)
|
|
272
|
+
if stat <= 0: self.pglog("{}: cannot start child process to copy".format(fromfile), self.LGEREX)
|
|
273
|
+
if self.PGSIG['PPID'] > 1: # in child process
|
|
274
|
+
self.copy_file(fromfile, finfo)
|
|
275
|
+
sys.exit(0)
|
|
276
|
+
self.CINFO['pcnt'] += 1 # in parent process; child already dropped its DB link
|
|
277
|
+
return 1
|
|
278
|
+
|
|
209
279
|
# copy one file
|
|
210
|
-
def copy_file(self, fromfile,
|
|
280
|
+
def copy_file(self, fromfile, finfo):
|
|
211
281
|
"""Resolve the destination path for one source file and perform the copy.
|
|
212
282
|
|
|
213
283
|
When a target directory is set (tpath), strips the source base path prefix
|
|
214
284
|
and joins the remainder to tpath. Otherwise copies directly to the -t value.
|
|
285
|
+
Skips the copy when the target already exists with the same size as the
|
|
286
|
+
source, unless -O is given to override an existing same-size target.
|
|
215
287
|
|
|
216
288
|
Args:
|
|
217
289
|
fromfile (str): Absolute source file path.
|
|
218
|
-
|
|
290
|
+
finfo (dict): Source file-info dict (with 'isfile' and 'data_size').
|
|
219
291
|
|
|
220
292
|
Returns:
|
|
221
293
|
int: 1 if the file was copied successfully, 0 otherwise.
|
|
222
294
|
"""
|
|
295
|
+
isfile = finfo['isfile']
|
|
223
296
|
if self.CINFO['tpath']:
|
|
224
297
|
fname = re.sub(r'^{}'.format(self.CINFO['fpath']), '', fromfile)
|
|
225
298
|
if isfile:
|
|
@@ -228,7 +301,77 @@ class GdexCp(PgFile):
|
|
|
228
301
|
tofile = self.CINFO['tpath'] + '/'
|
|
229
302
|
else:
|
|
230
303
|
tofile = self.RDACP['t']
|
|
231
|
-
|
|
304
|
+
if isfile and not self.RDACP['O']:
|
|
305
|
+
tinfo = self.check_gdex_file(tofile, self.RDACP['th'], 0, self.LGWNEX)
|
|
306
|
+
if tinfo and tinfo['data_size'] == finfo['data_size']:
|
|
307
|
+
self.pglog("{}{}: Target exists with same size, skip copying".format(self.CINFO['thost'], tofile), self.LOGWRN)
|
|
308
|
+
return 0
|
|
309
|
+
if self.RDACP['o']: return self.force_owner_copy(tofile, fromfile)
|
|
310
|
+
logact = self.LGWNEX | (self.OVRIDE if self.RDACP['O'] else 0)
|
|
311
|
+
return (1 if self.copy_gdex_file(tofile, fromfile, self.RDACP['th'], self.RDACP['fh'], logact) else 0)
|
|
312
|
+
|
|
313
|
+
# copy one file from a Globus endpoint and force COMMONUSER ownership
|
|
314
|
+
def force_owner_copy(self, tofile, fromfile):
|
|
315
|
+
"""Download a Globus file via a tmp file so the final copy is owned by COMMONUSER.
|
|
316
|
+
|
|
317
|
+
A Globus endpoint dumps the local file owned by the endpoint's mapped user
|
|
318
|
+
rather than COMMONUSER ('gdexdata'). This downloads to a tmp file under
|
|
319
|
+
PGLOG['TMPPATH'], makes it group readable/writable as its owner via the
|
|
320
|
+
pgstart_<user> setuid wrapper, then copies it locally so the final file is
|
|
321
|
+
owned by COMMONUSER, and removes the tmp file.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
tofile (str): Final local destination path.
|
|
325
|
+
fromfile (str): Source file path on the Globus endpoint.
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
int: 1 if the file was copied successfully, 0 otherwise.
|
|
329
|
+
"""
|
|
330
|
+
tmpfile = self.join_paths(self.PGLOG['TMPPATH'], "{}.{}".format(op.basename(fromfile), os.getpid()))
|
|
331
|
+
if not self.copy_gdex_file(tmpfile, fromfile, self.RDACP['th'], self.RDACP['fh'], self.LGWNEX): return 0
|
|
332
|
+
finfo = self.check_local_file(tmpfile, 2, self.LGWNEX)
|
|
333
|
+
owner = finfo['logname'] if finfo else None
|
|
334
|
+
if owner and owner != self.PGLOG['COMMONUSER']:
|
|
335
|
+
self.pgsystem(self.get_local_command("chmod g+rw " + tmpfile, owner), self.LGWNEX)
|
|
336
|
+
ret = self.copy_gdex_file(tofile, tmpfile, self.RDACP['th'], None, self.LGWNEX)
|
|
337
|
+
self.delete_local_file(tmpfile, self.LGWNEX)
|
|
338
|
+
return (1 if ret else 0)
|
|
339
|
+
|
|
340
|
+
# add a dscheck record so this gdexcp command runs later as a PBS batch job
|
|
341
|
+
def add_delayed_check(self):
|
|
342
|
+
"""Queue this gdexcp invocation as a delayed PBS batch job via a dscheck record.
|
|
343
|
+
|
|
344
|
+
Records the current command (with the -d flag stripped so the batch run
|
|
345
|
+
performs the actual copy) into the RDADB dscheck table for the dscheck
|
|
346
|
+
daemon to later submit to PBS through bashqsub/tcshqsub. The qsub resource
|
|
347
|
+
option always sets a 24 hour walltime; when -m > 1 it also reserves a single
|
|
348
|
+
node with (number of processes) cpus and 1gb of memory per cpu.
|
|
349
|
+
"""
|
|
350
|
+
argv = [arg for arg in sys.argv[1:] if arg != '-d']
|
|
351
|
+
argstr = self.argv_to_string(argv, 1)
|
|
352
|
+
argextra = None
|
|
353
|
+
if len(argstr) > 100:
|
|
354
|
+
argextra = argstr[100:]
|
|
355
|
+
argstr = argstr[0:100]
|
|
356
|
+
record = {
|
|
357
|
+
'command': 'gdexcp',
|
|
358
|
+
'argv': argstr,
|
|
359
|
+
'specialist': self.PGLOG['CURUID'],
|
|
360
|
+
'workdir': self.CINFO['curdir'],
|
|
361
|
+
'oindex': 0,
|
|
362
|
+
'otype': '',
|
|
363
|
+
'action': None,
|
|
364
|
+
'dsid': None,
|
|
365
|
+
'mcount': 1,
|
|
366
|
+
}
|
|
367
|
+
(record['date'], record['time']) = self.get_date_time()
|
|
368
|
+
if argextra: record['argextra'] = argextra
|
|
369
|
+
qoptions = "-l walltime=24:00:00"
|
|
370
|
+
if self.RDACP['m'] > 1:
|
|
371
|
+
qoptions += ",select=1:ncpus={0}:mem={0}gb".format(self.RDACP['m'])
|
|
372
|
+
record['qoptions'] = qoptions
|
|
373
|
+
cidx = self.pgadd("dscheck", record, self.LGWNEX|self.AUTOID)
|
|
374
|
+
self.pglog("Chk{}: gdexcp {} added for delayed batch process".format(cidx, argstr), self.LOGWRN)
|
|
232
375
|
|
|
233
376
|
# main function to execute this script
|
|
234
377
|
def main():
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
|
|
2
|
+
Name: gdexcp - copy files and directories as user 'gdexdata'
|
|
3
|
+
|
|
4
|
+
Copy files and directories to a target location. The source and the target may
|
|
5
|
+
each reside on the local host, a remote host, an Object Store bucket, or a Globus
|
|
6
|
+
endpoint. Target files are owned by 'gdexdata' and created with configurable
|
|
7
|
+
permission modes.
|
|
8
|
+
|
|
9
|
+
Usage: gdexcp [-f] FromDirectories/Files [-t ToDirectory/FileName] \
|
|
10
|
+
[-i InputFile] [-m ProcessCount] [-d] [-r] [-R RecursiveLevel] \
|
|
11
|
+
[-fh FromHostName] [-th ToHostName] \
|
|
12
|
+
[-fb FromBucket] [-tb ToBucket] \
|
|
13
|
+
[-fp FromGlobusEndpoint] [-tp ToGlobusEndpoint] \
|
|
14
|
+
[-F FileMode] [-D DirectoryMode] [-o] [-O] [-h]
|
|
15
|
+
|
|
16
|
+
gdexcp can be run from any directory. Usage is displayed when no source paths
|
|
17
|
+
are given.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
SOURCE AND TARGET
|
|
21
|
+
|
|
22
|
+
-f FromDirectories/Files
|
|
23
|
+
Source directories and/or files to copy. This is the default option,
|
|
24
|
+
so paths may be given without the -f flag. Shell wildcards are
|
|
25
|
+
supported; use './' or '*' to copy everything in the current directory.
|
|
26
|
+
A trailing '/' on a source directory path copies the contents of that
|
|
27
|
+
directory (as a file list) rather than the directory entry itself.
|
|
28
|
+
Source paths must be readable by user 'gdexdata'; gdexcp attempts to
|
|
29
|
+
fix the mode when they are not.
|
|
30
|
+
|
|
31
|
+
-i InputFile
|
|
32
|
+
A file holding a list of source paths to copy, one path per line.
|
|
33
|
+
Blank lines and lines starting with '#' are ignored. The paths read
|
|
34
|
+
are appended to the -f source list.
|
|
35
|
+
|
|
36
|
+
-t ToDirectory/FileName
|
|
37
|
+
Target directory or file name. Defaults to '.' (the current
|
|
38
|
+
directory). A trailing '/' forces the target to be treated as a
|
|
39
|
+
directory. Multiple source files cannot be copied to a single target
|
|
40
|
+
file name.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
SOURCE/TARGET LOCATIONS (default to the local host)
|
|
44
|
+
|
|
45
|
+
-fh FromHostName host name where the source files reside.
|
|
46
|
+
-th ToHostName host name where the target files are written.
|
|
47
|
+
-fb FromBucket Object Store bucket name for the source files.
|
|
48
|
+
-tb ToBucket Object Store bucket name for the target files.
|
|
49
|
+
-fp FromGlobusEndpoint Globus endpoint for the source files.
|
|
50
|
+
-tp ToGlobusEndpoint Globus endpoint for the target files.
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
COPY BEHAVIOR
|
|
54
|
+
|
|
55
|
+
-r Copy directories and files recursively, with no depth limit.
|
|
56
|
+
|
|
57
|
+
-R RecursiveLevel
|
|
58
|
+
Copy recursively up to the given depth. -R 1 copies only the
|
|
59
|
+
immediate contents of each source directory.
|
|
60
|
+
|
|
61
|
+
-m ProcessCount
|
|
62
|
+
Number of processes used to copy files in parallel. Defaults to 1.
|
|
63
|
+
When greater than 1, the source files are distributed across that many
|
|
64
|
+
concurrent child processes. Capped at 16; a larger value is reduced to
|
|
65
|
+
16 with a warning.
|
|
66
|
+
|
|
67
|
+
-d Add a dscheck record so this gdexcp command runs later as a delayed PBS
|
|
68
|
+
batch job (submitted by the dscheck daemon via bashqsub / tcshqsub).
|
|
69
|
+
The qsub resource always sets a 24 hour walltime; when -m is greater
|
|
70
|
+
than 1 it also reserves a single node with (ProcessCount) cpus and 1gb
|
|
71
|
+
of memory per cpu.
|
|
72
|
+
|
|
73
|
+
-o Force a downloaded file to be owned by 'gdexdata'. A Globus endpoint
|
|
74
|
+
writes the local file owned by the endpoint's mapped user; with -o the
|
|
75
|
+
file is downloaded to a tmp file, then copied locally so the final file
|
|
76
|
+
is owned by 'gdexdata'. Only valid together with -fp and for
|
|
77
|
+
downloading to local files (not with -th/-tp/-tb).
|
|
78
|
+
|
|
79
|
+
-O Override an existing target. By default a source file is skipped when
|
|
80
|
+
the target already exists with the same size; give -O to copy it anyway
|
|
81
|
+
and overwrite the existing target.
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
TARGET PERMISSIONS (octal notation)
|
|
85
|
+
|
|
86
|
+
-F FileMode permission mode for target files. Defaults to 664.
|
|
87
|
+
-D DirectoryMode permission mode for target directories. Defaults to 775.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
MISCELLANEOUS
|
|
91
|
+
|
|
92
|
+
-h Display this help document.
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
NOTES
|
|
96
|
+
|
|
97
|
+
- A trailing '/' on a source directory path copies the contents of that
|
|
98
|
+
directory rather than the directory entry itself.
|
|
99
|
+
- By default an unchanged target (same size) is skipped; use -O to overwrite.
|
|
100
|
+
- If a Globus endpoint (-fp/-tp) is locally accessible, a direct local copy
|
|
101
|
+
(omitting -fp/-tp and giving the local path) is faster, avoiding the Globus
|
|
102
|
+
transfer overhead.
|
|
103
|
+
- A delayed batch job (-d) is given a 24 hour walltime. Do not submit a single
|
|
104
|
+
batch job to copy too many files at once; if the copy cannot finish within 24
|
|
105
|
+
hours the job is killed. Split a very large copy into multiple -d jobs (and/or
|
|
106
|
+
raise -m) so each one completes well within the walltime.
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
EXAMPLES
|
|
110
|
+
|
|
111
|
+
1. Copy all files and subdirectories under the current directory to a remote
|
|
112
|
+
host:
|
|
113
|
+
|
|
114
|
+
gdexcp -r -f * -t /PathTo/d277006/ -th castle
|
|
115
|
+
|
|
116
|
+
2. Copy the contents of a local directory to a remote location (trailing '/'
|
|
117
|
+
on the source omits the directory entry itself):
|
|
118
|
+
|
|
119
|
+
gdexcp -r -f /PathTo/DirectoryName/ -t /PathTo/d277006/ -th castle
|
|
120
|
+
|
|
121
|
+
Without the trailing '/', DirectoryName itself is also copied:
|
|
122
|
+
|
|
123
|
+
gdexcp -r -f /PathTo/DirectoryName -t /PathTo/d277006/ -th castle
|
|
124
|
+
|
|
125
|
+
3. Copy a single file to an Object Store bucket:
|
|
126
|
+
|
|
127
|
+
gdexcp -f /PathTo/myfile.nc -tb my-bucket -t myfile.nc
|
|
128
|
+
|
|
129
|
+
4. Copy files from a remote host to the local current directory:
|
|
130
|
+
|
|
131
|
+
gdexcp -fh castle -f /PathTo/d277006/myfile.nc
|
|
132
|
+
|
|
133
|
+
5. Download a file from a source Globus endpoint and force the local file to
|
|
134
|
+
be owned by 'gdexdata' (-o requires -fp):
|
|
135
|
+
|
|
136
|
+
gdexcp -fp gdex-quasar -f /d277006/myfile.nc -t /PathTo/myfile.nc -o
|
|
137
|
+
|
|
138
|
+
6. Copy the source paths listed in an input file using 4 parallel processes:
|
|
139
|
+
|
|
140
|
+
gdexcp -i filelist.txt -t /PathTo/d277006/ -m 4
|
|
141
|
+
|
|
142
|
+
7. Queue a delayed PBS batch job to copy a directory in parallel; the dscheck
|
|
143
|
+
daemon submits it later, reserving one node with 4 cpus and 4gb of memory:
|
|
144
|
+
|
|
145
|
+
gdexcp -r -f /PathTo/DirectoryName/ -t /PathTo/d277006/ -m 4 -d
|
|
@@ -140,10 +140,10 @@ class PgRST(PgFile, PgUtil):
|
|
|
140
140
|
"""
|
|
141
141
|
self.OPTS = opts
|
|
142
142
|
self.ALIAS = alias
|
|
143
|
+
self.DOCS['DOCNAM'] = docname
|
|
143
144
|
|
|
144
145
|
self.parse_docs(docname)
|
|
145
146
|
if not self.sections: self.pglog(docname + ": empty document", self.LGWNEX)
|
|
146
|
-
self.DOCS['DOCNAM'] = docname
|
|
147
147
|
if docname in self.LINKS: self.LINKS.remove(docname)
|
|
148
148
|
self.DOCS['DOCLNK'] = r"({})".format('|'.join(self.LINKS))
|
|
149
149
|
self.DOCS['DOCTIT'] = docname.upper()
|
|
@@ -152,6 +152,7 @@ class PgRST(PgFile, PgUtil):
|
|
|
152
152
|
self.write_index(self.sections[0])
|
|
153
153
|
for section in self.sections:
|
|
154
154
|
self.write_section(section)
|
|
155
|
+
self.write_appendix()
|
|
155
156
|
|
|
156
157
|
#
|
|
157
158
|
# parse the original document and return a array of sections,
|
|
@@ -172,7 +173,9 @@ class PgRST(PgFile, PgUtil):
|
|
|
172
173
|
with open(docfile, 'r') as fh:
|
|
173
174
|
line = fh.readline()
|
|
174
175
|
while line:
|
|
175
|
-
|
|
176
|
+
# Skip full-line authoring comments, but keep '#!' shebang lines so
|
|
177
|
+
# shell scripts shown in example content blocks stay intact.
|
|
178
|
+
if re.match(r'\s*#(?!!)', line):
|
|
176
179
|
line = fh.readline()
|
|
177
180
|
continue # skip comment lines
|
|
178
181
|
ms = re.match(r'^(.*\S)\s+#', line)
|
|
@@ -191,13 +194,21 @@ class PgRST(PgFile, PgUtil):
|
|
|
191
194
|
option = self.record_option(section, option, example, ms.group(1), ms.group(2))
|
|
192
195
|
example = None
|
|
193
196
|
elif option:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
example['desc'] += line + "\n"
|
|
197
|
+
if option.get('inexm'):
|
|
198
|
+
# inside an 'Examples:' block: collect raw lines verbatim
|
|
199
|
+
# (split into individual examples later in split_examples)
|
|
200
|
+
option['exmraw'] += line + "\n"
|
|
199
201
|
else:
|
|
200
|
-
|
|
202
|
+
ms = re.match(r'^ (?:For(?: | another )example,|Example[ ]*[,\-])\s*(.*)$', line)
|
|
203
|
+
if ms: # found a single labeled example
|
|
204
|
+
example = self.record_example(option, example, ms.group(1))
|
|
205
|
+
elif re.match(r'^ Examples:\s*$', line):
|
|
206
|
+
option['inexm'] = True # start of a multi-example block
|
|
207
|
+
option['exmraw'] = ""
|
|
208
|
+
elif example:
|
|
209
|
+
example['desc'] += line + "\n"
|
|
210
|
+
else:
|
|
211
|
+
option['desc'] += line + "\n"
|
|
201
212
|
else:
|
|
202
213
|
section['desc'] += line + "\n"
|
|
203
214
|
|
|
@@ -261,11 +272,62 @@ class PgRST(PgFile, PgUtil):
|
|
|
261
272
|
"""
|
|
262
273
|
if option:
|
|
263
274
|
if example: self.record_example(option, example)
|
|
275
|
+
self.split_examples(option)
|
|
264
276
|
self.options[option['opt']] = option # record option globally
|
|
265
277
|
section['opts'].append(option['opt']) # record option short name in section
|
|
266
278
|
|
|
267
279
|
if nopt: return self.init_option(section['secid'], nopt, ndesc)
|
|
268
280
|
|
|
281
|
+
def split_examples(self, option):
|
|
282
|
+
"""Split an option's pending ``Examples:`` block into individual examples.
|
|
283
|
+
|
|
284
|
+
The raw text collected after an ``Examples:`` header is segmented into
|
|
285
|
+
blank-line-separated blocks. A block whose last line ends with ``:`` and
|
|
286
|
+
whose first line is descriptive prose (not a command, option flag, or a
|
|
287
|
+
``<<Content ...>>`` header) starts a new example; following blocks
|
|
288
|
+
(command synopsis, script content, trailing notes) belong to that
|
|
289
|
+
example until the next title block.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
option (dict): The option whose ``exmraw`` buffer is parsed; the
|
|
293
|
+
buffer is removed and one example is recorded per
|
|
294
|
+
title block found.
|
|
295
|
+
"""
|
|
296
|
+
buf = option.pop('exmraw', None)
|
|
297
|
+
option.pop('inexm', None)
|
|
298
|
+
if not buf: return
|
|
299
|
+
|
|
300
|
+
blocks = []
|
|
301
|
+
cur = []
|
|
302
|
+
for ln in buf.split('\n'):
|
|
303
|
+
if ln.strip() == '':
|
|
304
|
+
if cur: blocks.append(cur); cur = []
|
|
305
|
+
else:
|
|
306
|
+
cur.append(ln)
|
|
307
|
+
if cur: blocks.append(cur)
|
|
308
|
+
|
|
309
|
+
def is_title(block):
|
|
310
|
+
if not block[-1].rstrip().endswith(':'): return False
|
|
311
|
+
first = block[0].strip()
|
|
312
|
+
if first.startswith('<<'): return False
|
|
313
|
+
if re.match(r'[-*(]', first): return False
|
|
314
|
+
if re.match(r'{}\b'.format(self.DOCS['DOCNAM']), first): return False
|
|
315
|
+
return True
|
|
316
|
+
|
|
317
|
+
exmtext = None
|
|
318
|
+
for block in blocks:
|
|
319
|
+
btext = '\n'.join(block)
|
|
320
|
+
if is_title(block):
|
|
321
|
+
if exmtext is not None:
|
|
322
|
+
self.record_example(option, self.init_example(option['opt'], exmtext))
|
|
323
|
+
exmtext = btext + "\n"
|
|
324
|
+
elif exmtext is not None:
|
|
325
|
+
exmtext += "\n" + btext + "\n"
|
|
326
|
+
else:
|
|
327
|
+
option['desc'] += btext + "\n" # stray text before the first example
|
|
328
|
+
if exmtext is not None:
|
|
329
|
+
self.record_example(option, self.init_example(option['opt'], exmtext))
|
|
330
|
+
|
|
269
331
|
def record_example(self, option, example, ndesc=None):
|
|
270
332
|
"""Append the completed *example* to ``self.examples`` and optionally start a new one.
|
|
271
333
|
|
|
@@ -478,18 +540,21 @@ class PgRST(PgFile, PgUtil):
|
|
|
478
540
|
"""Build and return the RST table-of-contents string of a given section.
|
|
479
541
|
|
|
480
542
|
Produces a nested bullet list of section links (indented by section
|
|
481
|
-
level)
|
|
543
|
+
level). For the index (``csection is None``) the example appendix is a
|
|
544
|
+
standalone page (``appendixA``) added to the toctree; for a section the
|
|
545
|
+
examples in its subtree are listed inline as a local Appendix A.
|
|
482
546
|
|
|
483
547
|
Returns:
|
|
484
548
|
str: RST-formatted TOC content ready for ``__TOC__`` substitution.
|
|
485
549
|
"""
|
|
486
|
-
|
|
550
|
+
|
|
487
551
|
content = ""
|
|
488
552
|
clevel = csection['level'] if csection else 0
|
|
489
553
|
csecid = csection['secid'] if csection else ""
|
|
490
554
|
depth = self.TLEVEL - clevel
|
|
491
555
|
level = clevel+1
|
|
492
556
|
preid = csecid+'.'
|
|
557
|
+
is_index = csection is None
|
|
493
558
|
|
|
494
559
|
# nested bullet list for all sections
|
|
495
560
|
for section in self.sections:
|
|
@@ -497,9 +562,14 @@ class PgRST(PgFile, PgUtil):
|
|
|
497
562
|
if csecid and not secid.startswith(preid): continue
|
|
498
563
|
if section['level'] == level: content += " section{}\n".format(secid)
|
|
499
564
|
|
|
565
|
+
# The full list of examples lives on its own appendix page in the index.
|
|
566
|
+
if is_index and self.examples: content += " appendixA\n"
|
|
567
|
+
|
|
500
568
|
if not content: return ""
|
|
501
569
|
|
|
502
570
|
content = f".. toctree::\n :maxdepth: {depth}\n :caption: Table of Contents\n\n{content}\n"
|
|
571
|
+
if is_index: return content
|
|
572
|
+
|
|
503
573
|
# appendix A: list of examples for the parent section and its subsections
|
|
504
574
|
appendix = ""
|
|
505
575
|
idx = 1 # used as example index
|
|
@@ -507,7 +577,7 @@ class PgRST(PgFile, PgUtil):
|
|
|
507
577
|
opt = exm['opt']
|
|
508
578
|
option = self.options[opt]
|
|
509
579
|
secid = option['secid']
|
|
510
|
-
if
|
|
580
|
+
if secid == csecid or secid.startswith(preid):
|
|
511
581
|
appendix += "- :ref:`A.{}. {} Option -{} (-{}) <{}_e{}>`\n".format(
|
|
512
582
|
idx, option['type'], opt, option['name'], secid, idx)
|
|
513
583
|
idx += 1
|
|
@@ -516,6 +586,28 @@ class PgRST(PgFile, PgUtil):
|
|
|
516
586
|
|
|
517
587
|
return content
|
|
518
588
|
|
|
589
|
+
#
|
|
590
|
+
# write the appendix page listing all examples in the document
|
|
591
|
+
#
|
|
592
|
+
def write_appendix(self):
|
|
593
|
+
"""Write ``appendixA.rst`` listing every example with a link.
|
|
594
|
+
|
|
595
|
+
Each entry links to the example anchor on its section page. Does nothing
|
|
596
|
+
when the document has no examples.
|
|
597
|
+
"""
|
|
598
|
+
if not self.examples: return
|
|
599
|
+
content = ""
|
|
600
|
+
idx = 1
|
|
601
|
+
for exm in self.examples:
|
|
602
|
+
option = self.options[exm['opt']]
|
|
603
|
+
secid = option['secid']
|
|
604
|
+
title = exm['title'].strip().rstrip(':')
|
|
605
|
+
content += "- :ref:`A.{}. {} Option -{} (-{}): {} <{}_e{}>`\n".format(
|
|
606
|
+
idx, option['type'], exm['opt'], option['name'], title, secid, idx)
|
|
607
|
+
idx += 1
|
|
608
|
+
|
|
609
|
+
self.template_to_rst("appendix", {'CONTENT': content}, "A")
|
|
610
|
+
|
|
519
611
|
#
|
|
520
612
|
# create a section rst content
|
|
521
613
|
#
|
|
@@ -672,7 +764,8 @@ class PgRST(PgFile, PgUtil):
|
|
|
672
764
|
|
|
673
765
|
for optary in opts:
|
|
674
766
|
opt = self.get_short_option(optary[1])
|
|
675
|
-
|
|
767
|
+
if opt is None: continue # not an option of this document; leave as-is
|
|
768
|
+
|
|
676
769
|
pre = optary[0]
|
|
677
770
|
after = optary[2]
|
|
678
771
|
secid = self.options[opt]['secid']
|
|
@@ -826,7 +919,7 @@ class PgRST(PgFile, PgUtil):
|
|
|
826
919
|
line0 = lines[0]
|
|
827
920
|
normal = 1
|
|
828
921
|
if dtype == 2:
|
|
829
|
-
ms = re.match(r'
|
|
922
|
+
ms = re.match(r'^\s*<<(Content .*)>>$', line0)
|
|
830
923
|
if ms: # input files for examples
|
|
831
924
|
content += ms.group(1) + ":\n\n.. code-block:: none\n\n"
|
|
832
925
|
normal = 0
|
|
@@ -928,13 +1021,23 @@ class PgRST(PgFile, PgUtil):
|
|
|
928
1021
|
rows.append(tuple(prev_vals))
|
|
929
1022
|
content = self.build_rst_list_table(rows)
|
|
930
1023
|
else:
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
for
|
|
934
|
-
line
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1024
|
+
raw = [lines[i].strip() for i in range(cnt)]
|
|
1025
|
+
cmdpat = r'(?:[*\d][\d* ]*\s+)?{}(\s|$)'.format(re.escape(self.DOCS['DOCNAM']))
|
|
1026
|
+
if raw and all(re.match(cmdpat, r) for r in raw):
|
|
1027
|
+
# Command line(s) following a label (e.g. a Quick Start entry):
|
|
1028
|
+
# render as a literal block instead of a (degenerate) table.
|
|
1029
|
+
content = ".. code-block:: none\n\n"
|
|
1030
|
+
for r in raw:
|
|
1031
|
+
content += " " + r + "\n"
|
|
1032
|
+
content += "\n"
|
|
1033
|
+
else:
|
|
1034
|
+
# multi-column table split on 2+ spaces
|
|
1035
|
+
rows = []
|
|
1036
|
+
for i in range(cnt):
|
|
1037
|
+
line = lines[i].strip()
|
|
1038
|
+
vals = re.split(r'\s{2,}', self.replace_option_link(line, secid, 1))
|
|
1039
|
+
rows.append(vals)
|
|
1040
|
+
content = self.build_rst_simple_table(rows) + "\n"
|
|
938
1041
|
|
|
939
1042
|
return content
|
|
940
1043
|
|
|
@@ -1046,10 +1149,10 @@ class PgRST(PgFile, PgUtil):
|
|
|
1046
1149
|
p (str): Option name to look up (short, long, or alias).
|
|
1047
1150
|
|
|
1048
1151
|
Returns:
|
|
1049
|
-
str: Canonical two-letter option short name
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1152
|
+
str | None: Canonical two-letter option short name, or ``None`` when
|
|
1153
|
+
*p* does not name an option of this document (e.g. an option of a
|
|
1154
|
+
different program referenced in prose). Callers skip such tokens
|
|
1155
|
+
so unrelated option-like text is left untouched.
|
|
1053
1156
|
"""
|
|
1054
1157
|
plen = len(p)
|
|
1055
1158
|
if plen == 2 and p in self.options: return p
|
|
@@ -1061,7 +1164,7 @@ class PgRST(PgFile, PgUtil):
|
|
|
1061
1164
|
for alias in self.ALIAS[opt]:
|
|
1062
1165
|
if re.match(r'^{}$'.format(alias), p, re.I): return opt
|
|
1063
1166
|
|
|
1064
|
-
|
|
1167
|
+
return None
|
|
1065
1168
|
|
|
1066
1169
|
#
|
|
1067
1170
|
# replace with rst link for a given section title
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
################################################################################
|
|
2
|
+
#
|
|
3
|
+
# Title : appendix_rst.temp
|
|
4
|
+
# Author : Zaihua Ji, zji@ucar.edu
|
|
5
|
+
# Date : 03/17/2026
|
|
6
|
+
# Purpose : template file for help document appendixA.rst (reStructuredText)
|
|
7
|
+
# Github : https://github.com/NCAR/rda-python-mics.git
|
|
8
|
+
#
|
|
9
|
+
################################################################################
|
|
10
|
+
|
|
11
|
+
.. _appendixA:
|
|
12
|
+
|
|
13
|
+
============================
|
|
14
|
+
Appendix A: List of Examples
|
|
15
|
+
============================
|
|
16
|
+
|
|
17
|
+
__CONTENT__
|
|
18
|
+
|
|
19
|
+
| :ref:`Back to Table of Contents <index>`
|
|
@@ -48,6 +48,7 @@ src/rda_python_miscs.egg-info/dependency_links.txt
|
|
|
48
48
|
src/rda_python_miscs.egg-info/entry_points.txt
|
|
49
49
|
src/rda_python_miscs.egg-info/requires.txt
|
|
50
50
|
src/rda_python_miscs.egg-info/top_level.txt
|
|
51
|
+
src/rda_python_miscs/rst_templates/appendix.rst.temp
|
|
51
52
|
src/rda_python_miscs/rst_templates/index.rst.temp
|
|
52
53
|
src/rda_python_miscs/rst_templates/section.rst.temp
|
|
53
54
|
tests/test_miscs.py
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
Copy files and directories to a target location. Source and target may each
|
|
3
|
-
reside on the local host, a remote host, an Object Store bucket, or a Globus
|
|
4
|
-
endpoint. Target files are owned by 'gdexdata' and created with configurable
|
|
5
|
-
permission modes.
|
|
6
|
-
|
|
7
|
-
Usage: gdexcp [-f] FromDirectories/Files [-t ToDirectory/FileName] \
|
|
8
|
-
[-fh FromHostName] [-th ToHostName] \
|
|
9
|
-
[-fb FromBucket] [-tb ToBucket] \
|
|
10
|
-
[-fp FromGlobusEndpoint] [-tp ToGlobusEndpoint] \
|
|
11
|
-
[-F FileMode] [-D DirectoryMode] [-r] [-R RecursiveLevel] [-h]
|
|
12
|
-
|
|
13
|
-
- Option -f, source directories and/or files to copy. This is the
|
|
14
|
-
default option, so paths may be given without the -f flag.
|
|
15
|
-
Shell wildcards are supported. Use './' or '*' to copy everything
|
|
16
|
-
in the current directory. Source paths must be readable by user
|
|
17
|
-
'gdexdata'; gdexcp will attempt to fix the mode if they are not;
|
|
18
|
-
|
|
19
|
-
- Option -t, target directory or file name. Defaults to '.' (current
|
|
20
|
-
directory). Multiple source files cannot be copied to a single
|
|
21
|
-
target file name. A trailing '/' on the target path treats it as
|
|
22
|
-
a directory;
|
|
23
|
-
|
|
24
|
-
- Option -fh, host name where the source files reside.
|
|
25
|
-
Defaults to the local host;
|
|
26
|
-
|
|
27
|
-
- Option -th, host name where the target files should be written.
|
|
28
|
-
Defaults to the local host;
|
|
29
|
-
|
|
30
|
-
- Option -fb, Object Store bucket name for the source files;
|
|
31
|
-
|
|
32
|
-
- Option -tb, Object Store bucket name for the target files;
|
|
33
|
-
|
|
34
|
-
- Option -fp, Globus endpoint for the source files;
|
|
35
|
-
|
|
36
|
-
- Option -tp, Globus endpoint for the target files;
|
|
37
|
-
|
|
38
|
-
- Option -F, permission mode for target files in octal notation.
|
|
39
|
-
Defaults to 664;
|
|
40
|
-
|
|
41
|
-
- Option -D, permission mode for target directories in octal notation.
|
|
42
|
-
Defaults to 775;
|
|
43
|
-
|
|
44
|
-
- Option -r, copy directories and files recursively (no depth limit);
|
|
45
|
-
|
|
46
|
-
- Option -R RecursiveLevel, copy recursively up to the specified depth.
|
|
47
|
-
-R 1 copies only the immediate contents of each source directory;
|
|
48
|
-
|
|
49
|
-
- Option -h, display this help document;
|
|
50
|
-
|
|
51
|
-
This utility can be run from any directory. Usage is displayed if no source
|
|
52
|
-
files are provided. A trailing '/' on a source directory path copies the
|
|
53
|
-
contents of that directory rather than the directory entry itself.
|
|
54
|
-
|
|
55
|
-
Examples:
|
|
56
|
-
|
|
57
|
-
1. Copy all files and subdirectories under the current directory to a
|
|
58
|
-
remote host:
|
|
59
|
-
|
|
60
|
-
gdexcp -r -f * -t /PathTo/d277006/ -th castle
|
|
61
|
-
|
|
62
|
-
2. Copy the contents of a specific local directory to a remote location
|
|
63
|
-
(trailing '/' on source omits the directory entry itself):
|
|
64
|
-
|
|
65
|
-
gdexcp -r -f /PathTo/DirectoryName/ -t /PathTo/d277006/ -th castle
|
|
66
|
-
|
|
67
|
-
Without the trailing '/', DirectoryName itself is also copied:
|
|
68
|
-
|
|
69
|
-
gdexcp -r -f /PathTo/DirectoryName -t /PathTo/d277006/ -th castle
|
|
70
|
-
|
|
71
|
-
3. Copy a single file to an Object Store bucket:
|
|
72
|
-
|
|
73
|
-
gdexcp -f /PathTo/myfile.nc -tb my-bucket -t myfile.nc
|
|
74
|
-
|
|
75
|
-
4. Copy files from a remote host to the local current directory:
|
|
76
|
-
|
|
77
|
-
gdexcp -fh castle -f /PathTo/d277006/myfile.nc
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs/rst_templates/index.rst.temp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs.egg-info/requires.txt
RENAMED
|
File without changes
|
{rda_python_miscs-3.0.2 → rda_python_miscs-3.0.4}/src/rda_python_miscs.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|