Commit f2201c1ace91ebbd921cb1cac00037814a7720c1

Authored by Jürgen Knödlseder
1 parent 94193f22

Code generator for new module adjusts now all relevant configuration, setup and Makefiles (#2190)

Showing 1 changed file with 259 additions and 8 deletions
dev/codegen.py
... ... @@ -141,7 +141,7 @@ def add_file(infile, outfile, tokens):
141 141  
142 142 # If we have a header line than format the line
143 143 if is_header:
144   - text = gammalib.strip_whitespace(line[2:69])
  144 + text = line.strip(' *\n')
145 145 if n_header == 2:
146 146 line = ' *'+gammalib.centre(text,73)+'*\n'
147 147 elif n_header == 4:
... ... @@ -202,7 +202,8 @@ def set_tokens(name, instrument, author):
202 202 year = str(date.today().year)
203 203  
204 204 # Set tokens
205   - tokens = [{'pattern': 'XXX', 'string': name.upper()},
  205 + tokens = [{'pattern': 'xxx', 'string': name.lower()},
  206 + {'pattern': 'XXX', 'string': name.upper()},
206 207 {'pattern': '[INSTRUMENT]', 'string': instrument},
207 208 {'pattern': '[AUTHOR]', 'string': author},
208 209 {'pattern': '[YEAR]', 'string': year}]
... ... @@ -247,9 +248,9 @@ def module_menu():
247 248  
248 249 # Ask to confirm module summary
249 250 print('All right. Have now:')
250   - print(' Module name ....: "%s"' % name)
251   - print(' Instrument name : "%s"' % instrument)
252   - print(' Your name ......: "%s"' % author)
  251 + print('Module name .....: "%s"' % name)
  252 + print('Instrument name .: "%s"' % instrument)
  253 + print('Your name .......: "%s"' % author)
253 254 if confirm('Is this correct?'):
254 255 break
255 256  
... ... @@ -257,12 +258,12 @@ def module_menu():
257 258 tokens = set_tokens(name, instrument, author)
258 259  
259 260 # If the module exists already then determine all base classes that are
260   - # not yet implemented
  261 + # not yet implemented and propose to add them one by one ...
261 262 if os.path.isdir('inst/%s' % name):
262 263  
263 264 # Determine which of the baseclasses are not yet implemented
264 265 baseclasses = ['GObservation', 'GResponse',
265   - 'GEventAtom', 'GEventBin', 'GEventCube', 'GEventList',
  266 + 'GEventList', 'GEventAtom', 'GEventCube', 'GEventBin',
266 267 'GInstDir', 'GRoi']
267 268 files = glob.glob('inst/%s/include/*.hpp' % name)
268 269 for file in files:
... ... @@ -276,7 +277,7 @@ def module_menu():
276 277 'are already implemented. Return now to main menu.')
277 278 return
278 279 else:
279   - print("All right. Now let's add some classes:")
  280 + print('All right. Now let\'s add some classes:')
280 281  
281 282 # Loop over all missing baseclasses
282 283 for baseclass in baseclasses:
... ... @@ -284,6 +285,256 @@ def module_menu():
284 285 if confirm('Add "%s" class?' % classname):
285 286 add_instrument_class(name, tokens, classname)
286 287  
  288 + # ... otherwise add a new module
  289 + else:
  290 +
  291 + # Setup base classes
  292 + baseclasses = ['GObservation', 'GResponse']
  293 +
  294 + # Ask further questions
  295 + print('All right. You want a new "%s" instrument module.' % name)
  296 + while True:
  297 + add_list = confirm('Do you want event list support?')
  298 + add_bin = confirm('Do you want binned event data support?')
  299 + if not add_list and not add_bin:
  300 + print('*** Warning: You need no support for event lists and '
  301 + 'binned event data. This means that you have no data :o')
  302 + if confirm('Is this true? You want a module that cannot handle data?'):
  303 + break
  304 + else:
  305 + break
  306 +
  307 + # Add base classes according to choice
  308 + if add_list or add_bin:
  309 + baseclasses.append('GInstDir')
  310 + if add_list:
  311 + baseclasses.extend(['GEventList', 'GEventAtom', 'GRoi'])
  312 + if add_bin:
  313 + baseclasses.extend(['GEventCube', 'GEventBin'])
  314 +
  315 + # Create directory structure
  316 + os.mkdir('inst/%s' % name)
  317 + os.mkdir('inst/%s/caldb' % name)
  318 + os.mkdir('inst/%s/include' % name)
  319 + os.mkdir('inst/%s/pyext' % name)
  320 + os.mkdir('inst/%s/src' % name)
  321 + os.mkdir('inst/%s/test' % name)
  322 + os.mkdir('inst/%s/test/data' % name)
  323 +
  324 + # Add some files
  325 + add_file('src/template/inst_Makefile.am',
  326 + 'inst/%s/Makefile.am' % name, tokens)
  327 + add_file('src/template/inst_README.md',
  328 + 'inst/%s/README.md' % name, tokens)
  329 + add_file('src/template/GXXXLib.hpp',
  330 + 'inst/%s/include/G%sLib.hpp' % (name, name.upper()), tokens)
  331 + add_file('src/template/xxx.i',
  332 + 'inst/%s/pyext/%s.i' % (name, name), tokens)
  333 + add_file('src/template/inst_test_Makefile.am',
  334 + 'inst/%s/test/Makefile.am' % name, tokens)
  335 + add_file('src/template/inst_test_XXX.hpp',
  336 + 'inst/%s/test/test_%s.hpp' % (name, name.upper()), tokens)
  337 + add_file('src/template/inst_test_XXX.cpp',
  338 + 'inst/%s/test/test_%s.cpp' % (name, name.upper()), tokens)
  339 + add_file('src/template/inst_test_XXX.py',
  340 + 'inst/%s/test/test_%s.py' % (name, name.upper()), tokens)
  341 +
  342 + # Adjust configuration
  343 + adjust_config(name)
  344 +
  345 + # Adjust Python configuration
  346 + adjust_python_config(name, instrument)
  347 +
  348 + # Adjust test configuration
  349 + adjust_test_config(name, instrument)
  350 +
  351 +
  352 + # Loop over all baseclasses
  353 + #for baseclass in baseclasses:
  354 + # classname = 'G'+name.upper()+baseclass[1:]
  355 + # if confirm('Add "%s" class?' % classname):
  356 + # add_instrument_class(name, tokens, classname)
  357 +
  358 + # Return
  359 + return
  360 +
  361 +
  362 +# ============================================== #
  363 +# Adjust configuration for new instrument module #
  364 +# ============================================== #
  365 +def adjust_config(name):
  366 + """
  367 + Parameters
  368 + ----------
  369 + name : str
  370 + Module name
  371 + """
  372 + # Adjust inst/Makefile.am
  373 + config = 'if WITH_INST_%s\nINST_%s = %s\nendif\n' % (name.upper(), name.upper(), name)
  374 + for line in fileinput.FileInput('inst/Makefile.am',inplace=1):
  375 + if 'Detect configuration' in line:
  376 + line = line.replace(line, line+config)
  377 + elif 'SUBDIRS=' in line.replace(' ', ''):
  378 + line = line.replace(line, line[:-1]+' $(INST_%s)\n' % name.upper())
  379 + print line,
  380 +
  381 + # Adjust configure.ac
  382 + checks = '# Checks for %s interface\n' \
  383 + 'AC_ARG_WITH([%s],\n' \
  384 + ' [AS_HELP_STRING([--with-%s],\n' \
  385 + ' [compile in %s specific interface [default=yes]])],\n' \
  386 + ' [],\n' \
  387 + ' [with_%s=yes])\n' \
  388 + 'if test "x$with_%s" = "xyes"; then\n' \
  389 + ' AC_CHECK_FILE([$srcdir/inst/%s/README.md],\n' \
  390 + ' [with_%s=yes],\n' \
  391 + ' [with_%s=no])\n' \
  392 + 'fi\n' \
  393 + 'AM_CONDITIONAL(WITH_INST_%s, test "x$with_%s" = "xyes")\n' % \
  394 + (name.upper(), name, name, name.upper(), name, name, name,
  395 + name, name, name.upper(), name)
  396 + wrap = ' if test "x$with_%s" = "xyes"; then\n' \
  397 + ' AC_CHECK_FILES([$srcdir/pyext/gammalib/%s_wrap.cpp\n' \
  398 + ' $srcdir/pyext/gammalib/%s.py],,\n' \
  399 + ' [has_wrappers="no"])\n' \
  400 + ' fi' % (name, name, name)
  401 + files = 'if test "x$with_%s" = "xyes"; then\n' \
  402 + ' AC_CONFIG_FILES([inst/%s/Makefile])\n' \
  403 + ' AC_CONFIG_FILES([inst/%s/test/Makefile])\n' \
  404 + 'fi' % (name, name, name)
  405 + info = 'if test "x$with_%s" = "xyes"; then\n' \
  406 + ' echo " * %s interface (yes)"\n' \
  407 + 'else\n' \
  408 + ' echo " - %s interface (no)"\n' \
  409 + 'fi' % (name, name.upper(), name.upper())
  410 + for line in fileinput.FileInput('configure.ac',inplace=1):
  411 + if '# Insert new checks here' in line:
  412 + print(checks)
  413 + elif '# Insert new wrappers here' in line:
  414 + print(wrap)
  415 + elif '# Inset new Makefiles here' in line:
  416 + print(files)
  417 + elif '# Insert new interface informations here' in line:
  418 + print(info)
  419 + print line,
  420 +
  421 + # Return
  422 + return
  423 +
  424 +
  425 +# ===================================================== #
  426 +# Adjust Python configuration for new instrument module #
  427 +# ===================================================== #
  428 +def adjust_python_config(name, instrument):
  429 + """
  430 + Parameters
  431 + ----------
  432 + name : str
  433 + Module name
  434 + instrument : str
  435 + Instrument
  436 + """
  437 + # Adjust pyext/setup.py.in
  438 + module = 'if \'@WITH_INST_%s_TRUE@\' != \'#\':\n' \
  439 + ' print(\'Include %s instrument interface in gammalib Python module.\')\n' \
  440 + ' inst_modules.append(\'%s\')' % \
  441 + (name.upper(), instrument, name)
  442 + for line in fileinput.FileInput('pyext/setup.py.in',inplace=1):
  443 + if '# Insert new module here' in line:
  444 + print(module)
  445 + print line,
  446 +
  447 + # Adjust pyext/Makefile.am
  448 + target = 'if WITH_INST_%s\n' \
  449 + ' %s_SWIG_TARGETS = $(wrapperdir)/gammalib/%s_wrap.cpp \\\n' \
  450 + ' $(wrapperdir)/gammalib/%s.py\n' \
  451 + ' %s_TESTS = $(top_srcdir)/inst/%s/test/test_%s.py\n' \
  452 + 'endif' % (name.upper(), name.upper(), name, name,
  453 + name.upper(), name, name.upper())
  454 + targets = ' $(%s_SWIG_TARGETS) ' % name.upper()
  455 + rule = '# Rule for %s module\n' \
  456 + 'if WITH_INST_%s\n' \
  457 + '$(wrapperdir)/gammalib/%s.py: $(wrapperdir)/gammalib/%s_wrap.cpp\n' \
  458 + '$(wrapperdir)/gammalib/%s_wrap.cpp: $(top_srcdir)/inst/%s/pyext/%s.i\n' \
  459 + ' if $(SWIGCOMPILE) -MMD -MF "gammalib/%s.Tpi" -I$(top_srcdir)/pyext -o gammalib/%s_wrap.cpp -outdir gammalib $<; \\\n' \
  460 + ' then mv -f "gammalib/%s.Tpi" "gammalib/%s.Pi"; else rm -f "gammalib/%s.Tpi"; exit 1; fi\n' \
  461 + 'endif\n' % (name.upper(), name.upper(), name, name, name,
  462 + name, name, name, name, name, name, name)
  463 + for line in fileinput.FileInput('pyext/Makefile.am',inplace=1):
  464 + if '# Insert new target here' in line:
  465 + print(target)
  466 + elif 'INST_SWIG_TARGETS=' in line.replace(' ', ''):
  467 + last = line[-2]
  468 + line = line.replace(line, line+targets+last+'\n')
  469 + elif '$(MWL_TESTS)' in line:
  470 + line = line.replace(line, line[:-1]+' $(%s_TESTS)\n' % name.upper())
  471 + if '# Insert new rule here' in line:
  472 + print(rule)
  473 + print line,
  474 +
  475 + # Return
  476 + return
  477 +
  478 +
  479 +# =================================================== #
  480 +# Adjust test configuration for new instrument module #
  481 +# =================================================== #
  482 +def adjust_test_config(name, instrument):
  483 + """
  484 + Parameters
  485 + ----------
  486 + name : str
  487 + Module name
  488 + instrument : str
  489 + Instrument
  490 + """
  491 + # Adjust test/Makefile.am
  492 + test = 'if WITH_INST_%s\n' \
  493 + ' INST_%s = $(top_builddir)/inst/%s/test/test_%s\n' \
  494 + ' TEST_%s = :$(top_srcdir)/inst/%s/test\n' \
  495 + ' TEST_%s_ENV = TEST_%s_DATA=$(top_srcdir)/inst/%s/test/data\n' \
  496 + 'endif' % (name.upper(), name.upper(), name, name.upper(),
  497 + name.upper(), name, name.upper(), name.upper(),
  498 + name)
  499 + testenv = ' $(TEST_%s_ENV) ' % name.upper()
  500 + tests = ' $(INST_%s) \\\n' % name.upper()
  501 + for line in fileinput.FileInput('test/Makefile.am',inplace=1):
  502 + if '# Insert new test here' in line:
  503 + print(test)
  504 + elif 'TEST_PYTHON_ENV=' in line.replace(' ', ''):
  505 + line = line.replace(line, line[:-1]+'$(TEST_%s)\n' % name.upper())
  506 + elif 'TEST_DATA=$(top_srcdir)/test/data' in line:
  507 + last = line[-2]
  508 + line = line.replace(line, line+testenv+last+'\n')
  509 + elif '$(TEST_PYTHON_SCRIPT)' in line:
  510 + line = line.replace(line, tests+line)
  511 + print line,
  512 +
  513 + # Adjust test/test_python.py
  514 + test = '# Try importing %s tests\n' \
  515 + 'try:\n' \
  516 + ' import test_%s\n' \
  517 + ' has_%s = True\n' \
  518 + 'except:\n' \
  519 + ' has_%s = False\n' % \
  520 + (instrument, name.upper(), name, name)
  521 + data = ' os.environ[\'TEST_%s_DATA\'] = \'%s/data\'' % \
  522 + (name.upper(), name)
  523 + suite = ' # Optionally handle %s suite\n' \
  524 + ' if has_%s:\n' \
  525 + ' suite_%s = test_%s.Test()\n' \
  526 + ' suite_%s.set()\n' \
  527 + ' suites.append(suite_%s)\n' % \
  528 + (instrument, name, name, name.upper(), name, name)
  529 + for line in fileinput.FileInput('test/test_python.py',inplace=1):
  530 + if '# Insert new test here' in line:
  531 + print(test)
  532 + if '# Insert new environment here' in line:
  533 + print(data)
  534 + if '# Insert new suite here' in line:
  535 + print(suite)
  536 + print line,
  537 +
287 538 # Return
288 539 return
289 540  
... ...