ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/JSOC/localize.py
Revision: 1.26
Committed: Fri Sep 23 16:38:30 2016 UTC (7 years ago) by arta
Content type: text/x-python
Branch: MAIN
CVS Tags: NetDRMS_Ver_8-12, NetDRMS_Ver_9-1, NetDRMS_Ver_9-0, Ver_9-1, Ver_8-12, Ver_9-0
Changes since 1.25: +18 -6 lines
Log Message:
Fix last check-in screw-up. Pull the proj/example Rules.mk code out of lower-level code, and put it in higher-level code so that it gets called only once.

File Contents

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