CMS 3D CMS Logo

runTheMatrix.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 from __future__ import print_function
3 import sys, os
4 
5 from Configuration.PyReleaseValidation.MatrixReader import MatrixReader
6 from Configuration.PyReleaseValidation.MatrixRunner import MatrixRunner
7 from Configuration.PyReleaseValidation.MatrixInjector import MatrixInjector,performInjectionOptionTest
8 
9 # ================================================================================
10 
11 def showRaw(opt):
12 
13  mrd = MatrixReader(opt)
14  mrd.showRaw(opt.useInput, opt.refRel, opt.fromScratch, opt.raw, opt.step1Only, selected=opt.testList)
15 
16  return 0
17 
18 # ================================================================================
19 
20 def runSelected(opt):
21 
22  mrd = MatrixReader(opt)
23  mrd.prepare(opt.useInput, opt.refRel, opt.fromScratch)
24 
25  # test for wrong input workflows
26  if opt.testList:
27  definedWf = [dwf.numId for dwf in mrd.workFlows]
28  definedSet = set(definedWf)
29  testSet = set(opt.testList)
30  undefSet = testSet - definedSet
31  if len(undefSet)>0: raise ValueError('Undefined workflows: '+', '.join(map(str,list(undefSet))))
32  duplicates = [wf for wf in testSet if definedWf.count(wf)>1 ]
33  if len(duplicates)>0: raise ValueError('Duplicated workflows: '+', '.join(map(str,list(duplicates))))
34 
35  ret = 0
36  if opt.show:
37  mrd.show(opt.testList, opt.extended, opt.cafVeto)
38  if opt.testList : print('testListected items:', opt.testList)
39  else:
40  mRunnerHi = MatrixRunner(mrd.workFlows, opt.nProcs, opt.nThreads)
41  ret = mRunnerHi.runTests(opt)
42 
43  if opt.wmcontrol:
44  if ret!=0:
45  print('Cannot go on with wmagent injection with failing workflows')
46  else:
47  wfInjector = MatrixInjector(opt,mode=opt.wmcontrol,options=opt.wmoptions)
48  ret= wfInjector.prepare(mrd,
49  mRunnerHi.runDirs)
50  if ret==0:
51  wfInjector.upload()
52  wfInjector.submit()
53  return ret
54 
55 # ================================================================================
56 
57 if __name__ == '__main__':
58 
59  #this can get out of here
60  predefinedSet={
61  'limited' : [5.1, #FastSim ttbar
62  7.3, #CosmicsSPLoose_UP17
63  8, #BH/Cosmic MC
64  25, #MC ttbar
65  4.22, #cosmic data
66  4.53, #run1 data + miniAOD
67  9.0, #Higgs200 charged taus
68  1000, #data+prompt
69  1001, #data+express
70  101.0, #SingleElectron120E120EHCAL
71  136.731, #2016B Photon data
72  136.7611, #2016E JetHT reMINIAOD from 80X legacy
73  136.8311, #2017F JetHT reMINIAOD from 94X reprocessing
74  136.88811,#2018D JetHT reMINIAOD from UL processing
75  136.793, #2017C DoubleEG
76  136.874, #2018C EGamma
77  138.4, #2021 MinimumBias prompt reco
78  138.5, #2021 MinimumBias express
79  139.001, #2021 MinimumBias offline with HLT step
80  140.53, #2011 HI data
81  140.56, #2018 HI data
82  158.01, #reMiniAOD of 2018 HI MC with pp-like reco
83  312.0, #2021/Run3 HI MC Pyquen_ZeemumuJets_pt10 with pp-like reco
84  1306.0, #SingleMu Pt1 UP15
85  2500.4, #test NanoAOD from existing MINI
86  1330, #Run2 2015/2016 MC Zmm
87  135.4, #Run 2 2015/2016 Zee ttbar fastsim
88  10042.0, #2017 ZMM
89  10024.0, #2017 ttbar
90  10824.0, #2018 ttbar
91  2018.1, #2018 ttbar fastsim
92  11634.911, #2021 DD4hep ttbar reading geometry from XML
93  11634.914, #2021 DDD ttbar reading geometry from the DB
94  11634.0, #2021 ttbar (switching to DD4hep by default)
95  13234.0, #2021 ttbar fastsim
96  12434.0, #2023 ttbar
97  12634.0, #2023 ttbar PU
98  12434.7, #2023 ttbar mkFit
99  14034.0, #2023 ttbar fastsim
100  14234.0, #2023 ttbar PU fastsim
101  24834.0, #2026D98 ttbar (Phase-2 baseline)
102  24834.911, #2026D98 ttbar DD4hep XML
103  25034.999, #2026D98 ttbar premixing stage1+stage2, PU50
104  24896.0, #CE_E_Front_120um D98
105  24900.0, #CE_H_Coarse_Scint D98
106  23234.0, #2026D94 ttbar (exercise with HFNose)
107  25202.0, #2016 ttbar UP15 PU
108  250202.181, #2018 ttbar stage1 + stage2 premix
109  141.044 # 2023D JetMET PD
110  ],
111  'jetmc': [5.1, 13, 15, 25, 38, 39], #MC
112  'metmc' : [5.1, 15, 25, 37, 38, 39], #MC
113  'muonmc' : [5.1, 124.4, 124.5, 20, 21, 22, 23, 25, 30], #MC
114  }
115 
116 
117  import argparse
118  usage = 'usage: runTheMatrix.py --show -s '
119 
120  parser = argparse.ArgumentParser(usage,formatter_class=argparse.ArgumentDefaultsHelpFormatter)
121 
122  parser.add_argument('-b','--batchName',
123  help='relval batch: suffix to be appended to Campaign name',
124  dest='batchName',
125  default='')
126 
127  parser.add_argument('-m','--memoryOffset',
128  help='memory of the wf for single core',
129  dest='memoryOffset',
130  type=int,
131  default=3000)
132 
133  parser.add_argument('--addMemPerCore',
134  help='increase of memory per each n > 1 core: memory(n_core) = memoryOffset + (n_core-1) * memPerCore',
135  dest='memPerCore',
136  type=int,
137  default=1500)
138 
139  parser.add_argument('-j','--nproc',
140  help='number of processes. 0 Will use 4 processes, not execute anything but create the wfs',
141  dest='nProcs',
142  type=int,
143  default=4)
144 
145  parser.add_argument('-t','--nThreads',
146  help='number of threads per process to use in cmsRun.',
147  dest='nThreads',
148  type=int,
149  default=1)
150 
151  parser.add_argument('--nStreams',
152  help='number of streams to use in cmsRun.',
153  dest='nStreams',
154  type=int,
155  default=0)
156 
157  parser.add_argument('--nEvents',
158  help='number of events to process in cmsRun. If 0 will use the standard 10 events.',
159  dest='nEvents',
160  type=int,
161  default=0)
162 
163  parser.add_argument('--numberEventsInLuminosityBlock',
164  help='number of events in a luminosity block',
165  dest='numberEventsInLuminosityBlock',
166  type=int,
167  default=-1)
168 
169  parser.add_argument('-n','--showMatrix',
170  help='Only show the worflows. Use --ext to show more',
171  dest='show',
172  default=False,
173  action='store_true')
174 
175  parser.add_argument('-e','--extended',
176  help='Show details of workflows, used with --show',
177  dest='extended',
178  default=False,
179  action='store_true')
180 
181  parser.add_argument('-s','--selected',
182  help='Run a pre-defined selected matrix of wf. Deprecated, please use -l limited',
183  dest='restricted',
184  default=False,
185  action='store_true')
186 
187  parser.add_argument('-l','--list',
188  help='Comma separated list of workflow to be shown or ran. Possible keys are also '+str(predefinedSet.keys())+'. and wild card like muon, or mc',
189  dest='testList',
190  default=None)
191 
192  parser.add_argument('-f','--failed-from',
193  help='Provide a matrix report to specify the workflows to be run again. Augments the -l option if specified already',
194  dest='failed_from',
195  default=None)
196 
197  parser.add_argument('-r','--raw',
198  help='Temporary dump the .txt needed for prodAgent interface. To be discontinued soon. Argument must be the name of the set (standard, pileup,...)',
199  dest='raw')
200 
201  parser.add_argument('-i','--useInput',
202  help='Use recyling where available. Either all, or a comma separated list of wf number.',
203  dest='useInput',
204  type=lambda x: x.split(','),
205  default=None)
206 
207  parser.add_argument('-w','--what',
208  help='Specify the set to be used. Argument must be the name of a set (standard, pileup,...) or multiple sets separated by commas (--what standard,pileup )',
209  dest='what',
210  default='all')
211 
212  parser.add_argument('--step1',
213  help='Used with --raw. Limit the production to step1',
214  dest='step1Only',
215  default=False)
216 
217  parser.add_argument('--maxSteps',
218  help='Only run maximum on maxSteps. Used when we are only interested in first n steps.',
219  dest='maxSteps',
220  default=9999,
221  type=int)
222 
223  parser.add_argument('--fromScratch',
224  help='Comma separated list of wf to be run without recycling. all is not supported as default.',
225  dest='fromScratch',
226  type=lambda x: x.split(','),
227  default=None)
228 
229  parser.add_argument('--refRelease',
230  help='Allow to modify the recycling dataset version',
231  dest='refRel',
232  default=None)
233 
234  parser.add_argument('--wmcontrol',
235  help='Create the workflows for injection to WMAgent. In the WORKING. -wmcontrol init will create the the workflows, -wmcontrol test will dryRun a test, -wmcontrol submit will submit to wmagent',
236  choices=['init','test','submit','force'],
237  dest='wmcontrol',
238  default=None)
239 
240  parser.add_argument('--revertDqmio',
241  help='When submitting workflows to wmcontrol, force DQM outout to use pool and not DQMIO',
242  choices=['yes','no'],
243  dest='revertDqmio',
244  default='no')
245 
246  parser.add_argument('--optionswm',
247  help='Specify a few things for wm injection',
248  default='',
249  dest='wmoptions')
250 
251  parser.add_argument('--keep',
252  help='allow to specify for which comma separated steps the output is needed',
253  default=None)
254 
255  parser.add_argument('--label',
256  help='allow to give a special label to the output dataset name',
257  default='')
258 
259  parser.add_argument('--command',
260  help='provide a way to add additional command to all of the cmsDriver commands in the matrix',
261  dest='command',
262  action='append',
263  default=None)
264 
265  parser.add_argument('--apply',
266  help='allow to use the --command only for 1 comma separeated',
267  dest='apply',
268  default=None)
269 
270  parser.add_argument('--workflow',
271  help='define a workflow to be created or altered from the matrix',
272  action='append',
273  dest='workflow',
274  default=None)
275 
276  parser.add_argument('--dryRun',
277  help='do not run the wf at all',
278  action='store_true',
279  dest='dryRun',
280  default=False)
281 
282  parser.add_argument('--testbed',
283  help='workflow injection to cmswebtest (you need dedicated rqmgr account)',
284  dest='testbed',
285  default=False,
286  action='store_true')
287 
288  parser.add_argument('--noCafVeto',
289  help='Run from any source, ignoring the CAF label',
290  dest='cafVeto',
291  default=True,
292  action='store_false')
293 
294  parser.add_argument('--overWrite',
295  help='Change the content of a step for another. List of pairs.',
296  dest='overWrite',
297  default=None)
298 
299  parser.add_argument('--noRun',
300  help='Remove all run list selection from wfs',
301  dest='noRun',
302  default=False,
303  action='store_true')
304 
305  parser.add_argument('--das-options',
306  help='Options to be passed to dasgoclient.',
307  dest='dasOptions',
308  default="--limit 0",
309  action='store')
310 
311  parser.add_argument('--job-reports',
312  help='Dump framework job reports',
313  dest='jobReports',
314  default=False,
315  action='store_true')
316 
317  parser.add_argument('--ibeos',
318  help='Use IB EOS site configuration',
319  dest='IBEos',
320  default=False,
321  action='store_true')
322 
323  parser.add_argument('--sites',
324  help='Run DAS query to get data from a specific site. Set it to empty string to search all sites.',
325  dest='dasSites',
326  default='T2_CH_CERN',
327  action='store')
328 
329  parser.add_argument('--interactive',
330  help="Open the Matrix interactive shell",
331  action='store_true',
332  default=False)
333 
334  parser.add_argument('--dbs-url',
335  help='Overwrite DbsUrl value in JSON submitted to ReqMgr2',
336  dest='dbsUrl',
337  default=None,
338  action='store')
339 
340  gpugroup = parser.add_argument_group('GPU-related options','These options are only meaningful when --gpu is used, and is not set to forbidden.')
341 
342  gpugroup.add_argument('--gpu','--requires-gpu',
343  help='Enable GPU workflows. Possible options are "forbidden" (default), "required" (implied if no argument is given), or "optional".',
344  dest='gpu',
345  choices=['forbidden', 'optional', 'required'],
346  nargs='?',
347  const='required',
348  default='forbidden',
349  action='store')
350 
351  gpugroup.add_argument('--gpu-memory',
352  help='Specify the minimum amount of GPU memory required by the job, in MB.',
353  dest='GPUMemoryMB',
354  type=int,
355  default=8000)
356 
357  gpugroup.add_argument('--cuda-capabilities',
358  help='Specify a comma-separated list of CUDA "compute capabilities", or GPU hardware architectures, that the job can use.',
359  dest='CUDACapabilities',
360  type=lambda x: x.split(','),
361  default='6.0,6.1,6.2,7.0,7.2,7.5,8.0,8.6')
362 
363  # read the CUDA runtime version included in CMSSW
364  cudart_version = None
365  libcudart = os.path.realpath(os.path.expandvars('$CMSSW_RELEASE_BASE/external/$SCRAM_ARCH/lib/libcudart.so'))
366  if os.path.isfile(libcudart):
367  cudart_basename = os.path.basename(libcudart)
368  cudart_version = '.'.join(cudart_basename.split('.')[2:4])
369  gpugroup.add_argument('--cuda-runtime',
370  help='Specify major and minor version of the CUDA runtime used to build the application.',
371  dest='CUDARuntime',
372  default=cudart_version)
373 
374  gpugroup.add_argument('--force-gpu-name',
375  help='Request a specific GPU model, e.g. "Tesla T4" or "NVIDIA GeForce RTX 2080". The default behaviour is to accept any supported GPU.',
376  dest='GPUName',
377  default='')
378 
379  gpugroup.add_argument('--force-cuda-driver-version',
380  help='Request a specific CUDA driver version, e.g. 470.57.02. The default behaviour is to accept any supported CUDA driver version.',
381  dest='CUDADriverVersion',
382  default='')
383 
384  gpugroup.add_argument('--force-cuda-runtime-version',
385  help='Request a specific CUDA runtime version, e.g. 11.4. The default behaviour is to accept any supported CUDA runtime version.',
386  dest='CUDARuntimeVersion',
387  default='')
388 
389  opt = parser.parse_args()
390  if opt.command: opt.command = ' '.join(opt.command)
391  os.environ["CMSSW_DAS_QUERY_SITES"]=opt.dasSites
392  if opt.failed_from:
393  rerunthese=[]
394  with open(opt.failed_from,'r') as report:
395  for report_line in report:
396  if 'FAILED' in report_line:
397  to_run,_=report_line.split('_',1)
398  rerunthese.append(to_run)
399  if opt.testList:
400  opt.testList+=','.join(['']+rerunthese)
401  else:
402  opt.testList = ','.join(rerunthese)
403 
404  if opt.IBEos:
405  from subprocess import getstatusoutput as run_cmd
406 
407  ibeos_cache = os.path.join(os.getenv("LOCALRT"), "ibeos_cache.txt")
408  if not os.path.exists(ibeos_cache):
409  err, out = run_cmd("curl -L -s -o %s https://raw.githubusercontent.com/cms-sw/cms-sw.github.io/master/das_queries/ibeos.txt" % ibeos_cache)
410  if err:
411  run_cmd("rm -f %s" % ibeos_cache)
412  print("Error: Unable to download ibeos cache information")
413  print(out)
414  sys.exit(err)
415 
416  for cmssw_env in [ "CMSSW_BASE", "CMSSW_RELEASE_BASE" ]:
417  cmssw_base = os.getenv(cmssw_env,None)
418  if not cmssw_base: continue
419  cmssw_base = os.path.join(cmssw_base,"src/Utilities/General/ibeos")
420  if os.path.exists(cmssw_base):
421  os.environ["PATH"]=cmssw_base+":"+os.getenv("PATH")
422  os.environ["CMS_PATH"]="/cvmfs/cms-ib.cern.ch"
423  os.environ["SITECONFIG_PATH"]="/cvmfs/cms-ib.cern.ch/SITECONF/local"
424  os.environ["CMSSW_USE_IBEOS"]="true"
425  print(">> WARNING: You are using SITECONF from /cvmfs/cms-ib.cern.ch")
426  break
427  if opt.restricted:
428  print('Deprecated, please use -l limited')
429  if opt.testList: opt.testList+=',limited'
430  else: opt.testList='limited'
431 
432  def stepOrIndex(s):
433  if s.isdigit():
434  return int(s)
435  else:
436  return s
437  if opt.apply:
438  opt.apply=map(stepOrIndex,opt.apply.split(','))
439  if opt.keep:
440  opt.keep=map(stepOrIndex,opt.keep.split(','))
441 
442  if opt.testList:
443  testList=[]
444  for entry in opt.testList.split(','):
445  if not entry: continue
446  mapped=False
447  for k in predefinedSet:
448  if k.lower().startswith(entry.lower()) or k.lower().endswith(entry.lower()):
449  testList.extend(predefinedSet[k])
450  mapped=True
451  break
452  if not mapped:
453  try:
454  testList.append(float(entry))
455  except:
456  print(entry,'is not a possible selected entry')
457 
458  opt.testList = list(set(testList))
459 
460  if opt.wmcontrol:
462  if opt.overWrite:
463  opt.overWrite=eval(opt.overWrite)
464  if opt.interactive:
465  import cmd
466  from colorama import Fore, Style
467  from os import isatty
468  import subprocess
469  import time
470 
471  class TheMatrix(cmd.Cmd):
472  intro = "Welcome to the Matrix (? for help)"
473  prompt = "matrix> "
474 
475  def __init__(self, opt):
476  cmd.Cmd.__init__(self)
477  self.opt_ = opt
478  self.matrices_ = {}
479  tmp = MatrixReader(self.opt_)
480  self.processes_ = dict()
481  for what in tmp.files:
482  what = what.replace('relval_','')
483  self.opt_.what = what
484  self.matrices_[what] = MatrixReader(self.opt_)
485  self.matrices_[what].prepare(self.opt_.useInput, self.opt_.refRel,
486  self.opt_.fromScratch)
487  os.system("clear")
488 
489  def do_clear(self, arg):
490  """Clear the screen, put prompt at the top"""
491  os.system("clear")
492 
493  def do_exit(self, arg):
494  print("Leaving the Matrix")
495  return True
496 
497  def default(self, inp):
498  if inp == 'x' or inp == 'q':
499  return self.do_exit(inp)
500  else:
501  is_pipe = not isatty(sys.stdin.fileno())
502  print(Fore.RED + "Error: " + Fore.RESET + "unrecognized command.")
503  # Quit only if given a piped command.
504  if is_pipe:
505  sys.exit(1)
506 
507  def help_predefined(self):
508  print("\n".join(["predefined [predef1 [...]]\n",
509  "Run w/o argument, it will print the list of known predefined workflows.",
510  "Run with space-separated predefined workflows, it will print the workflow-ids registered to them"]))
511 
512  def complete_predefined(self, text, line, start_idx, end_idx):
513  if text and len(text) > 0:
514  return [t for t in predefinedSet.keys() if t.startswith(text)]
515  else:
516  return predefinedSet.keys()
517 
518  def do_predefined(self, arg):
519  """Print the list of predefined workflows"""
520  print("List of predefined workflows")
521  if arg:
522  for w in arg.split():
523  if w in predefinedSet.keys():
524  print("Predefined Set: %s" % w)
525  print(predefinedSet[w])
526  else:
527  print("Unknown Set: %s" % w)
528  else:
529  print("[ " + Fore.RED + ", ".join([str(k) for k in predefinedSet.keys()]) + Fore.RESET + " ]")
530 
531  def help_showWorkflow(self):
532  print("\n".join(["showWorkflow [workflow1 [...]]\n",
533  "Run w/o arguments, it will print the list of registered macro-workflows.",
534  "Run with space-separated workflows, it will print the full list of workflow-ids registered to them"]))
535 
536  def complete_showWorkflow(self, text, line, start_idx, end_idx):
537  if text and len(text) > 0:
538  return [t for t in self.matrices_.keys() if t.startswith(text)]
539  else:
540  return self.matrices_.keys()
541 
542  def do_showWorkflow(self, arg):
543  if arg == '':
544  print("Available workflows:")
545  for k in self.matrices_.keys():
546  print(Fore.RED + Style.BRIGHT + k)
547  print(Style.RESET_ALL)
548  else:
549  selected = arg.split()
550  for k in selected:
551  if k not in self.matrices_.keys():
552  print("Unknown workflow %s: skipping" % k)
553  else:
554  for wfl in self.matrices_[k].workFlows:
555  print("%s %s" % (Fore.BLUE + str(wfl.numId) + Fore.RESET,
556  Fore.GREEN + wfl.nameId + Fore.RESET))
557  print("%s contains %d workflows" % (Fore.RED + k + Fore.RESET, len(self.matrices_[k].workFlows)))
558 
559  def do_runWorkflow(self, arg):
560  # Split the input arguments into a list
561  args = arg.split()
562  if len(args) < 2:
563  print(Fore.RED + Style.BRIGHT + "Wrong number of parameters passed")
564  print(Style.RESET_ALL)
565  return
566  workflow_class = args[0]
567  workflow_id = args[1]
568  passed_down_args = list()
569  if len(args) > 2:
570  passed_down_args = args[2:]
571  print(Fore.YELLOW + Style.BRIGHT + "Running with the following options:\n")
572  print(Fore.GREEN + Style.BRIGHT + "Workflow class: {}".format(workflow_class))
573  print(Fore.GREEN + Style.BRIGHT + "Workflow ID: {}".format(workflow_id))
574  print(Fore.GREEN + Style.BRIGHT + "Additional runTheMatrix options: {}".format(passed_down_args))
575  print(Style.RESET_ALL)
576  if workflow_class not in self.matrices_.keys():
577  print(Fore.RED + Style.BRIGHT + "Unknown workflow selected: {}".format(workflow_class))
578  print("Available workflows:")
579  for k in self.matrices_.keys():
580  print(Fore.RED + Style.BRIGHT + k)
581  print(Style.RESET_ALL)
582  return
583  wflnums = [x.numId for x in self.matrices_[workflow_class].workFlows]
584  if float(workflow_id) not in wflnums:
585  print(Fore.RED + Style.BRIGHT + "Unknown workflow {}".format(workflow_id))
586  print(Fore.GREEN + Style.BRIGHT)
587  print(wflnums)
588  print(Style.RESET_ALL)
589  return
590  if workflow_id in self.processes_.keys():
591  # Check if the process is still active
592  if self.processes_[workflow_id][0].poll() is None:
593  print(Fore.RED + Style.BRIGHT + "Workflow {} already running!".format(workflow_id))
594  print(Style.RESET_ALL)
595  return
596  # If it was there but it's gone, proceeed and update the value for the same key
597  # run a job, redirecting standard output and error to files
598  lognames = ['stdout', 'stderr']
599  logfiles = tuple('%s_%s_%s.log' % (workflow_class, workflow_id, name) for name in lognames)
600  stdout = open(logfiles[0], 'w')
601  stderr = open(logfiles[1], 'w')
602  command = ('runTheMatrix.py', '-w', workflow_class, '-l', workflow_id)
603  if len(passed_down_args) > 0:
604  command += tuple(passed_down_args)
605  print(command)
606  p = subprocess.Popen(command,
607  stdout = stdout,
608  stderr = stderr)
609  self.processes_[workflow_id] = (p, time.time())
610 
611 
612  def complete_runWorkflow(self, text, line, start_idx, end_idx):
613  if text and len(text) > 0:
614  return [t for t in self.matrices_.keys() if t.startswith(text)]
615  else:
616  return self.matrices_.keys()
617 
618  def help_runWorkflow(self):
619  print("\n".join(["runWorkflow workflow_class workflow_id\n",
620  "This command will launch a new and independent process that invokes",
621  "the command:\n",
622  "runTheMatrix.py -w workflow_class -l workflow_id [runTheMatrix.py options]",
623  "\nYou can specify just one workflow_class and workflow_id per invocation.",
624  "The job will continue even after quitting the interactive session.",
625  "stdout and stderr of the new process will be automatically",
626  "redirected to 2 logfiles whose names contain the workflow_class",
627  "and workflow_id. Mutiple command can be issued one after the other.",
628  "The working directory of the new process will be the directory",
629  "from which the interactive session has started.",
630  "Autocompletion is available for workflow_class, but",
631  "not for workflow_id. Supplying a wrong workflow_class or",
632  "a non-existing workflow_id for a valid workflow_class",
633  "will trigger an error and no process will be invoked.",
634  "The interactive shell will keep track of all active processes",
635  "and will prevent the accidental resubmission of an already",
636  "active jobs."]))
637 
638  def do_jobs(self, args):
639  print(Fore.GREEN + Style.BRIGHT + "List of jobs:")
640  for w in self.processes_.keys():
641  if self.processes_[w][0].poll() is None:
642  print(Fore.YELLOW + Style.BRIGHT + "Active job: {} since {:.2f} seconds.".format(w, time.time() - self.processes_[w][1]))
643  else:
644  print(Fore.RED + Style.BRIGHT + "Done job: {}".format(w))
645  print(Style.RESET_ALL)
646 
647  def help_jobs(self):
648  print("\n".join(["Print a full list of active and done jobs submitted",
649  "in the ongoing interactive session"]))
650 
652  print("\n".join(["searchInWorkflow wfl_name search_regexp\n",
653  "This command will search for a match within all workflows registered to wfl_name.",
654  "The search is done on both the workflow name and the names of steps registered to it."]))
655 
656  def complete_searchInWorkflow(self, text, line, start_idx, end_idx):
657  if text and len(text) > 0:
658  return [t for t in self.matrices_.keys() if t.startswith(text)]
659  else:
660  return self.matrices_.keys()
661 
662  def do_searchInWorkflow(self, arg):
663  args = arg.split()
664  if len(args) < 2:
665  print("searchInWorkflow name regexp")
666  return
667  if args[0] not in self.matrices_.keys():
668  print("Unknown workflow")
669  return
670  import re
671  pattern = None
672  try:
673  pattern = re.compile(args[1])
674  except:
675  print("Failed to compile regexp %s" % args[1])
676  return
677  counter = 0
678  for wfl in self.matrices_[args[0]].workFlows:
679  if re.match(pattern, wfl.nameId):
680  print("%s %s" % (Fore.BLUE + str(wfl.numId) + Fore.RESET,
681  Fore.GREEN + wfl.nameId + Fore.RESET))
682  counter +=1
683  print("Found %s compatible workflows inside %s" % (Fore.RED + str(counter) + Fore.RESET,
684  Fore.YELLOW + str(args[0])) + Fore.RESET)
685 
686  def help_search(self):
687  print("\n".join(["search search_regexp\n",
688  "This command will search for a match within all workflows registered.",
689  "The search is done on both the workflow name and the names of steps registered to it."]))
690 
691  def do_search(self, arg):
692  args = arg.split()
693  if len(args) < 1:
694  print("search regexp")
695  return
696  for wfl in self.matrices_.keys():
697  self.do_searchInWorkflow(' '.join([wfl, args[0]]))
698 
700  print("\n".join(["dumpWorkflowId [wfl-id1 [...]]\n",
701  "Dumps the details (cmsDriver commands for all steps) of the space-separated workflow-ids in input."]))
702 
703  def do_dumpWorkflowId(self, arg):
704  wflids = arg.split()
705  if len(wflids) == 0:
706  print("dumpWorkflowId [wfl-id1 [...]]")
707  return
708 
709  fmt = "[%s]: %s\n"
710  maxLen = 100
711  for wflid in wflids:
712  dump = True
713  for key, mrd in self.matrices_.items():
714  for wfl in mrd.workFlows:
715  if wfl.numId == float(wflid):
716  if dump:
717  dump = False
718  print(Fore.GREEN + str(wfl.numId) + Fore.RESET + " " + Fore.YELLOW + wfl.nameId + Fore.RESET)
719  for i,s in enumerate(wfl.cmds):
720  print(fmt % (Fore.RED + str(i+1) + Fore.RESET,
721  (str(s)+' ')))
722  print("\nWorkflow found in %s." % key)
723  else:
724  print("Workflow also found in %s." % key)
725 
726  do_EOF = do_exit
727 
728  TheMatrix(opt).cmdloop()
729  sys.exit(0)
730 
731  if opt.raw and opt.show:
732  ret = showRaw(opt)
733  else:
734  ret = runSelected(opt)
735 
736 
737  sys.exit(ret)
def performInjectionOptionTest(opt)
def runSelected(opt)
Definition: runTheMatrix.py:20
def do_predefined(self, arg)
def do_showWorkflow(self, arg)
def complete_showWorkflow(self, text, line, start_idx, end_idx)
def do_search(self, arg)
def showRaw(opt)
Definition: runTheMatrix.py:11
def do_clear(self, arg)
def help_dumpWorkflowId(self)
def complete_predefined(self, text, line, start_idx, end_idx)
def help_searchInWorkflow(self)
def do_dumpWorkflowId(self, arg)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
def __init__(self, opt)
static std::string join(char **cmd)
Definition: RemoteFile.cc:19
def do_exit(self, arg)
def default(self, inp)
def complete_searchInWorkflow(self, text, line, start_idx, end_idx)
def stepOrIndex(s)
def complete_runWorkflow(self, text, line, start_idx, end_idx)
def do_runWorkflow(self, arg)
#define str(s)
def do_jobs(self, args)
def do_searchInWorkflow(self, arg)