panda-client-light 2.0.1__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.
Files changed (46) hide show
  1. panda_client_light-2.0.1.dist-info/METADATA +56 -0
  2. panda_client_light-2.0.1.dist-info/RECORD +46 -0
  3. panda_client_light-2.0.1.dist-info/WHEEL +4 -0
  4. panda_client_light-2.0.1.dist-info/licenses/LICENSE +201 -0
  5. pandaclient/AthenaUtils.py +1601 -0
  6. pandaclient/BookConfig.py +89 -0
  7. pandaclient/Client.py +1995 -0
  8. pandaclient/CommonArgs.py +213 -0
  9. pandaclient/FileSpec.py +130 -0
  10. pandaclient/Group_argparse.py +107 -0
  11. pandaclient/JobSpec.py +992 -0
  12. pandaclient/LocalJobSpec.py +401 -0
  13. pandaclient/LocalJobsetSpec.py +288 -0
  14. pandaclient/MiscUtils.py +371 -0
  15. pandaclient/PBookCore.py +506 -0
  16. pandaclient/PBookScript.py +670 -0
  17. pandaclient/PChainScript_native.py +414 -0
  18. pandaclient/PLogger.py +51 -0
  19. pandaclient/PandaToolsPkgInfo.py +1 -0
  20. pandaclient/ParseJobXML.py +395 -0
  21. pandaclient/PathenaScript.py +3231 -0
  22. pandaclient/PchainScript.py +323 -0
  23. pandaclient/PcontainerScript.py +13 -0
  24. pandaclient/PhpoScript.py +616 -0
  25. pandaclient/PrunScript.py +2782 -0
  26. pandaclient/PsubUtils.py +789 -0
  27. pandaclient/__init__.py +0 -0
  28. pandaclient/example_task.py +64 -0
  29. pandaclient/idds_api.py +61 -0
  30. pandaclient/localSpecs.py +142 -0
  31. pandaclient/openidc_utils.py +245 -0
  32. pandaclient/panda_api.py +301 -0
  33. pandaclient/panda_gui.py +124 -0
  34. pandaclient/panda_jupyter.py +140 -0
  35. pandaclient/pcontainer_core.py +174 -0
  36. pandaclient/test_client_file.py +14 -0
  37. pandaclient/test_client_job.py +18 -0
  38. pandaclient/test_client_misc.py +18 -0
  39. pandaclient/test_client_submit_job.py +20 -0
  40. pandaclient/test_client_task.py +89 -0
  41. pandaclient/time_utils.py +21 -0
  42. pandaclient/workflow_description.py +512 -0
  43. pandaclient/workflow_template_dispatcher.py +37 -0
  44. pandaclient/workflow_templates/__init__.py +5 -0
  45. pandaclient/workflow_templates/multistep_merge.py +143 -0
  46. pandaclient/workflow_utils.py +34 -0
@@ -0,0 +1,1601 @@
1
+ import copy
2
+ import json
3
+ import os
4
+ import re
5
+ import sys
6
+
7
+ from . import MiscUtils, PLogger
8
+ from .MiscUtils import commands_fail_on_non_zero_exit_status, commands_get_output, commands_get_output_with_env
9
+ from .PsubUtils import check_invalid_char
10
+
11
+ # error code
12
+ EC_Config = 10
13
+ EC_Archive = 60
14
+
15
+
16
+ # get CMT projects
17
+ def getCmtProjects(dir="."):
18
+ # cmt or cmake
19
+ if not useCMake():
20
+ # keep current dir
21
+ curdir = os.getcwd()
22
+ # change dir
23
+ os.chdir(dir)
24
+ # get projects
25
+ out = commands_get_output_with_env("cmt show projects")
26
+ lines = out.split("\n")
27
+ # remove CMT warnings
28
+ tupLines = tuple(lines)
29
+ lines = []
30
+ for line in tupLines:
31
+ if "CMTUSERCONTEXT" in line:
32
+ continue
33
+ if not line.startswith("#"):
34
+ lines.append(line)
35
+ # back to the current dir
36
+ os.chdir(curdir)
37
+ # return
38
+ return lines, out
39
+ else:
40
+ lines = []
41
+ # use current dir as test area
42
+ tmpStr = f"(in {os.getcwd()})"
43
+ lines.append(tmpStr)
44
+ # AtlasProject
45
+ if not "AtlasProject" in os.environ:
46
+ return [], "AtlasProject is not defined in runtime environment"
47
+ tmpStr = "{0} (in {0}/{1})".format(os.environ["AtlasProject"], os.environ["AtlasVersion"])
48
+ lines.append(tmpStr)
49
+ if "AtlasOffline_VERSION" in os.environ:
50
+ tmpStr = "{0} (in {0}/{1})".format("AtlasOffline", os.environ["AtlasOffline_VERSION"])
51
+ lines.append(tmpStr)
52
+ prodVerStr = "{}_VERSION".format(os.environ["AtlasProject"])
53
+ if prodVerStr in os.environ:
54
+ tmpStr = "{0} (in {0}/{1})".format(os.environ["AtlasProject"], os.environ[prodVerStr])
55
+ lines.append(tmpStr)
56
+ return lines, ""
57
+
58
+
59
+ # check if ath release
60
+ def isAthRelease(cacheVer):
61
+ try:
62
+ if "AthAnalysis" in cacheVer or re.search("Ath[a-zA-Z]+Base", cacheVer) is not None:
63
+ return True
64
+ except Exception:
65
+ pass
66
+ return False
67
+
68
+
69
+ # get Athena version
70
+ def getAthenaVer(verbose=True):
71
+ # get logger
72
+ tmpLog = PLogger.getPandaLogger()
73
+ # get project parameters
74
+ lines, out = getCmtProjects()
75
+ if len(lines) < 2:
76
+ # make a tmp dir to execute cmt
77
+ tmpDir = "cmttmp.%s" % MiscUtils.wrappedUuidGen()
78
+ os.mkdir(tmpDir)
79
+ # try cmt under a subdir since it doesn't work in top dir
80
+ lines, tmpOut = getCmtProjects(tmpDir)
81
+ # delete the tmp dir
82
+ commands_get_output("rm -rf %s" % tmpDir)
83
+ if len(lines) < 2:
84
+ if verbose:
85
+ print(out)
86
+ tmpLog.error("cmt gave wrong info")
87
+ return False, {}
88
+ # private work area
89
+ res = re.search(r"\(in ([^\)]+)\)", lines[0])
90
+ if res is None:
91
+ print(lines[0])
92
+ tmpLog.error("no TestArea. could not get path to private work area")
93
+ return False, {}
94
+ workArea = os.path.realpath(res.group(1))
95
+ # get Athena version and group area
96
+ athenaVer = ""
97
+ groupArea = ""
98
+ cacheVer = ""
99
+ nightVer = ""
100
+ cmtConfig = ""
101
+ for line in lines[1:]:
102
+ res = re.search(r"\(in ([^\)]+)\)", line)
103
+ if res is not None:
104
+ items = line.split()
105
+ if (
106
+ items[0].startswith("Athena")
107
+ or items[0].startswith("Analysis")
108
+ or items[0] in ["AthDerivations", "AnalysisBase", "AthSimulation", "AthDerivation", "AthAnalysis", "AthGeneration", "AtlasStats"]
109
+ ):
110
+ isGitBase = True
111
+ else:
112
+ isGitBase = False
113
+ # base release
114
+ if items[0] in ("dist", "AtlasRelease", "AtlasOffline", "AtlasAnalysis", "AtlasTrigger", "AtlasReconstruction") or isGitBase:
115
+ # Atlas release
116
+ if "AtlasBuildStamp" in os.environ and ("AtlasReleaseType" not in os.environ or os.environ["AtlasReleaseType"] != "stable"):
117
+ athenaVer = os.environ["AtlasBuildStamp"]
118
+ useBuildStamp = True
119
+ else:
120
+ athenaVer = os.path.basename(res.group(1))
121
+ useBuildStamp = False
122
+ # nightly
123
+ if athenaVer.startswith("rel") or useBuildStamp or isGitBase:
124
+ # extract base release
125
+ if not useCMake():
126
+ tmpMatch = re.search(r"/([^/]+)(/rel_\d+)*/Atlas[^/]+/rel_\d+", line)
127
+ if tmpMatch is None:
128
+ tmpLog.error("unsupported nightly %s" % line)
129
+ return False, {}
130
+ # set athenaVer and cacheVer
131
+ cacheVer = "-AtlasOffline_%s" % athenaVer
132
+ athenaVer = tmpMatch.group(1)
133
+ else:
134
+ if athenaVer.startswith("rel"):
135
+ tmpLog.error("Nightlies with AFS setup are unsupported on the grid. Setup with CVMFS")
136
+ return False, {}
137
+ if isGitBase:
138
+ cacheVer = f"-{items[0]}_{athenaVer}"
139
+ else:
140
+ cacheVer = "-AtlasOffline_%s" % athenaVer
141
+ if useBuildStamp:
142
+ athenaVer = os.environ["AtlasBuildBranch"]
143
+ break
144
+ # cache or analysis projects
145
+ elif (
146
+ items[0] in ["AtlasProduction", "AtlasPoint1", "AtlasTier0", "AtlasP1HLT", "AtlasDerivation", "TrigMC"]
147
+ or isAthRelease(items[0])
148
+ or items[1].count(".") >= 4
149
+ ):
150
+ # cache is used
151
+ if cacheVer != "":
152
+ continue
153
+ # production cache
154
+ cacheTag = os.path.basename(res.group(1))
155
+ if items[0] == "AtlasProduction" and cacheTag.startswith("rel"):
156
+ # nightlies for cache
157
+ tmpMatch = re.search(r"/([^/]+)(/rel_\d+)*/Atlas[^/]+/rel_\d+", line)
158
+ if tmpMatch is None:
159
+ tmpLog.error("unsupported nightly %s" % line)
160
+ return False, {}
161
+ cacheVer = "-AtlasOffline_%s" % cacheTag
162
+ athenaVer = tmpMatch.group(1)
163
+ break
164
+ elif items[0] == "TrigMC" and cacheTag.startswith("rel"):
165
+ # nightlies for cache
166
+ tmpMatch = re.search(r"/([^/]+)(/rel_\d+)*/[^/]+/rel_\d+", line)
167
+ if tmpMatch is None:
168
+ tmpLog.error("unsupported nightly %s" % line)
169
+ return False, {}
170
+ cacheVer = "-{}_{}".format(items[0], cacheTag)
171
+ athenaVer = tmpMatch.group(1)
172
+ break
173
+ elif isAthRelease(items[0]):
174
+ cacheVer = "-{}_{}".format(items[0], cacheTag)
175
+ else:
176
+ # doesn't use when it is a base release since it is not installed in EGEE
177
+ if re.search(r"^\d+\.\d+\.\d+$", cacheTag) is None:
178
+ cacheVer = "-{}_{}".format(items[0], cacheTag)
179
+ # no more check for AthAnalysis
180
+ if isAthRelease(items[0]):
181
+ break
182
+ else:
183
+ # group area
184
+ groupArea = os.path.realpath(res.group(1))
185
+ # cmtconfig
186
+ if "CMTCONFIG" in os.environ:
187
+ cmtConfig = os.environ["CMTCONFIG"]
188
+ # last resort
189
+ if athenaVer == "":
190
+ if "AtlasProject" in os.environ and "AtlasBuildBranch" in os.environ:
191
+ prodVerStr = "{}_VERSION".format(os.environ["AtlasProject"])
192
+ if prodVerStr in os.environ:
193
+ athenaVer = os.environ["AtlasBuildBranch"]
194
+ cacheVer = "-{}_{}".format(os.environ["AtlasProject"], os.environ[prodVerStr])
195
+ groupArea = ""
196
+ # pack return values
197
+ retVal = {
198
+ "workArea": workArea,
199
+ "athenaVer": athenaVer,
200
+ "groupArea": groupArea,
201
+ "cacheVer": cacheVer,
202
+ "nightVer": nightVer,
203
+ "cmtConfig": cmtConfig,
204
+ }
205
+ # check error
206
+ if athenaVer == "" and not isAthRelease(cacheVer):
207
+ tmpStr = ""
208
+ for line in lines:
209
+ tmpStr += line + "\n"
210
+ tmpLog.info("cmt showed\n" + tmpStr)
211
+ tmpLog.error("could not get Athena version. perhaps your requirements file doesn't have ATLAS_TEST_AREA")
212
+ return False, retVal
213
+ # return
214
+ return True, retVal
215
+
216
+
217
+ # wrapper for attribute access
218
+ class ConfigAttr(dict):
219
+ # override __getattribute__ for dot access
220
+ def __getattribute__(self, name):
221
+ if name in dict.__dict__.keys():
222
+ return dict.__getattribute__(self, name)
223
+ if name.startswith("__"):
224
+ return dict.__getattribute__(self, name)
225
+ if name in dict.keys(self):
226
+ return dict.__getitem__(self, name)
227
+ return False
228
+
229
+ def __setattr__(self, name, value):
230
+ if name in dict.__dict__.keys():
231
+ dict.__setattr__(self, name, value)
232
+ else:
233
+ dict.__setitem__(self, name, value)
234
+
235
+
236
+ # extract run configuration
237
+ def extractRunConfig(jobO, supStream, shipinput, trf, verbose=False, useAMI=False, inDS="", tmpDir=".", one_liner=""):
238
+ # get logger
239
+ tmpLog = PLogger.getPandaLogger()
240
+ outputConfig = ConfigAttr()
241
+ inputConfig = ConfigAttr()
242
+ otherConfig = ConfigAttr()
243
+ statsCode = True
244
+ if trf:
245
+ pass
246
+ else:
247
+ # use AMI
248
+ amiJobO = ""
249
+ if useAMI:
250
+ amiJobO = getJobOtoUseAmiForAutoConf(inDS, tmpDir)
251
+ baseName = os.environ["PANDA_SYS"] + "/etc/panda/share"
252
+ if " - " in jobO:
253
+ jobO = re.sub(" - ", " %s/ConfigExtractor.py - " % baseName, jobO)
254
+ else:
255
+ jobO = jobO + " %s/ConfigExtractor.py " % baseName
256
+ com = "athena.py "
257
+ if one_liner:
258
+ com += '-c "%s" ' % one_liner
259
+ com += "{} {}/FakeAppMgr.py {}".format(amiJobO, baseName, jobO)
260
+ if verbose:
261
+ tmpLog.debug(com)
262
+ # run ConfigExtractor for normal jobO
263
+ out = commands_get_output_with_env(com)
264
+ failExtractor = True
265
+ outputConfig["alloutputs"] = []
266
+ skipOutName = False
267
+ for line in out.split("\n"):
268
+ match = re.findall("^ConfigExtractor > (.+)", line)
269
+ if len(match):
270
+ # suppress some streams
271
+ if match[0].startswith("Output="):
272
+ tmpSt0 = "NoneNoneNone"
273
+ tmpSt1 = "NoneNoneNone"
274
+ tmpSt2 = "NoneNoneNone"
275
+ try:
276
+ tmpSt0 = match[0].replace("=", " ").split()[1].upper()
277
+ except Exception:
278
+ pass
279
+ try:
280
+ tmpSt1 = match[0].replace("=", " ").split()[-1].upper()
281
+ except Exception:
282
+ pass
283
+ try:
284
+ tmpSt2 = match[0].replace("=", " ").split()[2].upper()
285
+ except Exception:
286
+ pass
287
+ toBeSuppressed = False
288
+ # normal check
289
+ if tmpSt0 in supStream or tmpSt1 in supStream or tmpSt2 in supStream:
290
+ toBeSuppressed = True
291
+ # wild card check
292
+ if not toBeSuppressed:
293
+ for tmpPatt in supStream:
294
+ if "*" in tmpPatt:
295
+ tmpPatt = "^" + tmpPatt.replace("*", ".*")
296
+ tmpPatt = tmpPatt.upper()
297
+ if re.search(tmpPatt, tmpSt0) is not None or re.search(tmpPatt, tmpSt1) is not None or re.search(tmpPatt, tmpSt2) is not None:
298
+ toBeSuppressed = True
299
+ break
300
+ # suppressed
301
+ if toBeSuppressed:
302
+ tmpLog.info("%s is suppressed" % line)
303
+ # set skipOutName to ignore output filename in the next loop
304
+ skipOutName = True
305
+ continue
306
+ failExtractor = False
307
+ # AIDA HIST
308
+ if match[0].startswith("Output=HIST"):
309
+ outputConfig["outHist"] = True
310
+ # AIDA NTuple
311
+ if match[0].startswith("Output=NTUPLE"):
312
+ if "outNtuple" not in outputConfig:
313
+ outputConfig["outNtuple"] = []
314
+ tmpItems = match[0].split()
315
+ outputConfig["outNtuple"].append(tmpItems[1])
316
+ # RDO
317
+ if match[0].startswith("Output=RDO"):
318
+ outputConfig["outRDO"] = match[0].split()[1]
319
+ # ESD
320
+ if match[0].startswith("Output=ESD"):
321
+ outputConfig["outESD"] = match[0].split()[1]
322
+ # AOD
323
+ if match[0].startswith("Output=AOD"):
324
+ outputConfig["outAOD"] = match[0].split()[1]
325
+ # TAG output
326
+ if match[0] == "Output=TAG":
327
+ outputConfig["outTAG"] = True
328
+ # TAGCOM
329
+ if match[0].startswith("Output=TAGX"):
330
+ if "outTAGX" not in outputConfig:
331
+ outputConfig["outTAGX"] = []
332
+ tmpItems = match[0].split()
333
+ outputConfig["outTAGX"].append(tuple(tmpItems[1:]))
334
+ # AANT
335
+ if match[0].startswith("Output=AANT"):
336
+ if "outAANT" not in outputConfig:
337
+ outputConfig["outAANT"] = []
338
+ tmpItems = match[0].split()
339
+ outputConfig["outAANT"].append(tuple(tmpItems[1:]))
340
+ # THIST
341
+ if match[0].startswith("Output=THIST"):
342
+ if "outTHIST" not in outputConfig:
343
+ outputConfig["outTHIST"] = []
344
+ tmpItems = match[0].split()
345
+ if not tmpItems[1] in outputConfig["outTHIST"]:
346
+ outputConfig["outTHIST"].append(tmpItems[1])
347
+ # IROOT
348
+ if match[0].startswith("Output=IROOT"):
349
+ if "outIROOT" not in outputConfig:
350
+ outputConfig["outIROOT"] = []
351
+ tmpItems = match[0].split()
352
+ outputConfig["outIROOT"].append(tmpItems[1])
353
+ # Stream1
354
+ if match[0].startswith("Output=STREAM1"):
355
+ outputConfig["outStream1"] = match[0].split()[1]
356
+ # Stream2
357
+ if match[0].startswith("Output=STREAM2"):
358
+ outputConfig["outStream2"] = match[0].split()[1]
359
+ # ByteStream output
360
+ if match[0] == "Output=BS":
361
+ outputConfig["outBS"] = True
362
+ # General Stream
363
+ if match[0].startswith("Output=STREAMG"):
364
+ tmpItems = match[0].split()
365
+ outputConfig["outStreamG"] = []
366
+ for tmpNames in tmpItems[1].split(","):
367
+ outputConfig["outStreamG"].append(tmpNames.split(":"))
368
+ # Metadata
369
+ if match[0].startswith("Output=META"):
370
+ if "outMeta" not in outputConfig:
371
+ outputConfig["outMeta"] = []
372
+ tmpItems = match[0].split()
373
+ outputConfig["outMeta"].append(tuple(tmpItems[1:]))
374
+ # UserDataSvc
375
+ if match[0].startswith("Output=USERDATA"):
376
+ if "outUserData" not in outputConfig:
377
+ outputConfig["outUserData"] = []
378
+ tmpItems = match[0].split()
379
+ outputConfig["outUserData"].append(tmpItems[-1])
380
+ # MultipleStream
381
+ if match[0].startswith("Output=MS"):
382
+ if "outMS" not in outputConfig:
383
+ outputConfig["outMS"] = []
384
+ tmpItems = match[0].split()
385
+ outputConfig["outMS"].append(tuple(tmpItems[1:]))
386
+ # No input
387
+ if match[0] == "No Input":
388
+ inputConfig["noInput"] = True
389
+ # ByteStream input
390
+ if match[0] == "Input=BS":
391
+ inputConfig["inBS"] = True
392
+ # selected ByteStream
393
+ if match[0].startswith("Output=SelBS"):
394
+ tmpItems = match[0].split()
395
+ inputConfig["outSelBS"] = tmpItems[1]
396
+ # TAG input
397
+ if match[0] == "Input=COLL":
398
+ inputConfig["inColl"] = True
399
+ # POOL references
400
+ if match[0].startswith("Input=COLLREF"):
401
+ tmpRef = match[0].split()[-1]
402
+ if tmpRef == "Input=COLLREF":
403
+ # use default token when ref is empty
404
+ tmpRef = "Token"
405
+ elif tmpRef != "Token" and (not tmpRef.endswith("_ref")):
406
+ # append _ref
407
+ tmpRef += "_ref"
408
+ inputConfig["collRefName"] = tmpRef
409
+ # TAG Query
410
+ if match[0].startswith("Input=COLLQUERY"):
411
+ tmpQuery = re.sub("Input=COLLQUERY", "", match[0])
412
+ tmpQuery = tmpQuery.strip()
413
+ inputConfig["tagQuery"] = tmpQuery
414
+ # Minimum bias
415
+ if match[0] == "Input=MINBIAS":
416
+ inputConfig["inMinBias"] = True
417
+ # Cavern input
418
+ if match[0] == "Input=CAVERN":
419
+ inputConfig["inCavern"] = True
420
+ # Beam halo
421
+ if match[0] == "Input=BEAMHALO":
422
+ inputConfig["inBeamHalo"] = True
423
+ # Beam gas
424
+ if match[0] == "Input=BEAMGAS":
425
+ inputConfig["inBeamGas"] = True
426
+ # Back navigation
427
+ if match[0] == "BackNavigation=ON":
428
+ inputConfig["backNavi"] = True
429
+ # Random stream
430
+ if match[0].startswith("RndmStream"):
431
+ if "rndmStream" not in otherConfig:
432
+ otherConfig["rndmStream"] = []
433
+ tmpItems = match[0].split()
434
+ otherConfig["rndmStream"].append(tmpItems[1])
435
+ # Generator file
436
+ if match[0].startswith("RndmGenFile"):
437
+ if "rndmGenFile" not in otherConfig:
438
+ otherConfig["rndmGenFile"] = []
439
+ tmpItems = match[0].split()
440
+ otherConfig["rndmGenFile"].append(tmpItems[-1])
441
+ # G4 Random seeds
442
+ if match[0].startswith("G4RandomSeeds"):
443
+ otherConfig["G4RandomSeeds"] = True
444
+ # input files for direct input
445
+ if match[0].startswith("InputFiles"):
446
+ if shipinput:
447
+ tmpItems = match[0].split()
448
+ otherConfig["inputFiles"] = tmpItems[1:]
449
+ else:
450
+ continue
451
+ # condition file
452
+ if match[0].startswith("CondInput"):
453
+ if "condInput" not in otherConfig:
454
+ otherConfig["condInput"] = []
455
+ tmpItems = match[0].split()
456
+ otherConfig["condInput"].append(tmpItems[-1])
457
+ # collect all outputs
458
+ if match[0].startswith(" Name:"):
459
+ # skipped output
460
+ if skipOutName:
461
+ skipOutName = False
462
+ continue
463
+ outputConfig["alloutputs"].append(match[0].split()[-1])
464
+ continue
465
+ tmpLog.info(line)
466
+ skipOutName = False
467
+ # extractor failed
468
+ if failExtractor:
469
+ print(out)
470
+ tmpLog.error("Could not parse jobOptions")
471
+ statsCode = False
472
+ # return
473
+ retConfig = ConfigAttr()
474
+ retConfig["input"] = inputConfig
475
+ retConfig["other"] = otherConfig
476
+ retConfig["output"] = outputConfig
477
+ return statsCode, retConfig
478
+
479
+
480
+ # extPoolRefs for old releases which don't contain CollectionTools
481
+ athenaStuff = []
482
+
483
+ # jobO files with full path names
484
+ fullPathJobOs = {}
485
+
486
+
487
+ # convert fullPathJobOs to str
488
+ def convFullPathJobOsToStr():
489
+ tmpStr = ""
490
+ for fullJobO in fullPathJobOs:
491
+ localName = fullPathJobOs[fullJobO]
492
+ tmpStr += "{}:{},".format(fullJobO, localName)
493
+ tmpStr = tmpStr[:-1]
494
+ return tmpStr
495
+
496
+
497
+ # convert str to fullPathJobOs
498
+ def convStrToFullPathJobOs(tmpStr):
499
+ retMap = {}
500
+ for tmpItem in tmpStr.split(","):
501
+ fullJobO, localName = tmpItem.split(":")
502
+ retMap[fullJobO] = localName
503
+ return retMap
504
+
505
+
506
+ # copy some athena specific files and full-path jobOs
507
+ def copyAthenaStuff(currentDir):
508
+ baseName = os.environ["PANDA_SYS"] + "/etc/panda/share"
509
+ for tmpFile in athenaStuff:
510
+ com = "cp -p {}/{} {}".format(baseName, tmpFile, currentDir)
511
+ commands_get_output(com)
512
+ for fullJobO in fullPathJobOs:
513
+ localName = fullPathJobOs[fullJobO]
514
+ com = "cp -p {} {}/{}".format(fullJobO, currentDir, localName)
515
+ commands_get_output(com)
516
+
517
+
518
+ # delete some athena specific files and copied jobOs
519
+ def deleteAthenaStuff(currentDir):
520
+ for tmpFile in athenaStuff:
521
+ com = "rm -f {}/{}".format(currentDir, tmpFile)
522
+ commands_get_output(com)
523
+ for tmpFile in fullPathJobOs.values():
524
+ com = "rm -f {}/{}".format(currentDir, tmpFile)
525
+ commands_get_output(com)
526
+
527
+
528
+ # set extFile
529
+ extFile = []
530
+ user_set_ext_files = []
531
+
532
+
533
+ def setExtFile(v_extFile):
534
+ global extFile
535
+ extFile = v_extFile
536
+
537
+
538
+ def set_user_set_ext_files(v_user_set_ext_files):
539
+ global user_set_ext_files
540
+ user_set_ext_files = copy.copy(v_user_set_ext_files)
541
+
542
+
543
+ # set excludeFile
544
+ excludeFile = []
545
+
546
+
547
+ def setExcludeFile(strExcludeFile):
548
+ # empty
549
+ if strExcludeFile == "":
550
+ strExcludeFile = "jobReport.json,jobReport.txt,jobReportExtract.pickle"
551
+ else:
552
+ strExcludeFile += ",jobReport.json,jobReport.txt,jobReportExtract.pickle"
553
+ # convert to list
554
+ global excludeFile
555
+ for tmpItem in strExcludeFile.split(","):
556
+ tmpItem = tmpItem.strip()
557
+ if tmpItem == "":
558
+ continue
559
+ # change . to \. for regexp
560
+ tmpItem = tmpItem.replace(".", r"\.")
561
+ # change * to .* for regexp
562
+ tmpItem = tmpItem.replace("*", ".*")
563
+ # append
564
+ excludeFile.append(tmpItem)
565
+
566
+
567
+ # matching for extFiles
568
+ def matchExtFile(fileName):
569
+ # check exclude files
570
+ for tmpPatt in excludeFile:
571
+ if re.search(tmpPatt, fileName) is not None:
572
+ return False
573
+ # gather files with special extensions
574
+ for tmpExtention in [".py", ".dat", ".C", ".xml", "Makefile", ".cc", ".cxx", ".h", ".hh", ".sh", ".cpp", ".hpp"]:
575
+ if fileName.endswith(tmpExtention):
576
+ return True
577
+ # check filename
578
+ baseName = fileName.split("/")[-1]
579
+ for patt in extFile:
580
+ if patt.find("*") == -1:
581
+ # regular matching
582
+ if patt == baseName:
583
+ return True
584
+ # patt may contain / for sub dir
585
+ if patt != "" and re.search(patt, fileName) is not None:
586
+ return True
587
+ else:
588
+ # use regex for *
589
+ tmpPatt = patt.replace("*", ".*")
590
+ if re.search(tmpPatt, baseName) is not None:
591
+ return True
592
+ # patt may contain / for sub dir
593
+ if patt != "" and re.search(tmpPatt, fileName) is not None:
594
+ return True
595
+ # not matched
596
+ return False
597
+
598
+
599
+ # get extended extra stream name
600
+ def getExtendedExtStreamName(sIndex, sName, enableExtension=False, addEXTNPrefix=True):
601
+ tmpBaseExtName = "EXT%s" % sIndex if addEXTNPrefix else ""
602
+
603
+ if enableExtension:
604
+ if addEXTNPrefix:
605
+ tmpBaseExtName += "_"
606
+
607
+ # change * to X and add .tgz
608
+ if sName.find("*") != -1:
609
+ sName = sName.replace("*", "XYZ")
610
+ sName = "%s.tgz" % sName
611
+
612
+ # use extended extra stream name
613
+ tmpItems = sName.split(".")
614
+ if len(tmpItems) > 0:
615
+ tmpBaseExtName += tmpItems[0]
616
+
617
+ tmpLog = PLogger.getPandaLogger()
618
+ if not tmpBaseExtName:
619
+ tmpLog.error(
620
+ "Invalid stream extension name! If you use --useFileFieldAsStream, all %OUT instances in --trf must contain a distinct suffix, e.g. %OUT.AOD.pool.root"
621
+ )
622
+ sys.exit(EC_Config)
623
+
624
+ return tmpBaseExtName
625
+
626
+
627
+ # special files to be treated carefully
628
+ specialFilesForAthena = ["dblookup.xml"]
629
+
630
+
631
+ # archive source files
632
+ def archiveSourceFiles(workArea, runDir, currentDir, tmpDir, verbose, gluePackages=[], dereferenceSymLinks=False, archiveName=""):
633
+ # archive sources
634
+ tmpLog = PLogger.getPandaLogger()
635
+ tmpLog.info("archiving source files")
636
+
637
+ #####################################################################
638
+ # subroutines
639
+
640
+ # scan InstallArea to get a list of local packages
641
+ def getFileList(dir, files, forPackage, readLink=True):
642
+ try:
643
+ list = os.listdir(dir)
644
+ except Exception:
645
+ return
646
+ for item in list:
647
+ # skip if doc or .svn
648
+ if item in ["doc", ".svn", "_CPack_Packages"]:
649
+ continue
650
+ fullName = dir + "/" + item
651
+ if os.path.isdir(fullName):
652
+ # ignore symlinked dir just under InstallArea/include
653
+ # they are created for g77
654
+ if os.path.islink(fullName) and re.search("/InstallArea/include$", dir) is not None:
655
+ pass
656
+ elif os.path.islink(fullName) and readLink and forPackage:
657
+ # resolve symlink
658
+ getFileList(os.readlink(fullName), files, forPackage, readLink)
659
+ else:
660
+ getFileList(fullName, files, forPackage, readLink)
661
+ else:
662
+ if os.path.islink(fullName):
663
+ if readLink:
664
+ tmpLink = os.readlink(fullName)
665
+ # put base dir when relative path
666
+ if not tmpLink.startswith("/"):
667
+ tmpLink = dir + "/" + tmpLink
668
+ tmpLink = os.path.abspath(tmpLink)
669
+ appFileName = tmpLink
670
+ else:
671
+ appFileName = os.path.abspath(fullName)
672
+ else:
673
+ appFileName = os.path.abspath(fullName)
674
+ # remove redundant //
675
+ appFilename = re.sub("//", "/", appFileName)
676
+ # append
677
+ files.append(appFileName)
678
+
679
+ # get package list
680
+ def getPackages(_workArea, gluePackages=[]):
681
+ # get logger
682
+ tmpLog = PLogger.getPandaLogger()
683
+ # special packages
684
+ specialPackages = {"External/Lhapdf": "external/MCGenerators/lhapdf"}
685
+ # get file list
686
+ installFiles = []
687
+ getFileList(_workArea + "/InstallArea", installFiles, True)
688
+ # get list of packages
689
+ cmt_config = os.environ["CMTCONFIG"]
690
+ _packages = []
691
+ for iFile in installFiles:
692
+ # ignore InstallArea stuff
693
+ if re.search("/InstallArea/", iFile):
694
+ continue
695
+ # converted to real path
696
+ file = os.path.realpath(iFile)
697
+ # remove special characters
698
+ sString = re.sub(r"[\+]", ".", os.path.realpath(_workArea))
699
+ # look for /share/ , /python/, /i686-slc3-gcc323-opt/, .h
700
+ for target in ("share/", "python/", cmt_config + "/", r"[^/]+\.h"):
701
+ res = re.search(sString + "/(.+)/" + target, file)
702
+ if res:
703
+ # append
704
+ pName = res.group(1)
705
+ if target in [r"[^/]+\.h"]:
706
+ # convert PackageDir/PackageName/PackageName to PackageDir/PackageName
707
+ pName = re.sub("/[^/]+$", "", pName)
708
+ if pName not in _packages:
709
+ if os.path.isdir(_workArea + "/" + pName):
710
+ _packages.append(pName)
711
+ break
712
+ # check special packages just in case
713
+ for pName in specialPackages:
714
+ pPath = specialPackages[pName]
715
+ if pName not in _packages:
716
+ # look for path pattern
717
+ if re.search(pPath, file) is not None:
718
+ if os.path.isdir(_workArea + "/" + pName):
719
+ # check structured style
720
+ tmpDirList = os.listdir(_workArea + "/" + pName)
721
+ useSS = False
722
+ for tmpDir in tmpDirList:
723
+ if re.search(r"-\d+-\d+-\d+$", tmpDir) is not None:
724
+ _packages.append(pName + "/" + tmpDir)
725
+ useSS = True
726
+ break
727
+ # normal structure
728
+ if not useSS:
729
+ _packages.append(pName)
730
+ # delete since no needs anymore
731
+ del specialPackages[pName]
732
+ break
733
+ # check glue packages
734
+ for pName in gluePackages:
735
+ if pName not in _packages:
736
+ if os.path.isdir(_workArea + "/" + pName):
737
+ # check structured style
738
+ tmpDirList = os.listdir(_workArea + "/" + pName)
739
+ useSS = False
740
+ for tmpDir in tmpDirList:
741
+ if re.search(r"-\d+-\d+-\d+$", tmpDir) is not None:
742
+ fullPName = pName + "/" + tmpDir
743
+ if fullPName not in _packages:
744
+ _packages.append(fullPName)
745
+ useSS = True
746
+ break
747
+ # normal structure
748
+ if not useSS:
749
+ _packages.append(pName)
750
+ else:
751
+ tmpLog.warning("glue package {} not found under {}".format(pName, _workArea))
752
+ # return
753
+ return _packages
754
+
755
+ # archive files
756
+ def archiveFiles(_workArea, _packages, _archiveFullName):
757
+ excludePattern = ".svn"
758
+ for tmpPatt in excludeFile:
759
+ # reverse regexp change
760
+ tmpPatt = tmpPatt.replace(".*", "*")
761
+ tmpPatt = tmpPatt.replace(r"\.", ".")
762
+ excludePattern += " --exclude '%s'" % tmpPatt
763
+ _curdir = os.getcwd()
764
+ # change dir
765
+ os.chdir(_workArea)
766
+ for pack in _packages:
767
+ # archive subdirs
768
+ list = os.listdir(pack)
769
+ for item in list:
770
+ # ignore libraries
771
+ if (
772
+ item.startswith("i686")
773
+ or item.startswith("i386")
774
+ or item.startswith("x86_64")
775
+ or item == "pool"
776
+ or item == "pool_plugins"
777
+ or item == "doc"
778
+ or item == ".svn"
779
+ ):
780
+ continue
781
+ # check exclude files
782
+ excludeFileFlag = False
783
+ for tmpPatt in excludeFile:
784
+ if re.search(tmpPatt, "{}/{}".format(pack, item)) is not None:
785
+ excludeFileFlag = True
786
+ break
787
+ if excludeFileFlag:
788
+ continue
789
+ # run dir
790
+ if item == "run":
791
+ files = []
792
+ getFileList("{}/{}/run".format(_workArea, pack), files, False)
793
+ # not resolve symlink (appending instead of replacing for backward compatibility)
794
+ tmpFiles = []
795
+ getFileList("{}/{}/run".format(_workArea, pack), tmpFiles, False, False)
796
+ for tmpFile in tmpFiles:
797
+ if tmpFile not in files:
798
+ files.append(tmpFile)
799
+ for iFile in files:
800
+ # converted to real path
801
+ file = os.path.realpath(iFile)
802
+ # archive .py/.dat/.C files only
803
+ if matchExtFile(file):
804
+ # remove special characters
805
+ sString = re.sub(r"[\+]", ".", os.path.realpath(_workArea))
806
+ relPath = re.sub("^%s/" % sString, "", file)
807
+ # if replace is failed or the file is symlink, try non-converted path names
808
+ if relPath.startswith("/") or os.path.islink(iFile):
809
+ sString = re.sub(r"[\+]", ".", workArea)
810
+ relPath = re.sub(sString + "/", "", iFile)
811
+ if os.path.islink(iFile):
812
+ comStr = "tar -rh '{}' -f '{}' --exclude '{}'".format(relPath, _archiveFullName, excludePattern)
813
+ else:
814
+ comStr = "tar rf '{}' '{}' --exclude '{}'".format(_archiveFullName, relPath, excludePattern)
815
+ if verbose:
816
+ print(relPath)
817
+
818
+ commands_fail_on_non_zero_exit_status(comStr, EC_Archive, logger=tmpLog, error_log_msg="tarball creation failed")
819
+ continue
820
+ # else
821
+ if dereferenceSymLinks:
822
+ comStr = "tar rfh '{}' '{}/{}' --exclude '{}'".format(_archiveFullName, pack, item, excludePattern)
823
+ else:
824
+ comStr = "tar rf '{}' '{}/{}' --exclude '{}'".format(_archiveFullName, pack, item, excludePattern)
825
+
826
+ if verbose:
827
+ print("{}/{}".format(pack, item))
828
+
829
+ commands_fail_on_non_zero_exit_status(comStr, EC_Archive, logger=tmpLog, error_log_msg="tarball creation failed")
830
+ # back to previous dir
831
+ os.chdir(_curdir)
832
+
833
+ #####################################################################
834
+ # execute
835
+
836
+ # get packages in private area
837
+ packages = getPackages(workArea, gluePackages)
838
+ # check TestRelease since it doesn't create any links in InstallArea
839
+ if os.path.exists("%s/TestRelease" % workArea):
840
+ # the TestRelease could be created by hand
841
+ packages.append("TestRelease")
842
+
843
+ if verbose:
844
+ tmpLog.debug("== private packages ==")
845
+ for pack in packages:
846
+ print(pack)
847
+ tmpLog.debug("== private files ==")
848
+
849
+ # create archive
850
+ if archiveName == "":
851
+ archiveName = "sources.%s.tar" % MiscUtils.wrappedUuidGen()
852
+ archiveFullName = "{}/{}".format(tmpDir, archiveName)
853
+ # archive private area
854
+ archiveFiles(workArea, packages, archiveFullName)
855
+ # archive current (run) dir
856
+ files = []
857
+ os.chdir(workArea)
858
+ getFileList("{}/{}".format(workArea, runDir), files, False, False)
859
+ files_in_run_dir = []
860
+ for file in files:
861
+ # remove special characters
862
+ sString = re.sub(r"[\+]", ".", os.path.realpath(workArea))
863
+ relPath = re.sub(sString + "/", "", os.path.realpath(file))
864
+ # if replace is failed or the file is symlink, try non-converted path names
865
+ if relPath.startswith("/") or os.path.islink(file):
866
+ sString = re.sub(r"[\+]", ".", workArea)
867
+ relPath = re.sub(sString + "/", "", file)
868
+ # archive .py/.dat/.C/.xml files only
869
+ if not matchExtFile(relPath):
870
+ continue
871
+ # ignore InstallArea
872
+ if relPath.startswith("InstallArea"):
873
+ continue
874
+ # check special files
875
+ spBaseName = relPath
876
+ if re.search("/", spBaseName) is not None:
877
+ spBaseName = spBaseName.split("/")[-1]
878
+ if spBaseName in specialFilesForAthena:
879
+ warStr = "%s in the current dir is sent to remote WNs, which might cause a database problem. " % spBaseName
880
+ warStr += "If this is intentional please ignore this WARNING"
881
+ tmpLog.warning(warStr)
882
+ # check if already archived
883
+ alreadyFlag = False
884
+ for pack in packages:
885
+ if relPath.startswith(pack):
886
+ alreadyFlag = True
887
+ break
888
+ # archive
889
+ if not alreadyFlag:
890
+ if os.path.islink(file):
891
+ comStr = "tar -rh '{}' -f '{}'".format(relPath, archiveFullName)
892
+ else:
893
+ comStr = "tar rf '{}' '{}'".format(archiveFullName, relPath)
894
+ if verbose:
895
+ print(relPath)
896
+
897
+ commands_fail_on_non_zero_exit_status(comStr, EC_Archive, logger=tmpLog, error_log_msg="tarball creation failed")
898
+ files_in_run_dir.append(os.path.abspath(file))
899
+ # check if extFile is includedor tmp_file_path in files_in_run_dir):
900
+ for tmp_ext_file in user_set_ext_files:
901
+ is_included = False
902
+ for tmp_file_path in files_in_run_dir:
903
+ if re.search(tmp_ext_file, tmp_file_path):
904
+ is_included = True
905
+ break
906
+ if not is_included:
907
+ tmpLog.warning("%s is specified as extFile but not found in the current dir" % tmp_ext_file)
908
+ # back to current dir
909
+ os.chdir(currentDir)
910
+ # return
911
+ return archiveName, archiveFullName
912
+
913
+
914
+ # archive jobO files
915
+ def archiveJobOFiles(workArea, runDir, currentDir, tmpDir, verbose, archiveName=""):
916
+ # archive jobO files
917
+ tmpLog = PLogger.getPandaLogger()
918
+ tmpLog.info("archiving jobOs and modules")
919
+
920
+ # get real jobOs
921
+ def getJobOs(dir, files):
922
+ list = os.listdir(dir)
923
+ for item in list:
924
+ if item in ["_CPack_Packages"]:
925
+ continue
926
+ fullName = dir + "/" + item
927
+ if os.path.isdir(fullName):
928
+ # skip symlinks in include since they cause full scan on releases
929
+ if os.path.islink(fullName) and re.search("InstallArea/include$", dir) is not None:
930
+ continue
931
+ # dir
932
+ getJobOs(fullName, files)
933
+ else:
934
+ # python and other extFiles
935
+ if matchExtFile(fullName):
936
+ files.append(fullName)
937
+
938
+ # get jobOs
939
+ files = []
940
+ os.chdir(workArea)
941
+ getJobOs("%s" % workArea, files)
942
+ # create archive
943
+ if archiveName == "":
944
+ archiveName = "jobO.%s.tar" % MiscUtils.wrappedUuidGen()
945
+ archiveFullName = "{}/{}".format(tmpDir, archiveName)
946
+ # archive
947
+ if verbose:
948
+ tmpLog.debug("== py files ==")
949
+ for file in files:
950
+ # remove special characters
951
+ sString = re.sub(r"[\+]", ".", workArea)
952
+ relPath = re.sub(sString + "/", "", file)
953
+ # append
954
+ comStr = "tar -rh '{}' -f '{}'".format(relPath, archiveFullName)
955
+ if verbose:
956
+ print(relPath)
957
+
958
+ commands_fail_on_non_zero_exit_status(comStr, EC_Archive, logger=tmpLog, error_log_msg="tarball creation failed")
959
+
960
+ # return
961
+ return archiveName, archiveFullName
962
+
963
+
964
+ # archive InstallArea
965
+ def archiveInstallArea(workArea, groupArea, archiveName, archiveFullName, tmpDir, nobuild, verbose):
966
+ # archive jobO files
967
+ tmpLog = PLogger.getPandaLogger()
968
+ tmpLog.info("archiving InstallArea")
969
+
970
+ # get file list
971
+ def getFiles(dir, files, ignoreLib, ignoreSymLink):
972
+ if verbose:
973
+ tmpLog.debug(" getFiles(%s)" % dir)
974
+ try:
975
+ list = os.listdir(dir)
976
+ except Exception:
977
+ return
978
+ for item in list:
979
+ if ignoreLib and (item.startswith("i686") or item.startswith("i386") or item.startswith("x86_64")):
980
+ continue
981
+ fullName = dir + "/" + item
982
+ if os.path.isdir(fullName):
983
+ # ignore symlinked dir just under InstallArea/include
984
+ if ignoreSymLink and os.path.islink(fullName) and re.search("InstallArea/include$", dir) is not None:
985
+ continue
986
+ # dir
987
+ getFiles(fullName, files, False, ignoreSymLink)
988
+ else:
989
+ files.append(fullName)
990
+
991
+ # get cmt files
992
+ def getCMTFiles(dir, files):
993
+ list = os.listdir(dir)
994
+ for item in list:
995
+ fullName = dir + "/" + item
996
+ if os.path.isdir(fullName):
997
+ # dir
998
+ getCMTFiles(fullName, files)
999
+ else:
1000
+ if re.search("cmt/requirements$", fullName) is not None:
1001
+ files.append(fullName)
1002
+
1003
+ # get files
1004
+ areaList = []
1005
+ # workArea must be first
1006
+ areaList.append(workArea)
1007
+ if groupArea != "":
1008
+ areaList.append(groupArea)
1009
+ # groupArea archive
1010
+ groupFileName = re.sub("^sources", "groupArea", archiveName)
1011
+ groupFullName = "{}/{}".format(tmpDir, groupFileName)
1012
+ allFiles = []
1013
+ for areaName in areaList:
1014
+ # archive
1015
+ if verbose:
1016
+ tmpLog.debug("== InstallArea under %s ==" % areaName)
1017
+ files = []
1018
+ cmtFiles = []
1019
+ os.chdir(areaName)
1020
+ if areaName == workArea:
1021
+ if not nobuild:
1022
+ # ignore i686 and include for workArea
1023
+ getFiles("InstallArea", files, True, True)
1024
+ else:
1025
+ # ignore include for workArea
1026
+ getFiles("InstallArea", files, False, True)
1027
+ else:
1028
+ # groupArea
1029
+ if not os.path.exists("InstallArea"):
1030
+ if verbose:
1031
+ print(" Doesn't exist. Skip")
1032
+ continue
1033
+ getFiles("InstallArea", files, False, False)
1034
+ # cmt/requirements is needed for non-release packages
1035
+ for itemDir in os.listdir(areaName):
1036
+ if itemDir != "InstallArea" and os.path.isdir(itemDir) and (not os.path.islink(itemDir)):
1037
+ getCMTFiles(itemDir, cmtFiles)
1038
+ # remove special characters
1039
+ sString = re.sub(r"[\+]", ".", os.path.realpath(areaName))
1040
+ # archive files if they are under the area
1041
+ for file in files + cmtFiles:
1042
+ relPath = re.sub(sString + "/", "", os.path.realpath(file))
1043
+ # check exclude files
1044
+ excludeFileFlag = False
1045
+ for tmpPatt in excludeFile:
1046
+ if re.search(tmpPatt, relPath) is not None:
1047
+ excludeFileFlag = True
1048
+ break
1049
+ if excludeFileFlag:
1050
+ continue
1051
+ if not relPath.startswith("/"):
1052
+ # use files in private InstallArea instead of group InstallArea
1053
+ if file not in allFiles:
1054
+ # append
1055
+ if file in files:
1056
+ comStr = "tar -rh '{}' -f '{}'".format(file, archiveFullName)
1057
+ else:
1058
+ # requirements files
1059
+ comStr = "tar -rh '{}' -f '{}'".format(file, groupFullName)
1060
+ allFiles.append(file)
1061
+ if verbose:
1062
+ print(file)
1063
+
1064
+ commands_fail_on_non_zero_exit_status(comStr, EC_Archive, logger=tmpLog, error_log_msg="tarball creation failed")
1065
+
1066
+ # append groupArea to sources
1067
+ if groupArea != "" and (not nobuild):
1068
+ os.chdir(tmpDir)
1069
+ if os.path.exists(groupFileName):
1070
+ comStr = "tar -rh '{}' -f '{}'".format(groupFileName, archiveFullName)
1071
+ commands_fail_on_non_zero_exit_status(comStr, EC_Archive, logger=tmpLog, error_log_msg="tarball creation failed")
1072
+
1073
+ commands_get_output("rm -rf %s" % groupFullName)
1074
+
1075
+
1076
+ # archive with cpack
1077
+ def archiveWithCpack(withSource, tmpDir, verbose):
1078
+ tmpLog = PLogger.getPandaLogger()
1079
+ # define archive name
1080
+ if withSource:
1081
+ tmpLog.info("archiving source files with cpack")
1082
+ archiveName = "sources.%s" % MiscUtils.wrappedUuidGen()
1083
+ else:
1084
+ tmpLog.info("archiving jobOs and modules with cpack")
1085
+ archiveName = "jobO.%s" % MiscUtils.wrappedUuidGen()
1086
+ archiveFullName = "{}/{}".format(tmpDir, archiveName)
1087
+ # extract build dir
1088
+ buildDir = os.environ["CMAKE_PREFIX_PATH"]
1089
+ buildDir = os.path.dirname(buildDir.split(":")[0])
1090
+ _curdir = os.getcwd()
1091
+ os.chdir(buildDir)
1092
+ tmpLog.info(f"the build directory is {buildDir}")
1093
+ check_file = "CPackConfig.cmake"
1094
+ if os.path.exists(os.path.join(buildDir, check_file)):
1095
+ use_cpack = True
1096
+ comStr = f"cpack -B {tmpDir} -D CPACK_PACKAGE_FILE_NAME={archiveName} -G TGZ "
1097
+ comStr += '-D CPACK_PACKAGE_NAME="" -D CPACK_PACKAGE_VERSION="" -D CPACK_PACKAGE_VERSION_MAJOR="" '
1098
+ comStr += '-D CPACK_PACKAGE_VERSION_MINOR="" -D CPACK_PACKAGE_VERSION_PATCH="" '
1099
+ comStr += '-D CPACK_PACKAGE_DESCRIPTION="" '
1100
+
1101
+ commands_fail_on_non_zero_exit_status(comStr, EC_Config, verbose_cmd=verbose, verbose_output=verbose, logger=tmpLog, error_log_msg="cpack failed")
1102
+
1103
+ else:
1104
+ use_cpack = False
1105
+ tmpLog.info(f"skip cpack since {check_file} is missing in the build directory")
1106
+
1107
+ archiveName += ".tar"
1108
+ archiveFullName += ".tar"
1109
+ os.chdir(tmpDir)
1110
+ if use_cpack:
1111
+ # recreate tar to allow appending other files in the subsequent steps, as gzip decompress is not enough
1112
+ comStr = "tar xfz {0}.gz; tar cf {0} usr > /dev/null 2>&1; rm -rf usr _CPack_Packages {0}.gz".format(archiveName)
1113
+ else:
1114
+ comStr = f"tar cf {archiveName} -T /dev/null > /dev/null 2>&1"
1115
+
1116
+ commands_fail_on_non_zero_exit_status(comStr, EC_Archive, logger=tmpLog, error_log_msg="tarball creation failed")
1117
+
1118
+ os.chdir(_curdir)
1119
+ return archiveName, archiveFullName
1120
+
1121
+
1122
+ # convert runConfig to outMap
1123
+ def convertConfToOutput(
1124
+ runConfig,
1125
+ extOutFile,
1126
+ original_outDS,
1127
+ destination="",
1128
+ spaceToken="",
1129
+ descriptionInLFN="",
1130
+ allowNoOutput=None,
1131
+ appendFileFieldToStreamName=False,
1132
+ useEXTStreamName=True,
1133
+ extOutStreams=None,
1134
+ ):
1135
+ tmpLog = PLogger.getPandaLogger()
1136
+ outMap = {}
1137
+ paramList = []
1138
+ # add IROOT
1139
+ if "IROOT" not in outMap:
1140
+ outMap["IROOT"] = []
1141
+ # remove /
1142
+ outDSwoSlash = re.sub("/$", "", original_outDS)
1143
+ outDsNameBase = outDSwoSlash
1144
+ tmpMatch = re.search(r"^([^\.]+)\.([^\.]+)\.", original_outDS)
1145
+ if tmpMatch is not None and original_outDS.endswith("/"):
1146
+ outDSwoSlash = "{}.{}".format(tmpMatch.group(1), tmpMatch.group(2))
1147
+ if descriptionInLFN != "":
1148
+ outDSwoSlash += descriptionInLFN
1149
+ outDSwoSlash += ".$JEDITASKID"
1150
+ # start conversion
1151
+ if runConfig.output.outNtuple:
1152
+ for sName in runConfig.output.outNtuple:
1153
+ lfn = "{}.{}._${{SN/P}}.root".format(outDSwoSlash, sName)
1154
+ tmpSuffix = "_%s" % sName
1155
+ dataset = outDsNameBase + tmpSuffix + "/"
1156
+ if "ntuple" not in outMap:
1157
+ outMap["ntuple"] = []
1158
+ outMap["ntuple"].append((sName, lfn))
1159
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1160
+ if runConfig.output.outHist:
1161
+ lfn = "%s.hist._${SN/P}.root" % outDSwoSlash
1162
+ tmpSuffix = "_HIST"
1163
+ dataset = outDsNameBase + tmpSuffix + "/"
1164
+ outMap["hist"] = lfn
1165
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1166
+ if runConfig.output.outRDO:
1167
+ lfn = "%s.RDO._${SN/P}.pool.root" % outDSwoSlash
1168
+ tmpSuffix = "_RDO"
1169
+ dataset = outDsNameBase + tmpSuffix + "/"
1170
+ outMap["IROOT"].append((runConfig.output.outRDO, lfn))
1171
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1172
+ if runConfig.output.outESD:
1173
+ lfn = "%s.ESD._${SN/P}.pool.root" % outDSwoSlash
1174
+ tmpSuffix = "_ESD"
1175
+ dataset = outDsNameBase + tmpSuffix + "/"
1176
+ outMap["IROOT"].append((runConfig.output.outESD, lfn))
1177
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1178
+ if runConfig.output.outAOD:
1179
+ lfn = "%s.AOD._${SN/P}.pool.root" % outDSwoSlash
1180
+ tmpSuffix = "_AOD"
1181
+ dataset = outDsNameBase + tmpSuffix + "/"
1182
+ outMap["IROOT"].append((runConfig.output.outAOD, lfn))
1183
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1184
+ if runConfig.output.outTAG:
1185
+ lfn = "%s.TAG._${SN/P}.coll.root" % outDSwoSlash
1186
+ tmpSuffix = "_TAG"
1187
+ dataset = outDsNameBase + tmpSuffix + "/"
1188
+ outMap["TAG"] = lfn
1189
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1190
+ if runConfig.output.outAANT:
1191
+ sNameList = []
1192
+ fsNameMap = {}
1193
+ for aName, sName, fName in runConfig.output.outAANT:
1194
+ # use first sName when multiple streams write to the same file
1195
+ realStreamName = sName
1196
+ if fName in fsNameMap:
1197
+ sName = fsNameMap[fName]
1198
+ else:
1199
+ fsNameMap[fName] = sName
1200
+ lfn = "{}.{}._${{SN/P}}.root".format(outDSwoSlash, sName)
1201
+ tmpSuffix = "_%s" % sName
1202
+ dataset = outDsNameBase + tmpSuffix + "/"
1203
+ if sName not in sNameList:
1204
+ sNameList.append(sName)
1205
+ if "AANT" not in outMap:
1206
+ outMap["AANT"] = []
1207
+ outMap["AANT"].append((aName, realStreamName, lfn))
1208
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1209
+ if runConfig.output.outTHIST:
1210
+ for sName in runConfig.output.outTHIST:
1211
+ lfn = "{}.{}._${{SN/P}}.root".format(outDSwoSlash, sName)
1212
+ tmpSuffix = "_%s" % sName
1213
+ dataset = outDsNameBase + tmpSuffix + "/"
1214
+ if "THIST" not in outMap:
1215
+ outMap["THIST"] = []
1216
+ outMap["THIST"].append((sName, lfn))
1217
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1218
+ if runConfig.output.outIROOT:
1219
+ for sIndex, sName in enumerate(runConfig.output.outIROOT):
1220
+ lfn = "{}.iROOT{}._${{SN/P}}.{}".format(outDSwoSlash, sIndex, sName)
1221
+ tmpSuffix = "_iROOT%s" % sIndex
1222
+ dataset = outDsNameBase + tmpSuffix + "/"
1223
+ outMap["IROOT"].append((sName, lfn))
1224
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1225
+ if extOutFile:
1226
+ if extOutStreams is not None:
1227
+ if len(extOutStreams) != len(extOutFile):
1228
+ tmpLog.error("Missmatched --outputStreamNames (%s) to ext output files (%s)" % extOutStreams, extOutFile)
1229
+ sys.exit(EC_Config)
1230
+ if len(extOutStreams) != len(set(extOutStreams)):
1231
+ tmpLog.error("All output stream names indicated with --outputStreamNames (%s) must be different" % extOutStreams)
1232
+ sys.exit(EC_Config)
1233
+ streams = []
1234
+ for sIndex, sName in enumerate(extOutFile):
1235
+ # change * to X and add .tgz
1236
+ origSName = sName
1237
+ if sName.find("*") != -1:
1238
+ sName = sName.replace("*", "XYZ")
1239
+ sName = "%s.tgz" % sName
1240
+ tmpStreamName = (
1241
+ getExtendedExtStreamName(sIndex, sName, appendFileFieldToStreamName, useEXTStreamName) if extOutStreams is None else extOutStreams[sIndex]
1242
+ )
1243
+ streams.append(tmpStreamName)
1244
+ lfn = "{}.{}._${{SN/P}}.{}".format(outDSwoSlash, tmpStreamName, sName)
1245
+ tmpSuffix = "_%s" % tmpStreamName
1246
+ dataset = outDsNameBase + tmpSuffix + "/"
1247
+ outMap["IROOT"].append((origSName, lfn))
1248
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1249
+ if len(streams) != len(set(streams)):
1250
+ tmpLog.error("All output stream names taken from the %OUT declarations (e.g. %OUT.streamname.root) and --extOutFile must be different")
1251
+ sys.exit(EC_Config)
1252
+ if runConfig.output.outTAGX:
1253
+ for sName, oName in runConfig.output.outTAGX:
1254
+ lfn = "{}.{}._${{SN/P}}.{}".format(outDSwoSlash, sName, oName)
1255
+ tmpSuffix = "_%s" % sName
1256
+ dataset = outDsNameBase + tmpSuffix + "/"
1257
+ if "IROOT" not in outMap:
1258
+ outMap["IROOT"] = []
1259
+ outMap["IROOT"].append((oName, lfn))
1260
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1261
+ if runConfig.output.outStream1:
1262
+ lfn = "%s.Stream1._${SN/P}.pool.root" % outDSwoSlash
1263
+ tmpSuffix = "_Stream1"
1264
+ dataset = outDsNameBase + tmpSuffix + "/"
1265
+ outMap["IROOT"].append((runConfig.output.outStream1, lfn))
1266
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1267
+ if runConfig.output.outStream2:
1268
+ lfn = "%s.Stream2._${SN/P}.pool.root" % outDSwoSlash
1269
+ tmpSuffix = "_Stream2"
1270
+ dataset = outDsNameBase + tmpSuffix + "/"
1271
+ outMap["IROOT"].append((runConfig.output.outStream2, lfn))
1272
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1273
+ if runConfig.output.outBS:
1274
+ lfn = "%s.BS._${SN/P}.data" % outDSwoSlash
1275
+ tmpSuffix = "_BS"
1276
+ dataset = outDsNameBase + tmpSuffix + "/"
1277
+ outMap["BS"] = lfn
1278
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1279
+ if runConfig.output.outSelBS:
1280
+ lfn = "{}.{}._${{SN/P}}.data".format(outDSwoSlash, runConfig.output.outSelBS)
1281
+ tmpSuffix = "_SelBS"
1282
+ dataset = outDsNameBase + tmpSuffix + "/"
1283
+ if "IROOT" not in outMap:
1284
+ outMap["IROOT"] = []
1285
+ outMap["IROOT"].append(("%s.*.data" % runConfig.output.outSelBS, lfn))
1286
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1287
+ if runConfig.output.outStreamG:
1288
+ for sName, sOrigFileName in runConfig.output.outStreamG:
1289
+ lfn = "{}.{}._${{SN/P}}.pool.root".format(outDSwoSlash, sName)
1290
+ tmpSuffix = "_%s" % sName
1291
+ dataset = outDsNameBase + tmpSuffix + "/"
1292
+ outMap["IROOT"].append((sOrigFileName, lfn))
1293
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1294
+ if runConfig.output.outMeta:
1295
+ iMeta = 0
1296
+ for sName, sAsso in runConfig.output.outMeta:
1297
+ foundLFN = ""
1298
+ if sAsso == "None":
1299
+ # non-associated metadata
1300
+ lfn = "{}.META{}._${{SN/P}}.root".format(outDSwoSlash, iMeta)
1301
+ tmpSuffix = "_META%s" % iMeta
1302
+ dataset = outDsNameBase + tmpSuffix + "/"
1303
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1304
+ iMeta += 1
1305
+ foundLFN = lfn
1306
+ elif sAsso in outMap:
1307
+ # Stream1,2
1308
+ foundLFN = outMap[sAsso]
1309
+ elif sAsso in ["StreamESD", "StreamAOD"]:
1310
+ # ESD,AOD
1311
+ stKey = re.sub("^Stream", "", sAsso)
1312
+ if stKey in outMap:
1313
+ foundLFN = outMap[stKey]
1314
+ else:
1315
+ # check StreamG when ESD/AOD are not defined as algorithms
1316
+ if "StreamG" in outMap:
1317
+ for tmpStName, tmpLFN in outMap["StreamG"]:
1318
+ if tmpStName == sAsso:
1319
+ foundLFN = tmpLFN
1320
+ elif sAsso == "StreamRDO" and "StreamRDO" in outMap:
1321
+ # RDO
1322
+ stKey = re.sub("^Stream", "", sAsso)
1323
+ if stKey in outMap:
1324
+ foundLFN = outMap[stKey]
1325
+ else:
1326
+ # general stream
1327
+ if "StreamG" in outMap:
1328
+ for tmpStName, tmpLFN in outMap["StreamG"]:
1329
+ if tmpStName == sAsso:
1330
+ foundLFN = tmpLFN
1331
+ if foundLFN != "":
1332
+ if "Meta" not in outMap:
1333
+ outMap["Meta"] = []
1334
+ outMap["Meta"].append((sName, foundLFN))
1335
+ if runConfig.output.outMS:
1336
+ for sName, sAsso in runConfig.output.outMS:
1337
+ lfn = "{}.{}._${{SN/P}}.pool.root".format(outDSwoSlash, sName)
1338
+ tmpSuffix = "_%s" % sName
1339
+ dataset = outDsNameBase + tmpSuffix + "/"
1340
+ if "IROOT" not in outMap:
1341
+ outMap["IROOT"] = []
1342
+ outMap["IROOT"].append((sAsso, lfn))
1343
+ paramList += MiscUtils.makeJediJobParam(lfn, dataset, "output", hidden=True, allowNoOutput=allowNoOutput)
1344
+ if runConfig.output.outUserData:
1345
+ for sAsso in runConfig.output.outUserData:
1346
+ # look for associated LFN
1347
+ foundLFN = ""
1348
+ if sAsso in outMap:
1349
+ # Stream1,2
1350
+ foundLFN = outMap[sAsso]
1351
+ elif sAsso in ["StreamRDO", "StreamESD", "StreamAOD"]:
1352
+ # RDO,ESD,AOD
1353
+ stKey = re.sub("^Stream", "", sAsso)
1354
+ if stKey in outMap:
1355
+ foundLFN = outMap[stKey]
1356
+ else:
1357
+ # general stream
1358
+ if "StreamG" in outMap:
1359
+ for tmpStName, tmpLFN in outMap["StreamG"]:
1360
+ if tmpStName == sAsso:
1361
+ foundLFN = tmpLFN
1362
+ if foundLFN != "":
1363
+ if "UserData" not in outMap:
1364
+ outMap["UserData"] = []
1365
+ outMap["UserData"].append(foundLFN)
1366
+ # remove IROOT if unnecessary
1367
+ if "IROOT" in outMap:
1368
+ if outMap["IROOT"] == []:
1369
+ del outMap["IROOT"]
1370
+ else:
1371
+ # check invalid characters
1372
+ for stream, lfn in outMap["IROOT"]:
1373
+ checked = check_invalid_char(stream, is_file=True)
1374
+ if checked is not None:
1375
+ tmp_log = PLogger.getPandaLogger()
1376
+ tmp_log.error('Invalid character "{}" used in output filename {}'.format(checked, stream))
1377
+ sys.exit(EC_Config)
1378
+
1379
+ # set destination
1380
+ if destination != "":
1381
+ for tmpParam in paramList:
1382
+ tmpParam["destination"] = destination
1383
+ # set token
1384
+ if spaceToken != "":
1385
+ for tmpParam in paramList:
1386
+ tmpParam["token"] = spaceToken
1387
+ # return
1388
+ return outMap, paramList
1389
+
1390
+
1391
+ # get CMTCONFIG + IMG
1392
+ def getCmtConfigImg(athenaVer=None, cacheVer=None, nightVer=None, cmtConfig=None, verbose=False, architecture=None):
1393
+ # check if json
1394
+ is_json = False
1395
+ if architecture and "{" in architecture:
1396
+ try:
1397
+ architecture = json.loads(architecture)
1398
+ is_json = True
1399
+ except Exception as e:
1400
+ tmp_log = PLogger.getPandaLogger()
1401
+ tmp_log.error("failed to parse architecture {} : {}".format(architecture, e))
1402
+ sys.exit(EC_Config)
1403
+ # get CMTCONFIG
1404
+ cmt_config = ""
1405
+ spec_str = ""
1406
+ if architecture and not is_json:
1407
+ tmp_m = re.search("^[^@&#]+", architecture)
1408
+ if tmp_m:
1409
+ cmt_config = tmp_m.group(0)
1410
+ spec_str = architecture.replace(cmt_config, "")
1411
+ else:
1412
+ tmp_m = re.search("[@&#].+$", architecture)
1413
+ if tmp_m:
1414
+ spec_str = tmp_m.group(0)
1415
+ if not cmt_config:
1416
+ cmt_config = getCmtConfig(athenaVer, cacheVer, nightVer, cmtConfig, verbose)
1417
+ if is_json and cmt_config and "sw_platform" not in architecture:
1418
+ architecture["sw_platform"] = cmt_config
1419
+ # get base platform + HW specs
1420
+ if spec_str:
1421
+ pass
1422
+ elif "ALRB_USER_PLATFORM" in os.environ:
1423
+ # base platform + HW specs from ALRB
1424
+ spec_str = "@" + os.environ["ALRB_USER_PLATFORM"]
1425
+ if is_json and "cpu_specs" not in architecture and "gpu_spec" not in architecture:
1426
+ architecture["encoded_platform"] = os.environ["ALRB_USER_PLATFORM"]
1427
+ else:
1428
+ # architecture w/o base platform or even empty architecture
1429
+ spec_str = architecture
1430
+ # append base platform + HW specs if any
1431
+ if spec_str and not is_json:
1432
+ if cmt_config is None:
1433
+ cmt_config = ""
1434
+ cmt_config = cmt_config + spec_str
1435
+ if is_json:
1436
+ return json.dumps(architecture)
1437
+ return cmt_config
1438
+
1439
+
1440
+ # get CMTCONFIG
1441
+ def getCmtConfig(athenaVer=None, cacheVer=None, nightVer=None, cmtConfig=None, verbose=False):
1442
+ # use user-specified cmtconfig
1443
+ if cmtConfig:
1444
+ return cmtConfig
1445
+ # local settting
1446
+ if "CMTCONFIG" in os.environ:
1447
+ return os.environ["CMTCONFIG"]
1448
+ # undefined in Athena
1449
+ if athenaVer or cacheVer:
1450
+ # get logger
1451
+ tmpLog = PLogger.getPandaLogger()
1452
+ tmpLog.error("environment variable CMTCONFIG is undefined. Please set --cmtConfig")
1453
+ sys.exit(EC_Config)
1454
+ return None
1455
+
1456
+
1457
+ # check CMTCONFIG
1458
+ def checkCmtConfig(localCmtConfig, userCmtConfig, noBuild):
1459
+ # didn't specify CMTCONFIG
1460
+ if userCmtConfig in ["", None]:
1461
+ return True
1462
+ # CVMFS version format
1463
+ if re.search(r"-gcc\d+\.\d+$", userCmtConfig) is not None:
1464
+ return True
1465
+ # get logger
1466
+ tmpLog = PLogger.getPandaLogger()
1467
+ # CMTCONFIG is undefined locally
1468
+ if localCmtConfig in ["", None]:
1469
+ return True
1470
+ # user-specified CMTCONFIG is inconsitent with local CMTCONFIG
1471
+ if userCmtConfig != localCmtConfig and noBuild:
1472
+ errStr = "You cannot use --noBuild when --cmtConfig={} is inconsistent with local CMTCONFIG={} ".format(userCmtConfig, localCmtConfig)
1473
+ errStr += "since you need re-compile source files on remote worker-node. Please remove --noBuild"
1474
+ tmpLog.error(errStr)
1475
+ return False
1476
+ # return OK
1477
+ return True
1478
+
1479
+
1480
+ # use AMI for AutoConf
1481
+ def getJobOtoUseAmiForAutoConf(inDS, tmpDir):
1482
+ # no input
1483
+ if inDS == "":
1484
+ return ""
1485
+ # use first one
1486
+ amiURL = "ami://%s" % inDS.split(",")[0]
1487
+ # remove /
1488
+ if amiURL.endswith("/"):
1489
+ amiURL = amiURL[:-1]
1490
+ inputFiles = [amiURL]
1491
+ # create jobO fragment
1492
+ optFileName = tmpDir + "/" + MiscUtils.wrappedUuidGen() + ".py"
1493
+ oFile = open(optFileName, "w")
1494
+ oFile.write(
1495
+ """
1496
+ try:
1497
+ import AthenaCommon.AthenaCommonFlags
1498
+
1499
+ def _dummyFilesInput(*argv):
1500
+ return %s
1501
+
1502
+ AthenaCommon.AthenaCommonFlags.FilesInput.__call__ = _dummyFilesInput
1503
+ except Exception:
1504
+ pass
1505
+
1506
+ try:
1507
+ import AthenaCommon.AthenaCommonFlags
1508
+
1509
+ def _dummyGet_Value(*argv):
1510
+ return %s
1511
+
1512
+ for tmpAttr in dir (AthenaCommon.AthenaCommonFlags):
1513
+ import re
1514
+ if re.search('^(Pool|BS).*Input$',tmpAttr) is not None:
1515
+ try:
1516
+ getattr(AthenaCommon.AthenaCommonFlags,tmpAttr).get_Value = _dummyGet_Value
1517
+ except Exception:
1518
+ pass
1519
+ except Exception:
1520
+ pass
1521
+ """
1522
+ % (inputFiles, inputFiles)
1523
+ )
1524
+ oFile.close()
1525
+ # return file name
1526
+ return optFileName
1527
+
1528
+
1529
+ # use CMake
1530
+ def useCMake():
1531
+ return "CMAKE_PREFIX_PATH" in os.environ
1532
+
1533
+
1534
+ # parse athenaTag
1535
+ def parse_athena_tag(athena_tag, verbose, tmp_log):
1536
+ athenaVer = ""
1537
+ cacheVer = ""
1538
+ nightVer = ""
1539
+ # loop over all tags
1540
+ items = athena_tag.split(",")
1541
+ usingNightlies = False
1542
+ for item in items:
1543
+ # releases
1544
+ match = re.search(r"^(\d+\.\d+\.\d+)", item)
1545
+ if match:
1546
+ athenaVer = "Atlas-%s" % match.group(1)
1547
+ # cache
1548
+ cmatch = re.search(r"^(\d+\.\d+\.\d+\.\d+\.*\d*)$", item)
1549
+ if cmatch is not None:
1550
+ cacheVer += "_%s" % cmatch.group(1)
1551
+ else:
1552
+ cacheVer += "_%s" % match.group(1)
1553
+ continue
1554
+ # nightlies
1555
+ match = re.search(r"^(\d+\.\d+\.X|\d+\.X\.\d+)$", item)
1556
+ if match:
1557
+ athenaVer = "Atlas-%s" % match.group(1)
1558
+ continue
1559
+ # master or XX.YY
1560
+ match = re.search(r"^\d+\.\d+$", item)
1561
+ if item.startswith("master") or match or item == "main":
1562
+ athenaVer = "Atlas-%s" % item
1563
+ continue
1564
+ # old nightlies
1565
+ if item.startswith("rel_"):
1566
+ usingNightlies = True
1567
+ if "dev" in items:
1568
+ athenaVer = "Atlas-dev"
1569
+ elif "devval" in items:
1570
+ athenaVer = "Atlas-devval"
1571
+ cacheVer = "-AtlasOffline_%s" % item
1572
+ continue
1573
+ # nightlies
1574
+ if item in ["latest", "r27"] or re.search(r"^\d{4}-\d{2}-\d{2}T\d{4}$", item):
1575
+ cacheVer += "_%s" % item
1576
+ continue
1577
+ # CMTCONFIG
1578
+ if item in ["32", "64"]:
1579
+ tmp_log.error("%s in --athenaTag is unsupported. Please use --cmtConfig instead" % item)
1580
+ sys.exit(EC_Config)
1581
+ # ignoring AtlasOffline
1582
+ if item in ["AtlasOffline"]:
1583
+ continue
1584
+ # regarded as project
1585
+ cacheVer = "-" + item + cacheVer
1586
+ # check cache
1587
+ if re.search(r"^-.+_.+$", cacheVer) is None:
1588
+ if re.search(r"^_\d+\.\d+\.\d+\.\d+$", cacheVer) is not None:
1589
+ # use AtlasProduction
1590
+ cacheVer = "-AtlasProduction" + cacheVer
1591
+ elif "AthAnalysisBase" in cacheVer or "AthAnalysis" in cacheVer:
1592
+ # AthAnalysis
1593
+ cacheVer = cacheVer + "_%s" % athenaVer
1594
+ athenaVer = ""
1595
+ else:
1596
+ # unknown
1597
+ cacheVer = ""
1598
+ # use dev nightlies
1599
+ if usingNightlies and athenaVer == "":
1600
+ athenaVer = "Atlas-dev"
1601
+ return athenaVer, cacheVer, nightVer