vortex-nwp 2.0.0b1__py3-none-any.whl → 2.0.0b2__py3-none-any.whl
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.
- vortex/__init__.py +59 -45
- vortex/algo/__init__.py +3 -2
- vortex/algo/components.py +940 -614
- vortex/algo/mpitools.py +802 -497
- vortex/algo/serversynctools.py +34 -33
- vortex/config.py +19 -22
- vortex/data/__init__.py +9 -3
- vortex/data/abstractstores.py +593 -655
- vortex/data/containers.py +217 -162
- vortex/data/contents.py +65 -39
- vortex/data/executables.py +93 -102
- vortex/data/flow.py +40 -34
- vortex/data/geometries.py +228 -132
- vortex/data/handlers.py +428 -225
- vortex/data/outflow.py +15 -15
- vortex/data/providers.py +185 -163
- vortex/data/resources.py +48 -42
- vortex/data/stores.py +544 -413
- vortex/gloves.py +114 -87
- vortex/layout/__init__.py +1 -8
- vortex/layout/contexts.py +150 -84
- vortex/layout/dataflow.py +353 -202
- vortex/layout/monitor.py +264 -128
- vortex/nwp/__init__.py +5 -2
- vortex/nwp/algo/__init__.py +14 -5
- vortex/nwp/algo/assim.py +205 -151
- vortex/nwp/algo/clim.py +683 -517
- vortex/nwp/algo/coupling.py +447 -225
- vortex/nwp/algo/eda.py +437 -229
- vortex/nwp/algo/eps.py +403 -231
- vortex/nwp/algo/forecasts.py +420 -271
- vortex/nwp/algo/fpserver.py +683 -307
- vortex/nwp/algo/ifsnaming.py +205 -145
- vortex/nwp/algo/ifsroot.py +210 -122
- vortex/nwp/algo/monitoring.py +132 -76
- vortex/nwp/algo/mpitools.py +321 -191
- vortex/nwp/algo/odbtools.py +617 -353
- vortex/nwp/algo/oopsroot.py +449 -273
- vortex/nwp/algo/oopstests.py +90 -56
- vortex/nwp/algo/request.py +287 -206
- vortex/nwp/algo/stdpost.py +878 -522
- vortex/nwp/data/__init__.py +22 -4
- vortex/nwp/data/assim.py +125 -137
- vortex/nwp/data/boundaries.py +121 -68
- vortex/nwp/data/climfiles.py +193 -211
- vortex/nwp/data/configfiles.py +73 -69
- vortex/nwp/data/consts.py +426 -401
- vortex/nwp/data/ctpini.py +59 -43
- vortex/nwp/data/diagnostics.py +94 -66
- vortex/nwp/data/eda.py +50 -51
- vortex/nwp/data/eps.py +195 -146
- vortex/nwp/data/executables.py +440 -434
- vortex/nwp/data/fields.py +63 -48
- vortex/nwp/data/gridfiles.py +183 -111
- vortex/nwp/data/logs.py +250 -217
- vortex/nwp/data/modelstates.py +180 -151
- vortex/nwp/data/monitoring.py +72 -99
- vortex/nwp/data/namelists.py +254 -202
- vortex/nwp/data/obs.py +400 -308
- vortex/nwp/data/oopsexec.py +22 -20
- vortex/nwp/data/providers.py +90 -65
- vortex/nwp/data/query.py +71 -82
- vortex/nwp/data/stores.py +49 -36
- vortex/nwp/data/surfex.py +136 -137
- vortex/nwp/syntax/__init__.py +1 -1
- vortex/nwp/syntax/stdattrs.py +173 -111
- vortex/nwp/tools/__init__.py +2 -2
- vortex/nwp/tools/addons.py +22 -17
- vortex/nwp/tools/agt.py +24 -12
- vortex/nwp/tools/bdap.py +16 -5
- vortex/nwp/tools/bdcp.py +4 -1
- vortex/nwp/tools/bdm.py +3 -0
- vortex/nwp/tools/bdmp.py +14 -9
- vortex/nwp/tools/conftools.py +728 -378
- vortex/nwp/tools/drhook.py +12 -8
- vortex/nwp/tools/grib.py +65 -39
- vortex/nwp/tools/gribdiff.py +22 -17
- vortex/nwp/tools/ifstools.py +82 -42
- vortex/nwp/tools/igastuff.py +167 -143
- vortex/nwp/tools/mars.py +14 -2
- vortex/nwp/tools/odb.py +234 -125
- vortex/nwp/tools/partitioning.py +61 -37
- vortex/nwp/tools/satrad.py +27 -12
- vortex/nwp/util/async.py +83 -55
- vortex/nwp/util/beacon.py +10 -10
- vortex/nwp/util/diffpygram.py +174 -86
- vortex/nwp/util/ens.py +144 -63
- vortex/nwp/util/hooks.py +30 -19
- vortex/nwp/util/taskdeco.py +28 -24
- vortex/nwp/util/usepygram.py +278 -172
- vortex/nwp/util/usetnt.py +31 -17
- vortex/sessions.py +72 -39
- vortex/syntax/__init__.py +1 -1
- vortex/syntax/stdattrs.py +410 -171
- vortex/syntax/stddeco.py +31 -22
- vortex/toolbox.py +327 -192
- vortex/tools/__init__.py +11 -2
- vortex/tools/actions.py +125 -59
- vortex/tools/addons.py +111 -92
- vortex/tools/arm.py +42 -22
- vortex/tools/compression.py +72 -69
- vortex/tools/date.py +11 -4
- vortex/tools/delayedactions.py +242 -132
- vortex/tools/env.py +75 -47
- vortex/tools/folder.py +342 -171
- vortex/tools/grib.py +311 -149
- vortex/tools/lfi.py +423 -216
- vortex/tools/listings.py +109 -40
- vortex/tools/names.py +218 -156
- vortex/tools/net.py +632 -298
- vortex/tools/parallelism.py +93 -61
- vortex/tools/prestaging.py +55 -31
- vortex/tools/schedulers.py +172 -105
- vortex/tools/services.py +402 -333
- vortex/tools/storage.py +293 -358
- vortex/tools/surfex.py +24 -24
- vortex/tools/systems.py +1211 -631
- vortex/tools/targets.py +156 -100
- vortex/util/__init__.py +1 -1
- vortex/util/config.py +377 -327
- vortex/util/empty.py +2 -2
- vortex/util/helpers.py +56 -24
- vortex/util/introspection.py +18 -12
- vortex/util/iosponge.py +8 -4
- vortex/util/roles.py +4 -6
- vortex/util/storefunctions.py +39 -13
- vortex/util/structs.py +3 -3
- vortex/util/worker.py +29 -17
- vortex_nwp-2.0.0b2.dist-info/METADATA +66 -0
- vortex_nwp-2.0.0b2.dist-info/RECORD +142 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/WHEEL +1 -1
- vortex/layout/appconf.py +0 -109
- vortex/layout/jobs.py +0 -1276
- vortex/layout/nodes.py +0 -1424
- vortex/layout/subjobs.py +0 -464
- vortex_nwp-2.0.0b1.dist-info/METADATA +0 -50
- vortex_nwp-2.0.0b1.dist-info/RECORD +0 -146
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/LICENSE +0 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/top_level.txt +0 -0
vortex/tools/folder.py
CHANGED
|
@@ -19,23 +19,38 @@ __all__ = []
|
|
|
19
19
|
|
|
20
20
|
logger = loggers.getLogger(__name__)
|
|
21
21
|
|
|
22
|
-
_folder_exposed_methods = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
_folder_exposed_methods = {
|
|
23
|
+
"cp",
|
|
24
|
+
"mv",
|
|
25
|
+
"forcepack",
|
|
26
|
+
"forceunpack",
|
|
27
|
+
"anyft_remote_rewrite",
|
|
28
|
+
"ftget",
|
|
29
|
+
"rawftget",
|
|
30
|
+
"batchrawftget",
|
|
31
|
+
"ftput",
|
|
32
|
+
"rawftput",
|
|
33
|
+
"scpget",
|
|
34
|
+
"scpput",
|
|
35
|
+
"ecfsget",
|
|
36
|
+
"ecfsput",
|
|
37
|
+
"ectransget",
|
|
38
|
+
"ectransput",
|
|
39
|
+
}
|
|
27
40
|
|
|
28
41
|
|
|
29
42
|
def folderize(cls):
|
|
30
43
|
"""Create the necessary methods in a class that inherits from :class:`FolderShell`."""
|
|
31
|
-
addon_kind = cls.footprint_retrieve().get_values(
|
|
44
|
+
addon_kind = cls.footprint_retrieve().get_values("kind")
|
|
32
45
|
if len(addon_kind) != 1:
|
|
33
|
-
raise SyntaxError(
|
|
46
|
+
raise SyntaxError(
|
|
47
|
+
"Authorised values for a given Addon's kind must be unique"
|
|
48
|
+
)
|
|
34
49
|
addon_kind = addon_kind[0]
|
|
35
50
|
for basic_mtdname in _folder_exposed_methods:
|
|
36
|
-
expected_mtdname =
|
|
51
|
+
expected_mtdname = "{:s}_{:s}".format(addon_kind, basic_mtdname)
|
|
37
52
|
if not hasattr(cls, expected_mtdname):
|
|
38
|
-
parent_mtd = getattr(cls,
|
|
53
|
+
parent_mtd = getattr(cls, "_folder_{:s}".format(basic_mtdname))
|
|
39
54
|
setattr(cls, expected_mtdname, parent_mtd)
|
|
40
55
|
return cls
|
|
41
56
|
|
|
@@ -45,41 +60,53 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
45
60
|
This abstract class defines methods to manipulate folders.
|
|
46
61
|
"""
|
|
47
62
|
|
|
48
|
-
_COMPRESSED =
|
|
63
|
+
_COMPRESSED = "gz"
|
|
49
64
|
|
|
50
65
|
_abstract = True
|
|
51
66
|
_footprint = dict(
|
|
52
|
-
info
|
|
53
|
-
attr
|
|
54
|
-
kind
|
|
55
|
-
values
|
|
67
|
+
info="Tools for manipulating folders",
|
|
68
|
+
attr=dict(
|
|
69
|
+
kind=dict(
|
|
70
|
+
values=["folder"],
|
|
56
71
|
),
|
|
57
|
-
tmpname
|
|
58
|
-
optional
|
|
59
|
-
default
|
|
72
|
+
tmpname=dict(
|
|
73
|
+
optional=True,
|
|
74
|
+
default="folder_tmpunpack",
|
|
60
75
|
),
|
|
61
|
-
pipeget
|
|
62
|
-
type
|
|
63
|
-
optional
|
|
64
|
-
default
|
|
76
|
+
pipeget=dict(
|
|
77
|
+
type=bool,
|
|
78
|
+
optional=True,
|
|
79
|
+
default=False,
|
|
65
80
|
),
|
|
66
|
-
supportedfmt
|
|
67
|
-
optional
|
|
68
|
-
default
|
|
81
|
+
supportedfmt=dict(
|
|
82
|
+
optional=True,
|
|
83
|
+
default="[kind]",
|
|
69
84
|
),
|
|
70
|
-
)
|
|
85
|
+
),
|
|
71
86
|
)
|
|
72
87
|
|
|
73
|
-
def _folder_cp(
|
|
74
|
-
|
|
88
|
+
def _folder_cp(
|
|
89
|
+
self,
|
|
90
|
+
source,
|
|
91
|
+
destination,
|
|
92
|
+
smartcp_threshold=0,
|
|
93
|
+
intent="in",
|
|
94
|
+
silent=False,
|
|
95
|
+
):
|
|
75
96
|
"""Extended copy for a folder repository."""
|
|
76
97
|
rc, source, destination = self._folder_tarfix_out(source, destination)
|
|
77
|
-
rc = rc and self.sh.cp(
|
|
78
|
-
|
|
98
|
+
rc = rc and self.sh.cp(
|
|
99
|
+
source,
|
|
100
|
+
destination,
|
|
101
|
+
smartcp_threshold=smartcp_threshold,
|
|
102
|
+
intent=intent,
|
|
103
|
+
)
|
|
79
104
|
if rc:
|
|
80
|
-
rc, source, destination = self._folder_tarfix_in(
|
|
81
|
-
|
|
82
|
-
|
|
105
|
+
rc, source, destination = self._folder_tarfix_in(
|
|
106
|
+
source, destination
|
|
107
|
+
)
|
|
108
|
+
if rc and intent == "inout":
|
|
109
|
+
self.sh.stderr("chmod", 0o644, destination)
|
|
83
110
|
with self.sh.mute_stderr():
|
|
84
111
|
for infile in self.sh.ffind(destination):
|
|
85
112
|
self.sh.chmod(infile, 0o644)
|
|
@@ -92,18 +119,27 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
92
119
|
if isinstance(source, str):
|
|
93
120
|
rc = rc and self.sh.remove(source)
|
|
94
121
|
else:
|
|
95
|
-
rc, source, destination = self._folder_tarfix_out(
|
|
122
|
+
rc, source, destination = self._folder_tarfix_out(
|
|
123
|
+
source, destination
|
|
124
|
+
)
|
|
96
125
|
rc = rc and self.sh.move(source, destination)
|
|
97
126
|
if rc:
|
|
98
|
-
rc, source, destination = self._folder_tarfix_in(
|
|
127
|
+
rc, source, destination = self._folder_tarfix_in(
|
|
128
|
+
source, destination
|
|
129
|
+
)
|
|
99
130
|
return rc
|
|
100
131
|
|
|
101
132
|
def _folder_forcepack(self, source, destination=None):
|
|
102
133
|
"""Returned a path to a packed data."""
|
|
103
134
|
if not self.sh.is_tarname(source):
|
|
104
|
-
destination = (
|
|
105
|
-
|
|
106
|
-
|
|
135
|
+
destination = (
|
|
136
|
+
destination
|
|
137
|
+
if destination
|
|
138
|
+
else "{:s}.{:s}".format(
|
|
139
|
+
self.sh.safe_fileaddsuffix(source),
|
|
140
|
+
self._folder_tarfix_extension,
|
|
141
|
+
)
|
|
142
|
+
)
|
|
107
143
|
if not self.sh.path.exists(destination):
|
|
108
144
|
absdestination = self.sh.path.abspath(destination)
|
|
109
145
|
with self.sh.cdcontext(self.sh.path.dirname(source)):
|
|
@@ -114,24 +150,33 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
114
150
|
|
|
115
151
|
def _folder_forceunpack(self, source):
|
|
116
152
|
"""Unpack the data "inplace"."""
|
|
117
|
-
fakesource =
|
|
118
|
-
|
|
153
|
+
fakesource = "{:s}.{:s}".format(
|
|
154
|
+
self.sh.safe_fileaddsuffix(source), self._folder_tarfix_extension
|
|
155
|
+
)
|
|
119
156
|
rc, _, _ = self._folder_tarfix_in(fakesource, source)
|
|
120
157
|
return rc
|
|
121
158
|
|
|
122
159
|
def _folder_pack_stream(self, source, stdout=True):
|
|
123
160
|
source_name = self.sh.path.basename(source)
|
|
124
161
|
source_dirname = self.sh.path.dirname(source)
|
|
125
|
-
compression_map = {
|
|
126
|
-
compression_opt = compression_map.get(self._COMPRESSED,
|
|
127
|
-
cmd = [
|
|
128
|
-
|
|
162
|
+
compression_map = {"gz": "z", "bz2": "j"}
|
|
163
|
+
compression_opt = compression_map.get(self._COMPRESSED, "")
|
|
164
|
+
cmd = [
|
|
165
|
+
"tar",
|
|
166
|
+
"--directory",
|
|
167
|
+
source_dirname,
|
|
168
|
+
"-c" + compression_opt,
|
|
169
|
+
source_name,
|
|
170
|
+
]
|
|
129
171
|
return self.sh.popen(cmd, stdout=stdout, bufsize=8192)
|
|
130
172
|
|
|
131
|
-
def _folder_unpack_stream(self, stdin=True, options=
|
|
173
|
+
def _folder_unpack_stream(self, stdin=True, options="xvf"):
|
|
132
174
|
return self.sh.popen(
|
|
133
175
|
# the z option is omitted consequently it also works if the file is not compressed
|
|
134
|
-
[
|
|
176
|
+
["tar", options, "-"],
|
|
177
|
+
stdin=stdin,
|
|
178
|
+
bufsize=8192,
|
|
179
|
+
)
|
|
135
180
|
|
|
136
181
|
def _packed_size(self, source):
|
|
137
182
|
"""Size of the final file, must be exact or be an overestimation.
|
|
@@ -150,17 +195,20 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
150
195
|
|
|
151
196
|
def _folder_preftget(self, source, destination):
|
|
152
197
|
"""Prepare source and destination"""
|
|
153
|
-
destination = self.sh.path.abspath(
|
|
198
|
+
destination = self.sh.path.abspath(
|
|
199
|
+
self.sh.path.expanduser(destination)
|
|
200
|
+
)
|
|
154
201
|
self.sh.rm(destination)
|
|
155
202
|
return source, destination
|
|
156
203
|
|
|
157
204
|
def _folder_postftget(self, destination):
|
|
158
205
|
"""Move the untared stuff to the destination and clean-up things."""
|
|
159
206
|
try:
|
|
160
|
-
unpacked = self.sh.glob(
|
|
207
|
+
unpacked = self.sh.glob("*")
|
|
161
208
|
if unpacked:
|
|
162
|
-
if
|
|
163
|
-
|
|
209
|
+
if len(unpacked) == 1 and self.sh.path.isdir(
|
|
210
|
+
self.sh.path.join(unpacked[-1])
|
|
211
|
+
):
|
|
164
212
|
# This is the most usual case... (ODB, DDH packs produced by Vortex)
|
|
165
213
|
self.sh.wpermtree(unpacked[-1], force=True)
|
|
166
214
|
if self.sh.path.isdir(unpacked[-1]):
|
|
@@ -174,17 +222,21 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
174
222
|
self.sh.mkdir(destination)
|
|
175
223
|
for item in unpacked:
|
|
176
224
|
self.sh.wpermtree(item, force=True)
|
|
177
|
-
self.sh.mv(
|
|
225
|
+
self.sh.mv(
|
|
226
|
+
item, self.sh.path.join(destination, item)
|
|
227
|
+
)
|
|
178
228
|
else:
|
|
179
|
-
logger.error(
|
|
229
|
+
logger.error("Nothing to unpack")
|
|
180
230
|
except Exception as trouble:
|
|
181
|
-
logger.critical(
|
|
231
|
+
logger.critical("Unable to proceed folder post-ftget step")
|
|
182
232
|
raise trouble
|
|
183
233
|
|
|
184
234
|
@contextlib.contextmanager
|
|
185
235
|
def _folder_postftget_context(self, destination):
|
|
186
236
|
"""Move the untared stuff to the destination and clean-up things."""
|
|
187
|
-
with self.sh.temporary_dir_cdcontext(
|
|
237
|
+
with self.sh.temporary_dir_cdcontext(
|
|
238
|
+
prefix="folder_", dir=self.sh.getcwd()
|
|
239
|
+
):
|
|
188
240
|
try:
|
|
189
241
|
yield
|
|
190
242
|
finally:
|
|
@@ -209,8 +261,11 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
209
261
|
|
|
210
262
|
@contextlib.contextmanager
|
|
211
263
|
def _folder_ftput_file_compress(self, source):
|
|
212
|
-
c_source = (
|
|
213
|
-
|
|
264
|
+
c_source = (
|
|
265
|
+
self.sh.safe_fileaddsuffix(source)
|
|
266
|
+
+ "."
|
|
267
|
+
+ self._folder_tarfix_extension
|
|
268
|
+
)
|
|
214
269
|
try:
|
|
215
270
|
self.sh.tar(c_source, source)
|
|
216
271
|
yield c_source
|
|
@@ -226,36 +281,54 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
226
281
|
def _folder_anyft_remote_rewrite(self, remote):
|
|
227
282
|
"""Add the folder suffix before using file transfert protocols."""
|
|
228
283
|
if not self.sh.is_tarname(self.sh.path.basename(remote)):
|
|
229
|
-
return
|
|
284
|
+
return "{:s}.{:s}".format(remote, self._folder_tarfix_extension)
|
|
230
285
|
else:
|
|
231
286
|
return remote
|
|
232
287
|
|
|
233
|
-
def _folder_ftget(
|
|
234
|
-
|
|
288
|
+
def _folder_ftget(
|
|
289
|
+
self,
|
|
290
|
+
source,
|
|
291
|
+
destination,
|
|
292
|
+
hostname=None,
|
|
293
|
+
logname=None,
|
|
294
|
+
port=DEFAULT_FTP_PORT,
|
|
295
|
+
cpipeline=None,
|
|
296
|
+
):
|
|
235
297
|
"""Proceed direct ftp get on the specified target."""
|
|
236
298
|
if cpipeline is not None:
|
|
237
299
|
raise OSError("It's not allowed to compress folder like data.")
|
|
238
300
|
hostname = self.sh.fix_fthostname(hostname)
|
|
239
301
|
with self.sh.ftpcontext(hostname, logname, port=port) as ftp:
|
|
240
302
|
if ftp:
|
|
241
|
-
source, destination = self._folder_preftget(
|
|
303
|
+
source, destination = self._folder_preftget(
|
|
304
|
+
source, destination
|
|
305
|
+
)
|
|
242
306
|
with self._folder_postftget_context(destination):
|
|
243
307
|
try:
|
|
244
308
|
if self.pipeget:
|
|
245
309
|
with self._folder_ftget_pipe_extract() as p:
|
|
246
310
|
rc = ftp.get(source, p.stdin)
|
|
247
311
|
else:
|
|
248
|
-
with self._folder_ftget_file_extract(
|
|
312
|
+
with self._folder_ftget_file_extract(
|
|
313
|
+
source
|
|
314
|
+
) as tmp_target:
|
|
249
315
|
rc = ftp.get(source, tmp_target)
|
|
250
316
|
except ftplib.all_errors as e:
|
|
251
|
-
logger.warning(
|
|
317
|
+
logger.warning("An FTP error occurred: %s", str(e))
|
|
252
318
|
rc = False
|
|
253
319
|
return rc
|
|
254
320
|
else:
|
|
255
321
|
return False
|
|
256
322
|
|
|
257
|
-
def _folder_rawftget(
|
|
258
|
-
|
|
323
|
+
def _folder_rawftget(
|
|
324
|
+
self,
|
|
325
|
+
source,
|
|
326
|
+
destination,
|
|
327
|
+
hostname=None,
|
|
328
|
+
logname=None,
|
|
329
|
+
port=None,
|
|
330
|
+
cpipeline=None,
|
|
331
|
+
):
|
|
259
332
|
"""Use ftserv as much as possible."""
|
|
260
333
|
if cpipeline is not None:
|
|
261
334
|
raise OSError("It's not allowed to compress folder like data.")
|
|
@@ -263,17 +336,30 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
263
336
|
source, destination = self._folder_preftget(source, destination)
|
|
264
337
|
with self._folder_postftget_context(destination):
|
|
265
338
|
with self._folder_ftget_file_extract(source) as tmp_target:
|
|
266
|
-
rc = self.sh.ftserv_get(
|
|
267
|
-
|
|
268
|
-
|
|
339
|
+
rc = self.sh.ftserv_get(
|
|
340
|
+
source,
|
|
341
|
+
tmp_target,
|
|
342
|
+
hostname=hostname,
|
|
343
|
+
logname=logname,
|
|
344
|
+
port=port,
|
|
345
|
+
)
|
|
269
346
|
return rc
|
|
270
347
|
else:
|
|
271
348
|
if port is None:
|
|
272
349
|
port = DEFAULT_FTP_PORT
|
|
273
|
-
return self._folder_ftget(
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
350
|
+
return self._folder_ftget(
|
|
351
|
+
source, destination, hostname, logname, port=port
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
def _folder_batchrawftget(
|
|
355
|
+
self,
|
|
356
|
+
source,
|
|
357
|
+
destination,
|
|
358
|
+
hostname=None,
|
|
359
|
+
logname=None,
|
|
360
|
+
port=None,
|
|
361
|
+
cpipeline=None,
|
|
362
|
+
):
|
|
277
363
|
"""Use ftserv to fetch several folder-like resources."""
|
|
278
364
|
if cpipeline is not None:
|
|
279
365
|
raise OSError("It's not allowed to compress folder like data.")
|
|
@@ -288,20 +374,35 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
288
374
|
actualdestinations.append(actual_d)
|
|
289
375
|
d_dirname = self.sh.path.dirname(actual_d)
|
|
290
376
|
self.sh.mkdir(d_dirname)
|
|
291
|
-
d_tmpdir = tempfile.mkdtemp(
|
|
377
|
+
d_tmpdir = tempfile.mkdtemp(
|
|
378
|
+
prefix="folder_", dir=d_dirname
|
|
379
|
+
)
|
|
292
380
|
d_extname = self.sh.tarname_splitext(actual_s)[1]
|
|
293
|
-
tmpdestinations.append(
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
381
|
+
tmpdestinations.append(
|
|
382
|
+
self.sh.path.join(d_tmpdir, self.tmpname + d_extname)
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
rc = self.sh.ftserv_batchget(
|
|
386
|
+
actualsources,
|
|
387
|
+
tmpdestinations,
|
|
388
|
+
hostname,
|
|
389
|
+
logname,
|
|
390
|
+
port=port,
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
for i, (d, t) in enumerate(
|
|
394
|
+
zip(actualdestinations, tmpdestinations)
|
|
395
|
+
):
|
|
299
396
|
if rc[i]:
|
|
300
397
|
with self.sh.cdcontext(self.sh.path.dirname(t)):
|
|
301
398
|
try:
|
|
302
399
|
try:
|
|
303
|
-
rc[i] = rc[i] and bool(
|
|
304
|
-
|
|
400
|
+
rc[i] = rc[i] and bool(
|
|
401
|
+
self.sh.untar(
|
|
402
|
+
self.sh.path.basename(t),
|
|
403
|
+
autocompress=False,
|
|
404
|
+
)
|
|
405
|
+
)
|
|
305
406
|
finally:
|
|
306
407
|
self.sh.rm(t)
|
|
307
408
|
finally:
|
|
@@ -311,10 +412,18 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
311
412
|
self.sh.rm(self.sh.path.dirname(t))
|
|
312
413
|
return rc
|
|
313
414
|
else:
|
|
314
|
-
raise RuntimeError(
|
|
315
|
-
|
|
316
|
-
def _folder_ftput(
|
|
317
|
-
|
|
415
|
+
raise RuntimeError("You are not supposed to land here !")
|
|
416
|
+
|
|
417
|
+
def _folder_ftput(
|
|
418
|
+
self,
|
|
419
|
+
source,
|
|
420
|
+
destination,
|
|
421
|
+
hostname=None,
|
|
422
|
+
logname=None,
|
|
423
|
+
port=DEFAULT_FTP_PORT,
|
|
424
|
+
cpipeline=None,
|
|
425
|
+
sync=False,
|
|
426
|
+
):
|
|
318
427
|
"""Proceed direct ftp put on the specified target."""
|
|
319
428
|
if cpipeline is not None:
|
|
320
429
|
raise OSError("It's not allowed to compress folder like data.")
|
|
@@ -326,42 +435,64 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
326
435
|
with self._folder_ftput_pipe_compress(source) as p:
|
|
327
436
|
sponge = IoSponge(p.stdout, guessed_size=packed_size)
|
|
328
437
|
try:
|
|
329
|
-
rc = ftp.put(
|
|
438
|
+
rc = ftp.put(
|
|
439
|
+
sponge, destination, size=sponge.size, exact=False
|
|
440
|
+
)
|
|
330
441
|
except ftplib.all_errors as e:
|
|
331
|
-
logger.warning(
|
|
442
|
+
logger.warning("An FTP error occurred: %s", str(e))
|
|
332
443
|
rc = False
|
|
333
444
|
return rc
|
|
334
445
|
else:
|
|
335
446
|
return False
|
|
336
447
|
|
|
337
|
-
def _folder_rawftput(
|
|
338
|
-
|
|
448
|
+
def _folder_rawftput(
|
|
449
|
+
self,
|
|
450
|
+
source,
|
|
451
|
+
destination,
|
|
452
|
+
hostname=None,
|
|
453
|
+
logname=None,
|
|
454
|
+
port=None,
|
|
455
|
+
cpipeline=None,
|
|
456
|
+
sync=False,
|
|
457
|
+
):
|
|
339
458
|
"""Use ftserv as much as possible."""
|
|
340
459
|
if cpipeline is not None:
|
|
341
460
|
raise OSError("It's not allowed to compress folder like data.")
|
|
342
461
|
if self.sh.ftraw and self.rawftshell is not None:
|
|
343
|
-
newsource = self.sh.copy2ftspool(
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
462
|
+
newsource = self.sh.copy2ftspool(
|
|
463
|
+
source, nest=True, fmt=self.supportedfmt
|
|
464
|
+
)
|
|
465
|
+
request = self.sh.path.dirname(newsource) + ".request"
|
|
466
|
+
with open(request, "w") as request_fh:
|
|
347
467
|
request_fh.write(str(self.sh.path.dirname(newsource)))
|
|
348
468
|
self.sh.readonly(request)
|
|
349
|
-
rc = self.sh.ftserv_put(
|
|
350
|
-
|
|
351
|
-
|
|
469
|
+
rc = self.sh.ftserv_put(
|
|
470
|
+
request,
|
|
471
|
+
destination,
|
|
472
|
+
hostname=hostname,
|
|
473
|
+
logname=logname,
|
|
474
|
+
port=port,
|
|
475
|
+
specialshell=self.rawftshell,
|
|
476
|
+
sync=sync,
|
|
477
|
+
)
|
|
352
478
|
self.sh.rm(request)
|
|
353
479
|
return rc
|
|
354
480
|
else:
|
|
355
481
|
if port is None:
|
|
356
482
|
port = DEFAULT_FTP_PORT
|
|
357
|
-
return self._folder_ftput(
|
|
358
|
-
|
|
483
|
+
return self._folder_ftput(
|
|
484
|
+
source, destination, hostname, logname, port=port, sync=sync
|
|
485
|
+
)
|
|
359
486
|
|
|
360
|
-
def _folder_scpget(
|
|
487
|
+
def _folder_scpget(
|
|
488
|
+
self, source, destination, hostname, logname=None, cpipeline=None
|
|
489
|
+
):
|
|
361
490
|
"""Retrieve a folder using scp."""
|
|
362
491
|
if cpipeline is not None:
|
|
363
492
|
raise OSError("It's not allowed to compress folder like data.")
|
|
364
|
-
logname = self.sh.fix_ftuser(
|
|
493
|
+
logname = self.sh.fix_ftuser(
|
|
494
|
+
hostname, logname, fatal=False, defaults_to_user=False
|
|
495
|
+
)
|
|
365
496
|
ssh = self.sh.ssh(hostname, logname)
|
|
366
497
|
rc = False
|
|
367
498
|
source, destination = self._folder_preftget(source, destination)
|
|
@@ -370,18 +501,22 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
370
501
|
rc = ssh.scpget_stream(source, p.stdin)
|
|
371
502
|
return rc
|
|
372
503
|
|
|
373
|
-
def _folder_scpput(
|
|
504
|
+
def _folder_scpput(
|
|
505
|
+
self, source, destination, hostname, logname=None, cpipeline=None
|
|
506
|
+
):
|
|
374
507
|
"""Upload a folder using scp."""
|
|
375
508
|
if cpipeline is not None:
|
|
376
509
|
raise OSError("It's not allowed to compress folder like data.")
|
|
377
510
|
source = self.sh.path.abspath(source)
|
|
378
|
-
logname = self.sh.fix_ftuser(
|
|
511
|
+
logname = self.sh.fix_ftuser(
|
|
512
|
+
hostname, logname, fatal=False, defaults_to_user=False
|
|
513
|
+
)
|
|
379
514
|
ssh = self.sh.ssh(hostname, logname)
|
|
380
515
|
with self._folder_ftput_pipe_compress(source) as p:
|
|
381
516
|
rc = ssh.scpput_stream(p.stdout, destination)
|
|
382
517
|
return rc
|
|
383
518
|
|
|
384
|
-
@addons.require_external_addon(
|
|
519
|
+
@addons.require_external_addon("ecfs")
|
|
385
520
|
def _folder_ecfsget(self, source, target, cpipeline=None, options=None):
|
|
386
521
|
"""Get a folder resource using ECfs.
|
|
387
522
|
|
|
@@ -397,10 +532,12 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
397
532
|
source, target = self._folder_preftget(source, target)
|
|
398
533
|
with self._folder_postftget_context(target):
|
|
399
534
|
with self._folder_ftget_file_extract(source) as tmp_target:
|
|
400
|
-
rc = self.sh.ecfsget(
|
|
535
|
+
rc = self.sh.ecfsget(
|
|
536
|
+
source=source, target=tmp_target, options=options
|
|
537
|
+
)
|
|
401
538
|
return rc
|
|
402
539
|
|
|
403
|
-
@addons.require_external_addon(
|
|
540
|
+
@addons.require_external_addon("ecfs")
|
|
404
541
|
def _folder_ecfsput(self, source, target, cpipeline=None, options=None):
|
|
405
542
|
"""Put a folder resource using ECfs.
|
|
406
543
|
|
|
@@ -414,11 +551,15 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
414
551
|
raise OSError("It's not allowed to compress folder like data.")
|
|
415
552
|
source = self.sh.path.abspath(source)
|
|
416
553
|
with self._folder_ftput_file_compress(source) as c_source:
|
|
417
|
-
rc = self.sh.ecfsput(
|
|
554
|
+
rc = self.sh.ecfsput(
|
|
555
|
+
source=c_source, target=target, options=options
|
|
556
|
+
)
|
|
418
557
|
return rc
|
|
419
558
|
|
|
420
|
-
@addons.require_external_addon(
|
|
421
|
-
def _folder_ectransget(
|
|
559
|
+
@addons.require_external_addon("ectrans")
|
|
560
|
+
def _folder_ectransget(
|
|
561
|
+
self, source, target, gateway=None, remote=None, cpipeline=None
|
|
562
|
+
):
|
|
422
563
|
"""Get a folder resource using ECtrans.
|
|
423
564
|
|
|
424
565
|
:param source: source file
|
|
@@ -434,15 +575,24 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
434
575
|
source, target = self._folder_preftget(source, target)
|
|
435
576
|
with self._folder_postftget_context(target):
|
|
436
577
|
with self._folder_ftget_file_extract(source) as tmp_target:
|
|
437
|
-
rc = self.sh.raw_ectransget(
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
578
|
+
rc = self.sh.raw_ectransget(
|
|
579
|
+
source=source,
|
|
580
|
+
target=tmp_target,
|
|
581
|
+
gateway=gateway,
|
|
582
|
+
remote=remote,
|
|
583
|
+
)
|
|
441
584
|
return rc
|
|
442
585
|
|
|
443
|
-
@addons.require_external_addon(
|
|
444
|
-
def _folder_ectransput(
|
|
445
|
-
|
|
586
|
+
@addons.require_external_addon("ectrans")
|
|
587
|
+
def _folder_ectransput(
|
|
588
|
+
self,
|
|
589
|
+
source,
|
|
590
|
+
target,
|
|
591
|
+
gateway=None,
|
|
592
|
+
remote=None,
|
|
593
|
+
cpipeline=None,
|
|
594
|
+
sync=False,
|
|
595
|
+
):
|
|
446
596
|
"""Put a folder resource using ECtrans.
|
|
447
597
|
|
|
448
598
|
:param source: source file
|
|
@@ -457,24 +607,29 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
457
607
|
raise OSError("It's not allowed to compress folder like data.")
|
|
458
608
|
source = self.sh.path.abspath(source)
|
|
459
609
|
with self._folder_ftput_file_compress(source) as c_source:
|
|
460
|
-
rc = self.sh.raw_ectransput(
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
610
|
+
rc = self.sh.raw_ectransput(
|
|
611
|
+
source=c_source,
|
|
612
|
+
target=target,
|
|
613
|
+
gateway=gateway,
|
|
614
|
+
remote=remote,
|
|
615
|
+
sync=sync,
|
|
616
|
+
)
|
|
465
617
|
return rc
|
|
466
618
|
|
|
467
619
|
@property
|
|
468
620
|
def _folder_tarfix_extension(self):
|
|
469
621
|
"""Return the extension of tar file associated with this extension."""
|
|
470
622
|
if self._COMPRESSED:
|
|
471
|
-
if self._COMPRESSED ==
|
|
623
|
+
if self._COMPRESSED == "gz":
|
|
472
624
|
return "tgz"
|
|
473
|
-
elif self._COMPRESSED ==
|
|
625
|
+
elif self._COMPRESSED == "bz2":
|
|
474
626
|
return "tar.bz2"
|
|
475
627
|
else:
|
|
476
|
-
raise ValueError(
|
|
477
|
-
|
|
628
|
+
raise ValueError(
|
|
629
|
+
"Unsupported compression type: {:s}".format(
|
|
630
|
+
self._COMPRESSED
|
|
631
|
+
)
|
|
632
|
+
)
|
|
478
633
|
else:
|
|
479
634
|
return "tar"
|
|
480
635
|
|
|
@@ -487,17 +642,23 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
487
642
|
ok = True
|
|
488
643
|
sh = self.sh
|
|
489
644
|
if sh.is_tarname(source) and not sh.is_tarname(destination):
|
|
490
|
-
logger.info(
|
|
645
|
+
logger.info(
|
|
646
|
+
"tarfix_in: untar from get <%s> to <%s>", source, destination
|
|
647
|
+
)
|
|
491
648
|
(destdir, destfile) = sh.path.split(sh.path.abspath(destination))
|
|
492
649
|
tar_ext = sh.tarname_splitext(source)[1]
|
|
493
650
|
desttar = sh.path.abspath(destination + tar_ext)
|
|
494
651
|
sh.remove(desttar)
|
|
495
652
|
ok = ok and sh.move(destination, desttar)
|
|
496
|
-
with sh.temporary_dir_cdcontext(prefix=
|
|
653
|
+
with sh.temporary_dir_cdcontext(prefix="untar_", dir=destdir):
|
|
497
654
|
ok = ok and sh.untar(desttar, output=False)
|
|
498
|
-
unpacked = sh.glob(
|
|
499
|
-
ok =
|
|
500
|
-
|
|
655
|
+
unpacked = sh.glob("*")
|
|
656
|
+
ok = (
|
|
657
|
+
ok and len(unpacked) == 1
|
|
658
|
+
) # Only one element allowed in this kind of tarfiles
|
|
659
|
+
ok = ok and sh.move(
|
|
660
|
+
unpacked[0], sh.path.join(destdir, destfile)
|
|
661
|
+
)
|
|
501
662
|
ok = ok and sh.remove(desttar)
|
|
502
663
|
return (ok, source, destination)
|
|
503
664
|
|
|
@@ -511,7 +672,9 @@ class FolderShell(addons.FtrawEnableAddon):
|
|
|
511
672
|
ok = True
|
|
512
673
|
sh = self.sh
|
|
513
674
|
if sh.is_tarname(destination) and not sh.is_tarname(source):
|
|
514
|
-
logger.info(
|
|
675
|
+
logger.info(
|
|
676
|
+
"tarfix_out: tar before put <%s> to <%s>", source, destination
|
|
677
|
+
)
|
|
515
678
|
tar_ext = sh.tarname_splitext(destination)[1]
|
|
516
679
|
sourcetar = sh.path.abspath(source + tar_ext)
|
|
517
680
|
source_rel = sh.path.basename(source)
|
|
@@ -532,12 +695,12 @@ class OdbShell(FolderShell):
|
|
|
532
695
|
"""
|
|
533
696
|
|
|
534
697
|
_footprint = dict(
|
|
535
|
-
info
|
|
536
|
-
attr
|
|
537
|
-
kind
|
|
538
|
-
values
|
|
698
|
+
info="Default ODB system interface",
|
|
699
|
+
attr=dict(
|
|
700
|
+
kind=dict(
|
|
701
|
+
values=["odb"],
|
|
539
702
|
),
|
|
540
|
-
)
|
|
703
|
+
),
|
|
541
704
|
)
|
|
542
705
|
|
|
543
706
|
|
|
@@ -549,12 +712,12 @@ class DdhPackShell(FolderShell):
|
|
|
549
712
|
"""
|
|
550
713
|
|
|
551
714
|
_footprint = dict(
|
|
552
|
-
info
|
|
553
|
-
attr
|
|
554
|
-
kind
|
|
555
|
-
values
|
|
715
|
+
info="Default DDHpack system interface",
|
|
716
|
+
attr=dict(
|
|
717
|
+
kind=dict(
|
|
718
|
+
values=["ddhpack"],
|
|
556
719
|
),
|
|
557
|
-
)
|
|
720
|
+
),
|
|
558
721
|
)
|
|
559
722
|
|
|
560
723
|
|
|
@@ -566,12 +729,12 @@ class RawFilesShell(FolderShell):
|
|
|
566
729
|
"""
|
|
567
730
|
|
|
568
731
|
_footprint = dict(
|
|
569
|
-
info
|
|
570
|
-
attr
|
|
571
|
-
kind
|
|
572
|
-
values
|
|
732
|
+
info="Default (g)RRRRawfiles system interface",
|
|
733
|
+
attr=dict(
|
|
734
|
+
kind=dict(
|
|
735
|
+
values=["rawfiles"],
|
|
573
736
|
),
|
|
574
|
-
)
|
|
737
|
+
),
|
|
575
738
|
)
|
|
576
739
|
|
|
577
740
|
|
|
@@ -583,12 +746,12 @@ class ObsLocationPackShell(FolderShell):
|
|
|
583
746
|
"""
|
|
584
747
|
|
|
585
748
|
_footprint = dict(
|
|
586
|
-
info
|
|
587
|
-
attr
|
|
588
|
-
kind
|
|
589
|
-
values
|
|
749
|
+
info="Default Obs Location packs system interface",
|
|
750
|
+
attr=dict(
|
|
751
|
+
kind=dict(
|
|
752
|
+
values=["obslocationpack"],
|
|
590
753
|
),
|
|
591
|
-
)
|
|
754
|
+
),
|
|
592
755
|
)
|
|
593
756
|
|
|
594
757
|
|
|
@@ -600,12 +763,12 @@ class ObsFirePackShell(FolderShell):
|
|
|
600
763
|
"""
|
|
601
764
|
|
|
602
765
|
_footprint = dict(
|
|
603
|
-
info
|
|
604
|
-
attr
|
|
605
|
-
kind
|
|
606
|
-
values
|
|
766
|
+
info="Default Obs Location packs system interface",
|
|
767
|
+
attr=dict(
|
|
768
|
+
kind=dict(
|
|
769
|
+
values=["obsfirepack"],
|
|
607
770
|
),
|
|
608
|
-
)
|
|
771
|
+
),
|
|
609
772
|
)
|
|
610
773
|
|
|
611
774
|
|
|
@@ -617,12 +780,12 @@ class WavesBCShell(FolderShell):
|
|
|
617
780
|
"""
|
|
618
781
|
|
|
619
782
|
_footprint = dict(
|
|
620
|
-
info
|
|
621
|
-
attr
|
|
622
|
-
kind
|
|
623
|
-
values
|
|
783
|
+
info="Default waves BC system interface",
|
|
784
|
+
attr=dict(
|
|
785
|
+
kind=dict(
|
|
786
|
+
values=["wbcpack"],
|
|
624
787
|
),
|
|
625
|
-
)
|
|
788
|
+
),
|
|
626
789
|
)
|
|
627
790
|
|
|
628
791
|
|
|
@@ -634,30 +797,38 @@ class FilesPackShell(FolderShell):
|
|
|
634
797
|
"""
|
|
635
798
|
|
|
636
799
|
_footprint = dict(
|
|
637
|
-
info
|
|
638
|
-
attr
|
|
639
|
-
kind
|
|
640
|
-
values
|
|
800
|
+
info="Default Files packs system interface",
|
|
801
|
+
attr=dict(
|
|
802
|
+
kind=dict(
|
|
803
|
+
values=["filespack"],
|
|
641
804
|
),
|
|
642
|
-
)
|
|
805
|
+
),
|
|
643
806
|
)
|
|
644
807
|
|
|
645
808
|
|
|
646
|
-
available_foldershells = [
|
|
647
|
-
|
|
648
|
-
|
|
809
|
+
available_foldershells = [
|
|
810
|
+
e.footprint_values("kind")[0]
|
|
811
|
+
for e in locals().values()
|
|
812
|
+
if (
|
|
813
|
+
isinstance(e, type)
|
|
814
|
+
and issubclass(e, FolderShell)
|
|
815
|
+
and not e.footprint_abstract()
|
|
816
|
+
)
|
|
817
|
+
]
|
|
649
818
|
|
|
650
819
|
|
|
651
820
|
class FolderShellsGroup(addons.AddonGroup):
|
|
652
821
|
"""The whole bunch of folder shells."""
|
|
653
822
|
|
|
654
823
|
_footprint = dict(
|
|
655
|
-
info
|
|
656
|
-
attr
|
|
657
|
-
kind
|
|
658
|
-
values
|
|
824
|
+
info="The whole bunch of folder shells",
|
|
825
|
+
attr=dict(
|
|
826
|
+
kind=dict(
|
|
827
|
+
values=[
|
|
828
|
+
"allfolders",
|
|
829
|
+
],
|
|
659
830
|
),
|
|
660
|
-
)
|
|
831
|
+
),
|
|
661
832
|
)
|
|
662
833
|
|
|
663
834
|
_addonslist = available_foldershells
|