1# -*- coding: utf-8 -*- 2 3# ============================================================================== 4# COPYRIGHT (C) 1991 - 2015 EDF R&D WWW.CODE-ASTER.ORG 5# THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY 6# IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY 7# THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR 8# (AT YOUR OPTION) ANY LATER VERSION. 9# 10# THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT 11# WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF 12# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU 13# GENERAL PUBLIC LICENSE FOR MORE DETAILS. 14# 15# YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE 16# ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER, 17# 1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE. 18# ============================================================================== 19 20"""AsterBuild class. 21""" 22 23 24import os 25import os.path as osp 26import sys 27import re 28import copy 29import time 30from glob import glob 31from zipfile import ZipFile 32from warnings import warn 33 34from asrun.core import magic 35from asrun.common.i18n import _ 36from asrun.mystring import ufmt, to_unicode 37from asrun.thread import Task, TaskAbort, Dispatcher 38from asrun.runner import Runner 39from asrun.common_func import get_tmpname 40from asrun.common.utils import re_search, YES_VALUES, unique_basename_remove 41from asrun.common.utils import make_writable 42from asrun.common.sysutils import is_newer, is_newer_mtime 43from asrun.system import split_path 44 45from asrun.backward_compatibility import bwc_deprecate_class 46 47fmt_catapy = 'cata%s.py%s' 48fcapy = fmt_catapy % ('', '') 49fcapy_ = fmt_catapy % ('', '*') 50 51repcatapy = ('entete', 'commun', 'commande') 52repcatalo = ('compelem', 'typelem', 'options') 53 54 55class CompilTask(Task): 56 """Compilation task. 57 """ 58 # declare attrs 59 run = fmsg = dep_h = None 60 force = verbose = debug = False 61 nbnook = nskip = 0 62 cmd = "" 63 def _mess(self, msg, cod='', store=False): 64 """pass""" 65 66 def execute(self, f, **kwargs): 67 """Function called for each item of the stack. 68 Warning : 'execute' should not modify attributes. 69 """ 70 if self.nbnook >= 3: 71 raise TaskAbort(_('Maximum number of errors reached : %d') % self.nbnook) 72 jret = 2 73 skip = not self.force 74 out = '' 75 lenmax = 50 76 tail = f 77 if len(f) > lenmax + 3: 78 tail = '...' + f[len(f) - lenmax:] 79 obj = osp.splitext(osp.basename(f))[0]+'.o' 80 # ----- skip file if .o more recent than source file 81 too_old = True 82 if osp.exists(obj): 83 too_old = False 84 dep_src = [f,] 85 for inc in get_include(f): 86 deps = self.dep_h.get(inc, []) 87 dep_src.extend(deps) 88 for ref in dep_src: 89 too_old = not is_newer(obj, ref) 90 if too_old: 91 break 92 if too_old: 93 skip = False 94 if not skip: 95 jret, out = self.run.Shell(self.cmd + ' ' + f) 96 return jret, skip, out, f, tail 97 98 def result(self, jret, skip, out, f, tail, **kwargs): 99 """Function called after each task to treat results of execute. 100 Arguments are 'execute' results + keywords args. 101 'result' is called thread-safely, so can store results in attributes. 102 """ 103 if skip: 104 self.nskip += 1 105 if self.verbose or self.debug: 106 self.run.VerbStart(ufmt(_('compiling %s'), tail), verbose=True) 107 self.run.VerbIgnore(verbose=True) 108 else: 109 self.run.VerbStart(ufmt(_('compiling %s'), tail), verbose=True) 110 if self.verbose: 111 print() 112 # ----- avoid to duplicate output 113 if not self.verbose: 114 if jret == 0 and out.strip() != '' \ 115 and self.run.get('print_compiler_output', "") in YES_VALUES: 116 print() 117 print(out) 118 self.run.VerbStart(ufmt(_('compiling %s'), tail), verbose=True) 119 self.run.VerbEnd(jret, output=out, verbose=True) 120 if jret != 0: 121 print(out, file=self.fmsg) 122 self._mess(ufmt(_('error during compiling %s (see %s)'), f, 123 osp.abspath(self.fmsg.name)), 124 '<E>_COMPIL_ERROR', store=True) 125 self.nbnook += 1 126 self.codret = max(self.codret, jret) 127 128 129class AsterBuild_Classic: 130 """This class provides functions to build a version of Code_Aster. 131 """ 132 attr = () 133 134 def __init__(self, run, conf): 135 """run : AsterRun object 136 conf : AsterConfig object 137 """ 138 # initialisations 139 self.verbose = False 140 self.debug = False 141 # ----- reference to AsterRun object which manages the execution 142 self.run = run 143 if run != None and run.__class__.__name__ == 'AsterRun': 144 self.verbose = run['verbose'] 145 self.debug = run['debug'] 146 # ----- Check if 'conf' is a valid AsterConfig object 147 self.conf = conf 148 if conf == None or conf.__class__.__name__ != 'AsterConfig': 149 self._mess(_('no configuration object provided !'), '<F>_ERROR') 150 else: 151 # ----- check that AsterConfig fields are correct (not nul !) 152 pass 153 # ----- Initialize Runner object 154 self.runner = Runner(self.conf.get_defines()) 155 self.runner.set_cpuinfo(1, 1) 156 157 def _mess(self, msg, cod='', store=False): 158 """Just print a message 159 """ 160 if hasattr(self.run, 'Mess'): 161 self.run.Mess(msg, cod, store) 162 else: 163 print('%-18s %s' % (cod, msg)) 164 165 def support(self, feature): 166 """Tell if the feature is supported""" 167 return feature in self.attr 168 169 def addFeature(self, feature): 170 """Add a supported feature""" 171 self.attr = tuple( set(self.attr).union([feature]) ) 172 173 def Compil(self, typ, rep, repobj, dbg, rep_trav='', 174 error_if_empty=False, numthread=1, dep_h=None): 175 """Compile 'rep/*.suffix' files and put '.o' files in 'repobj' 176 dbg : debug or nodebug 177 (rep can also be a file) 178 rep can be remote. 179 """ 180 prev = os.getcwd() 181 self.run.DBG('type : %s' % typ, 'rep : %s' % rep, 'repobj : %s' % repobj) 182 183 # ----- how many threads ? 184 if numthread == 'auto': 185 numthread = self.run.GetCpuInfo('numthread') 186 187 # ----- modified or added includes 188 if self.run.IsRemote(rep): 189 opt_incl = '-I.' 190 elif self.run.IsDir(rep): 191 opt_incl = '-I%s' % rep 192 else: 193 opt_incl = '' 194 195 # ----- get command line from conf object 196 defines = [] 197 for defs in self.conf['DEFS']: 198 defines.extend(re.split('[ ,]', defs)) 199 add_defines = ' '.join(['-D%s' % define for define in defines if define != '']) 200 self.run.DBG('Add defines : %s' % add_defines) 201 if typ == 'C': 202 l_mask = ['*.c'] 203 if self.conf['CC'][0] == '': 204 self._mess(_("C compiler not defined in 'config.txt' (CC)"), \ 205 '<F>_CMD_NOT_FOUND') 206 cmd = self.conf['CC'][:] 207 if dbg == 'debug': 208 cmd.extend(self.conf['OPTC_D']) 209 else: 210 cmd.extend(self.conf['OPTC_O']) 211 cmd.append(add_defines) 212 cmd.append(opt_incl) 213 cmd.extend(self.conf['INCL']) 214 elif typ == 'F': 215 l_mask = ['*.f'] 216 if self.conf['F77'][0] == '': 217 self._mess(_("Fortran 77 compiler not defined in 'config.txt' (F77)"), \ 218 '<F>_CMD_NOT_FOUND') 219 cmd = self.conf['F77'][:] 220 if dbg == 'debug': 221 cmd.extend(self.conf['OPTF_D']) 222 else: 223 cmd.extend(self.conf['OPTF_O']) 224 cmd.append(add_defines) 225 cmd.append(opt_incl) 226 cmd.extend(self.conf['INCLF']) 227 elif typ == 'F90': 228 l_mask = ['*.f', '*.F'] 229 if self.conf['F90'][0] == '': 230 self._mess(_("Fortran 90 compiler not defined in 'config.txt' (F90)"), \ 231 '<F>_CMD_NOT_FOUND') 232 cmd = self.conf['F90'][:] 233 if dbg == 'debug': 234 cmd.extend(self.conf['OPTF90_D']) 235 else: 236 cmd.extend(self.conf['OPTF90_O']) 237 cmd.append(add_defines) 238 cmd.append(opt_incl) 239 cmd.extend(self.conf['INCLF90']) 240 else: 241 self._mess(ufmt(_('unknown type : %s'), typ), '<F>_PROGRAM_ERROR') 242 cmd = ' '.join(cmd) 243 244 # ----- if force is True, don't use ctime to skip a file 245 force = self.run['force'] 246 247 # ----- copy source files if remote 248 if self.run.IsRemote(rep): 249 if rep_trav == '': 250 self._mess(_('rep_trav must be defined'), '<F>_PROGRAM_ERROR') 251 obj = osp.join(rep_trav, '__tmp__'+osp.basename(rep)) 252 iret = self.run.MkDir(obj) 253 if self.run.IsDir(rep): 254 src = [osp.join(rep, mask) for mask in l_mask + ['*.h']] 255 else: 256 src = [rep,] 257 iret = self.run.Copy(obj, niverr='SILENT', *src) 258 rep = obj 259 else: 260 rep = self.run.PathOnly(rep) 261 262 # ----- check that directories exist 263 if not osp.isdir(repobj): 264 iret = self.run.MkDir(repobj, verbose=True) 265 266 # ----- work in repobj 267 os.chdir(repobj) 268 269 # ----- log file 270 msg = osp.basename(rep)+'.msg' 271 if osp.exists(msg): 272 os.remove(msg) 273 fmsg = open(msg, 'w') 274 fmsg.write(os.linesep + \ 275 'Messages de compilation' + os.linesep + \ 276 '=======================' + os.linesep) 277 278 # ----- list of source files 279 files = [] 280 if self.run.IsDir(rep): 281 for suffix in l_mask: 282 files.extend(glob(osp.join(rep, suffix))) 283 elif osp.splitext(rep)[-1] != '.h': 284 files.append(rep) 285 if len(files) == 0: 286 iret = 0 287 niverr = '' 288 if error_if_empty: 289 iret = 2 290 niverr = '<A>_NO_SOURCE_FILE' 291 self._mess(ufmt(_('no source file in %s'), rep), niverr) 292 return iret, [] 293 294 # ----- Compile all files in parallel using a Dispatcher object 295 task = CompilTask(cmd=cmd, run=self.run, force=force, # IN 296 verbose=self.verbose, debug=self.debug, # IN 297 _mess=self._mess, fmsg=fmsg, # IN 298 dep_h=dep_h, # IN 299 codret=0, nskip=0, nbnook=0) # OUT 300 compilation = Dispatcher(files, task, numthread) 301 self.run.DBG(compilation.report()) 302 303 self._mess(ufmt(_('%4d files compiled from %s'), len(files), rep)) 304 if task.nskip > 0: 305 self._mess(_('%4d files skipped (object more recent than source)') \ 306 % task.nskip) 307 308 fmsg.close() 309 os.chdir(prev) 310 return task.codret, files 311 312 def CompilAster(self, REPREF, repdest='', dbg='nodebug', ignore_ferm=False, 313 numthread='auto'): 314 """Compile all Aster source files, put '.o' files in 'repdest'/DIR 315 and DIR_f with DIR=obj or dbg depends on 'dbg' 316 (DIR for "real" source files and DIR_f for fermetur). 317 """ 318 self._mess(_('Compilation of source files'), 'TITLE') 319 dest_o = { 'nodebug' : self.conf['BINOBJ_NODBG'][0], 320 'debug' : self.conf['BINOBJ_DBG'][0] } 321 dest_f_o = {'nodebug' : self.conf['BINOBJF_NODBG'][0], 322 'debug' : self.conf['BINOBJF_DBG'][0] } 323 324 # ----- define type and destination of '*.o' files for each directory 325 if repdest == '': 326 repdest = REPREF 327 dest = osp.join(repdest, dest_o[dbg]) 328 dest_f = osp.join(repdest, dest_f_o[dbg]) 329 para = { 330 self.conf['SRCC'][0] : ['C', dest], 331 self.conf['SRCFOR'][0] : ['F', dest], 332 self.conf['SRCF90'][0] : ['F90', dest], 333 } 334 if not ignore_ferm: 335 para[self.conf['SRCFERM'][0]] = ['F', dest_f] 336 lmods = [d for d in list(para.keys()) if d != ''] 337 lfull = [osp.join(REPREF, rep) for rep in lmods] 338 339 # ----- check that directories exist 340 for obj in lfull: 341 if not osp.exists(obj): 342 self._mess(ufmt(_('directory does not exist : %s'), obj), 343 '<E>_FILE_NOT_FOUND') 344 self.run.CheckOK() 345 346 # ----- nobuild list 347 nobuild = [] 348 for d in self.conf['NOBUILD']: 349 nobuild.extend([osp.join(REPREF, d) for d in d.split()]) 350 # bibf90 dirs automatically added if there is no F90 compiler 351 if self.conf['F90'][0] == '' and self.conf['SRCF90'][0] != '': 352 nobuild.extend([d for d in \ 353 glob(osp.join(REPREF, self.conf['SRCF90'][0], '*')) 354 if not d in nobuild]) 355 self._mess(ufmt(_("There is no Fortran 90 compiler in 'config.txt'. " \ 356 "All source files from '%s' were ignored."), 357 self.conf['SRCF90'][0]), 358 '<A>_IGNORE_F90', store=True) 359 if len(nobuild)>0: 360 self._mess(_('These directories will not be built :')) 361 for d in nobuild: 362 print(' '*10+'>>> %s' % d) 363 364 # ----- compilation 365 dep_h = build_include_depend(*lfull) 366 iret = 0 367 for module in lmods: 368 if module != self.conf['SRCFERM'][0]: 369 # ----- glob subdirectories 370 lrep = glob(osp.join(REPREF, module, '*')) 371 else: 372 lrep = (osp.join(REPREF, module), ) 373 for rep in lrep: 374 if osp.isdir(rep): 375 tail = '...'+re.sub('^'+REPREF, '', rep) 376 print() 377 jret = 0 378 if not rep in nobuild: 379 self._mess(ufmt(_('Compilation from %s directory'), tail)) 380 jret, bid = self.Compil(para[module][0], rep, para[module][1], 381 dbg, numthread=numthread, dep_h=dep_h) 382 else: 383 self.run.VerbStart(ufmt(_('Directory %s is in NOBUILD list'), tail), 384 verbose=True) 385 self.run.VerbIgnore(verbose=True) 386 iret = max(iret, jret) 387 388 return iret 389 390 def Archive(self, repobj, lib, force=False): 391 """Archive all .o files from 'repobj' into 'lib' 392 All args must be local. 393 """ 394 self._mess(_('Archive object files'), 'TITLE') 395 prev = os.getcwd() 396 # ----- get command line from conf object 397 cmd0 = [self.conf['LIB'][0]+' '+lib] 398 399 # ----- check that directories exist 400 if not osp.isdir(repobj): 401 self._mess(ufmt(_('directory does not exist : %s'), repobj), '<E>_FILE_NOT_FOUND') 402 rep = osp.dirname(lib) 403 if not osp.isdir(rep): 404 iret = self.run.MkDir(rep, verbose=True) 405 self.run.CheckOK() 406 407 # ----- if force is True, don't use ctime to skip a file 408 force = force or self.run['force'] 409 if osp.exists(lib): 410 mtlib = os.stat(lib).st_mtime 411 else: 412 mtlib = 0 413 force = True 414 415 # ----- work in repobj 416 os.chdir(repobj) 417 418 # ----- list of source files 419 files = glob('*.o') 420 ntot = len(files) 421 if ntot == 0: 422 self._mess(ufmt(_('no object file in %s'), rep)) 423 return 0 424 425 # ----- sleep 1 s to be sure than last .o will be older than lib ! 426 time.sleep(1) 427 428 # ----- use MaxCmdLen to limit command length 429 iret = 0 430 nskip = 0 431 while len(files) > 0: 432 cmd = copy.copy(cmd0) 433 clen = len(cmd[0])+1 434 nadd = 0 435 while len(files) > 0 and clen+len(files[0]) < self.run.system.MaxCmdLen-15: 436 if not force and is_newer_mtime(mtlib, files[0]): 437 nskip += 1 438 bid = files.pop(0) 439 else: 440 clen = clen+len(files[0])+1 441 cmd.append(files.pop(0)) 442 nadd += 1 443 self.run.VerbStart(_('%4d / %4d objects added to archive...') % \ 444 (nadd, ntot), verbose=True) 445 if nadd > 0: 446 if self.verbose: 447 print() 448 jret, out = self.run.Shell(' '.join(cmd)) 449 # ----- avoid to duplicate output 450 if not self.verbose: 451 self.run.VerbEnd(jret, output=out, verbose=True) 452 if jret != 0: 453 self._mess(_('error during archiving'), '<E>_ARCHIVE_ERROR') 454 iret = max(iret, jret) 455 else: 456 self.run.VerbIgnore(verbose=True) 457 458 self._mess(_('%4d files archived') % ntot) 459 if nskip > 0: 460 self._mess(_('%4d files skipped (objects older than library)') \ 461 % nskip) 462 os.chdir(prev) 463 return iret 464 465 def Link(self, exe, lobj, libaster, libferm, reptrav): 466 """Link a number of object and archive files into an executable. 467 exe : name of the executable to build 468 lobj : list of object files 469 libaster : Code_Aster main library 470 libferm : Code_Aster fermetur library 471 reptrav : working directory 472 If "python.o" is not in 'lobj' it will be extracted from 'libaster'. 473 Other libs are given by AsterConfig object. 474 None argument must not be remote ! 475 """ 476 self._mess(_('Build Code_Aster executable'), 'TITLE') 477 prev = os.getcwd() 478 # ----- check that directories exist 479 for obj in lobj+[libaster, libferm]: 480 if not osp.exists(obj): 481 self._mess(ufmt(_('file not found : %s'), obj), '<E>_FILE_NOT_FOUND') 482 rep = osp.dirname(exe) 483 if not osp.isdir(rep): 484 iret = self.run.MkDir(rep, verbose=True) 485 self.run.CheckOK() 486 487 # ----- if force is True, don't use ctime to skip a file 488 force = self.run['force'] 489 if not osp.exists(exe): 490 force = True 491 else: 492 for f in lobj + [libaster, libferm]: 493 if not is_newer(exe, f): 494 force = True 495 self.run.DBG('%s more recent than %s' % (f, exe)) 496 break 497 498 # ----- work in reptrav 499 os.chdir(reptrav) 500 501 # ----- python.o in lobj ? 502 mainobj = self.conf['BINOBJ_MAIN'][0] 503 if mainobj not in [osp.basename(o) for o in lobj] and force: 504 # get 'ar' command without arguments, if it's not 'ar' &$#@! 505 cmd = [self.conf['LIB'][0].split()[0]] 506 cmd.extend(['-xv', libaster, mainobj]) 507 cmd = ' '.join(cmd) 508 self.run.VerbStart(ufmt(_('extracting %s from %s...'), repr(mainobj), 509 osp.basename(libaster)), verbose=True) 510 if self.verbose: 511 print() 512 iret, out = self.run.Shell(cmd) 513 # ----- avoid to duplicate output 514 if not self.verbose: 515 self.run.VerbEnd(iret, output=out, verbose=True) 516 if iret != 0: 517 self._mess(ufmt(_('error during extracting %s'), repr(mainobj)), 518 '<F>_LIBRARY_ERROR') 519 lobj.insert(0, mainobj) 520 else: 521 lobj = [o for o in lobj if osp.basename(o) == mainobj] +\ 522 [o for o in lobj if osp.basename(o) != mainobj] 523 524 # ----- get command line from conf object and args 525 cmd = copy.copy(self.conf['LINK']) 526 cmd.extend(self.conf['OPTL']) 527 cmd.append('-o') 528 cmd.append(exe) 529 cmd.extend(lobj) 530 cmd.append(libaster) 531 cmd.extend(self.conf['BIBL']) 532 cmd.append(libferm) 533 cmd = ' '.join(cmd) 534 535 # ----- run ld or skip this stage 536 iret = 0 537 tail = osp.join('...', osp.basename(rep), osp.basename(exe)) 538 self.run.VerbStart(ufmt(_('creating %s...'), tail), verbose=True) 539 if force: 540 if self.verbose: 541 print() 542 iret, out = self.run.Shell(cmd) 543 self.run.DBG(out, all=True) 544 # ----- avoid to duplicate output 545 if not self.verbose: 546 self.run.VerbEnd(iret, output=out, verbose=True) 547 if iret != 0: 548 self._mess(_('error during linking'), '<E>_LINK_ERROR') 549 else: 550 self.run.VerbIgnore(verbose=True) 551 self._mess(_('executable more recent than objects and libs ' \ 552 'in arguments')) 553 554 os.chdir(prev) 555 return iret 556 557 def PrepEnv(self, REPREF, repdest, dbg='nodebug', lang='', **kargs): 558 """Prepare 'repdest' with Code_Aster environment from REPREF and 559 given arguments in kargs[k] (k in 'exe', 'cmde', 'ele', 'py', 'unigest'). 560 Note : - REPREF/elements and kargs['ele'] don't exist when building 561 elements for the first time. 562 - only PYSUPPR entries from 'unigest' are considered here. 563 All elements of kargs can be remote. 564 """ 565 reptrav = osp.join(repdest, self.conf['REPPY'][0], '__tmp__') 566 prev = os.getcwd() 567 # ----- check that files and directories in kargs exist 568 self._check_file_args(list(kargs.values())) 569 if not osp.isdir(repdest): 570 iret = self.run.MkDir(repdest, verbose=True) 571 self.run.CheckOK() 572 573 # ----- language 574 if lang in ('', 'fr'): 575 lang = 'fr' 576 suff = '' 577 else: 578 suff = '_' + lang 579 mask_catapy = fmt_catapy % (suff, '*') 580 mask_catapy_all = fmt_catapy % ('*', '*') 581 582 # ----- copy REPREF/aster?.exe or kargs['exe'] 583 iret = 0 584 if 'exe' in kargs: 585 src = kargs['exe'] 586 else: 587 if dbg == 'debug': 588 src = osp.join(REPREF, self.conf['BIN_DBG'][0]) 589 else: 590 src = osp.join(REPREF, self.conf['BIN_NODBG'][0]) 591 # do not make symlinks if we only prepare the environment because 592 # the copy of remote files will be deleted from proxy_dir before the 593 # manual execution. 594 use_symlink = not kargs.get('only_env', False) and self.run['symlink'] 595 dest = repdest 596 if src != osp.join(repdest, osp.basename(src)): 597 if use_symlink and not self.run.IsRemote(src): 598 src = self.run.PathOnly(src) 599 lien = osp.join(repdest, osp.basename(src)) 600 iret = self.run.Symlink(src, lien, verbose=True) 601 else: 602 iret = self.run.Copy(dest, src, verbose=True) 603 else: 604 self.run.VerbStart(ufmt(_('copying %s...'), src), verbose=True) 605 self.run.VerbIgnore(verbose=True) 606 607 # ----- copy REPREF/bibpyt 608 self.run.MkDir(osp.join(repdest, self.conf['REPPY'][0], 'Cata')) 609 iret = 0 610 src = osp.join(REPREF, self.conf['SRCPY'][0], '*') 611 dest = osp.join(repdest, self.conf['REPPY'][0]) 612 iret = self.run.Copy(dest, src) 613 614 # if 'py' is in kargs 615 if 'py' in kargs: 616 self._mess(_("copy user's python source files")) 617 # ----- python source given by user 618 lobj = kargs['py'] 619 if not type(lobj) in (list, tuple): 620 lobj = [lobj, ] 621 for occ in lobj: 622 obj = occ 623 if self.run.IsRemote(occ): 624 obj = reptrav 625 iret = self.run.MkDir(obj) 626 iret = self.run.Copy(obj, occ, verbose=True) 627 files = self.run.FindPattern(obj, '*.py', maxdepth=10) 628 629 for f in files: 630 mod, rep = self.GetCModif('py', f) 631 reppydest = osp.join(repdest, self.conf['REPPY'][0], rep) 632 if not self.run.Exists(reppydest): 633 self.run.MkDir(reppydest) 634 self._mess(ufmt(_("unknown package '%s' in %s"), 635 rep, osp.join(REPREF, self.conf['SRCPY'][0])), '<A>_ALARM') 636 dest = osp.join(reppydest, mod+'.py') 637 iret = self.run.Copy(dest, f, verbose=True) 638 639 # ----- apply PYSUPPR directives from unigest 640 if 'unigest' in kargs: 641 for f in kargs['unigest']['py']: 642 self.run.Delete(osp.join(repdest, \ 643 re.sub('^'+self.conf['SRCPY'][0], self.conf['REPPY'][0], f)), 644 verbose=True) 645 646 # ----- copy REPREF/commande or kargs['cmde'] 647 iret = 0 648 if 'cmde' in kargs: 649 src = kargs['cmde'] 650 else: 651 src = osp.join(REPREF, self.conf['BINCMDE'][0]) 652 dest = osp.join(repdest, self.conf['REPPY'][0], 'Cata') 653 if use_symlink and not self.run.IsRemote(src): 654 src = self.run.PathOnly(src) 655 # checks catalogue exists 656 l_capy = glob(osp.join(src, mask_catapy)) 657 if len(l_capy) == 0 and lang != '': 658 self._mess(ufmt(_("no catalogue found for language '%s', " \ 659 "use standard (fr) one..."), lang)) 660 mask_catapy = fmt_catapy % ('', '*') 661 l_capy = glob(osp.join(src, mask_catapy)) 662 if len(l_capy) == 0: 663 self._mess(ufmt(_('no catalogue found : %s'), osp.join(src, mask_catapy)), 664 '<F>_FILE_NOT_FOUND') 665 # add symlink 666 for f in l_capy: 667 root = osp.splitext(fcapy)[0] 668 ext = osp.splitext(f)[-1] 669 lien = osp.join(dest, root + ext) 670 iret = self.run.Symlink(f, lien, verbose=True) 671 else: 672 iret = self.run.Copy(dest, osp.join(src, mask_catapy_all), verbose=True) 673 # checks catalogue exists 674 l_capy = glob(osp.join(dest, mask_catapy)) 675 if len(l_capy) == 0 and lang != '': 676 self._mess(ufmt(_("no catalogue found for language '%s', " \ 677 "use standard (fr) one..."), lang)) 678 mask_catapy = fmt_catapy % ('', '*') 679 l_capy = glob(osp.join(dest, mask_catapy)) 680 for f in l_capy: 681 root = osp.splitext(fcapy)[0] 682 ext = osp.splitext(f)[-1] 683 self.run.Rename(f, osp.join(dest, root + ext)) 684 685 # ----- copy REPREF/elements or kargs['ele'] 686 iret = 0 687 if 'ele' in kargs: 688 src = kargs['ele'] 689 else: 690 src = osp.join(REPREF, self.conf['BINELE'][0]) 691 if self.run.Exists(src) and src != osp.join(repdest, 'elem.1'): 692 # symlink not allowed for elem.1 (rw) 693 iret = self.run.Copy(osp.join(repdest, 'elem.1'), src, verbose=True) 694 else: 695 self.run.VerbStart(ufmt(_('copying %s...'), src), verbose=True) 696 self.run.VerbIgnore(verbose=True) 697 698 # ----- result directories 699 os.chdir(repdest) 700 self.run.MkDir('REPE_OUT') 701 702 os.chdir(prev) 703 self.run.Delete(reptrav) 704 return iret 705 706 def CompilCapy(self, REPREF, reptrav, exe='', cmde='', i18n=False, **kargs): 707 """Compile commands catalogue from REPREF/commande using 'exe' 708 and puts result in 'cmde'. kargs can contain : 709 capy : list of user's capy files 710 unigest : GetUnigest dict with "CATSUPPR catapy module" entries 711 All args can be remote. 712 If `i18n` is True, translates cata.py. 713 """ 714 self._mess(_('Compilation of commands catalogue'), 'TITLE') 715 prev = os.getcwd() 716 if exe == '': 717 exe = osp.join(REPREF, self.conf['BIN_NODBG'][0]) 718 if not self.run.Exists(exe): 719 exe = osp.join(REPREF, self.conf['BIN_DBG'][0]) 720 if cmde == '': 721 cmde = osp.join(REPREF, self.conf['BINCMDE'][0]) 722 # ----- check that files and directories in kargs exist 723 self._check_file_args(list(kargs.values())) 724 if not osp.isdir(cmde): 725 iret = self.run.MkDir(cmde, verbose=True) 726 if not osp.isdir(reptrav): 727 iret = self.run.MkDir(reptrav, verbose=True) 728 self.run.CheckOK() 729 730 # ----- work in reptrav 731 reptrav = self.runner.set_rep_trav(reptrav) 732 os.chdir(reptrav) 733 734 # ----- if force is True, don't use ctime to skip a file 735 force = self.run['force'] 736 737 # ----- copy capy from REPREF 738 bascpy = osp.basename(self.conf['SRCCAPY'][0]) 739 if osp.exists(bascpy): 740 self.run.Delete(bascpy) 741 iret = self.run.Copy(bascpy, 742 osp.join(REPREF, self.conf['SRCCAPY'][0]), verbose=True) 743 744 # if 'capy' is in kargs 745 if 'capy' in kargs: 746 force = True 747 self._mess(_("copy user's catalogues")) 748 # ----- catapy given by user 749 lobj = kargs['capy'] 750 if not type(lobj) in (list, tuple): 751 lobj = [lobj, ] 752 for occ in lobj: 753 obj = occ 754 if self.run.IsRemote(occ): 755 obj = osp.join(bascpy, 756 '__tmp__'+osp.basename(occ)) 757 iret = self.run.MkDir(obj) 758 if self.run.IsDir(occ): 759 src = osp.join(occ, '*.capy') 760 else: 761 src = occ 762 iret = self.run.Copy(obj, src) 763 files = glob(osp.join(obj, '*.capy')) 764 else: 765 occ = self.run.PathOnly(occ) 766 if self.run.IsDir(occ): 767 files = glob(osp.join(occ, '*.capy')) 768 else: 769 files = [occ, ] 770 for f in files: 771 mod, rep = self.GetCModif('capy', f) 772 # because filename is important, remove sha1 digest 773 mod = unique_basename_remove(mod) 774 dest = osp.join(bascpy, rep, mod + '.capy') 775 iret = self.run.Copy(dest, f, verbose=True) 776 if not rep in repcatapy: 777 self._mess(ufmt(_('unknown module name : %s'), rep), '<A>_ALARM') 778 779 # ----- apply CATSUPPR directives from unigest 780 if 'unigest' in kargs: 781 force = True 782 for f in kargs['unigest']['capy']: 783 self.run.Delete(osp.join(reptrav, f), verbose=True) 784 785 # ----- build cata.py 786 if osp.exists(fcapy): 787 self.run.Delete(fcapy) 788 789 # ----- test if compilation can be skipped 790 if force or not osp.exists(osp.join(cmde, fcapy)): 791 force = True 792 else: 793 ltest = glob(osp.join(bascpy, '*', '*.capy')) 794 for f in ltest: 795 if not is_newer(osp.join(cmde, fcapy), f): 796 force = True 797 break 798 799 if not force: 800 self.run.VerbStart(_('compilation of commands'), verbose=True) 801 self.run.VerbIgnore(verbose=True) 802 else: 803 fo = open(fcapy, 'w') 804 for rep in repcatapy: 805 lcapy = glob(osp.join(bascpy, rep, '*.capy')) 806 lcapy.sort() 807 for capy in lcapy: 808 fo2 = open(capy, 'r') 809 fo.write(fo2.read()) 810 fo2.close() 811 fo.close() 812 813 # ----- compile cata.py 814 dtmp = kargs.copy() 815 dtmp['exe'] = exe 816 dtmp['cmde'] = reptrav 817 if 'py' in kargs: 818 dtmp['py'] = kargs['py'] 819 self.PrepEnv(REPREF, reptrav, **dtmp) 820 821 self.run.VerbStart(_('compilation of commands'), verbose=True) 822 cmd_import = """ 823import sys 824sys.path.insert(0, "%s") 825iret = 0 826try: 827 from Cata import cata 828 from Cata.cata import JdC 829 cr = JdC.report() 830 if not cr.estvide() : 831 iret = 4 832 print ">> Catalogue de commandes : DEBUT RAPPORT" 833 print cr 834 print ">> Catalogue de commandes : FIN RAPPORT" 835except: 836 iret = 4 837 import traceback 838 traceback.print_exc(file=sys.stdout) 839sys.exit(iret) 840""" % self.conf['REPPY'][0] 841 cmd_import_file = osp.join(reptrav, 'cmd_import.py') 842 with open(cmd_import_file, 'w') as f: 843 f.write(cmd_import) 844 845 if self.verbose: 846 print() 847 cmd = [osp.join('.', osp.basename(exe))] 848 cmd.append(cmd_import_file) 849 cmd_exec = self.runner.get_exec_command(' '.join(cmd), 850 env=self.conf.get_with_absolute_path('ENV_SH')) 851 iret, out = self.run.Shell(cmd_exec) 852 # ----- avoid to duplicate output 853 if not self.verbose: 854 self.run.VerbEnd(iret, output=out, verbose=True) 855 if iret != 0: 856 self._mess(ufmt(_('error during compiling %s'), fcapy), '<E>_CATAPY_ERROR') 857 else: 858 kret = self.run.Copy(cmde, 859 osp.join(self.conf['REPPY'][0], 'Cata', fcapy_), verbose=True) 860 self._mess(_('Commands catalogue successfully compiled'), 'OK') 861 862 863 # --- translations... 864 if i18n: 865 pattern = '#:LANG:%s:LANG_END:' 866 old = pattern % '.*' 867 exp = re.compile(old, re.MULTILINE | re.DOTALL) 868 for lang in [l for l in self.conf['I18N'] if not l in ('', 'fr')]: 869 self.run.VerbStart(ufmt(_('working for i18n (language %s)...'), lang), 870 verbose=True) 871 print() 872 new = pattern % (os.linesep + "lang = '%s'" % lang + os.linesep + '#') 873 cata_out = fmt_catapy % ('_' + lang, '') 874 cata_out_ = fmt_catapy % ('_' + lang, '*') 875 tmpl_dict = get_tmpname(self.run, basename='template_dict_%s.py' % lang) 876 # fake aster module 877 with open(osp.join(self.conf['REPPY'][0], 'aster.py'), 'w') as f: 878 f.write(""" 879# fake aster module 880""") 881 sys.path.insert(0, self.conf['REPPY'][0]) 882 iret = 0 883 try: 884 from Cata.i18n_cata import i18n_make_cata_fich 885 txt_cata = i18n_make_cata_fich(fichier_dtrans=tmpl_dict, lang=lang) 886 txt_orig = [] 887 fo = open(cata_out, 'w') 888 # prendre l'entete 889 for rep in repcatapy[:1]: 890 for capy in glob(osp.join(bascpy, rep, '*.capy')): 891 with open(capy, 'r') as f: 892 txt0 = f.read() 893 txt2 = exp.sub(new, txt0) 894 fo.write(txt2) 895 # reprendre les imports 896 for rep in repcatapy[1:]: 897 for capy in glob(osp.join(bascpy, rep, '*.capy')): 898 fo.write(get_txt_capy(capy)) 899 with open(capy, 'r') as f: 900 txt_orig.append(f.read()) 901 fo.write(os.linesep) 902 fo.write(txt_cata) 903 fo.write(os.linesep) 904 fo.write(os.linesep.join(txt_orig)) 905 fo.close() 906 except: 907 iret = 4 908 import traceback 909 traceback.print_exc(file=magic.get_stdout()) 910 911 # ----- avoid to duplicate output 912 if not self.verbose: 913 self.run.VerbEnd(iret, output=out, verbose=True) 914 915 if iret != 0: 916 self._mess(ufmt(_("error during building %s"), cata_out), '<E>_I18N_ERROR') 917 else: 918 kret = self.run.Copy(cmde, cata_out_, verbose=True) 919 self._mess(ufmt(_('Commands catalogue successfully translated ' \ 920 '(language %s)'), lang), 'OK') 921 922 os.chdir(prev) 923 if not kargs.get('keep_reptrav'): 924 self.run.Delete(reptrav) 925 return iret 926 927 def CompilEle(self, REPREF, reptrav, ele='', **kargs): 928 """Compile elements catalogue as 'ele' from cata_ele.pickled. 929 kargs must contain arguments for a Code_Aster execution (i.e. for PrepEnv) 930 and optionaly : 931 cata : a list of user's elements files 932 unigest : GetUnigest dict with "CATSUPPR catalo module" entries 933 pickled : use a different cata_ele.pickled (not in REPREF) 934 (make_surch_offi needs unigest filename) 935 All args can be remote. 936 """ 937 self._mess(_('Compilation of elements catalogue'), 'TITLE') 938 required = ('exe', 'cmde') 939 if ele == '': 940 ele = osp.join(REPREF, self.conf['BINELE'][0]) 941 pickled = kargs.get("pickled", osp.join(REPREF, self.conf['BINPICKLED'][0])) 942 prev = os.getcwd() 943 # ----- check for required arguments 944 for a in required: 945 if a not in kargs: 946 self._mess('(CompilEle) '+_('argument %s is required') % a, 947 '<E>_PROGRAM_ERROR') 948 949 # ----- check that files and directories in kargs exist 950 self._check_file_args(list(kargs.values())) 951 if not osp.isdir(reptrav): 952 iret = self.run.MkDir(reptrav, verbose=True) 953 self.run.CheckOK() 954 955 # ----- work in repobj 956 reptrav = self.runner.set_rep_trav(reptrav) 957 os.chdir(reptrav) 958 959 # ----- if force is True, don't use ctime to skip a file 960 force = self.run['force'] 961 962 # 1. ----- if 'cata' is in kargs 963 if 'cata' in kargs: 964 force = True 965 self._mess(_("copy user's catalogues")) 966 fo = open('surch.cata', 'w') 967 # ----- catapy given by user 968 lobj = kargs['cata'] 969 if not type(lobj) in (list, tuple): 970 lobj = [kargs['cata'], ] 971 for occ in lobj: 972 obj = occ 973 if self.run.IsRemote(occ): 974 obj = osp.join(reptrav, '__tmp__'+osp.basename(occ)) 975 iret = self.run.MkDir(obj) 976 if self.run.IsDir(occ): 977 src = osp.join(occ, '*.cata') 978 else: 979 src = occ 980 iret = self.run.Copy(obj, src) 981 files = glob(osp.join(obj, '*.cata')) 982 else: 983 occ = self.run.PathOnly(occ) 984 if self.run.IsDir(occ): 985 files = glob(osp.join(occ, '*.cata')) 986 else: 987 files = [occ, ] 988 for f in files: 989 fo2 = open(f, 'r') 990 self.run.VerbStart(ufmt(_('adding %s'), f), verbose=True) 991 fo.write(fo2.read()) 992 self.run.VerbEnd(iret=0, output='', verbose=True) 993 fo2.close() 994 fo.close() 995 996 # 2. ----- compile elements with MAKE_SURCH_OFFI 997 self.PrepEnv(REPREF, reptrav, **kargs) 998 iret = 0 999 cmd = [osp.join('.', osp.basename(kargs['exe']))] 1000 cmd.append(osp.join(self.conf['REPPY'][0], self.conf['MAKE_SURCH_OFFI'][0])) 1001 cmd.extend(self.conf['REPPY']) 1002 cmd.append('MAKE_SURCH') 1003 cmd.append('surch.cata') 1004 funig = 'unigest_bidon' 1005 if 'unigest' in kargs: 1006 force = True 1007 funig = kargs['unigest']['filename'] 1008 if self.run.IsRemote(funig): 1009 funig = 'unigest' 1010 kret = self.run.Copy(funig, kargs['unigest']['filename']) 1011 else: 1012 funig = self.run.PathOnly(funig) 1013 cmd.append(funig) 1014 cmd.append(pickled) 1015 cmd.append('fort.4') 1016 self.run.VerbStart(ufmt(_('pre-compilation of elements with %s'), 1017 osp.basename(self.conf['MAKE_SURCH_OFFI'][0])), verbose=True) 1018 1019 # 2.1. ----- test if compilation can be skipped 1020 if force or not osp.exists(ele): 1021 force = True 1022 else: 1023 ltest = [pickled, ] 1024 ltest.extend(glob(osp.join(self.conf['REPPY'][0], '*', '*.py'))) 1025 for f in ltest: 1026 if not is_newer(ele, f): 1027 force = True 1028 self.run.DBG('%s more recent than %s' % (f, ele)) 1029 break 1030 1031 if not force: 1032 self.run.VerbIgnore(verbose=True) 1033 else: 1034 if self.verbose: 1035 print() 1036 cmd_exec = self.runner.get_exec_command(' '.join(cmd), 1037 env=self.conf.get_with_absolute_path('ENV_SH')) 1038 jret, out = self.run.Shell(cmd_exec) 1039 # ----- avoid to duplicate output 1040 if not self.verbose: 1041 self.run.VerbEnd(jret, output=out, verbose=True) 1042 if jret != 0: 1043 self._mess(_('error during pre-compilation of elements'), 1044 '<F>_CATAELE_ERROR') 1045 1046 # 3. ----- build elem.1 with kargs['exe'] 1047 cmd = [osp.join('.', osp.basename(kargs['exe']))] 1048 cmd.append(osp.join(self.conf['REPPY'][0], self.conf['ARGPYT'][0])) 1049 cmd.extend(self.conf['ARGEXE']) 1050 # <512 for 32 bits builds 1051 cmd.append('-commandes fort.1 -memjeveux 500 -tpmax 120') 1052 fo = open('fort.1', 'w') 1053 fo.write(""" 1054# COMPILATION DU CATALOGUE D'ELEMENT 1055DEBUT ( CATALOGUE = _F( FICHIER = 'CATAELEM' , UNITE = 4 )) 1056MAJ_CATA ( ELEMENT = _F()) 1057FIN() 1058""") 1059 fo.close() 1060 self.run.VerbStart(ufmt(_('compilation of elements with %s'), kargs['exe']), verbose=True) 1061 1062 jret = 0 1063 if not force: 1064 self.run.VerbIgnore(verbose=True) 1065 else: 1066 if self.verbose: 1067 print() 1068 cmd_exec = self.runner.get_exec_command(' '.join(cmd), 1069 env=self.conf.get_with_absolute_path('ENV_SH')) 1070 jret, out = self.run.Shell(cmd_exec) 1071 # ----- diagnostic of Code_Aster execution 1072 diag = self.getDiag()[0] 1073 if self.run.GetGrav(diag) < self.run.GetGrav('<S>') \ 1074 and osp.exists('elem.1'): 1075 pass 1076 else: 1077 jret = 4 1078 # ----- avoid to duplicate output 1079 if not self.verbose: 1080 self.run.VerbEnd(jret, output=out, verbose=True) 1081 if jret == 0: 1082 self._mess(_('Elements catalogue successfully compiled'), diag) 1083 else: 1084 self.run.DoNotDelete(reptrav) 1085 print(_(' To re-run compilation manually :')) 1086 print(' cd %s' % reptrav) 1087 print(' ', cmd_exec) 1088 self._mess(_('error during compilation of elements'), 1089 '<F>_CATAELE_ERROR') 1090 1091 # 4. ----- copy elements to 'ele' 1092 iret = self.run.Copy(ele, 'elem.1', verbose=True) 1093 1094 os.chdir(prev) 1095 self.run.Delete(reptrav) 1096 return iret 1097 1098 def MakePickled(self, REPREF, reptrav, repdest='', **kargs): 1099 """Make 'repdest'/cata_ele.pickled. 1100 kargs can contain : 1101 exe : Code_Aster executable or Python interpreter (can be remote) 1102 """ 1103 self._mess(_('Prepare cata_ele.pickled'), 'TITLE') 1104 if repdest == '': 1105 repdest = REPREF 1106 prev = os.getcwd() 1107 # ----- check if reptrav exists 1108 if not osp.isdir(reptrav): 1109 iret = self.run.MkDir(reptrav, verbose=True) 1110 1111 # ----- work in repobj 1112 reptrav = self.runner.set_rep_trav(reptrav) 1113 os.chdir(reptrav) 1114 1115 # ----- if force is True, don't use ctime to skip a file 1116 force = self.run['force'] 1117 1118 # ----- use REPREF/aster?.exe or kargs['exe'] 1119 iret = 0 1120 if 'exe' in kargs: 1121 exe = kargs['exe'] 1122 if self.run.IsRemote(exe): 1123 kret = self.run.Copy(reptrav, exe) 1124 exe = osp.join(reptrav, osp.basename(exe)) 1125 else: 1126 exe = self.run.PathOnly(exe) 1127 else: 1128 exe = osp.join(REPREF, self.conf['BIN_NODBG'][0]) 1129 if not self.run.Exists(exe): 1130 exe = osp.join(REPREF, self.conf['BIN_DBG'][0]) 1131 1132 # ----- call MAKE_CAPY_OFFI 1133 cmd = [exe, ] 1134 cmd.append(osp.join(REPREF, self.conf['SRCPY'][0], self.conf['MAKE_CAPY_OFFI'][0])) 1135 cmd.append(osp.join(REPREF, self.conf['SRCPY'][0])) 1136 cmd.append('TRAV_PICKLED') 1137 cmd.append(osp.join(REPREF, self.conf['SRCCATA'][0])) 1138 cata_pickled = osp.basename(self.conf['BINPICKLED'][0]) 1139 cmd.append(cata_pickled) 1140 1141 # ----- test if compilation can be skipped 1142 if not osp.exists(osp.join(repdest, self.conf['BINPICKLED'][0])): 1143 force = True 1144 else: 1145 ltest = glob(osp.join(REPREF, self.conf['SRCCATA'][0], '*', '*.cata')) 1146 ltest.extend(glob(osp.join(REPREF, self.conf['SRCPY'][0], '*', '*.py'))) 1147 for f in ltest: 1148 if not is_newer(osp.join(repdest, self.conf['BINPICKLED'][0]), f): 1149 force = True 1150 break 1151 1152 self.run.VerbStart(ufmt(_('build cata_ele.pickled with %s'), 1153 osp.basename(self.conf['MAKE_CAPY_OFFI'][0])), verbose=True) 1154 1155 if not force: 1156 self.run.VerbIgnore(verbose=True) 1157 else: 1158 if self.verbose: 1159 print() 1160 cmd_exec = self.runner.get_exec_command(' '.join(cmd), 1161 env=self.conf.get_with_absolute_path('ENV_SH')) 1162 jret, out = self.run.Shell(cmd_exec) 1163 # ----- avoid to duplicate output 1164 if not self.verbose: 1165 self.run.VerbEnd(jret, output=out, verbose=True) 1166 if jret == 0 and osp.exists(cata_pickled): 1167 self._mess(_('cata_ele.pickled successfully created'), 'OK') 1168 else: 1169 self._mess(_('error during making cata_ele.pickled'), 1170 '<F>_PICKLED_ERROR') 1171 1172 # ----- copy cata_ele.pickled to 'repdest' 1173 iret = self.run.Copy(osp.join(repdest, self.conf['BINPICKLED'][0]), 1174 cata_pickled, verbose=True) 1175 1176 os.chdir(prev) 1177 self.run.Delete(reptrav) 1178 return iret 1179 1180 def GetUnigest(self, funig): 1181 """Build a dict of the file names by parsing unigest file 'funig' where 1182 the keys are 'f', 'f90', 'c', 'py', 'capy', 'cata', 'test' and 'fdepl'. 1183 funig can be remote. 1184 """ 1185 dico = {} 1186 # ----- check that file exists 1187 if not self.run.Exists(funig): 1188 self._mess(ufmt(_('file not found : %s'), funig), '<A>_ALARM') 1189 return dico 1190 # ----- copy funig if it's a remote file 1191 if self.run.IsRemote(funig): 1192 name = '__tmp__.unigest' 1193 kret = self.run.Copy(name, funig) 1194 else: 1195 name = self.run.PathOnly(funig) 1196 1197 dico = unigest2dict(name, self.conf) 1198 return dico 1199 1200 def getDiag(self, err='fort.9', resu='fort.8', mess='fort.6', 1201 cas_test=False): 1202 """Return the diagnostic after a Code_Aster execution 1203 as a list : [diag, tcpu, tsys, ttotal, telapsed] 1204 err : error file 1205 resu : result file (None = ignored) 1206 mess : messages file (None = ignored) 1207 """ 1208 run = self.run 1209 diag, tcpu, tsys, ttot, telap = '<F>_ABNORMAL_ABORT', 0., 0., 0., 0. 1210 1211 # 1. ----- parse error file 1212 diag2, stop = _diag_erre(err) 1213 run.DBG('Fichier : %s' % err, '_diag_erre : %s' % diag2) 1214 diag = diag2 or diag 1215 if stop: 1216 run.ASSERT(diag != None) 1217 else: 1218 # if .erre doesn't exist, do the same analysis with .resu 1219 if diag2 is None: 1220 diag2, stop = _diag_erre(resu) 1221 run.DBG('Fichier : %s' % resu, '_diag_erre : %s' % diag2) 1222 diag = diag2 or diag 1223 1224 if stop: 1225 run.ASSERT(diag != None) 1226 else: 1227 # 2. ----- parse result and mess files 1228 diag, tcpu, tsys, ttot, telap = _diag_resu(resu, cas_test=cas_test) 1229 run.DBG('Fichier : %s' % resu, '_diag_resu : %s' % diag) 1230 diag2, stop2 = _diag_erre(mess, mess=True) 1231 run.DBG('Fichier : %s' % mess, '_diag_erre : %s' % diag2) 1232 if diag and diag2 and run.GetGrav(diag2) > run.GetGrav(diag): 1233 diag = diag2 1234 # if resu doesn't exist, trying with .mess 1235 if diag is None or diag.startswith('<S>'): 1236 diag = _diag_mess(mess) or 'NO_RESU_FILE' 1237 run.DBG('Fichier : %s' % mess, '_diag_mess : %s' % diag) 1238 1239 return diag, tcpu, tsys, ttot, telap 1240 1241 def GetCModif(self, typ, fich): 1242 """Retourne, pour `typ` = 'capy'/'py', le nom du module et du package. 1243 `fich` est local. 1244 """ 1245 para = { 1246 'capy' : { 'comment' : '#&', 'nmin' : 3 }, 1247 'py' : { 'comment' : '#@', 'nmin' : 4 }, 1248 } 1249 if typ not in list(para.keys()): 1250 self._mess(ufmt(_('invalid type : %s'), typ), '<F>_PROGRAM_ERROR') 1251 1252 with open(fich, 'r') as f: 1253 lig = f.readline().split() 1254 if len(lig) < para[typ]['nmin'] or \ 1255 (len(lig) > 0 and lig[0] != para[typ]['comment']): 1256 self._mess(ufmt(_("invalid first line of file : %s\n" \ 1257 " Should start with '%s' and have at least %s fields"), 1258 osp.basename(fich), para[typ]['comment'], para[typ]['nmin']), 1259 '<F>_INVALID_FILE') 1260 1261 if typ == 'py': 1262 mod = lig[2] 1263 rep = lig[3] 1264 elif typ == 'capy': 1265 mod = osp.splitext(osp.basename(fich))[0] 1266 rep = lig[2].lower() 1267 1268 return mod, rep 1269 1270 1271 def _check_file_args(self, args): 1272 """Check that files and directories in arguments exist.""" 1273 if type(args) not in (list, tuple): 1274 args = [args, ] 1275 for occ in args: 1276 obj = occ 1277 if not type(occ) in (list, tuple): 1278 obj = [occ,] 1279 for rep in obj: 1280 if type(rep) not in (str, str): 1281 continue 1282 if not self.run.Exists(rep): 1283 self._mess(ufmt(_('path does not exist : %s'), rep), 1284 '<E>_FILE_NOT_FOUND') 1285 1286class AsterBuild_CataZip(AsterBuild_Classic): 1287 1288 def CompilCapy(self, REPREF, reptrav, exe='', cmde='', i18n=False, **kargs): 1289 """Also build the zipped catalogue.""" 1290 kargs['keep_reptrav'] = True 1291 iret = AsterBuild_Classic.CompilCapy(self, REPREF, reptrav, exe, cmde, i18n, **kargs) 1292 if iret != 0: 1293 return iret 1294 prev = os.getcwd() 1295 reptrav = self.runner.set_rep_trav(reptrav) 1296 os.chdir(osp.join(reptrav, self.conf['REPPY'][0])) 1297 name = osp.join(osp.dirname(cmde), self.conf['BINCMDE_ZIP'][0]) 1298 zip = ZipFile(name, 'w') 1299 for fname in ('__init__.py', 'cata.py', 'ops.py'): 1300 zip.write(osp.join('Cata', fname)) 1301 zip.close() 1302 os.chdir(prev) 1303 self.run.Delete(reptrav) 1304 return iret 1305 1306class AsterBuildInstalled(AsterBuild_Classic): 1307 """For a version installed by waf: 1308 - do not copy the executable, 1309 - do not copy bibpyt, Cata is already available in PYTHONPATH 1310 """ 1311 attr = ('waf', ) 1312 1313 def PrepEnv(self, REPREF, repdest, dbg='nodebug', lang='', **kargs): 1314 """Prepare 'repdest' with Code_Aster environment from REPREF and 1315 given arguments in kargs[k] (k in 'exe', 'cmde', 'ele', 'py', 'unigest'). 1316 Note : - REPREF/elements and kargs['ele'] don't exist when building 1317 elements for the first time. 1318 All elements of kargs can be remote. 1319 """ 1320 prev = os.getcwd() 1321 if not osp.isdir(repdest): 1322 iret = self.run.MkDir(repdest, verbose=True) 1323 self.run.CheckOK() 1324 1325 # ----- copy REPREF/elements or kargs['ele'] 1326 iret = 0 1327 if 'ele' in kargs: 1328 src = kargs['ele'] 1329 else: 1330 src = osp.join(REPREF, self.conf['BINELE'][0]) 1331 if self.run.Exists(src) and src != osp.join(repdest, 'elem.1'): 1332 # symlink not allowed for elem.1 (rw) 1333 iret = self.run.Copy(osp.join(repdest, 'elem.1'), src, verbose=True) 1334 make_writable(osp.join(repdest, 'elem.1')) 1335 else: 1336 self.run.VerbStart(ufmt(_('copying %s...'), src), verbose=True) 1337 self.run.VerbIgnore(verbose=True) 1338 1339 # ----- result directories 1340 os.chdir(repdest) 1341 self.run.MkDir('REPE_OUT') 1342 1343 os.chdir(prev) 1344 return iret 1345 1346class AsterBuildInstalledNoCopy(AsterBuild_Classic): 1347 """For a version installed by waf and with enhancements to directly use the 1348 installation directory with no copy. 1349 The elements catalog is found using the ASTER_ELEMENTSDIR environment 1350 variable, Cata is already available in PYTHONPATH. 1351 """ 1352 attr = ('waf', 'nocopy') 1353 1354 def PrepEnv(self, REPREF, repdest, dbg='nodebug', lang='', **kargs): 1355 """Prepare 'repdest' with Code_Aster environment from REPREF""" 1356 iret = 0 1357 prev = os.getcwd() 1358 if not osp.isdir(repdest): 1359 iret = self.run.MkDir(repdest, verbose=True) 1360 self.run.CheckOK() 1361 1362 # ----- result directories 1363 os.chdir(repdest) 1364 self.run.MkDir('REPE_OUT') 1365 1366 os.chdir(prev) 1367 return iret 1368 1369class AsterBuildInstalledNoResu(AsterBuildInstalledNoCopy): 1370 """For a version installed by waf, with enhancements to directly use the 1371 installation directory with no copy. 1372 This version does not create '.resu' file. 1373 """ 1374 attr = ('waf', 'nocopy', 'noresu') 1375 1376 def getDiag(self, mess='fort.6', cas_test=False, **kwargs): 1377 """Return the diagnostic after a Code_Aster execution 1378 as a list : [diag, tcpu, tsys, ttotal, telapsed] 1379 mess : messages file (None = ignored) 1380 """ 1381 return AsterBuildInstalledNoCopy.getDiag(self, mess, mess, mess, 1382 cas_test) 1383 1384class AsterBuildInstalledNoSuperv(AsterBuildInstalledNoCopy): 1385 """For a version installed by waf, with enhancements to directly use the 1386 installation directory with no copy, and without the Python supervisor. 1387 """ 1388 attr = ('waf', 'nocopy', 'nosuperv') 1389 1390 1391class AsterBuildInstalledNoSupervNoResu(AsterBuildInstalledNoResu): 1392 """For a version installed by waf, with enhancements to directly use the 1393 installation directory with no copy, and without the Python supervisor. 1394 This version does not create '.resu' file. 1395 """ 1396 attr = ('waf', 'nocopy', 'noresu', 'nosuperv') 1397 1398 1399def AsterBuild(run, conf): 1400 """Return the relevant AsterBuild_xxx implementation depending on 1401 parameters of the AsterConfig object.""" 1402 klass = AsterBuild_Classic 1403 if 'nosuperv' in conf['BUILD_TYPE'][0]: 1404 if 'noresu' in conf['BUILD_TYPE'][0]: 1405 klass = AsterBuildInstalledNoSupervNoResu 1406 else: 1407 klass = AsterBuildInstalledNoSuperv 1408 elif 'noresu' in conf['BUILD_TYPE'][0]: 1409 klass = AsterBuildInstalledNoResu 1410 elif 'nocopy' in conf['BUILD_TYPE'][0]: 1411 klass = AsterBuildInstalledNoCopy 1412 elif 'waf' in conf['BUILD_TYPE'][0]: 1413 klass = AsterBuildInstalled 1414 elif conf['BINCMDE_ZIP'][0] != '': 1415 klass = AsterBuild_CataZip 1416 builder = klass(run, conf) 1417 # add extras features (better than check the version) 1418 for feature in ('use_numthreads', 'orbinitref', 'container'): 1419 if feature in conf['BUILD_TYPE'][0]: 1420 builder.addFeature(feature) 1421 run.DBG("version supports: {0}".format(builder.attr)) 1422 return builder 1423 1424 1425def get_txt_capy(capy): 1426 """On utilise le fait qu'il n'y a rien après la définition de l'OPER, PROC ou MACRO. 1427 """ 1428 with open(capy, 'r') as f: 1429 txt = f.read() 1430 expr = re.compile('^[A-Za-z_0-9]+ *= *[OPERPROCMACROFORM]+ *\(.*', 1431 re.MULTILINE | re.DOTALL) 1432 sans_op = expr.sub('', txt) 1433 keep = [''] 1434 for line in sans_op.splitlines(): 1435 if not re.search('^ *#', line): 1436 keep.append(line) 1437 keep.append('') 1438 return os.linesep.join(keep) 1439 1440_no_convergence_exceptions = ( 1441 'NonConvergenceError', 'EchecComportementError', 'PilotageError', 1442) 1443_contact_exceptions = ( 1444 'TraitementContactError', 'MatriceContactSinguliereError', 1445 'BoucleGeometrieError', 'BoucleFrottementError', 'BoucleContactError', 1446 'CollisionError', 'InterpenetrationError', 1447) 1448 1449def _diag_erre(err, mess=False): 1450 """Diagnostic à partir du fichier '.erre'. 1451 Si le fichier n'existe pas, on retourne (None, False). 1452 Pour un fichier de message, 'ARRET NORMAL DANS FIN' est absent, donc on ne 1453 peut pas déterminer 'ok'. 1454 """ 1455 run = magic.run 1456 diag = None 1457 stop = False 1458 if err is None or not os.access(err, os.R_OK): 1459 pass 1460 else: 1461 with open(err, 'rb') as f: 1462 txt = to_unicode(f.read()) 1463 1464 n_debut = re_search(txt, string="-- CODE_ASTER -- VERSION", result='number') 1465 n_fin = re_search(txt, 1466 string="""<I> <FIN> ARRET NORMAL DANS "FIN" PAR APPEL A "JEFINI".""", 1467 result='number', flag=re.IGNORECASE) 1468 1469 alarm = re_search(txt, pattern='^ *. *%s', string='<A>') 1470 fatal = re_search(txt, pattern='^ *. *%s', string='<F>') 1471 exitcode = re_search(txt, pattern='^ *%s_EXIT_CODE = ([0-9]+)', 1472 string='<I>', result='value') 1473 exitcode = exitcode and int(exitcode[0]) or 0 1474 1475 if fatal: 1476 expir = re_search(txt, pattern='^ *. *%s', 1477 string='<F> <INIAST> VERSION EXPIREE', flag=re.IGNORECASE) 1478 superv = re_search(txt, pattern='^ *. *%s', 1479 string='<F> <SUPERVISEUR> ARRET SUR ERREUR(S) UTILISATEUR', 1480 flag=re.IGNORECASE) 1481 else: 1482 expir = superv = False 1483 1484 errs = re_search(txt, pattern='^ *. *%s', string='<S>') 1485 1486 if errs: 1487 mem = re_search(txt, string='MEMOIRE INSUFFISANTE POUR ALLOUER', flag=re.IGNORECASE) 1488 arretcpu = re_search(txt, string='ARRET PAR MANQUE DE TEMPS', flag=re.IGNORECASE) \ 1489 or re_search(txt, pattern='<%s>', string='ArretCPUError') \ 1490 or re_search(txt, string='timelimit expired', flag=re.IGNORECASE) 1491 nonconverg = max([re_search(txt, pattern='<%s>', string=exc) \ 1492 for exc in _no_convergence_exceptions]) 1493 contact = max([re_search(txt, pattern='<%s>', string=exc) \ 1494 for exc in _contact_exceptions]) 1495 else: 1496 mem = arretcpu = nonconverg = contact = False 1497 1498 ok = (n_debut == n_fin and n_fin > 0) or mess 1499 run.DBG('n_debut=%s, n_fin=%s, mess=%s : ok=%s' % (n_debut, n_fin, mess, ok)) 1500 run.DBG('alarm=%s, errs=%s, fatal=%s, exitcode=%s' % (alarm, errs, fatal, exitcode)) 1501 if ok: 1502 diag = 'OK' 1503 if alarm: 1504 diag = '<A>_ALARM' 1505 if exitcode != 0: 1506 errs = True 1507 # "S" (recoverable) error 1508 if errs: 1509 diag = '<S>_ERROR' 1510 if arretcpu: 1511 diag = '<S>_CPU_LIMIT' 1512 elif nonconverg: 1513 diag = '<S>_NO_CONVERGENCE' 1514 elif contact: 1515 diag = '<S>_CONTACT_ERROR' 1516 elif mem: 1517 diag = '<S>_MEMORY_ERROR' 1518 # fatal error 1519 if fatal: 1520 diag = '<F>_ERROR' 1521 if superv: 1522 diag = '<F>_SUPERVISOR' 1523 elif expir: 1524 diag = '<F>_EXPIRED_VERS' 1525 if not ok or fatal or errs: 1526 stop = True 1527 1528 return diag, stop 1529 1530 1531def _diag_resu(resu, cas_test): 1532 """Diagnostic à partir du fichier '.resu'. 1533 """ 1534 diag, tcpu, tsys, ttot, telap = None, 0., 0., 0., 0. 1535 # 2. ----- parse result file 1536 if resu is None or not os.access(resu, os.R_OK): 1537 pass 1538 else: 1539 # OK / NOOK 1540 ok = False 1541 nook = False 1542 # <A>_ALARME 1543 alarm = False 1544 diag0 = diag 1545 1546 with open(resu, 'rb') as f: 1547 txt = to_unicode(f.read()) 1548 ok = re_search(txt, pattern='^ *OK +') 1549 nook = re_search(txt, pattern='^ *NOOK +') 1550 alarm = re_search(txt, pattern='^ *. *%s', string='<A>') 1551 1552 value = re_search(txt, result='value', 1553 pattern='TOTAL_JOB +: +([0-9\.]+) +: +([0-9\.]+) +: +([0-9\.]+) +: +([0-9\.]+)') 1554 if len(value) > 0: 1555 tcpu, tsys, ttot, telap = [float(v) for v in value[0]] 1556 1557 if nook: 1558 diag0 = 'NOOK_TEST_RESU' 1559 else: 1560 if cas_test and not ok: 1561 diag0 = 'NO_TEST_RESU' 1562 else: 1563 diag0 = 'OK' 1564 if alarm: 1565 diag0 = '<A>_ALARM' 1566 diag = diag0 1567 1568 return diag, tcpu, tsys, ttot, telap 1569 1570 1571def _diag_mess(mess): 1572 """Essaie de trouver des pistes supplémentaires si le .mess existe. 1573 """ 1574 diag = None 1575 if mess is None or not osp.isfile(mess): 1576 pass 1577 else: 1578 with open(mess, 'rb') as f: 1579 txt = to_unicode(f.read()) 1580 syntax = re_search(txt, string="ERREUR A LA VERIFICATION SYNTAXIQUE") or \ 1581 re_search(txt, pattern="ERREUR .*ACCAS") 1582 if syntax: 1583 diag = '<F>_SYNTAX_ERROR' 1584 1585 else: 1586 # recherche de la levée non récupérée d'exception 1587 arretcpu = re_search(txt, pattern='<%s>', string='ArretCPUError') \ 1588 or re_search(txt, string='timelimit expired', flag=re.IGNORECASE) 1589 if arretcpu: 1590 diag = '<S>_CPU_LIMIT' 1591 1592 return diag 1593 1594 1595def unigest2dict(funig, conf, with_fordepla=False): 1596 """Build a dict of the file names by parsing unigest file 'funig' where 1597 the keys are 'f', 'f90', 'c', 'py', 'capy', 'cata', 'test' and 'fdepl'. 1598 funig can be remote. 1599 """ 1600 repref = { 'bibfor' : 'f', 'bibf90' : 'f90', 'bibc' : 'c', 'bibpyt' : 'py', 1601 'catapy' : 'capy', 'catalo' : 'cata', 'astest' : 'test' } 1602 dico = {} 1603 for cat in ('f', 'f90', 'c', 'py', 'capy', 'cata', 'test', 'fdepl'): 1604 dico[cat] = [] 1605 1606 # ----- keep a reference to the file for CompilEle 1607 dico['filename'] = funig 1608 assert osp.exists(funig), 'file not found : %s' % funig 1609 1610 # parse unigest 1611 fo = open(funig, 'r') 1612 for line in fo: 1613 # new syntax : SUPPR bibfor/algeline/zzzzzz.f 1614 mat = re.search('^ *SUPPR +([^\s]+)', line) 1615 if mat: 1616 path = mat.group(1).strip() 1617 mod = split_path(path)[0] 1618 key = repref.get(mod) 1619 if key: 1620 if key == 'test' and osp.splitext(path)[-1] in ('', '.comm'): 1621 path = osp.splitext(path)[0] + '.*' 1622 # force use of native separator 1623 path = osp.join(*split_path(path)) 1624 dico[key].append(path) 1625 1626 mat = re.search('^ *FORSUPPR +([-_a-zA-Z0-9]+) +([-_a-zA-Z0-9]+)', line) 1627 if mat: 1628 nam = mat.group(1).lower()+'.f' 1629 mod = mat.group(2).lower() 1630 dico['f'].append(osp.join(conf['SRCFOR'][0], mod, nam)) 1631 1632 mat = re.search('^ *F90SUPPR +([-_a-zA-Z0-9]+) +([-_a-zA-Z0-9]+)', line) 1633 if mat: 1634 nam = mat.group(1).lower()+'.F' 1635 mod = mat.group(2).lower() 1636 dico['f90'].append(osp.join(conf['SRCF90'][0], mod, nam)) 1637 1638 mat = re.search('^ *CSUPPR +([-_a-zA-Z0-9]+) +([-_a-zA-Z0-9]+)', line) 1639 if mat: 1640 nam = mat.group(1).lower()+'.c' 1641 mod = mat.group(2).lower() 1642 dico['c'].append(osp.join(conf['SRCC'][0], mod, nam)) 1643 1644 mat = re.search('^ *PYSUPPR +([-_a-zA-Z0-9]+) +([-_a-zA-Z0-9]+)', line) 1645 if mat: 1646 nam = mat.group(1)+'.py' 1647 mod = mat.group(2) 1648 dico['py'].append(osp.join(conf['SRCPY'][0], mod, nam)) 1649 1650 mat = re.search('^ *CATSUPPR +([-_a-zA-Z0-9]+) +([-_a-zA-Z0-9]+)', line) 1651 if mat: 1652 nam = mat.group(1).lower() 1653 mod = mat.group(2).lower() 1654 if mod in repcatapy: 1655 dico['capy'].append(osp.join(conf['SRCCAPY'][0], mod, nam+'.capy')) 1656 elif mod in repcatalo: 1657 dico['cata'].append(osp.join(conf['SRCCATA'][0], mod, nam+'.cata')) 1658 else: 1659 print('<A>_ALARM', ufmt(_('unknown type %s in unigest file'), mod), end=' ') 1660 1661 mat = re.search('^ *TESSUPPR +([-_a-zA-Z0-9\.]+)', line) 1662 if mat: 1663 nam = mat.group(1).lower() 1664 ext = osp.splitext(nam)[-1] 1665 if ext in ('', '.comm'): 1666 nam = osp.splitext(nam)[0] + '.*' 1667 dico['test'].extend([osp.join(dtest, nam) for dtest in conf['SRCTEST']]) 1668 1669 mat = re.search('^ *FORDEPLA +([-_a-zA-Z0-9]+) +([-_a-zA-Z0-9]+)' \ 1670 ' +([-_a-zA-Z0-9]+)', line) 1671 if mat: 1672 nam = mat.group(1).lower()+'.f' 1673 old = mat.group(2).lower() 1674 new = mat.group(3).lower() 1675 if with_fordepla: 1676 dico['fdepl'].append([osp.join(conf['SRCFOR'][0], old, nam), 1677 osp.join(conf['SRCFOR'][0], new, nam)]) 1678 else: 1679 dico['f'].append(osp.join(conf['SRCFOR'][0], old, nam)) 1680 fo.close() 1681 return dico 1682 1683def glob_unigest(dico, repref): 1684 """Expand paths relatively to `repref`.""" 1685 prev = os.getcwd() 1686 os.chdir(repref) 1687 dico = dico.copy() 1688 for key, values in list(dico.items()): 1689 if key == 'filename': 1690 continue 1691 new = [] 1692 for path in values: 1693 new.extend(glob(path)) 1694 dico[key] = new 1695 os.chdir(prev) 1696 return dico 1697 1698def get_include(src): 1699 """Returns include files in the given source.""" 1700 code = open(src, 'r').read() 1701 linc = re.findall('^\#include *[\"\<]{1}(.*)[\"\>]{1}', code, re.MULTILINE) 1702 return linc 1703 1704 1705def build_include_depend(*dirs): 1706 """Build a tree of dependencies between include files.""" 1707 linc = [] 1708 for dirsrc in dirs: 1709 for base, l_dirs, l_nondirs in os.walk(dirsrc): 1710 linc.extend(glob(osp.join(base, "*.h"))) 1711 wrk = {} 1712 for inc in linc: 1713 wrk[inc] = set() 1714 code = open(inc, 'r').read() 1715 for other in linc: 1716 if inc == other: 1717 continue 1718 mat = re.search('^\#include.*%s' % osp.basename(other), code, re.MULTILINE) 1719 if mat: 1720 wrk[inc].add(other) 1721 new = -1 1722 while new != 0: 1723 new = 0 1724 for inc in linc: 1725 n0 = len(wrk[inc]) 1726 for other in linc: 1727 if other in wrk[inc]: 1728 wrk[inc].update(wrk[other]) 1729 new = new + len(wrk[inc]) - n0 1730 dep = {} 1731 for key, val in list(wrk.items()): 1732 dep[osp.basename(key)] = list(val) 1733 return dep 1734 1735ASTER_BUILD = bwc_deprecate_class('ASTER_BUILD', AsterBuild) 1736