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