(file) Return to localize.py CVS log (file) (dir) Up to [Development] / JSOC

   1 arta  1.29 #!/usr/bin/env python
   2 arta  1.1  
   3 arta  1.13 # When run with the -s flag, localize.py configures the SUMS-server component of NetDRMS.
   4 arta  1.1  import sys
   5            import getopt
   6            import re
   7 arta  1.6  import os
   8            import stat
   9 arta  1.13 import filecmp
  10 arta  1.6  import xml.etree.ElementTree as ET
  11 arta  1.1  from subprocess import check_output, CalledProcessError
  12            
  13 arta  1.24 
  14 arta  1.1  # Constants
  15            VERS_FILE = 'jsoc_version.h'
  16            SDP_CFG = 'configsdp.txt'
  17            NET_CFG = 'config.local'
  18            NET_CFGMAP = 'config.local.map'
  19            RET_SUCCESS = 0
  20            RET_NOTDRMS = 1
  21            
  22 arta  1.2  PREFIX = """# This file was auto-generated by localize.py. Please do not edit it directly (running
  23            # configure will run localize.py, which will then overwrite any edits manually performed).
  24            """
  25 arta  1.1  
  26 arta  1.2  C_PREFIX = """/* This file was auto-generated by localize.py. Please do not edit it directly (running
  27             * configure will run localize.py, which will then overwrite any edits manually performed). */
  28 arta  1.1  """
  29            
  30 arta  1.2  PERL_BINPATH = '#!/usr/bin/perl\n'
  31            
  32            PERL_INTIAL = """package drmsparams;
  33 arta  1.28 
  34 arta  1.2  use warnings;
  35            use strict;
  36            """
  37            
  38            PERL_FXNS_A = """sub new
  39 arta  1.1  {
  40                my($clname) = shift;
  41 arta  1.28 
  42                my($self) =
  43 arta  1.1      {
  44                    _paramsH => undef
  45                };
  46 arta  1.28 
  47 arta  1.1      bless($self, $clname);
  48 arta  1.9      $self->{_paramsH} = {};
  49                $self->initialize();
  50 arta  1.28 
  51 arta  1.1      return $self;
  52            }
  53 arta  1.28 
  54 arta  1.1  sub DESTROY
  55            {
  56                my($self) = shift;
  57            }
  58 arta  1.2  """
  59            
  60            PERL_FXNS_B = """sub get
  61            {
  62                my($self) = shift;
  63                my($name) = shift;
  64                my($rv);
  65 arta  1.28 
  66 arta  1.2      if (exists($self->{_paramsH}->{$name}))
  67                {
  68                    return $self->{_paramsH}->{$name};
  69                }
  70                else
  71                {
  72                    return undef;
  73                }
  74            }
  75            1;"""
  76 arta  1.1  
  77 arta  1.29 PY_BINPATH = '#!/usr/bin/env python\n'
  78            
  79            PY_ERROR_CLASSES = """
  80            class DPError(Exception):
  81                def __init__(self):
  82                    self._msg = 'DRMS Parameter Error: '
  83            
  84            class DPMissingParameterError(DPError):
  85                def __init__(self, parameter):
  86                    super().__init__()
  87                    self._msg += 'missing DRMS parameter ' + parameter
  88            
  89                def __str__(self):
  90                    return self._msg
  91            """
  92 arta  1.18 
  93            PY_FXNS_A = """
  94 arta  1.23 class DRMSParams(object):
  95 arta  1.18     def __init__(self):
  96                    self.params = {}
  97                    self.initialize()
  98 arta  1.28 
  99 arta  1.18     def __del__(self):
 100                    del self.params
 101 arta  1.28 
 102 arta  1.18     def initialize(self):
 103            """
 104            
 105            PY_FXNS_B = """    def get(self, name):
 106                    if name in self.params:
 107 arta  1.20             return self.params[name]
 108 arta  1.18         else:
 109                        return None
 110            """
 111            
 112 arta  1.29 PY_FXNS_C = """    def get_required(self, name):
 113                    try:
 114                        value = self.params[name]
 115                    except:
 116                        raise DPMissingParameterError(name)
 117            
 118                    return value
 119            
 120                def getBool(self, name):
 121 arta  1.22         if name in self.params:
 122                        return bool(self.params[name] == '1')
 123                    else:
 124                        return None
 125 arta  1.29 
 126                def __getattr__(self, name):
 127                    # only called if object.__getattribute__(self, name) raises; and if that is true, then we want
 128                    # to look in self.params for it, and set the instance attribute if it does exist in self.params
 129                    if name in self.params:
 130                        attr = self.params[name]
 131                        self.__setattr__(name, attr)
 132                    else:
 133                        attr = None
 134            
 135                    return attr
 136            
 137                def __setattr__(self, name, value):
 138                    # call neither __setattr__ nor __getattr__
 139                    try:
 140                        params = object.__getattr__(self, 'params')
 141            
 142                        # put into self.params dict, overwriting if necessary
 143                        params[name] = value
 144                    except:
 145                        pass
 146 arta  1.29 
 147                    # store in instance dict as well
 148                    object.__setattr__(self, name, value)
 149 arta  1.22 """
 150            
 151 arta  1.25 SH_BINPATH = '#!/bin/bash\n'
 152            
 153 arta  1.22 
 154 arta  1.13 SUMRM_COMMENT = """# This is the configuration file for the sum_rm program. It was auto-generated by the DRMS master configure script.
 155            # It controls the behavior of the sum_rm program, and is loaded each time sum_rm runs. To change the
 156            # parameter values in this configuration file, modify config.local, then re-run configure. This configuration
 157            # file will be updated only if parameters affecting it are modified. If such changes are made to config.local,
 158            # please make sure that the sum_rm service is disabled while configure in running.
 159            """
 160            
 161 arta  1.28 SUMRM_DOC = """# sum_rm removes end-of-life SUMS data files to prevent disk-partitions from becomming 100% full.
 162 arta  1.13 # sum_svc, the main SUMS service, starts this daemon when it is launched. Within an infinite loop, sum_rm sleeps
 163            # for SLEEP number of seconds (defined below). When it awakes, it loads the sum_rm configuration file. For each SU,
 164            # it then examines the 'effective_date' column within the sum_partn_alloc table of the SUMS database. It does so by
 165            # sorting all SUs by effective date (this date is actually an expiration date - the SU is good until the end of that day),
 166            # and then, starting with the SU with the oldest effective date, it deletes the SUs. It continues deleting SUs until one
 167            # of three conditions is met:
 168            #
 169            #   (a) The disk has at least PART_PERCENT_FREE percent free space.
 170            #   (b) All SUs have effective_date values in the future.
 171            #   (c) At least 600 SUs have been deleted (this is defined in the LIMIT statement in the file SUMLIB_RmDoX.pgc).
 172            #
 173            # After sum_rm stops deleteing SUs, it then sleeps for SLEEP seconds, completing the first iteration of the
 174            # infinite loop.
 175            """
 176            
 177            SUMRM_PARTN_PERCENT_FREE = """
 178            # This is the percentage at which all disk partitions are to be kept free.
 179            # If not specified, this defaults to 3. For example, setting PART_PERCENT_FREE = 5 will allow all partitions to
 180            # fill to 95% full. Dividing the number of unused blocks by the total number of blocks, and rounding up,
 181            # will result in the number specified by PART_PERCENT_FREE.
 182            #
 183 arta  1.13 # NOTE : This behavior was previously controlled by the MAX_FREE_{n} family of parameters. {n} referred to the
 184            # disk-partition number and the value of parameter MAX_FREE_{n} was the MINIMUM number of free MB in the
 185            # partition [No clue why the word MAX was used]. As of NetDRMS 7.0, MAX_FREE_{n} has no effect."""
 186            
 187            SUMRM_SLEEP = """
 188            # The value is the number of seconds to sleep between iterations of the main loop in sum_rm."""
 189            
 190            SUMRM_LOG = """
 191            # The value is the log file (opened only at sum_rm startup; the sum_rm pid is appended to this file name)."""
 192            
 193            SUMRM_MAIL = """
 194            # The value is the email address of the recipient to be notified in case of a problem."""
 195            
 196            SUMRM_NOOP = """
 197            # If the value is set to anything other than 0, then sum_rm is rendered inactive. Otherwise, sum_rm is active."""
 198            
 199            SUMRM_USER = """
 200            # The value designates the linux user who is allowed to run sum_rm."""
 201            
 202            SUMRM_NORUN = """
 203            # This pair of paramters defines a window of time, during which sum_rm will become torpid - in this
 204 arta  1.13 # window, sum_rm will not scan for SUs to delete, not will it delete any SUs. Each value is an integer, 0-23, that
 205            # represents an hour of the day. For example, if NORUN_START=8 and NORUN_STOP=10, then between 8am and 10am
 206            # local time, sum_rm will be dormant. To disable this behavior, set both parameters to the same value."""
 207 arta  1.6  
 208            RULESPREFIX = """# Standard things
 209            sp 		:= $(sp).x
 210            dirstack_$(sp)	:= $(d)
 211            d		:= $(dir)
 212            """
 213            
 214            RULESSUFFIX = """dir	:= $(d)/example
 215            -include		$(SRCDIR)/$(dir)/Rules.mk
 216            dir	:= $(d)/cookbook
 217            -include		$(SRCDIR)/$(dir)/Rules.mk
 218            dir	:= $(d)/myproj
 219            -include		$(SRCDIR)/$(dir)/Rules.mk
 220            
 221            # Standard things
 222            d		:= $(dirstack_$(sp))
 223            sp		:= $(basename $(sp))
 224            """
 225            
 226            TARGETPREFIX = """$(PROJOBJDIR):\n\t+@[ -d $@ ] || mkdir -p $@"""
 227            
 228 arta  1.3  ICC_MAJOR = 9
 229            ICC_MINOR = 0
 230            GCC_MAJOR = 3
 231            GCC_MINOR = 0
 232            IFORT_MAJOR = 9
 233            IFORT_MINOR = 0
 234            GFORT_MAJOR = 4
 235            GFORT_MINOR = 2
 236            
 237            
 238 arta  1.1  # Read arguments
 239            #  d - localization directory
 240            #  b - base name of all parameter files (e.g., -b drmsparams --> drmsparams.h, drmsparams.mk, drmsparams.pm, etc.)
 241 arta  1.13 #  s - configure a NetDRMS server (i.e., SUMS server). Otherwise, do client configuration only. A server
 242            #      configuration will modify something that only the production user has access to. An example is the sum_rm.cfg
 243            #      file. To modify that file, the user running configure must be running configure on the SUMS-server host, and
 244            #      must have write permission on sum_rm.cfg.
 245 arta  1.1  def GetArgs(args):
 246                rv = bool(0)
 247                optD = {}
 248 arta  1.28 
 249 arta  1.1      try:
 250 arta  1.13         opts, remainder = getopt.getopt(args, "hd:b:s",["dir=", "base="])
 251 arta  1.1      except getopt.GetoptError:
 252                    print('Usage:')
 253                    print('localize.py [-h] -d <localization directory> -b <parameter file base>')
 254                    rv = bool(1)
 255 arta  1.28 
 256 arta  1.1      if rv == bool(0):
 257                    for opt, arg in opts:
 258                        if opt == '-h':
 259                            print('localize.py [-h] -d <localization directory> -b <parameter file base>')
 260                        elif opt in ("-d", "--dir"):
 261                            regexp = re.compile(r"(\S+)/?")
 262                            matchobj = regexp.match(arg)
 263                            if matchobj is None:
 264                                rv = bool(1)
 265                            else:
 266                                optD['dir'] = matchobj.group(1)
 267                        elif opt in ("-b", "--base"):
 268                            optD['base'] = arg
 269 arta  1.13             elif opt in ("-s"):
 270                            optD['server'] = ""
 271 arta  1.1              else:
 272                            optD[opt] = arg
 273 arta  1.28 
 274 arta  1.1      return optD
 275            
 276            def createMacroStr(key, val, keyColLen, status):
 277                if keyColLen < len(key):
 278                    status = bool(1)
 279                    return None
 280                else:
 281                    nsp = keyColLen - len(key)
 282                    spaces = str()
 283                    for isp in range(nsp):
 284                        spaces += ' '
 285                    status = bool(0)
 286                    return '#define ' + key + spaces + val + '\n'
 287            
 288            def createPerlConst(key, val, keyColLen, status):
 289                if keyColLen < len(key):
 290                    status = bool(1)
 291                    return None
 292                else:
 293                    nsp = keyColLen - len(key)
 294                    spaces = str()
 295 arta  1.1          for isp in range(nsp):
 296                        spaces += ' '
 297                    status = bool(0)
 298                    return 'use constant ' + key + ' => ' + spaces + val + ';\n'
 299            
 300 arta  1.18 def createPyConst(key, val, keyColLen, status):
 301                if keyColLen < len(key):
 302                    status = bool(1)
 303                    return None
 304                else:
 305                    nsp = keyColLen - len(key)
 306                    spaces = str()
 307                    for isp in range(nsp):
 308                        spaces += ' '
 309                    status = bool(0)
 310                    return key + ' = ' + spaces + val + '\n'
 311 arta  1.28 
 312 arta  1.25 def createShConst(key, val, status):
 313                status = bool(0)
 314                return key + '=' + val + '\n'
 315 arta  1.28 
 316 arta  1.18 
 317 arta  1.3  def isSupportedPlat(plat):
 318                regexp = re.compile(r"\s*(^x86_64|^ia32|^ia64|^avx)", re.IGNORECASE)
 319                matchobj = regexp.match(plat);
 320 arta  1.28 
 321 arta  1.3      if not matchobj is None:
 322                    return bool(1);
 323                else:
 324                    return bool(0);
 325            
 326 arta  1.6  def processMakeParam(mDefs, key, val, platDict, machDict):
 327 arta  1.3      varMach = None
 328                regexp = re.compile(r"(\S+):(\S+)")
 329                matchobj = regexp.match(key)
 330                if not matchobj is None:
 331                    varName = matchobj.group(1)
 332                    varMach = matchobj.group(2)
 333                else:
 334                    varName = key
 335 arta  1.28 
 336 arta  1.3      varValu = val
 337 arta  1.28 
 338 arta  1.3      if varMach is None:
 339                    mDefs.extend(list('\n' + varName + ' = ' + varValu))
 340                else:
 341                    if isSupportedPlat(varMach):
 342                        # The guard will compare varValu to $JSOC_MACHINE.
 343                        if not varMach in platDict:
 344                            platDict[varMach] = {}
 345                        platDict[varMach][varName] = varValu
 346                    else:
 347                        # The guard will compare varValu to $MACHINETYPE (this is just the hostname of the machine on which localize.py is running).
 348                        if not varMach in machDict:
 349                            machDict[varMach] = {}
 350                        machDict[varMach][varName] = varValu
 351            
 352 arta  1.25 def processParam(cfgfile, line, regexpQuote, regexp, keymap, defs, cDefs, mDefsGen, mDefsMake, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection, platDict, machDict, section):
 353 arta  1.1      status = 0
 354 arta  1.28 
 355 arta  1.1      if ''.join(section) == 'defs' or not cfgfile:
 356                    matchobj = regexp.match(line)
 357                    if not matchobj is None:
 358                        # We have a key-value line
 359                        keyCfgSp = matchobj.group(1)
 360                        val = matchobj.group(2)
 361 arta  1.28 
 362 arta  1.1              # Must map the indirect name to the actual name
 363                        if keymap:
 364                            # Map to actual name only if the keymap is not empty (which signifies NA).
 365                            if keyCfgSp in keymap:
 366                                key = keymap[keyCfgSp]
 367                            elif keyCfgSp == 'LOCAL_CONFIG_SET' or keyCfgSp == 'DRMS_SAMPLE_NAMESPACE':
 368 arta  1.6                      # Ignore parameters that are not useful and shouldn't have been there in the first place. But
 369                                # they have been released to the world, so we have to account for them.
 370 arta  1.1                      return bool(0)
 371                            elif not cfgfile:
 372                                # Should not be doing mapping for addenda
 373                                key = keyCfgSp
 374                            else:
 375                                raise Exception('badKeyMapKey', keyCfgSp)
 376                        else:
 377                            key = keyCfgSp
 378 arta  1.28 
 379 arta  1.1              matchobj = regexpQuote.match(key)
 380                        if not matchobj is None:
 381                            quote = matchobj.group(1)
 382                            key = matchobj.group(2)
 383            
 384                            # master defs dictionary
 385                            defs[key] = val
 386 arta  1.28 
 387 arta  1.1                  # C header file
 388                            if quote == "q":
 389                                # Add double-quotes
 390                                cDefs.extend(list(createMacroStr(key, '"' + val + '"', 40, status)))
 391                            elif quote == "p":
 392                                # Add parentheses
 393                                cDefs.extend(list(createMacroStr(key, '(' + val + ')', 40, status)))
 394                            elif quote == "a":
 395                                # Leave as-is
 396                                cDefs.extend(list(createMacroStr(key, val, 40, status)))
 397                            else:
 398                                # Unknown quote type
 399                                raise Exception('badQuoteQual', key)
 400 arta  1.28 
 401 arta  1.1                  if status:
 402                                raise Exception('paramNameTooLong', key)
 403 arta  1.28 
 404 arta  1.1                  # Make file - val should never be quoted; just use as is
 405 arta  1.4                  mDefsGen.extend(list('\n' + key + ' = ' + val))
 406 arta  1.28 
 407 arta  1.1                  # Perl file - val should ALWAYS be single-quote quoted
 408                            # Save const info to a string
 409                            perlConstSection.extend(list(createPerlConst(key, "'" + val + "'", 40, status)))
 410 arta  1.28 
 411 arta  1.18                 # Python file
 412                            pyConstSection.extend(list(createPyConst(key, "'" + val + "'", 40, status)))
 413 arta  1.28 
 414 arta  1.25                 # Shell source file
 415                            shConstSection.extend(list(createShConst(key, "'" + val + "'", status)))
 416 arta  1.28 
 417 arta  1.1                  if status:
 418                                raise Exception('paramNameTooLong', key)
 419 arta  1.28 
 420 arta  1.1                  # Save initialization information as a string. Now that we've defined
 421 arta  1.28                 # constants (the names of which are the parameter names)
 422 arta  1.1                  # we can refer to those in the init section. The key variable holds the
 423                            # name of the constant.
 424 arta  1.9                  perlInitSection.extend(list("\n  $self->{_paramsH}->{'" + key + "'} = " + key + ';'))
 425 arta  1.28 
 426 arta  1.18                 # The amount of indenting matters! This is Python.
 427                            pyInitSection.extend(list("        self.params['" + key + "'] = " + key + '\n'))
 428 arta  1.1              else:
 429                            # No quote qualifier
 430                            raise Exception('missingQuoteQual', key)
 431 arta  1.3      elif ''.join(section) == 'make' and cfgfile:
 432                    # Configure the remaining make variables defined in the __MAKE__ section of the configuration file. Third-party
 433                    # library make variables are specified in the __MAKE__ section.
 434                    matchobj = regexp.match(line)
 435                    if not matchobj is None:
 436                        # We have a key-value line
 437                        key = matchobj.group(1)
 438                        val = matchobj.group(2)
 439            
 440                        # This information is for making make variables only. We do not need to worry about quoting any values
 441                        defs[key] = val
 442 arta  1.4              processMakeParam(mDefsMake, key, val, platDict, machDict)
 443 arta  1.28 
 444 arta  1.1      return bool(0)
 445            
 446            # We have some extraneous line or a newline - ignore.
 447            
 448 arta  1.6  def processXML(xml, projRules, projTarget):
 449                rv = bool(0)
 450 arta  1.28 
 451 arta  1.6      # <projects>
 452                root = ET.fromstring(xml)
 453 arta  1.28 
 454 arta  1.6      # Iterate through each proj child.
 455                for proj in root.iter('proj'):
 456                    # Rules.mk
 457                    nameElem = proj.find('name')
 458                    rulesStr = 'dir     := $(d)/' + nameElem.text + '\n-include          $(SRCDIR)/$(dir)/Rules.mk\n'
 459 arta  1.28 
 460                    # make doesn't support logical operations in ifeq conditionals (you can't do ifeq (A AND B)),
 461 arta  1.6          # so we need to write:
 462                    #   ifeq (A)
 463                    #      ifeq (B)
 464                    #        <do something>
 465                    #      endif
 466                    #   endif
 467 arta  1.28 
 468 arta  1.6          rulesPref = '';
 469                    rulesSuff = '';
 470 arta  1.28 
 471 arta  1.6          filters = proj.find('filters')
 472                    if filters is not None:
 473                        for filter in filters.findall('filter'):
 474                            rulesPref += 'ifeq ($(' + filter.find('name').text + '),' + filter.find('value').text + ')\n'
 475                            rulesSuff += 'endif\n'
 476 arta  1.28 
 477 arta  1.6          if len(rulesPref) > 0 and len(rulesSuff) > 0:
 478                        projRules.extend(list(rulesPref))
 479                        projRules.extend(list(rulesStr))
 480                        projRules.extend(list(rulesSuff))
 481                    else:
 482                        projRules.extend(list(rulesStr))
 483 arta  1.28 
 484 arta  1.6          # target.mk
 485                    subdirs = proj.find('subdirs')
 486                    if subdirs is not None:
 487                        for subdir in subdirs.findall('subdir'):
 488                            targetStr = '\n\t+@[ -d $@/' + nameElem.text + '/' + subdir.text + ' ] || mkdir -p $@/' + nameElem.text + '/' + subdir.text
 489                            projTarget.extend(list(targetStr))
 490            
 491                return rv
 492            
 493 arta  1.27 def determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg):
 494                matchobj = regexpStyle.match(line)
 495                if matchobj:
 496                    return 'style'
 497            
 498 arta  1.6      matchobj = regexpDefs.match(line)
 499                if not matchobj is None:
 500                    return 'defs'
 501 arta  1.28 
 502 arta  1.6      matchobj = regexpMake.match(line)
 503                if not matchobj is None:
 504                    return 'make'
 505 arta  1.28 
 506 arta  1.6      matchobj = regexpProjMkRules.match(line)
 507                if not matchobj is None:
 508                    return 'projmkrules'
 509 arta  1.28 
 510 arta  1.6      matchobj = regexpProj.match(line)
 511                if not matchobj is None:
 512                    return 'proj'
 513 arta  1.28 
 514 arta  1.6      matchobj = regexpProjCfg.match(line)
 515                if not matchobj is None:
 516                    return 'projcfg'
 517            
 518                return None
 519            
 520 arta  1.1  # defs is a dictionary containing all parameters (should they be needed in this script)
 521 arta  1.6  # projCfg is the list containing the configure script content.
 522            # projMkRules is the list containing the make_basic.mk content.
 523            # projRules is the list containing the Rules.mk content.
 524            # projTargert is the list containing the target.mk content.
 525 arta  1.25 def parseConfig(fin, keymap, addenda, defs, cDefs, mDefsGen, mDefsMake, projCfg, projMkRules, projRules, projTarget, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection):
 526 arta  1.1      rv = bool(0)
 527 arta  1.28 
 528 arta  1.1      # Open required config file (config.local)
 529                try:
 530                    # Examine each line, looking for key=value pairs.
 531 arta  1.27         regexpStyle = re.compile(r"^__STYLE__")
 532 arta  1.1          regexpDefs = re.compile(r"^__DEFS__")
 533                    regexpMake = re.compile(r"^__MAKE__")
 534 arta  1.6          regexpProjMkRules = re.compile(r"__PROJ_MK_RULES__")
 535                    regexpProj = re.compile(r"^__PROJ__")
 536                    regexpProjCfg = re.compile(r"^__PROJCFG__")
 537 arta  1.1          regexpComm = re.compile(r"^\s*#")
 538 arta  1.6          regexpSp = re.compile(r"^s*$")
 539 arta  1.1          regexpQuote = re.compile(r"^\s*(\w):(.+)")
 540 arta  1.6          regexpCustMkBeg = re.compile(r"^_CUST_")
 541                    regexpCustMkEnd = re.compile(r"^_ENDCUST_")
 542                    regexpDiv = re.compile(r"^__")
 543 arta  1.11         regexp = re.compile(r"^\s*(\S+)\s+(\S.*)")
 544 arta  1.27 
 545                    ignoreKeymap = False
 546 arta  1.3          platDict = {}
 547                    machDict = {}
 548 arta  1.28 
 549 arta  1.6          xml = None
 550 arta  1.28 
 551 arta  1.1          # Process the parameters in the configuration file
 552                    if not fin is None:
 553                        for line in fin:
 554 arta  1.6                  matchobj = regexpComm.match(line)
 555                            if not matchobj is None:
 556                                # Skip comment line
 557                                continue
 558 arta  1.28 
 559 arta  1.6                  matchobj = regexpSp.match(line)
 560                            if not matchobj is None:
 561                                # Skip whitespace line
 562                                continue
 563 arta  1.28 
 564 arta  1.27                 newSection = determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg)
 565 arta  1.6                  if not newSection is None:
 566                                section = newSection
 567 arta  1.28 
 568 arta  1.27                 if not section:
 569                                raise Exception('invalidConfigFile', 'line ' + line.strip() + ' is not in any section')
 570 arta  1.28 
 571 arta  1.27                 if section == 'style':
 572                                # if the config.local file has new in the __STYLE__ section, then ignore the keymap and treat config.local like configsdp.txt;
 573                                # do not map from NetDRMS config.local parameter names to configsdp.txt names
 574                                for line in fin:
 575                                    matchobj = regexpDiv.match(line)
 576                                    if matchobj:
 577                                        break;
 578                                    if line.strip(' \n').lower() == 'new' and keymap:
 579                                        ignoreKeymap = True
 580            
 581                                newSection = determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg)
 582                                if not newSection is None:
 583                                    section = newSection
 584                                continue
 585                            elif section == 'make':
 586 arta  1.10 
 587 arta  1.28                     # There are some blocks of lines in the __MAKE__ section that must be copied ver batim to the output make file.
 588 arta  1.6                      # The blocks are defined by _CUST_/_ENDCUST_ tags.
 589                                matchobj = regexpCustMkBeg.match(line)
 590 arta  1.28 
 591 arta  1.6                      if not matchobj is None:
 592                                    mDefsMake.extend(list('\n'))
 593                                    for line in fin:
 594                                        matchobj = regexpCustMkEnd.match(line)
 595                                        if not matchobj is None:
 596                                            break;
 597                                        mDefsMake.extend(list(line))
 598 arta  1.27                         newSection = determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg)
 599 arta  1.6                          if not newSection is None:
 600                                        section = newSection
 601                                    continue
 602                                # Intentional fall through to next if statement
 603                            if section == 'defs' or section == 'make':
 604                                iscfg = bool(1)
 605 arta  1.27                     if ignoreKeymap:
 606                                    keymapActual = None
 607                                else:
 608                                    keymapActual = keymap
 609                                ppRet = processParam(iscfg, line, regexpQuote, regexp, keymapActual, defs, cDefs, mDefsGen, mDefsMake, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection, platDict, machDict, section)
 610 arta  1.28 
 611 arta  1.6                      if ppRet:
 612 arta  1.10                         break
 613 arta  1.6                  elif section == 'projcfg':
 614                                # Copy the line ver batim to the projCfg list (configure)
 615                                for line in fin:
 616                                    matchobj = regexpDiv.match(line)
 617                                    if not matchobj is None:
 618                                        break;
 619                                    projCfg.extend(list(line))
 620 arta  1.27                     newSection = determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg)
 621 arta  1.6                      if not newSection is None:
 622                                    section = newSection
 623                                continue
 624                            elif section == 'projmkrules':
 625                                # Copy the line ver batim to the projMkRules list (make_basic.mk)
 626                                for line in fin:
 627                                    matchobj = regexpDiv.match(line)
 628                                    if not matchobj is None:
 629                                        break;
 630                                    projMkRules.extend(list(line))
 631 arta  1.27                     newSection = determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg)
 632 arta  1.6                      if not newSection is None:
 633                                    section = newSection
 634                                continue
 635                            elif section == 'proj':
 636                                # Must parse xml and use the project-specific information to populate the Rules.mk and target.mk files.
 637                                # Collect all xml lines for now, then process after file-read loop.
 638                                if xml is None:
 639 arta  1.21                         # The first time through this section, line is the config.local div, __PROJ__. Discard that.
 640                                    xml = ''
 641                                    continue
 642 arta  1.6                      else:
 643                                    xml += line
 644                            else:
 645 arta  1.10                     # Unknown section
 646 arta  1.6                      raise Exception('unknownSection', section)
 647 arta  1.1      except Exception as exc:
 648 arta  1.17         if len(exc.args) >= 2:
 649                        msg = exc.args[0]
 650                    else:
 651                        # re-raise the exception
 652                        raise
 653 arta  1.28 
 654 arta  1.27         if msg == 'invalidConfigFile':
 655                        violator = exc.args[1]
 656                        print(violator, file=sys.stderr)
 657                        rv = bool(1)
 658                    elif msg == 'badKeyMapKey':
 659 arta  1.1              # If we are here, then there was a non-empty keymap, and the parameter came from
 660                        # the configuration file.
 661 arta  1.6              violator = exc.args[1]
 662 arta  1.17             print('Unknown parameter name ' + "'" + violator + "'" + ' in ' + fin.name + '.', file=sys.stderr)
 663 arta  1.1              rv = bool(1)
 664                    elif msg == 'badQuoteQual':
 665                        # The bad quote qualifier came from the configuration file, not the addenda, since
 666                        # we will have fixed any bad qualifiers in the addenda (which is populated by code).
 667 arta  1.6              violator = exc.args[1]
 668 arta  1.17             print('Unknown quote qualifier ' + "'" + violator + "'" + ' in ' + fin.name + '.', file=sys.stderr)
 669 arta  1.1              rv = bool(1)
 670                    elif msg == 'missingQuoteQual':
 671 arta  1.6              violator = exc.args[1]
 672 arta  1.17             print('Missing quote qualifier for parameter ' + "'" + violator + "'" + ' in ' + fin.name + '.', file=sys.stderr)
 673 arta  1.1              rv = bool(1)
 674                    elif msg == 'paramNameTooLong':
 675 arta  1.6              violator = exc.args[1]
 676 arta  1.1              print('Macro name ' + "'" + violator + "' is too long.", file=sys.stderr)
 677                        rv = bool(1)
 678 arta  1.6          elif msg == 'unknownSection':
 679                        violator = exc.args[1]
 680                        print('Unknown section ' + "'" + violator + "' in configuration file.", file=sys.stderr)
 681                        rv = bool(1)
 682 arta  1.1          else:
 683                        # re-raise the exception
 684                        raise
 685            
 686 arta  1.6      if not rv:
 687                    if not xml is None:
 688                        # Process xml.
 689                        rv = processXML(xml, projRules, projTarget)
 690            
 691 arta  1.28     # Process addenda - these are parameters that are not configurable and must be set in the
 692 arta  1.6      # NetDRMS build.
 693                if not rv:
 694                    iscfg = bool(0)
 695                    for key in addenda:
 696                        item = key + ' ' + addenda[key]
 697 arta  1.27             if ignoreKeymap:
 698                            keymapActual = None
 699                        else:
 700                            keymapActual = keymap
 701                        ppRet = processParam(iscfg, item, regexpQuote, regexp, keymapActual, defs, cDefs, mDefsGen, mDefsMake, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection, platDict, machDict, 'defs')
 702 arta  1.6              if ppRet:
 703                            break;
 704            
 705 arta  1.4      # Put information collected in platDict and machDict into mDefs. Must do this here, and not in processParam, since
 706                # we need to parse all platform-specific make variables before grouping them into platform categories.
 707 arta  1.3      if not rv:
 708                    for plat in platDict:
 709 arta  1.4              mDefsMake.extend(list('\nifeq ($(JSOC_MACHINE), linux_' + plat.lower() + ')'))
 710 arta  1.3              for var in platDict[plat]:
 711 arta  1.4                  mDefsMake.extend(list('\n' + var + ' = ' + platDict[plat][var]))
 712                        mDefsMake.extend(list('\nendif\n'))
 713 arta  1.28 
 714 arta  1.3      if not rv:
 715                    for mach in machDict:
 716 arta  1.4              mDefsMake.extend(list('\nifeq ($(MACHTYPE), ' + mach + ')'))
 717 arta  1.7              for var in machDict[mach]:
 718                            mDefsMake.extend(list('\n' + var + ' = ' + machDict[mach][var]))
 719 arta  1.4              mDefsMake.extend(list('\nendif\n'))
 720 arta  1.1      return rv
 721            
 722            def getMgrUIDLine(defs, uidParam):
 723                rv = bool(0)
 724 arta  1.28 
 725 arta  1.1      cmd = 'id -u ' + defs['SUMS_MANAGER']
 726                try:
 727                    ret = check_output(cmd, shell=True)
 728                    uidParam['q:SUMS_MANAGER_UID'] = ret.decode("utf-8")
 729                except ValueError:
 730                    print('Unable to run cmd: ' + cmd + '.')
 731                    rv = bool(1)
 732                except CalledProcessError:
 733                    print('Command ' + "'" + cmd + "'" + ' ran improperly.')
 734                    rv = bool(1)
 735            
 736                return rv
 737            
 738 arta  1.3  def isVersion(maj, min, majDef, minDef):
 739                res = 0
 740 arta  1.28 
 741 arta  1.3      if maj > majDef or (maj == majDef and min >= minDef):
 742                    res = 1
 743 arta  1.28 
 744 arta  1.3      return res
 745            
 746            def configureComps(defs, mDefs):
 747                rv = bool(0)
 748 arta  1.6      autoConfig = bool(1)
 749            
 750                if 'AUTOSELCOMP' in defs:
 751                    autoConfig = (not defs['AUTOSELCOMP'] == '0')
 752 arta  1.28 
 753 arta  1.3      if autoConfig:
 754                    hasicc = bool(0)
 755                    hasgcc = bool(0)
 756                    hasifort = bool(0)
 757                    hasgfort = bool(0)
 758 arta  1.28 
 759 arta  1.3          # Try icc.
 760 arta  1.12         cmd = 'icc --version 2>&1'
 761 arta  1.3          try:
 762                        ret = check_output(cmd, shell=True)
 763                        ret = ret.decode("utf-8")
 764                    except CalledProcessError:
 765                        print('Command ' + "'" + cmd + "'" + ' ran improperly.')
 766                        rv = bool(1)
 767 arta  1.28 
 768 arta  1.6          if not rv:
 769 arta  1.12             regexp = re.compile(r"\s*\S+\s+\S+\s+(\d+)[.](\d+)", re.DOTALL)
 770 arta  1.3              matchobj = regexp.match(ret)
 771                        if matchobj is None:
 772                            raise Exception('unexpectedIccRet', ret)
 773                        else:
 774                            major = matchobj.group(1)
 775                            minor = matchobj.group(2)
 776                            if isVersion(int(major), int(minor), ICC_MAJOR, ICC_MINOR):
 777                                hasicc = bool(1)
 778 arta  1.19 
 779 arta  1.3          # Try gcc.
 780                    if not hasicc:
 781 arta  1.19             rv = bool(0)
 782 arta  1.3              cmd = 'gcc -v 2>&1'
 783                        try:
 784                            ret = check_output(cmd, shell=True)
 785                            ret = ret.decode("utf-8")
 786                        except CalledProcessError:
 787                            print('Command ' + "'" + cmd + "'" + ' ran improperly.')
 788                            rv = bool(1)
 789            
 790 arta  1.19             if not rv:
 791 arta  1.3                  regexp = re.compile(r".+gcc\s+version\s+(\d+)\.(\d+)", re.DOTALL)
 792                            matchobj = regexp.match(ret)
 793                            if matchobj is None:
 794                                raise Exception('unexpectedGccRet', ret)
 795                            else:
 796                                major = matchobj.group(1)
 797                                minor = matchobj.group(2)
 798                                if isVersion(int(major), int(minor), GCC_MAJOR, GCC_MINOR):
 799                                    hasgcc = bool(1)
 800            
 801                    # Try ifort.
 802 arta  1.19         rv = bool(0)
 803 arta  1.12         cmd = 'ifort --version 2>&1'
 804 arta  1.3          try:
 805                        ret = check_output(cmd, shell=True)
 806                        ret = ret.decode("utf-8")
 807                    except CalledProcessError:
 808                        print('Command ' + "'" + cmd + "'" + ' ran improperly.')
 809                        rv = bool(1)
 810            
 811 arta  1.6          if not rv:
 812 arta  1.12             regexp = re.compile(r"\s*\S+\s+\S+\s+(\d+)\.(\d+)", re.DOTALL)
 813 arta  1.3              matchobj = regexp.match(ret)
 814                        if matchobj is None:
 815                            raise Exception('unexpectedIfortRet', ret)
 816                        else:
 817                            major = matchobj.group(1)
 818                            minor = matchobj.group(2)
 819                            if isVersion(int(major), int(minor), IFORT_MAJOR, IFORT_MINOR):
 820                                hasifort = bool(1)
 821 arta  1.28 
 822 arta  1.3          # Try gfortran
 823                    if not hasifort:
 824 arta  1.19             rv = bool(0)
 825 arta  1.3              cmd = 'gfortran -v 2>&1'
 826                        try:
 827                            ret = check_output(cmd, shell=True)
 828                            ret = ret.decode("utf-8")
 829                        except CalledProcessError:
 830                            print('Command ' + "'" + cmd + "'" + ' ran improperly.')
 831                            rv = bool(1)
 832            
 833 arta  1.19             if not rv:
 834 arta  1.3                  regexp = re.compile(r".+gcc\s+version\s+(\d+)\.(\d+)", re.DOTALL)
 835                            matchobj = regexp.match(ret)
 836                            if matchobj is None:
 837                                raise Exception('unexpectedGfortranRet', ret)
 838                            else:
 839                                major = matchobj.group(1)
 840                                minor = matchobj.group(2)
 841                                if isVersion(int(major), int(minor), GFORT_MAJOR, GFORT_MINOR):
 842                                    hasgfort = bool(1)
 843 arta  1.28 
 844 arta  1.19         # Append the compiler make variables to the make file
 845                    rv = bool(0)
 846 arta  1.28 
 847 arta  1.3          if not hasicc and not hasgcc:
 848                        print('Fatal error: Acceptable C compiler not found! You will be unable to build the DRMS library.', file=sys.stderr)
 849                        rv = bool(1)
 850                    elif hasicc:
 851                        mDefs.extend(list('\nCOMPILER = icc'))
 852 arta  1.28             # mDefs.extend(list('\nICC_VERSION = blah'))
 853 arta  1.3          else:
 854                        mDefs.extend(list('\nCOMPILER = gcc'))
 855            
 856                    if not hasifort and not hasgfort:
 857                        print('Warning: Acceptable Fortran compiler not found! Fortran interface will not be built, and you will be unable to build Fortran modules.', file=sys.stderr)
 858                    elif hasifort:
 859                        mDefs.extend(list('\nFCOMPILER = ifort'))
 860                    else:
 861                        mDefs.extend(list('\nFCOMPILER = gfortran'))
 862 arta  1.28 
 863 arta  1.3          # Environment overrides. These get written, regardless of the disposition of auto-configuration.
 864 arta  1.9          mDefs.extend(list('\nifneq ($(JSOC_COMPILER),)\n  COMPILER = $(JSOC_COMPILER)\nendif'))
 865                    mDefs.extend(list('\nifneq ($(JSOC_FCOMPILER),)\n  FCOMPILER = $(JSOC_FCOMPILER)\nendif'))
 866 arta  1.3  
 867                return rv
 868            
 869 arta  1.25 def writeParamsFiles(base, cfile, mfile, pfile, pyfile, shfile, cDefs, mDefsGen, mDefsMake, mDefsComps, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection):
 870 arta  1.1      rv = bool(0)
 871 arta  1.4  
 872                # Merge mDefsGen, mDefsMake, and mDefsComps into a single string with compiler configuration first, general parameters next, then
 873                # make-specific make variables (e.g., third-party library information) last.
 874                mDefs = '\n# Compiler Selection\n' + ''.join(mDefsComps) + '\n\n# General Parameters\n' + ''.join(mDefsGen) + '\n\n# Parameters to Configure make\n' + ''.join(mDefsMake)
 875 arta  1.28 
 876 arta  1.1      try:
 877 arta  1.25         with open(cfile, 'w') as cout, open(mfile, 'w') as mout, open(pfile, 'w') as pout, open(pyfile, 'w') as pyout, open(shfile, 'w') as shout:
 878 arta  1.1              # C file of macros
 879 arta  1.2              print(C_PREFIX, file=cout)
 880                        print('/* This file contains a set of preprocessor macros - one for each configuration parameter. */\n', file=cout)
 881 arta  1.1              buf = '__' + base.upper() + '_H'
 882                        print('#ifndef ' + buf, file=cout)
 883                        print('#define ' + buf, file=cout)
 884                        print(''.join(cDefs), file=cout)
 885                        print('#endif', file=cout)
 886 arta  1.28 
 887 arta  1.1              # Make file of make variables
 888 arta  1.2              print(PREFIX, file=mout)
 889 arta  1.4              print('# This file contains a set of make-variable values. The first section contains compiler-selection variables, the second contains general configuration variables, and the third section contains variables that configure how make is run.', file=mout)
 890                        print(mDefs, file=mout)
 891 arta  1.28 
 892 arta  1.2              # Perl module
 893                        print(PERL_BINPATH, file=pout)
 894                        print(PREFIX, file=pout)
 895                        print('# This file contains a set of constants - one for each configuration parameter.\n', file=pout)
 896                        print(PERL_INTIAL, file=pout)
 897 arta  1.1              print(''.join(perlConstSection), file=pout)
 898 arta  1.2              print(PERL_FXNS_A, file=pout)
 899 arta  1.1              print('sub initialize', file=pout)
 900                        print('{', file=pout)
 901 arta  1.2              print('  my($self) = shift;', file=pout, end='')
 902 arta  1.1              print('', file=pout)
 903                        print(''.join(perlInitSection), file=pout)
 904 arta  1.2              print('}\n', file=pout)
 905                        print(PERL_FXNS_B, file=pout)
 906 arta  1.18 
 907                        # Python module
 908                        print(PY_BINPATH, file=pyout)
 909                        print(PREFIX, file=pyout)
 910                        print('# This file contains a set of constants - one for each configuration parameter.\n', file=pyout)
 911                        print(''.join(pyConstSection), file=pyout)
 912 arta  1.29 
 913                        print(PY_ERROR_CLASSES, file=pyout)
 914 arta  1.18             print(PY_FXNS_A, file=pyout, end='')
 915                        print(''.join(pyInitSection), file=pyout)
 916                        print(PY_FXNS_B, file=pyout)
 917 arta  1.22             print(PY_FXNS_C, file=pyout)
 918 arta  1.28 
 919 arta  1.25             # Shell (bash) source file
 920                        print(SH_BINPATH, file=shout)
 921                        print(PREFIX, file=shout)
 922                        print('# This file contains a set of variable assignments - one for each configuration parameter.\n', file=shout)
 923                        print(''.join(shConstSection), file=shout)
 924 arta  1.18 
 925 arta  1.1      except IOError as exc:
 926 arta  1.6          type, value, traceback = sys.exc_info()
 927                    print(exc.strerror, file=sys.stderr)
 928 arta  1.28         print('Unable to open ' + "'" + value.filename + "'.", file=sys.stderr)
 929 arta  1.6          rv = bool(1)
 930            
 931                return rv
 932            
 933            def writeProjFiles(pCfile, pMfile, pRfile, pTfile, projCfg, projMkRules, projRules, projTarget):
 934                rv = bool(0)
 935            
 936                try:
 937                    if projCfg:
 938                        with open(pCfile, 'w') as cout:
 939                            # configure
 940                            print(''.join(projCfg), file=cout)
 941 arta  1.28 
 942 arta  1.6          if projMkRules:
 943                        with open(pMfile, 'w') as mout:
 944                            # make_basic.mk
 945                            print(PREFIX, file=mout)
 946                            print(''.join(projMkRules), file=mout)
 947 arta  1.28 
 948 arta  1.6          if projRules:
 949                        with open(pRfile, 'w') as rout:
 950                            # Rules.mk
 951                            print(PREFIX, file=rout)
 952                            print(''.join(projRules), file=rout)
 953 arta  1.28 
 954 arta  1.6          if projTarget:
 955                        with open(pTfile, 'w') as tout:
 956                            # target.mk
 957                            print(PREFIX, file=tout)
 958 arta  1.10                 print(''.join(projTarget), file=tout)
 959 arta  1.6      except IOError as exc:
 960                    type, value, traceback = sys.exc_info()
 961                    print(exc.strerror, file=sys.stderr)
 962                    print('Unable to open ' + "'" + value.filename + "'.", file=sys.stderr)
 963 arta  1.1          rv = bool(1)
 964            
 965 arta  1.6      if not rv:
 966 arta  1.10         if os.path.exists(pCfile):
 967                        try:
 968                            os.chmod(pCfile, stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH)
 969                        except OSError as exc:
 970                            type, value, traceback = sys.exc_info()
 971                            print('Unable to chmod file ' + "'" + value.filename + "'.", file=sys.stderr)
 972                            print(exc.strerror, file=sys.stderr)
 973                            rv = bool(1)
 974 arta  1.6  
 975 arta  1.1      return rv
 976 arta  1.3  
 977 arta  1.13 def generateSumRmCfg(defs):
 978                rv = bool(0)
 979                # ACK! Remember that Rick renamed these parameters. The ones in config.local are the aliases - do not use those.
 980                # Use the ones that those map to (defined in config.local.map).
 981                cFileTmp = defs['SUMLOG_BASEDIR'] + '/' + '.sum_rm.cfg.tmp'
 982                cFile = defs['SUMLOG_BASEDIR'] + '/' + 'sum_rm.cfg'
 983            
 984                # Write a temporary file sum_rm configuration file.
 985                try:
 986                    with open(cFileTmp, 'w') as fout:
 987                        # Print comment at the top of the configuration file.
 988                        print(SUMRM_COMMENT, file=fout)
 989                        print(SUMRM_DOC, file=fout)
 990                        print(SUMRM_PARTN_PERCENT_FREE, file=fout)
 991                        if 'SUMRM_PART_PERCENT_FREE' in defs:
 992                            print('PART_PERCENT_FREE=' + defs['SUMRM_PART_PERCENT_FREE'], file=fout)
 993                        else:
 994                            print('PART_PERCENT_FREE=3', file=fout)
 995            
 996                        print(SUMRM_SLEEP, file=fout)
 997                        if 'SUMRM_SLEEP' in defs:
 998 arta  1.13                 print('SLEEP=' + defs['SUMRM_SLEEP'], file=fout)
 999                        else:
1000                            print('SLEEP=300', file=fout)
1001            
1002                        print(SUMRM_LOG, file=fout)
1003                        if 'SUMRM_LOG' in defs:
1004                            print('LOG=' + defs['SUMRM_LOG'], file=fout)
1005                        else:
1006                            print('LOG=/tmp/sum_rm.log', file=fout)
1007            
1008                        print(SUMRM_MAIL, file=fout)
1009                        # No default for mail - don't send nothing to nobody unless the operator has asked for notifications.
1010                        if 'SUMRM_MAIL' in defs:
1011                            print('MAIL=' + defs['SUMRM_MAIL'], file=fout)
1012                        else:
1013                            print('# MAIL=president@whitehouse.gov', file=fout)
1014            
1015                        print(SUMRM_NOOP, file=fout)
1016                        if 'SUMRM_NOOP' in defs:
1017                            print('NOOP=' + defs['SUMRM_NOOP'], file=fout)
1018                        else:
1019 arta  1.13                 print('NOOP=0', file=fout)
1020            
1021                        print(SUMRM_USER, file=fout)
1022                        if 'SUMRM_USER' in defs:
1023                            print('USER=' + defs['SUMRM_USER'], file=fout)
1024                        else:
1025                            print('USER=production', file=fout)
1026            
1027                        print(SUMRM_NORUN, file=fout)
1028                        # Default norun window is to have no such window. This can be accomplished by simply not providing either argument.
1029                        if 'SUMRM_NORUN_START' in defs or 'SUMRM_NORUN_STOP' in defs:
1030                            if 'SUMRM_NORUN_START' in defs:
1031                                print('NORUN_START=' + defs['SUMRM_NORUN_START'], file=fout)
1032                            else:
1033                                print('NORUN_START=0', file=fout)
1034                            if 'SUMRM_NORUN_STOP' in defs:
1035                                print('NORUN_STOP=' + defs['SUMRM_NORUN_STOP'], file=fout)
1036                            else:
1037                                print('NORUN_STOP=0', file=fout)
1038                        else:
1039                            print('# NORUN_START=0', file=fout)
1040 arta  1.13                 print('# NORUN_STOP=0', file=fout)
1041 arta  1.28 
1042 arta  1.13     except OSError:
1043                    print('Unable to open sum_rm temporary configuration file ' + cFileTmp + 'for writing.', file=sys.stderr)
1044                    rv = bool(1)
1045            
1046                # If the content of the temporary file differs from the content of the existing configuration file, then overwrite
1047                # the original file. Otherwise, delete the temporary file
1048                if not rv:
1049                    try:
1050                        if filecmp.cmp(cFile, cFileTmp):
1051                            # Files identical - delete temporary file
1052                            try:
1053                                os.remove(cFileTmp)
1054 arta  1.28 
1055 arta  1.13                 except OSError as exc:
1056                                print('Unable to remove temporary file ' + exc.filename + '.', file=sys.stderr)
1057                                print(exc.strerr, file=sys.stderr)
1058                        else:
1059                            # Replace original with temporary file
1060                            try:
1061                                os.rename(cFileTmp, cFile)
1062            
1063                            except OSError as exc:
1064                                print('Unable to update sum_rm configuration file ' + cFile + '.', file=sys.stderr)
1065                                print(exc.strerr, file=sys.stderr)
1066                                rv = bool(1)
1067                    except OSError as exc:
1068                        # One of the files doesn't exist.
1069                        if exc.filename == cFile:
1070                            # We are ok - there might be no configuration file yet.
1071                            # Replace original with temporary file
1072                            try:
1073                                os.rename(cFileTmp, cFile)
1074            
1075                            except OSError as exc:
1076 arta  1.13                     print('Unable to update sum_rm configuration file ' + cFile + '.', file=sys.stderr)
1077                                print(exc.strerr, file=sys.stderr)
1078                                rv = bool(1)
1079                        else:
1080                            # There is a problem with the temp file - bail.
1081                            print('Unable to update sum_rm configuration file ' + cFile + '.', file=sys.stderr)
1082                            print(exc.strerr, file=sys.stderr)
1083                            rv = bool(1)
1084            
1085                return rv
1086            
1087 arta  1.25 def configureNet(cfgfile, cfile, mfile, pfile, pyfile, shfile, pCfile, pMfile, pRfile, pTfile, base, keymap, createSumRmCfg):
1088 arta  1.1      rv = bool(0)
1089 arta  1.28 
1090 arta  1.1      defs = {}
1091                cDefs = list()
1092 arta  1.4      mDefsGen = list()
1093                mDefsMake = list()
1094                mDefsComps = list()
1095 arta  1.6      projCfg = list()
1096                projMkRules = list()
1097                projRules = list()
1098                projTarget = list()
1099 arta  1.1      perlConstSection = list()
1100                perlInitSection = list()
1101 arta  1.18     pyConstSection = list()
1102                pyInitSection = list()
1103 arta  1.25     shConstSection = list()
1104 arta  1.2      addenda = {}
1105 arta  1.28 
1106 arta  1.6      # There are three parameters that were not included in the original config.local parameter set, for some reason.
1107                # Due to this omission, then are not configurable, and must be set in the script.
1108 arta  1.2      addenda['a:USER'] = 'NULL'
1109                addenda['a:PASSWD'] = 'NULL'
1110                addenda['p:DSDS_SUPPORT'] = '0'
1111 arta  1.28 
1112 arta  1.6      # This parameter is not configurable. BUILD_TYPE is used to distinguish between a NetDRMS and an JSOC-SDP build.
1113 arta  1.2      addenda['a:BUILD_TYPE'] = 'NETDRMS' # Means a non-Stanford build. This will set two additional macros used by make:
1114                                                    #   __LOCALIZED_DEFS__ and NETDRMS_BUILD. The former is to support legacy code
1115 arta  1.28                                         #   which incorrectly used this macro, and the latter is for future use.
1116 arta  1.2                                          #   __LOCALIZED_DEFS__ is deprecated and should not be used in new code.
1117 arta  1.1  
1118                try:
1119                    with open(cfgfile, 'r') as fin:
1120 arta  1.3              # Process configuration parameters
1121 arta  1.26 
1122                        # Always create a Rules.mk and target.mk, even if no proj XML is provided. All builds should have the proj/example and
1123                        # proj/cookbook directories. The required make information is in RULESPREFIX, TARGETPREFIX, and RULESSUFFIX. RULESSUFFIX
1124                        # must be added after the xml has been parsed.
1125                        projRules.extend(list(RULESPREFIX))
1126                        projTarget.extend(list(TARGETPREFIX))
1127            
1128 arta  1.25             rv = parseConfig(fin, keymap, addenda, defs, cDefs, mDefsGen, mDefsMake, projCfg, projMkRules, projRules, projTarget, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection)
1129 arta  1.6              if not rv:
1130 arta  1.26                 projRules.extend(RULESSUFFIX)
1131 arta  1.28 
1132 arta  1.3                  # Must add a parameter for the SUMS_MANAGER UID (for some reason). This must be done after the
1133                            # config file is processed since an input to getMgrUIDLine() is one of the config file's
1134                            # parameter values.
1135 arta  1.1                  uidParam = {}
1136                            rv = getMgrUIDLine(defs, uidParam)
1137                            if rv == bool(0):
1138 arta  1.25                     rv = parseConfig(None, keymap, uidParam, defs, cDefs, mDefsGen, None, projCfg, projMkRules, projRules, projTarget, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection)
1139 arta  1.3              # Configure the compiler-selection make variables.
1140 arta  1.6              if not rv:
1141 arta  1.4                  rv = configureComps(defs, mDefsComps)
1142 arta  1.1  
1143 arta  1.3              # Write out the parameter files.
1144 arta  1.6              if not rv:
1145 arta  1.25                 rv = writeParamsFiles(base, cfile, mfile, pfile, pyfile, shfile, cDefs, mDefsGen, mDefsMake, mDefsComps, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection)
1146 arta  1.13 
1147 arta  1.6              # Write out the project-specific make files (make_basic.mk, Rules.mk, and target.mk).
1148                        if not rv:
1149                            rv = writeProjFiles(pCfile, pMfile, pRfile, pTfile, projCfg, projMkRules, projRules, projTarget)
1150 arta  1.13 
1151                        # Write out the sum_rm.cfg file.
1152                        if not rv and createSumRmCfg:
1153                            rv = generateSumRmCfg(defs)
1154 arta  1.1      except IOError as exc:
1155 arta  1.6          print(exc.strerror, file=sys.stderr)
1156                    print('Unable to read configuration file ' + cfgfile + '.', file=sys.stderr)
1157 arta  1.3      except Exception as exc:
1158 arta  1.16         if len(exc.args) >= 2:
1159 arta  1.14             type, msg = exc.args
1160                    else:
1161                        # re-raise the exception
1162                        raise
1163            
1164 arta  1.3          if type == 'unexpectedIccRet':
1165                        print('icc -V returned this unexpected message:\n' + msg, file=sys.stderr)
1166                        rv = bool(1)
1167                    elif type == 'unexpectedGccRet':
1168                        print('gcc -v returned this unexpected message:\n' + msg, file=sys.stderr)
1169                        rv = bool(1)
1170                    elif type == 'unexpectedIfortRet':
1171                        print('ifort -V returned this unexpected message:\n' + msg, file=sys.stderr)
1172                        rv = bool(1)
1173                    elif type == 'unexpectedGfortranRet':
1174                        print('gfortran -v returned this unexpected message:\n' + msg, file=sys.stderr)
1175                        rv = bool(1)
1176                    else:
1177                        # re-raise the exception
1178                        raise
1179 arta  1.28 
1180 arta  1.2      return rv
1181 arta  1.1  
1182 arta  1.25 def configureSdp(cfgfile, cfile, mfile, pfile, pyfile, shfile, pCfile, pMfile, pRfile, pTfile, base):
1183 arta  1.1      rv = bool(0)
1184 arta  1.28 
1185 arta  1.1      defs = {}
1186                cDefs = list()
1187 arta  1.5      mDefsGen = list()
1188                mDefsMake = list()
1189 arta  1.6      projCfg = list()
1190                projMkRules = list()
1191                projRules = list()
1192                projTarget = list()
1193 arta  1.5      mDefsComps = list()
1194 arta  1.1      perlConstSection = list()
1195                perlInitSection = list()
1196 arta  1.18     pyConstSection = list()
1197                pyInitSection = list()
1198 arta  1.25     shConstSection = list()
1199 arta  1.18 
1200 arta  1.2      addenda = {}
1201 arta  1.28 
1202 arta  1.6      # There are three parameters that were not included in the original config.local parameter set, for some reason.
1203                # Due to this omission, then are not configurable, and must be set in the script.
1204 arta  1.5      addenda['a:USER'] = 'NULL'
1205                addenda['a:PASSWD'] = 'NULL'
1206                addenda['p:DSDS_SUPPORT'] = '1'
1207 arta  1.28 
1208 arta  1.6      # This parameter is not configurable. BUILD_TYPE is used to distinguish between a NetDRMS and an JSOC-SDP build.
1209 arta  1.5      addenda['a:BUILD_TYPE'] = 'JSOC_SDP' # Means a Stanford build. This will set one additional macro used by make: JSOC_SDP_BUILD.
1210 arta  1.28 
1211 arta  1.1      try:
1212                    with open(cfgfile, 'r') as fin:
1213 arta  1.28 
1214 arta  1.26             # Always create a Rules.mk and target.mk, even if no proj XML is provided. All builds should have the proj/example and
1215                        # proj/cookbook directories. The required make information is in RULESPREFIX, TARGETPREFIX, and RULESSUFFIX. RULESSUFFIX
1216                        # must be added after the xml has been parsed.
1217                        projRules.extend(list(RULESPREFIX))
1218                        projTarget.extend(list(TARGETPREFIX))
1219 arta  1.28 
1220 arta  1.25             rv = parseConfig(fin, None, addenda, defs, cDefs, mDefsGen, mDefsMake, projCfg, projMkRules, projRules, projTarget, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection)
1221 arta  1.28 
1222 arta  1.6              if not rv:
1223 arta  1.26                 projRules.extend(RULESSUFFIX)
1224 arta  1.28 
1225 arta  1.2                  # Must add a parameter for the SUMS_MANAGER UID (for some reason)
1226                            uidParam = {}
1227                            rv = getMgrUIDLine(defs, uidParam)
1228 arta  1.6                  if not rv:
1229 arta  1.25                     rv = parseConfig(None, None, uidParam, defs, cDefs, mDefsGen, None, projCfg, projMkRules, projRules, projTarget, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection)
1230 arta  1.6  
1231 arta  1.5                  # Configure the compiler-selection make variables.
1232 arta  1.6                  if not rv:
1233 arta  1.5                      rv = configureComps(defs, mDefsComps)
1234 arta  1.28 
1235 arta  1.6                  # Write out the parameter files.
1236                            if not rv:
1237 arta  1.25                     rv = writeParamsFiles(base, cfile, mfile, pfile, pyfile, shfile, cDefs, mDefsGen, mDefsMake, mDefsComps, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection)
1238 arta  1.6  
1239                            # Write out the project-specific make files (make_basic.mk, Rules.mk, and target.mk).
1240                            if not rv:
1241                                rv = writeProjFiles(pCfile, pMfile, pRfile, pTfile, projCfg, projMkRules, projRules, projTarget)
1242 arta  1.13 
1243                            # At Stanford, skip the creation of the sum_rm configuration file. config.local will still
1244                            # have the SUMRM parameters, but they will not be used.
1245 arta  1.1      except IOError as exc:
1246 arta  1.6          print(exc.strerror, file=sys.stderr)
1247                    print('Unable to read configuration file ' + cfgfile + '.', file=sys.stderr)
1248 arta  1.5      except Exception as exc:
1249 arta  1.17         if len(exc.args) >= 2:
1250                        type = exc.args[0]
1251                    else:
1252                        # re-raise the exception
1253                        raise
1254 arta  1.28 
1255 arta  1.5          if type == 'unexpectedIccRet':
1256 arta  1.6              msg = exc.args[1]
1257 arta  1.5              print('icc -V returned this unexpected message:\n' + msg, file=sys.stderr)
1258                        rv = bool(1)
1259                    elif type == 'unexpectedGccRet':
1260 arta  1.6              msg = exc.args[1]
1261 arta  1.5              print('gcc -v returned this unexpected message:\n' + msg, file=sys.stderr)
1262                        rv = bool(1)
1263                    elif type == 'unexpectedIfortRet':
1264 arta  1.6              msg = exc.args[1]
1265 arta  1.5              print('ifort -V returned this unexpected message:\n' + msg, file=sys.stderr)
1266                        rv = bool(1)
1267                    elif type == 'unexpectedGfortranRet':
1268 arta  1.6              msg = exc.args[1]
1269 arta  1.5              print('gfortran -v returned this unexpected message:\n' + msg, file=sys.stderr)
1270                        rv = bool(1)
1271                    else:
1272                        # re-raise the exception
1273                        raise
1274 arta  1.28 
1275 arta  1.2      return rv
1276            
1277 arta  1.1  # Beginning of program
1278            rv = RET_SUCCESS
1279            net = bool(1)
1280            
1281            # Parse arguments
1282            if __name__ == "__main__":
1283                optD = GetArgs(sys.argv[1:])
1284            
1285            if not(optD is None):
1286                # Ensure we are configuring a DRMS tree
1287                cdir = os.path.realpath(os.getcwd())
1288                versfile = cdir + '/base/' + VERS_FILE
1289            
1290                if not os.path.isfile(versfile):
1291                    rv = RET_NOTDRMS
1292            
1293            # Determine whether we are localizing a Stanford build, or a NetDRMS build. If configsdp.txt exists, then
1294            # it is a Stanford build, otherwise it is a NetDRMS build.
1295            if rv == RET_SUCCESS:
1296                stanfordFile = cdir + '/' + SDP_CFG
1297                if os.path.isfile(stanfordFile):
1298 arta  1.1          net = bool(0)
1299 arta  1.28 
1300 arta  1.1      cfile = optD['dir'] + '/' + optD['base'] + '.h'
1301                mfile = optD['dir'] + '/' + optD['base'] + '.mk'
1302                pfile = optD['dir'] + '/' + optD['base'] + '.pm'
1303 arta  1.18     pyfile = optD['dir'] + '/' + optD['base'] + '.py'
1304 arta  1.25     shfile = optD['dir'] + '/' + optD['base'] + '.sh'
1305 arta  1.6      pCfile = optD['dir'] + '/configure'
1306                pMfile = optD['dir'] + '/make_basic.mk'
1307                pRfile = optD['dir'] + '/Rules.mk'
1308                pTfile = optD['dir'] + '/target.mk'
1309 arta  1.1  
1310                if net:
1311                    try:
1312                        with open(NET_CFGMAP, 'r') as fin:
1313                            regexpComm = re.compile(r"^\s*#")
1314                            regexp = re.compile(r"^\s*(\S+)\s+(\w:\S+)")
1315                            # Must map from config.local namespace to DRMS namespace (e.g., the names used for the C macros)
1316                            keymap = {}
1317                            for line in fin:
1318                                matchobj = regexpComm.match(line)
1319                                if not matchobj is None:
1320                                    # Skip comment line
1321                                    continue
1322            
1323                                matchobj = regexp.match(line)
1324                                if not(matchobj is None):
1325                                    # We have a key-value line
1326                                    key = matchobj.group(1)
1327                                    val = matchobj.group(2)
1328                                    keymap[key] = val
1329                    except OSError:
1330 arta  1.1              sys.stderr.write('Unable to read configuration map-file ' + NET_CFGMAP + '.')
1331                        rv = bool(1)
1332            
1333                    # We also need to set the UID of the SUMS manager. We have the name of the
1334                    # SUMS manager (it is in the configuration file)
1335 arta  1.25         configureNet(NET_CFG, cfile, mfile, pfile, pyfile, shfile, pCfile, pMfile, pRfile, pTfile, optD['base'], keymap, 'server' in optD)
1336 arta  1.1      else:
1337 arta  1.28         # A Stanford user can override the parameters in configsdp.txt by copying that file to config.local,
1338 arta  1.8          # and then editing config.local. So, if config.local exists, use that.
1339                    if os.path.isfile(cdir + '/' + NET_CFG):
1340 arta  1.25             configureSdp(NET_CFG, cfile, mfile, pfile, pyfile, shfile, pCfile, pMfile, pRfile, pTfile, optD['base'])
1341 arta  1.8          else:
1342 arta  1.25             configureSdp(SDP_CFG, cfile, mfile, pfile, pyfile, shfile, pCfile, pMfile, pRfile, pTfile, optD['base'])

Karen Tian
Powered by
ViewCVS 0.9.4