rda-python-miscs 3.0.7__tar.gz → 3.0.9__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.
Files changed (63) hide show
  1. {rda_python_miscs-3.0.7/src/rda_python_miscs.egg-info → rda_python_miscs-3.0.9}/PKG-INFO +7 -1
  2. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/README.md +6 -0
  3. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/pyproject.toml +1 -1
  4. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexcp.py +43 -8
  5. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexcp.usg +8 -4
  6. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexdrop.py +30 -0
  7. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexdrop.usg +10 -1
  8. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9/src/rda_python_miscs.egg-info}/PKG-INFO +7 -1
  9. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/LICENSE +0 -0
  10. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/MANIFEST.in +0 -0
  11. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/setup.cfg +0 -0
  12. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/__init__.py +0 -0
  13. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/bash_qsub.py +0 -0
  14. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/bashqsub.py +0 -0
  15. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/bashqsub.usg +0 -0
  16. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/decsdata_restore.py +0 -0
  17. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/decsdata_restore.usg +0 -0
  18. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/decsdata_storage.py +0 -0
  19. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/decsdata_storage.usg +0 -0
  20. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdex_ls.py +0 -0
  21. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexdrop_standalone.py +0 -0
  22. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexkill.py +0 -0
  23. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexkill.usg +0 -0
  24. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexls.py +0 -0
  25. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexls.usg +0 -0
  26. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexls_standalone.py +0 -0
  27. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexmod.py +0 -0
  28. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexmod.usg +0 -0
  29. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexown.py +0 -0
  30. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexown.usg +0 -0
  31. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexps.py +0 -0
  32. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexps.usg +0 -0
  33. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexsub.py +0 -0
  34. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexsub.usg +0 -0
  35. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexzip.py +0 -0
  36. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/gdexzip.usg +0 -0
  37. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/pg_docs.py +0 -0
  38. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/pg_rst.py +0 -0
  39. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/pg_rst.usg +0 -0
  40. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/pg_wget.py +0 -0
  41. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/pgwget.py +0 -0
  42. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/pgwget.usg +0 -0
  43. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rda_cp.py +0 -0
  44. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rda_kill.py +0 -0
  45. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rda_mod.py +0 -0
  46. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rda_own.py +0 -0
  47. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rda_ps.py +0 -0
  48. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rda_sub.py +0 -0
  49. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rda_zip.py +0 -0
  50. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rdals.py +0 -0
  51. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rdals.usg +0 -0
  52. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rst_templates/appendix.rst.temp +0 -0
  53. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rst_templates/index.rst.temp +0 -0
  54. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/rst_templates/section.rst.temp +0 -0
  55. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/tcsh_qsub.py +0 -0
  56. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/tcshqsub.py +0 -0
  57. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs/tcshqsub.usg +0 -0
  58. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs.egg-info/SOURCES.txt +0 -0
  59. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs.egg-info/dependency_links.txt +0 -0
  60. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs.egg-info/entry_points.txt +0 -0
  61. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs.egg-info/requires.txt +0 -0
  62. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/src/rda_python_miscs.egg-info/top_level.txt +0 -0
  63. {rda_python_miscs-3.0.7 → rda_python_miscs-3.0.9}/tests/test_miscs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_miscs
3
- Version: 3.0.7
3
+ Version: 3.0.9
4
4
  Summary: RDA Python package to hold RDA miscellaneous utility programs
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-miscs
@@ -172,6 +172,12 @@ deliberately narrow alternative to `gdexcp`: the destination is always
172
172
  directory is rejected, and every source must be readable by the calling user
173
173
  rather than only by `gdexdata`.
174
174
 
175
+ An absolute `-t` under `/tmp/` names any sub-path of `/tmp` instead of a sub-path
176
+ of the dataset directory, so that a drop can be tried out without touching the
177
+ dataset tree. The dataset of `-ds` is still checked against the access list, and
178
+ because `/tmp` is world writable — unlike a dataset directory — the part of the
179
+ path that already exists must belong to the calling user or to `gdexdata`.
180
+
175
181
  Everything dropped, including sub-directories created for `-t`, is also set to the
176
182
  GDEX group `PGLOG['GDEXGRP']`. The setuid wrapper switches only the user to
177
183
  `gdexdata`, not the group, so without that step a dropped file would stay in the
@@ -155,6 +155,12 @@ deliberately narrow alternative to `gdexcp`: the destination is always
155
155
  directory is rejected, and every source must be readable by the calling user
156
156
  rather than only by `gdexdata`.
157
157
 
158
+ An absolute `-t` under `/tmp/` names any sub-path of `/tmp` instead of a sub-path
159
+ of the dataset directory, so that a drop can be tried out without touching the
160
+ dataset tree. The dataset of `-ds` is still checked against the access list, and
161
+ because `/tmp` is world writable — unlike a dataset directory — the part of the
162
+ path that already exists must belong to the calling user or to `gdexdata`.
163
+
158
164
  Everything dropped, including sub-directories created for `-t`, is also set to the
159
165
  GDEX group `PGLOG['GDEXGRP']`. The setuid wrapper switches only the user to
160
166
  `gdexdata`, not the group, so without that step a dropped file would stay in the
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "rda_python_miscs"
9
- version = "3.0.7"
9
+ version = "3.0.9"
10
10
  authors = [
11
11
  { name="Zaihua Ji", email="zji@ucar.edu" },
12
12
  ]
@@ -135,6 +135,28 @@ class GdexCp(PgFile):
135
135
  self.dssdb_dbname()
136
136
  self.validate_decs_group('gdexcp', self.PGLOG['CURUID'], 1)
137
137
  if not self.RDACP['R'] and self.RDACP['r']: self.RDACP['R'] = 1000
138
+ # a bucket implies the Object Store host, so -tb/-fb need no -th/-fh
139
+ if self.RDACP['fb']:
140
+ self.PGLOG['OBJCTBKT'] = self.RDACP['fb']
141
+ if not self.RDACP['fh']:
142
+ self.RDACP['fh'] = self.OHOST
143
+ self.CINFO['fhost'] = self.OHOST + '-'
144
+ if self.RDACP['tb']:
145
+ if not self.RDACP['fb']: self.PGLOG['OBJCTBKT'] = self.RDACP['tb']
146
+ if not self.RDACP['th']:
147
+ self.RDACP['th'] = self.OHOST
148
+ self.CINFO['thost'] = self.OHOST + '-'
149
+ # a Globus endpoint implies its host, so -tp/-fp need no -th/-fh
150
+ if self.RDACP['fp']:
151
+ self.PGLOG['BACKUPEP'] = self.RDACP['fp']
152
+ if not self.RDACP['fh']:
153
+ self.RDACP['fh'] = self.endpoint_host(self.RDACP['fp'])
154
+ if self.RDACP['fh']: self.CINFO['fhost'] = self.RDACP['fh'] + '-'
155
+ if self.RDACP['tp']:
156
+ if not self.RDACP['fp']: self.PGLOG['BACKUPEP'] = self.RDACP['tp']
157
+ if not self.RDACP['th']:
158
+ self.RDACP['th'] = self.endpoint_host(self.RDACP['tp'])
159
+ if self.RDACP['th']: self.CINFO['thost'] = self.RDACP['th'] + '-'
138
160
  if not self.RDACP['t']:
139
161
  self.CINFO['tpath'] = self.RDACP['t'] = "."
140
162
  else:
@@ -151,14 +173,6 @@ class GdexCp(PgFile):
151
173
  self.pglog("{}{}: Cannot copy multiple files to a single file".format(self.CINFO['thost'], self.RDACP['t']), self.LGEREX)
152
174
  if self.RDACP['th'] and self.RDACP['fh'] and self.RDACP['th'] == self.RDACP['fh'] and self.RDACP['fh'] != 'HPSS':
153
175
  self.pglog(self.RDACP['fh'] + ": Cannot copy file onto the same host", self.LGEREX)
154
- if self.RDACP['fb']:
155
- self.PGLOG['OBJCTBKT'] = self.RDACP['fb']
156
- elif self.RDACP['tb']:
157
- self.PGLOG['OBJCTBKT'] = self.RDACP['tb']
158
- if self.RDACP['fp']:
159
- self.PGLOG['BACKUPEP'] = self.RDACP['fp']
160
- elif self.RDACP['tp']:
161
- self.PGLOG['BACKUPEP'] = self.RDACP['tp']
162
176
  if self.RDACP['o']:
163
177
  if not self.RDACP['fp']:
164
178
  self.pglog("-o: works only when source Globus endpoint -fp is provided", self.LGEREX)
@@ -185,6 +199,27 @@ class GdexCp(PgFile):
185
199
  self.pglog("{}: No File copied{}".format((self.CINFO['fpath'] if self.CINFO['fpath'] else self.CINFO['curdir']), hinfo), self.LOGWRN)
186
200
  self.cmdlog()
187
201
 
202
+ # get the host name a Globus endpoint is reached by
203
+ def endpoint_host(self, endpoint):
204
+ """Return the host name that copy_gdex_file() routes a Globus endpoint through.
205
+
206
+ Known endpoints map through QHOSTS: 'gdex-quasar' to the Quasar backup host,
207
+ 'gdex-quasar-drdata' to the DRDATA host, and 'gdex-glade' to the local host
208
+ (returned as None, the default). Any other endpoint is routed as the Quasar
209
+ backup host with QPOINTS['B'] pointed at it.
210
+
211
+ Args:
212
+ endpoint (str): Globus endpoint name from -fp or -tp.
213
+
214
+ Returns:
215
+ str | None: Host name for -fh/-th, or None for the local host.
216
+ """
217
+ host = self.QHOSTS.get(endpoint)
218
+ if host is None:
219
+ self.QPOINTS['B'] = endpoint
220
+ host = self.BHOST
221
+ return (None if host == self.LHOST else host)
222
+
188
223
  # copy the top level list
189
224
  def copy_top_list(self, files):
190
225
  """Iterate the top-level source paths and initiate copies or recursive traversal.
@@ -44,10 +44,14 @@
44
44
 
45
45
  -fh FromHostName host name where the source files reside.
46
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.
47
+ -fb FromBucket Object Store bucket name for the source files; implies
48
+ the Object Store as the source host (no -fh needed).
49
+ -tb ToBucket Object Store bucket name for the target files; implies
50
+ the Object Store as the target host (no -th needed).
51
+ -fp FromGlobusEndpoint Globus endpoint for the source files; implies the
52
+ endpoint's host as the source (no -fh needed).
53
+ -tp ToGlobusEndpoint Globus endpoint for the target files; implies the
54
+ endpoint's host as the target (no -th needed).
51
55
 
52
56
 
53
57
  COPY BEHAVIOR
@@ -24,6 +24,7 @@ DROPROOT = "/glade/campaign/collections/gdex/data" # dataset data root path
24
24
  DROPCONF = "/glade/u/home/gdexdata/config/gdexdrop.conf" # access list
25
25
  DROPLOG = "/glade/u/home/gdexdata/dssdb/log" # log path
26
26
  DROPUSER = "gdexdata" # owner of dropped files
27
+ DROPTMP = "/tmp" # alternate root, for testing
27
28
 
28
29
  class GdexDrop(PgFile):
29
30
  """Copy local files and directories into a GDEX dataset directory as 'gdexdata'.
@@ -187,18 +188,47 @@ class GdexDrop(PgFile):
187
188
  real path of the dataset directory, so that neither a '..' component in -t
188
189
  nor an existing symbolic link can move the drop outside the dataset.
189
190
 
191
+ An absolute -t under DROPTMP names any sub-path of that directory instead,
192
+ for trying a drop out without touching the dataset tree. The dataset of
193
+ -ds is still validated against the access list.
194
+
190
195
  Returns:
191
196
  str: Resolved absolute target directory.
192
197
  """
193
198
  dsid = self.DROP['ds']
194
199
  if not re.match(r'^[a-z]\d{6}$', dsid):
195
200
  self.pglog(dsid + ": Invalid Dataset ID of -ds, expecting the form d123456", self.LGEREX)
201
+ if self.DROP['t'] and re.match(r'^{}/'.format(DROPTMP), self.DROP['t']):
202
+ return self.tmp_target()
196
203
  dsroot = op.realpath(op.join(DROPROOT, dsid))
197
204
  if not op.isdir(dsroot):
198
205
  self.pglog("{}: Dataset directory NOT exists under {}".format(dsid, DROPROOT), self.LGEREX)
199
206
  target = self.confine_path(op.join(dsroot, self.DROP['t']) if self.DROP['t'] else dsroot, dsroot)
200
207
  return target
201
208
 
209
+ # resolve a target of -t that names a sub-path of DROPTMP
210
+ def tmp_target(self):
211
+ """Return the resolved -t path under DROPTMP, exiting if it may not be used.
212
+
213
+ DROPTMP is world writable, unlike a dataset directory, so a path there can
214
+ be replaced by another user between this check and the copy, and may well
215
+ belong to somebody else already. The existing part of the path is therefore
216
+ required to belong to the caller or to DROPUSER, so that a drop cannot be
217
+ aimed at a directory a third user controls.
218
+
219
+ Returns:
220
+ str: Resolved absolute target directory under DROPTMP.
221
+ """
222
+ tmproot = op.realpath(DROPTMP)
223
+ target = self.confine_path(self.DROP['t'], tmproot)
224
+ dir = target
225
+ while not op.isdir(dir): dir = op.dirname(dir)
226
+ if dir == tmproot: return target # nothing of the path exists yet
227
+ info = self.check_local_file(dir, 2, self.LOGWRN)
228
+ if info and info['logname'] not in (self.PGLOG['CURUID'], DROPUSER):
229
+ self.pglog("{}: Target path under {} is owned by {}".format(dir, DROPTMP, info['logname']), self.LGEREX)
230
+ return target
231
+
202
232
  # make sure a path stays inside the dataset directory
203
233
  def confine_path(self, path, dsroot):
204
234
  """Return the resolved path, exiting if it falls outside the dataset directory.
@@ -17,7 +17,12 @@
17
17
  files into. Missing sub-directories are created. The path must stay
18
18
  inside the dataset directory; '..' components and symbolic links
19
19
  leading out of it are rejected. Defaults to the dataset directory
20
- itself;
20
+ itself.
21
+ An absolute path under /tmp/ names any sub-path of /tmp instead, for
22
+ trying a drop out without touching the dataset tree. The dataset of
23
+ -ds is still checked against the access list, and because /tmp is
24
+ world writable, the existing part of the path must belong to the
25
+ calling user or to 'gdexdata';
21
26
 
22
27
  - Option -f File/Directory List is the default option, so the source paths
23
28
  may be given without it and in any position. Relative paths are
@@ -77,3 +82,7 @@
77
82
  4. Drop a long list of files named in a file, with group-writable modes:
78
83
 
79
84
  gdexdrop -ds d123456 -i filelist.txt -F 664 -D 775
85
+
86
+ 5. Try a drop out under /tmp, leaving the dataset directory alone:
87
+
88
+ gdexdrop -ds d123456 -t /tmp/mydrop hourly.2026*.nc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_miscs
3
- Version: 3.0.7
3
+ Version: 3.0.9
4
4
  Summary: RDA Python package to hold RDA miscellaneous utility programs
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-miscs
@@ -172,6 +172,12 @@ deliberately narrow alternative to `gdexcp`: the destination is always
172
172
  directory is rejected, and every source must be readable by the calling user
173
173
  rather than only by `gdexdata`.
174
174
 
175
+ An absolute `-t` under `/tmp/` names any sub-path of `/tmp` instead of a sub-path
176
+ of the dataset directory, so that a drop can be tried out without touching the
177
+ dataset tree. The dataset of `-ds` is still checked against the access list, and
178
+ because `/tmp` is world writable — unlike a dataset directory — the part of the
179
+ path that already exists must belong to the calling user or to `gdexdata`.
180
+
175
181
  Everything dropped, including sub-directories created for `-t`, is also set to the
176
182
  GDEX group `PGLOG['GDEXGRP']`. The setuid wrapper switches only the user to
177
183
  `gdexdata`, not the group, so without that step a dropped file would stay in the