1 |
#!/usr/bin/python |
2 |
|
3 |
# When run with the -s flag, localize.py configures the SUMS-server component of NetDRMS. |
4 |
from __future__ import print_function |
5 |
import sys |
6 |
import getopt |
7 |
import re |
8 |
import os |
9 |
import stat |
10 |
import filecmp |
11 |
import xml.etree.ElementTree as ET |
12 |
from subprocess import check_output, CalledProcessError |
13 |
|
14 |
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 |
# 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 |
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 |
|
29 |
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 |
""" |
32 |
|
33 |
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 |
{ |
43 |
my($clname) = shift; |
44 |
|
45 |
my($self) = |
46 |
{ |
47 |
_paramsH => undef |
48 |
}; |
49 |
|
50 |
bless($self, $clname); |
51 |
$self->{_paramsH} = {}; |
52 |
$self->initialize(); |
53 |
|
54 |
return $self; |
55 |
} |
56 |
|
57 |
sub DESTROY |
58 |
{ |
59 |
my($self) = shift; |
60 |
} |
61 |
""" |
62 |
|
63 |
PERL_FXNS_B = """sub get |
64 |
{ |
65 |
my($self) = shift; |
66 |
my($name) = shift; |
67 |
my($rv); |
68 |
|
69 |
if (exists($self->{_paramsH}->{$name})) |
70 |
{ |
71 |
return $self->{_paramsH}->{$name}; |
72 |
} |
73 |
else |
74 |
{ |
75 |
return undef; |
76 |
} |
77 |
} |
78 |
1;""" |
79 |
|
80 |
PY_BINPATH = '#!/usr/bin/python\n' |
81 |
|
82 |
PY_FXNS_A = """ |
83 |
class DRMSParams(object): |
84 |
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 |
return self.params[name] |
97 |
else: |
98 |
return None |
99 |
""" |
100 |
|
101 |
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 |
SH_BINPATH = '#!/bin/bash\n' |
109 |
|
110 |
|
111 |
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 |
|
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 |
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 |
# 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 |
# 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 |
def GetArgs(args): |
203 |
rv = bool(0) |
204 |
optD = {} |
205 |
|
206 |
try: |
207 |
opts, remainder = getopt.getopt(args, "hd:b:s",["dir=", "base="]) |
208 |
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 |
elif opt in ("-s"): |
227 |
optD['server'] = "" |
228 |
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 |
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 |
|
269 |
def createShConst(key, val, status): |
270 |
status = bool(0) |
271 |
return key + '=' + val + '\n' |
272 |
|
273 |
|
274 |
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 |
def processMakeParam(mDefs, key, val, platDict, machDict): |
284 |
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 |
def processParam(cfgfile, line, regexpQuote, regexp, keymap, defs, cDefs, mDefsGen, mDefsMake, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection, platDict, machDict, section): |
310 |
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 |
# 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 |
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 |
mDefsGen.extend(list('\n' + key + ' = ' + val)) |
363 |
|
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 |
# Python file |
369 |
pyConstSection.extend(list(createPyConst(key, "'" + val + "'", 40, status))) |
370 |
|
371 |
# Shell source file |
372 |
shConstSection.extend(list(createShConst(key, "'" + val + "'", status))) |
373 |
|
374 |
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 |
perlInitSection.extend(list("\n $self->{_paramsH}->{'" + key + "'} = " + key + ';')) |
382 |
|
383 |
# The amount of indenting matters! This is Python. |
384 |
pyInitSection.extend(list(" self.params['" + key + "'] = " + key + '\n')) |
385 |
else: |
386 |
# No quote qualifier |
387 |
raise Exception('missingQuoteQual', key) |
388 |
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 |
processMakeParam(mDefsMake, key, val, platDict, machDict) |
400 |
|
401 |
return bool(0) |
402 |
|
403 |
# We have some extraneous line or a newline - ignore. |
404 |
|
405 |
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, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg): |
451 |
matchobj = regexpStyle.match(line) |
452 |
if matchobj: |
453 |
return 'style' |
454 |
|
455 |
matchobj = regexpDefs.match(line) |
456 |
if not matchobj is None: |
457 |
return 'defs' |
458 |
|
459 |
matchobj = regexpMake.match(line) |
460 |
if not matchobj is None: |
461 |
return 'make' |
462 |
|
463 |
matchobj = regexpProjMkRules.match(line) |
464 |
if not matchobj is None: |
465 |
return 'projmkrules' |
466 |
|
467 |
matchobj = regexpProj.match(line) |
468 |
if not matchobj is None: |
469 |
return 'proj' |
470 |
|
471 |
matchobj = regexpProjCfg.match(line) |
472 |
if not matchobj is None: |
473 |
return 'projcfg' |
474 |
|
475 |
return None |
476 |
|
477 |
# defs is a dictionary containing all parameters (should they be needed in this script) |
478 |
# projCfg is the list containing the configure script content. |
479 |
# projMkRules is the list containing the make_basic.mk content. |
480 |
# projRules is the list containing the Rules.mk content. |
481 |
# projTargert is the list containing the target.mk content. |
482 |
def parseConfig(fin, keymap, addenda, defs, cDefs, mDefsGen, mDefsMake, projCfg, projMkRules, projRules, projTarget, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection): |
483 |
rv = bool(0) |
484 |
|
485 |
# Open required config file (config.local) |
486 |
try: |
487 |
# Examine each line, looking for key=value pairs. |
488 |
regexpStyle = re.compile(r"^__STYLE__") |
489 |
regexpDefs = re.compile(r"^__DEFS__") |
490 |
regexpMake = re.compile(r"^__MAKE__") |
491 |
regexpProjMkRules = re.compile(r"__PROJ_MK_RULES__") |
492 |
regexpProj = re.compile(r"^__PROJ__") |
493 |
regexpProjCfg = re.compile(r"^__PROJCFG__") |
494 |
regexpComm = re.compile(r"^\s*#") |
495 |
regexpSp = re.compile(r"^s*$") |
496 |
regexpQuote = re.compile(r"^\s*(\w):(.+)") |
497 |
regexpCustMkBeg = re.compile(r"^_CUST_") |
498 |
regexpCustMkEnd = re.compile(r"^_ENDCUST_") |
499 |
regexpDiv = re.compile(r"^__") |
500 |
regexp = re.compile(r"^\s*(\S+)\s+(\S.*)") |
501 |
|
502 |
ignoreKeymap = False |
503 |
platDict = {} |
504 |
machDict = {} |
505 |
|
506 |
xml = None |
507 |
|
508 |
# Process the parameters in the configuration file |
509 |
if not fin is None: |
510 |
for line in fin: |
511 |
matchobj = regexpComm.match(line) |
512 |
if not matchobj is None: |
513 |
# Skip comment line |
514 |
continue |
515 |
|
516 |
matchobj = regexpSp.match(line) |
517 |
if not matchobj is None: |
518 |
# Skip whitespace line |
519 |
continue |
520 |
|
521 |
newSection = determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg) |
522 |
if not newSection is None: |
523 |
section = newSection |
524 |
|
525 |
if not section: |
526 |
raise Exception('invalidConfigFile', 'line ' + line.strip() + ' is not in any section') |
527 |
|
528 |
if section == 'style': |
529 |
# if the config.local file has new in the __STYLE__ section, then ignore the keymap and treat config.local like configsdp.txt; |
530 |
# do not map from NetDRMS config.local parameter names to configsdp.txt names |
531 |
for line in fin: |
532 |
matchobj = regexpDiv.match(line) |
533 |
if matchobj: |
534 |
break; |
535 |
if line.strip(' \n').lower() == 'new' and keymap: |
536 |
ignoreKeymap = True |
537 |
|
538 |
newSection = determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg) |
539 |
if not newSection is None: |
540 |
section = newSection |
541 |
continue |
542 |
elif section == 'make': |
543 |
|
544 |
# There are some blocks of lines in the __MAKE__ section that must be copied ver batim to the output make file. |
545 |
# The blocks are defined by _CUST_/_ENDCUST_ tags. |
546 |
matchobj = regexpCustMkBeg.match(line) |
547 |
|
548 |
if not matchobj is None: |
549 |
mDefsMake.extend(list('\n')) |
550 |
for line in fin: |
551 |
matchobj = regexpCustMkEnd.match(line) |
552 |
if not matchobj is None: |
553 |
break; |
554 |
mDefsMake.extend(list(line)) |
555 |
newSection = determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg) |
556 |
if not newSection is None: |
557 |
section = newSection |
558 |
continue |
559 |
# Intentional fall through to next if statement |
560 |
if section == 'defs' or section == 'make': |
561 |
iscfg = bool(1) |
562 |
if ignoreKeymap: |
563 |
keymapActual = None |
564 |
else: |
565 |
keymapActual = keymap |
566 |
ppRet = processParam(iscfg, line, regexpQuote, regexp, keymapActual, defs, cDefs, mDefsGen, mDefsMake, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection, platDict, machDict, section) |
567 |
|
568 |
if ppRet: |
569 |
break |
570 |
elif section == 'projcfg': |
571 |
# Copy the line ver batim to the projCfg list (configure) |
572 |
for line in fin: |
573 |
matchobj = regexpDiv.match(line) |
574 |
if not matchobj is None: |
575 |
break; |
576 |
projCfg.extend(list(line)) |
577 |
newSection = determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg) |
578 |
if not newSection is None: |
579 |
section = newSection |
580 |
continue |
581 |
elif section == 'projmkrules': |
582 |
# Copy the line ver batim to the projMkRules list (make_basic.mk) |
583 |
for line in fin: |
584 |
matchobj = regexpDiv.match(line) |
585 |
if not matchobj is None: |
586 |
break; |
587 |
projMkRules.extend(list(line)) |
588 |
newSection = determineSection(line, regexpStyle, regexpDefs, regexpMake, regexpProjMkRules, regexpProj, regexpProjCfg) |
589 |
if not newSection is None: |
590 |
section = newSection |
591 |
continue |
592 |
elif section == 'proj': |
593 |
# Must parse xml and use the project-specific information to populate the Rules.mk and target.mk files. |
594 |
# Collect all xml lines for now, then process after file-read loop. |
595 |
if xml is None: |
596 |
# The first time through this section, line is the config.local div, __PROJ__. Discard that. |
597 |
xml = '' |
598 |
continue |
599 |
else: |
600 |
xml += line |
601 |
else: |
602 |
# Unknown section |
603 |
raise Exception('unknownSection', section) |
604 |
except Exception as exc: |
605 |
if len(exc.args) >= 2: |
606 |
msg = exc.args[0] |
607 |
else: |
608 |
# re-raise the exception |
609 |
raise |
610 |
|
611 |
if msg == 'invalidConfigFile': |
612 |
violator = exc.args[1] |
613 |
print(violator, file=sys.stderr) |
614 |
rv = bool(1) |
615 |
elif msg == 'badKeyMapKey': |
616 |
# If we are here, then there was a non-empty keymap, and the parameter came from |
617 |
# the configuration file. |
618 |
violator = exc.args[1] |
619 |
print('Unknown parameter name ' + "'" + violator + "'" + ' in ' + fin.name + '.', file=sys.stderr) |
620 |
rv = bool(1) |
621 |
elif msg == 'badQuoteQual': |
622 |
# The bad quote qualifier came from the configuration file, not the addenda, since |
623 |
# we will have fixed any bad qualifiers in the addenda (which is populated by code). |
624 |
violator = exc.args[1] |
625 |
print('Unknown quote qualifier ' + "'" + violator + "'" + ' in ' + fin.name + '.', file=sys.stderr) |
626 |
rv = bool(1) |
627 |
elif msg == 'missingQuoteQual': |
628 |
violator = exc.args[1] |
629 |
print('Missing quote qualifier for parameter ' + "'" + violator + "'" + ' in ' + fin.name + '.', file=sys.stderr) |
630 |
rv = bool(1) |
631 |
elif msg == 'paramNameTooLong': |
632 |
violator = exc.args[1] |
633 |
print('Macro name ' + "'" + violator + "' is too long.", file=sys.stderr) |
634 |
rv = bool(1) |
635 |
elif msg == 'unknownSection': |
636 |
violator = exc.args[1] |
637 |
print('Unknown section ' + "'" + violator + "' in configuration file.", file=sys.stderr) |
638 |
rv = bool(1) |
639 |
else: |
640 |
# re-raise the exception |
641 |
raise |
642 |
|
643 |
if not rv: |
644 |
if not xml is None: |
645 |
# Process xml. |
646 |
rv = processXML(xml, projRules, projTarget) |
647 |
|
648 |
# Process addenda - these are parameters that are not configurable and must be set in the |
649 |
# NetDRMS build. |
650 |
if not rv: |
651 |
iscfg = bool(0) |
652 |
for key in addenda: |
653 |
item = key + ' ' + addenda[key] |
654 |
if ignoreKeymap: |
655 |
keymapActual = None |
656 |
else: |
657 |
keymapActual = keymap |
658 |
ppRet = processParam(iscfg, item, regexpQuote, regexp, keymapActual, defs, cDefs, mDefsGen, mDefsMake, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection, platDict, machDict, 'defs') |
659 |
if ppRet: |
660 |
break; |
661 |
|
662 |
# Put information collected in platDict and machDict into mDefs. Must do this here, and not in processParam, since |
663 |
# we need to parse all platform-specific make variables before grouping them into platform categories. |
664 |
if not rv: |
665 |
for plat in platDict: |
666 |
mDefsMake.extend(list('\nifeq ($(JSOC_MACHINE), linux_' + plat.lower() + ')')) |
667 |
for var in platDict[plat]: |
668 |
mDefsMake.extend(list('\n' + var + ' = ' + platDict[plat][var])) |
669 |
mDefsMake.extend(list('\nendif\n')) |
670 |
|
671 |
if not rv: |
672 |
for mach in machDict: |
673 |
mDefsMake.extend(list('\nifeq ($(MACHTYPE), ' + mach + ')')) |
674 |
for var in machDict[mach]: |
675 |
mDefsMake.extend(list('\n' + var + ' = ' + machDict[mach][var])) |
676 |
mDefsMake.extend(list('\nendif\n')) |
677 |
return rv |
678 |
|
679 |
def getMgrUIDLine(defs, uidParam): |
680 |
rv = bool(0) |
681 |
|
682 |
cmd = 'id -u ' + defs['SUMS_MANAGER'] |
683 |
try: |
684 |
ret = check_output(cmd, shell=True) |
685 |
uidParam['q:SUMS_MANAGER_UID'] = ret.decode("utf-8") |
686 |
except ValueError: |
687 |
print('Unable to run cmd: ' + cmd + '.') |
688 |
rv = bool(1) |
689 |
except CalledProcessError: |
690 |
print('Command ' + "'" + cmd + "'" + ' ran improperly.') |
691 |
rv = bool(1) |
692 |
|
693 |
return rv |
694 |
|
695 |
def isVersion(maj, min, majDef, minDef): |
696 |
res = 0 |
697 |
|
698 |
if maj > majDef or (maj == majDef and min >= minDef): |
699 |
res = 1 |
700 |
|
701 |
return res |
702 |
|
703 |
def configureComps(defs, mDefs): |
704 |
rv = bool(0) |
705 |
autoConfig = bool(1) |
706 |
|
707 |
if 'AUTOSELCOMP' in defs: |
708 |
autoConfig = (not defs['AUTOSELCOMP'] == '0') |
709 |
|
710 |
if autoConfig: |
711 |
hasicc = bool(0) |
712 |
hasgcc = bool(0) |
713 |
hasifort = bool(0) |
714 |
hasgfort = bool(0) |
715 |
|
716 |
# Try icc. |
717 |
cmd = 'icc --version 2>&1' |
718 |
try: |
719 |
ret = check_output(cmd, shell=True) |
720 |
ret = ret.decode("utf-8") |
721 |
except CalledProcessError: |
722 |
print('Command ' + "'" + cmd + "'" + ' ran improperly.') |
723 |
rv = bool(1) |
724 |
|
725 |
if not rv: |
726 |
regexp = re.compile(r"\s*\S+\s+\S+\s+(\d+)[.](\d+)", re.DOTALL) |
727 |
matchobj = regexp.match(ret) |
728 |
if matchobj is None: |
729 |
raise Exception('unexpectedIccRet', ret) |
730 |
else: |
731 |
major = matchobj.group(1) |
732 |
minor = matchobj.group(2) |
733 |
if isVersion(int(major), int(minor), ICC_MAJOR, ICC_MINOR): |
734 |
hasicc = bool(1) |
735 |
|
736 |
# Try gcc. |
737 |
if not hasicc: |
738 |
rv = bool(0) |
739 |
cmd = 'gcc -v 2>&1' |
740 |
try: |
741 |
ret = check_output(cmd, shell=True) |
742 |
ret = ret.decode("utf-8") |
743 |
except CalledProcessError: |
744 |
print('Command ' + "'" + cmd + "'" + ' ran improperly.') |
745 |
rv = bool(1) |
746 |
|
747 |
if not rv: |
748 |
regexp = re.compile(r".+gcc\s+version\s+(\d+)\.(\d+)", re.DOTALL) |
749 |
matchobj = regexp.match(ret) |
750 |
if matchobj is None: |
751 |
raise Exception('unexpectedGccRet', ret) |
752 |
else: |
753 |
major = matchobj.group(1) |
754 |
minor = matchobj.group(2) |
755 |
if isVersion(int(major), int(minor), GCC_MAJOR, GCC_MINOR): |
756 |
hasgcc = bool(1) |
757 |
|
758 |
# Try ifort. |
759 |
rv = bool(0) |
760 |
cmd = 'ifort --version 2>&1' |
761 |
try: |
762 |
ret = check_output(cmd, shell=True) |
763 |
ret = ret.decode("utf-8") |
764 |
except CalledProcessError: |
765 |
print('Command ' + "'" + cmd + "'" + ' ran improperly.') |
766 |
rv = bool(1) |
767 |
|
768 |
if not rv: |
769 |
regexp = re.compile(r"\s*\S+\s+\S+\s+(\d+)\.(\d+)", re.DOTALL) |
770 |
matchobj = regexp.match(ret) |
771 |
if matchobj is None: |
772 |
raise Exception('unexpectedIfortRet', ret) |
773 |
else: |
774 |
major = matchobj.group(1) |
775 |
minor = matchobj.group(2) |
776 |
if isVersion(int(major), int(minor), IFORT_MAJOR, IFORT_MINOR): |
777 |
hasifort = bool(1) |
778 |
|
779 |
# Try gfortran |
780 |
if not hasifort: |
781 |
rv = bool(0) |
782 |
cmd = 'gfortran -v 2>&1' |
783 |
try: |
784 |
ret = check_output(cmd, shell=True) |
785 |
ret = ret.decode("utf-8") |
786 |
except CalledProcessError: |
787 |
print('Command ' + "'" + cmd + "'" + ' ran improperly.') |
788 |
rv = bool(1) |
789 |
|
790 |
if not rv: |
791 |
regexp = re.compile(r".+gcc\s+version\s+(\d+)\.(\d+)", re.DOTALL) |
792 |
matchobj = regexp.match(ret) |
793 |
if matchobj is None: |
794 |
raise Exception('unexpectedGfortranRet', ret) |
795 |
else: |
796 |
major = matchobj.group(1) |
797 |
minor = matchobj.group(2) |
798 |
if isVersion(int(major), int(minor), GFORT_MAJOR, GFORT_MINOR): |
799 |
hasgfort = bool(1) |
800 |
|
801 |
# Append the compiler make variables to the make file |
802 |
rv = bool(0) |
803 |
|
804 |
if not hasicc and not hasgcc: |
805 |
print('Fatal error: Acceptable C compiler not found! You will be unable to build the DRMS library.', file=sys.stderr) |
806 |
rv = bool(1) |
807 |
elif hasicc: |
808 |
mDefs.extend(list('\nCOMPILER = icc')) |
809 |
else: |
810 |
mDefs.extend(list('\nCOMPILER = gcc')) |
811 |
|
812 |
if not hasifort and not hasgfort: |
813 |
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) |
814 |
elif hasifort: |
815 |
mDefs.extend(list('\nFCOMPILER = ifort')) |
816 |
else: |
817 |
mDefs.extend(list('\nFCOMPILER = gfortran')) |
818 |
|
819 |
# Environment overrides. These get written, regardless of the disposition of auto-configuration. |
820 |
mDefs.extend(list('\nifneq ($(JSOC_COMPILER),)\n COMPILER = $(JSOC_COMPILER)\nendif')) |
821 |
mDefs.extend(list('\nifneq ($(JSOC_FCOMPILER),)\n FCOMPILER = $(JSOC_FCOMPILER)\nendif')) |
822 |
|
823 |
return rv |
824 |
|
825 |
def writeParamsFiles(base, cfile, mfile, pfile, pyfile, shfile, cDefs, mDefsGen, mDefsMake, mDefsComps, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection): |
826 |
rv = bool(0) |
827 |
|
828 |
# Merge mDefsGen, mDefsMake, and mDefsComps into a single string with compiler configuration first, general parameters next, then |
829 |
# make-specific make variables (e.g., third-party library information) last. |
830 |
mDefs = '\n# Compiler Selection\n' + ''.join(mDefsComps) + '\n\n# General Parameters\n' + ''.join(mDefsGen) + '\n\n# Parameters to Configure make\n' + ''.join(mDefsMake) |
831 |
|
832 |
try: |
833 |
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: |
834 |
# C file of macros |
835 |
print(C_PREFIX, file=cout) |
836 |
print('/* This file contains a set of preprocessor macros - one for each configuration parameter. */\n', file=cout) |
837 |
buf = '__' + base.upper() + '_H' |
838 |
print('#ifndef ' + buf, file=cout) |
839 |
print('#define ' + buf, file=cout) |
840 |
print(''.join(cDefs), file=cout) |
841 |
print('#endif', file=cout) |
842 |
|
843 |
# Make file of make variables |
844 |
print(PREFIX, file=mout) |
845 |
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) |
846 |
print(mDefs, file=mout) |
847 |
|
848 |
# Perl module |
849 |
print(PERL_BINPATH, file=pout) |
850 |
print(PREFIX, file=pout) |
851 |
print('# This file contains a set of constants - one for each configuration parameter.\n', file=pout) |
852 |
print(PERL_INTIAL, file=pout) |
853 |
print(''.join(perlConstSection), file=pout) |
854 |
print(PERL_FXNS_A, file=pout) |
855 |
print('sub initialize', file=pout) |
856 |
print('{', file=pout) |
857 |
print(' my($self) = shift;', file=pout, end='') |
858 |
print('', file=pout) |
859 |
print(''.join(perlInitSection), file=pout) |
860 |
print('}\n', file=pout) |
861 |
print(PERL_FXNS_B, file=pout) |
862 |
|
863 |
# Python module |
864 |
print(PY_BINPATH, file=pyout) |
865 |
print(PREFIX, file=pyout) |
866 |
print('# This file contains a set of constants - one for each configuration parameter.\n', file=pyout) |
867 |
print(''.join(pyConstSection), file=pyout) |
868 |
print(PY_FXNS_A, file=pyout, end='') |
869 |
print(''.join(pyInitSection), file=pyout) |
870 |
print(PY_FXNS_B, file=pyout) |
871 |
print(PY_FXNS_C, file=pyout) |
872 |
|
873 |
# Shell (bash) source file |
874 |
print(SH_BINPATH, file=shout) |
875 |
print(PREFIX, file=shout) |
876 |
print('# This file contains a set of variable assignments - one for each configuration parameter.\n', file=shout) |
877 |
print(''.join(shConstSection), file=shout) |
878 |
|
879 |
except IOError as exc: |
880 |
type, value, traceback = sys.exc_info() |
881 |
print(exc.strerror, file=sys.stderr) |
882 |
print('Unable to open ' + "'" + value.filename + "'.", file=sys.stderr) |
883 |
rv = bool(1) |
884 |
|
885 |
return rv |
886 |
|
887 |
def writeProjFiles(pCfile, pMfile, pRfile, pTfile, projCfg, projMkRules, projRules, projTarget): |
888 |
rv = bool(0) |
889 |
|
890 |
try: |
891 |
if projCfg: |
892 |
with open(pCfile, 'w') as cout: |
893 |
# configure |
894 |
print(''.join(projCfg), file=cout) |
895 |
|
896 |
if projMkRules: |
897 |
with open(pMfile, 'w') as mout: |
898 |
# make_basic.mk |
899 |
print(PREFIX, file=mout) |
900 |
print(''.join(projMkRules), file=mout) |
901 |
|
902 |
if projRules: |
903 |
with open(pRfile, 'w') as rout: |
904 |
# Rules.mk |
905 |
print(PREFIX, file=rout) |
906 |
print(''.join(projRules), file=rout) |
907 |
|
908 |
if projTarget: |
909 |
with open(pTfile, 'w') as tout: |
910 |
# target.mk |
911 |
print(PREFIX, file=tout) |
912 |
print(''.join(projTarget), file=tout) |
913 |
except IOError as exc: |
914 |
type, value, traceback = sys.exc_info() |
915 |
print(exc.strerror, file=sys.stderr) |
916 |
print('Unable to open ' + "'" + value.filename + "'.", file=sys.stderr) |
917 |
rv = bool(1) |
918 |
|
919 |
if not rv: |
920 |
if os.path.exists(pCfile): |
921 |
try: |
922 |
os.chmod(pCfile, stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH) |
923 |
except OSError as exc: |
924 |
type, value, traceback = sys.exc_info() |
925 |
print('Unable to chmod file ' + "'" + value.filename + "'.", file=sys.stderr) |
926 |
print(exc.strerror, file=sys.stderr) |
927 |
rv = bool(1) |
928 |
|
929 |
return rv |
930 |
|
931 |
def generateSumRmCfg(defs): |
932 |
rv = bool(0) |
933 |
# ACK! Remember that Rick renamed these parameters. The ones in config.local are the aliases - do not use those. |
934 |
# Use the ones that those map to (defined in config.local.map). |
935 |
cFileTmp = defs['SUMLOG_BASEDIR'] + '/' + '.sum_rm.cfg.tmp' |
936 |
cFile = defs['SUMLOG_BASEDIR'] + '/' + 'sum_rm.cfg' |
937 |
|
938 |
# Write a temporary file sum_rm configuration file. |
939 |
try: |
940 |
with open(cFileTmp, 'w') as fout: |
941 |
# Print comment at the top of the configuration file. |
942 |
print(SUMRM_COMMENT, file=fout) |
943 |
print(SUMRM_DOC, file=fout) |
944 |
print(SUMRM_PARTN_PERCENT_FREE, file=fout) |
945 |
if 'SUMRM_PART_PERCENT_FREE' in defs: |
946 |
print('PART_PERCENT_FREE=' + defs['SUMRM_PART_PERCENT_FREE'], file=fout) |
947 |
else: |
948 |
print('PART_PERCENT_FREE=3', file=fout) |
949 |
|
950 |
print(SUMRM_SLEEP, file=fout) |
951 |
if 'SUMRM_SLEEP' in defs: |
952 |
print('SLEEP=' + defs['SUMRM_SLEEP'], file=fout) |
953 |
else: |
954 |
print('SLEEP=300', file=fout) |
955 |
|
956 |
print(SUMRM_LOG, file=fout) |
957 |
if 'SUMRM_LOG' in defs: |
958 |
print('LOG=' + defs['SUMRM_LOG'], file=fout) |
959 |
else: |
960 |
print('LOG=/tmp/sum_rm.log', file=fout) |
961 |
|
962 |
print(SUMRM_MAIL, file=fout) |
963 |
# No default for mail - don't send nothing to nobody unless the operator has asked for notifications. |
964 |
if 'SUMRM_MAIL' in defs: |
965 |
print('MAIL=' + defs['SUMRM_MAIL'], file=fout) |
966 |
else: |
967 |
print('# MAIL=president@whitehouse.gov', file=fout) |
968 |
|
969 |
print(SUMRM_NOOP, file=fout) |
970 |
if 'SUMRM_NOOP' in defs: |
971 |
print('NOOP=' + defs['SUMRM_NOOP'], file=fout) |
972 |
else: |
973 |
print('NOOP=0', file=fout) |
974 |
|
975 |
print(SUMRM_USER, file=fout) |
976 |
if 'SUMRM_USER' in defs: |
977 |
print('USER=' + defs['SUMRM_USER'], file=fout) |
978 |
else: |
979 |
print('USER=production', file=fout) |
980 |
|
981 |
print(SUMRM_NORUN, file=fout) |
982 |
# Default norun window is to have no such window. This can be accomplished by simply not providing either argument. |
983 |
if 'SUMRM_NORUN_START' in defs or 'SUMRM_NORUN_STOP' in defs: |
984 |
if 'SUMRM_NORUN_START' in defs: |
985 |
print('NORUN_START=' + defs['SUMRM_NORUN_START'], file=fout) |
986 |
else: |
987 |
print('NORUN_START=0', file=fout) |
988 |
if 'SUMRM_NORUN_STOP' in defs: |
989 |
print('NORUN_STOP=' + defs['SUMRM_NORUN_STOP'], file=fout) |
990 |
else: |
991 |
print('NORUN_STOP=0', file=fout) |
992 |
else: |
993 |
print('# NORUN_START=0', file=fout) |
994 |
print('# NORUN_STOP=0', file=fout) |
995 |
|
996 |
except OSError: |
997 |
print('Unable to open sum_rm temporary configuration file ' + cFileTmp + 'for writing.', file=sys.stderr) |
998 |
rv = bool(1) |
999 |
|
1000 |
# If the content of the temporary file differs from the content of the existing configuration file, then overwrite |
1001 |
# the original file. Otherwise, delete the temporary file |
1002 |
if not rv: |
1003 |
try: |
1004 |
if filecmp.cmp(cFile, cFileTmp): |
1005 |
# Files identical - delete temporary file |
1006 |
try: |
1007 |
os.remove(cFileTmp) |
1008 |
|
1009 |
except OSError as exc: |
1010 |
print('Unable to remove temporary file ' + exc.filename + '.', file=sys.stderr) |
1011 |
print(exc.strerr, file=sys.stderr) |
1012 |
else: |
1013 |
# Replace original with temporary file |
1014 |
try: |
1015 |
os.rename(cFileTmp, cFile) |
1016 |
|
1017 |
except OSError as exc: |
1018 |
print('Unable to update sum_rm configuration file ' + cFile + '.', file=sys.stderr) |
1019 |
print(exc.strerr, file=sys.stderr) |
1020 |
rv = bool(1) |
1021 |
except OSError as exc: |
1022 |
# One of the files doesn't exist. |
1023 |
if exc.filename == cFile: |
1024 |
# We are ok - there might be no configuration file yet. |
1025 |
# Replace original with temporary file |
1026 |
try: |
1027 |
os.rename(cFileTmp, cFile) |
1028 |
|
1029 |
except OSError as exc: |
1030 |
print('Unable to update sum_rm configuration file ' + cFile + '.', file=sys.stderr) |
1031 |
print(exc.strerr, file=sys.stderr) |
1032 |
rv = bool(1) |
1033 |
else: |
1034 |
# There is a problem with the temp file - bail. |
1035 |
print('Unable to update sum_rm configuration file ' + cFile + '.', file=sys.stderr) |
1036 |
print(exc.strerr, file=sys.stderr) |
1037 |
rv = bool(1) |
1038 |
|
1039 |
return rv |
1040 |
|
1041 |
def configureNet(cfgfile, cfile, mfile, pfile, pyfile, shfile, pCfile, pMfile, pRfile, pTfile, base, keymap, createSumRmCfg): |
1042 |
rv = bool(0) |
1043 |
|
1044 |
defs = {} |
1045 |
cDefs = list() |
1046 |
mDefsGen = list() |
1047 |
mDefsMake = list() |
1048 |
mDefsComps = list() |
1049 |
projCfg = list() |
1050 |
projMkRules = list() |
1051 |
projRules = list() |
1052 |
projTarget = list() |
1053 |
perlConstSection = list() |
1054 |
perlInitSection = list() |
1055 |
pyConstSection = list() |
1056 |
pyInitSection = list() |
1057 |
shConstSection = list() |
1058 |
addenda = {} |
1059 |
|
1060 |
# There are three parameters that were not included in the original config.local parameter set, for some reason. |
1061 |
# Due to this omission, then are not configurable, and must be set in the script. |
1062 |
addenda['a:USER'] = 'NULL' |
1063 |
addenda['a:PASSWD'] = 'NULL' |
1064 |
addenda['p:DSDS_SUPPORT'] = '0' |
1065 |
|
1066 |
# This parameter is not configurable. BUILD_TYPE is used to distinguish between a NetDRMS and an JSOC-SDP build. |
1067 |
addenda['a:BUILD_TYPE'] = 'NETDRMS' # Means a non-Stanford build. This will set two additional macros used by make: |
1068 |
# __LOCALIZED_DEFS__ and NETDRMS_BUILD. The former is to support legacy code |
1069 |
# which incorrectly used this macro, and the latter is for future use. |
1070 |
# __LOCALIZED_DEFS__ is deprecated and should not be used in new code. |
1071 |
|
1072 |
try: |
1073 |
with open(cfgfile, 'r') as fin: |
1074 |
# Process configuration parameters |
1075 |
|
1076 |
# Always create a Rules.mk and target.mk, even if no proj XML is provided. All builds should have the proj/example and |
1077 |
# proj/cookbook directories. The required make information is in RULESPREFIX, TARGETPREFIX, and RULESSUFFIX. RULESSUFFIX |
1078 |
# must be added after the xml has been parsed. |
1079 |
projRules.extend(list(RULESPREFIX)) |
1080 |
projTarget.extend(list(TARGETPREFIX)) |
1081 |
|
1082 |
rv = parseConfig(fin, keymap, addenda, defs, cDefs, mDefsGen, mDefsMake, projCfg, projMkRules, projRules, projTarget, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection) |
1083 |
if not rv: |
1084 |
projRules.extend(RULESSUFFIX) |
1085 |
|
1086 |
# Must add a parameter for the SUMS_MANAGER UID (for some reason). This must be done after the |
1087 |
# config file is processed since an input to getMgrUIDLine() is one of the config file's |
1088 |
# parameter values. |
1089 |
uidParam = {} |
1090 |
rv = getMgrUIDLine(defs, uidParam) |
1091 |
if rv == bool(0): |
1092 |
rv = parseConfig(None, keymap, uidParam, defs, cDefs, mDefsGen, None, projCfg, projMkRules, projRules, projTarget, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection) |
1093 |
# Configure the compiler-selection make variables. |
1094 |
if not rv: |
1095 |
rv = configureComps(defs, mDefsComps) |
1096 |
|
1097 |
# Write out the parameter files. |
1098 |
if not rv: |
1099 |
rv = writeParamsFiles(base, cfile, mfile, pfile, pyfile, shfile, cDefs, mDefsGen, mDefsMake, mDefsComps, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection) |
1100 |
|
1101 |
# Write out the project-specific make files (make_basic.mk, Rules.mk, and target.mk). |
1102 |
if not rv: |
1103 |
rv = writeProjFiles(pCfile, pMfile, pRfile, pTfile, projCfg, projMkRules, projRules, projTarget) |
1104 |
|
1105 |
# Write out the sum_rm.cfg file. |
1106 |
if not rv and createSumRmCfg: |
1107 |
rv = generateSumRmCfg(defs) |
1108 |
except IOError as exc: |
1109 |
print(exc.strerror, file=sys.stderr) |
1110 |
print('Unable to read configuration file ' + cfgfile + '.', file=sys.stderr) |
1111 |
except Exception as exc: |
1112 |
if len(exc.args) >= 2: |
1113 |
type, msg = exc.args |
1114 |
else: |
1115 |
# re-raise the exception |
1116 |
raise |
1117 |
|
1118 |
if type == 'unexpectedIccRet': |
1119 |
print('icc -V returned this unexpected message:\n' + msg, file=sys.stderr) |
1120 |
rv = bool(1) |
1121 |
elif type == 'unexpectedGccRet': |
1122 |
print('gcc -v returned this unexpected message:\n' + msg, file=sys.stderr) |
1123 |
rv = bool(1) |
1124 |
elif type == 'unexpectedIfortRet': |
1125 |
print('ifort -V returned this unexpected message:\n' + msg, file=sys.stderr) |
1126 |
rv = bool(1) |
1127 |
elif type == 'unexpectedGfortranRet': |
1128 |
print('gfortran -v returned this unexpected message:\n' + msg, file=sys.stderr) |
1129 |
rv = bool(1) |
1130 |
else: |
1131 |
# re-raise the exception |
1132 |
raise |
1133 |
|
1134 |
return rv |
1135 |
|
1136 |
def configureSdp(cfgfile, cfile, mfile, pfile, pyfile, shfile, pCfile, pMfile, pRfile, pTfile, base): |
1137 |
rv = bool(0) |
1138 |
|
1139 |
defs = {} |
1140 |
cDefs = list() |
1141 |
mDefsGen = list() |
1142 |
mDefsMake = list() |
1143 |
projCfg = list() |
1144 |
projMkRules = list() |
1145 |
projRules = list() |
1146 |
projTarget = list() |
1147 |
mDefsComps = list() |
1148 |
perlConstSection = list() |
1149 |
perlInitSection = list() |
1150 |
pyConstSection = list() |
1151 |
pyInitSection = list() |
1152 |
shConstSection = list() |
1153 |
|
1154 |
addenda = {} |
1155 |
|
1156 |
# There are three parameters that were not included in the original config.local parameter set, for some reason. |
1157 |
# Due to this omission, then are not configurable, and must be set in the script. |
1158 |
addenda['a:USER'] = 'NULL' |
1159 |
addenda['a:PASSWD'] = 'NULL' |
1160 |
addenda['p:DSDS_SUPPORT'] = '1' |
1161 |
|
1162 |
# This parameter is not configurable. BUILD_TYPE is used to distinguish between a NetDRMS and an JSOC-SDP build. |
1163 |
addenda['a:BUILD_TYPE'] = 'JSOC_SDP' # Means a Stanford build. This will set one additional macro used by make: JSOC_SDP_BUILD. |
1164 |
|
1165 |
try: |
1166 |
with open(cfgfile, 'r') as fin: |
1167 |
|
1168 |
# Always create a Rules.mk and target.mk, even if no proj XML is provided. All builds should have the proj/example and |
1169 |
# proj/cookbook directories. The required make information is in RULESPREFIX, TARGETPREFIX, and RULESSUFFIX. RULESSUFFIX |
1170 |
# must be added after the xml has been parsed. |
1171 |
projRules.extend(list(RULESPREFIX)) |
1172 |
projTarget.extend(list(TARGETPREFIX)) |
1173 |
|
1174 |
rv = parseConfig(fin, None, addenda, defs, cDefs, mDefsGen, mDefsMake, projCfg, projMkRules, projRules, projTarget, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection) |
1175 |
|
1176 |
if not rv: |
1177 |
projRules.extend(RULESSUFFIX) |
1178 |
|
1179 |
# Must add a parameter for the SUMS_MANAGER UID (for some reason) |
1180 |
uidParam = {} |
1181 |
rv = getMgrUIDLine(defs, uidParam) |
1182 |
if not rv: |
1183 |
rv = parseConfig(None, None, uidParam, defs, cDefs, mDefsGen, None, projCfg, projMkRules, projRules, projTarget, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection) |
1184 |
|
1185 |
# Configure the compiler-selection make variables. |
1186 |
if not rv: |
1187 |
rv = configureComps(defs, mDefsComps) |
1188 |
|
1189 |
# Write out the parameter files. |
1190 |
if not rv: |
1191 |
rv = writeParamsFiles(base, cfile, mfile, pfile, pyfile, shfile, cDefs, mDefsGen, mDefsMake, mDefsComps, perlConstSection, perlInitSection, pyConstSection, pyInitSection, shConstSection) |
1192 |
|
1193 |
# Write out the project-specific make files (make_basic.mk, Rules.mk, and target.mk). |
1194 |
if not rv: |
1195 |
rv = writeProjFiles(pCfile, pMfile, pRfile, pTfile, projCfg, projMkRules, projRules, projTarget) |
1196 |
|
1197 |
# At Stanford, skip the creation of the sum_rm configuration file. config.local will still |
1198 |
# have the SUMRM parameters, but they will not be used. |
1199 |
except IOError as exc: |
1200 |
print(exc.strerror, file=sys.stderr) |
1201 |
print('Unable to read configuration file ' + cfgfile + '.', file=sys.stderr) |
1202 |
except Exception as exc: |
1203 |
if len(exc.args) >= 2: |
1204 |
type = exc.args[0] |
1205 |
else: |
1206 |
# re-raise the exception |
1207 |
raise |
1208 |
|
1209 |
if type == 'unexpectedIccRet': |
1210 |
msg = exc.args[1] |
1211 |
print('icc -V returned this unexpected message:\n' + msg, file=sys.stderr) |
1212 |
rv = bool(1) |
1213 |
elif type == 'unexpectedGccRet': |
1214 |
msg = exc.args[1] |
1215 |
print('gcc -v returned this unexpected message:\n' + msg, file=sys.stderr) |
1216 |
rv = bool(1) |
1217 |
elif type == 'unexpectedIfortRet': |
1218 |
msg = exc.args[1] |
1219 |
print('ifort -V returned this unexpected message:\n' + msg, file=sys.stderr) |
1220 |
rv = bool(1) |
1221 |
elif type == 'unexpectedGfortranRet': |
1222 |
msg = exc.args[1] |
1223 |
print('gfortran -v returned this unexpected message:\n' + msg, file=sys.stderr) |
1224 |
rv = bool(1) |
1225 |
else: |
1226 |
# re-raise the exception |
1227 |
raise |
1228 |
|
1229 |
return rv |
1230 |
|
1231 |
# Beginning of program |
1232 |
rv = RET_SUCCESS |
1233 |
net = bool(1) |
1234 |
|
1235 |
# Parse arguments |
1236 |
if __name__ == "__main__": |
1237 |
optD = GetArgs(sys.argv[1:]) |
1238 |
|
1239 |
if not(optD is None): |
1240 |
# Ensure we are configuring a DRMS tree |
1241 |
cdir = os.path.realpath(os.getcwd()) |
1242 |
versfile = cdir + '/base/' + VERS_FILE |
1243 |
|
1244 |
if not os.path.isfile(versfile): |
1245 |
rv = RET_NOTDRMS |
1246 |
|
1247 |
# Determine whether we are localizing a Stanford build, or a NetDRMS build. If configsdp.txt exists, then |
1248 |
# it is a Stanford build, otherwise it is a NetDRMS build. |
1249 |
if rv == RET_SUCCESS: |
1250 |
stanfordFile = cdir + '/' + SDP_CFG |
1251 |
if os.path.isfile(stanfordFile): |
1252 |
net = bool(0) |
1253 |
|
1254 |
cfile = optD['dir'] + '/' + optD['base'] + '.h' |
1255 |
mfile = optD['dir'] + '/' + optD['base'] + '.mk' |
1256 |
pfile = optD['dir'] + '/' + optD['base'] + '.pm' |
1257 |
pyfile = optD['dir'] + '/' + optD['base'] + '.py' |
1258 |
shfile = optD['dir'] + '/' + optD['base'] + '.sh' |
1259 |
pCfile = optD['dir'] + '/configure' |
1260 |
pMfile = optD['dir'] + '/make_basic.mk' |
1261 |
pRfile = optD['dir'] + '/Rules.mk' |
1262 |
pTfile = optD['dir'] + '/target.mk' |
1263 |
|
1264 |
if net: |
1265 |
try: |
1266 |
with open(NET_CFGMAP, 'r') as fin: |
1267 |
regexpComm = re.compile(r"^\s*#") |
1268 |
regexp = re.compile(r"^\s*(\S+)\s+(\w:\S+)") |
1269 |
# Must map from config.local namespace to DRMS namespace (e.g., the names used for the C macros) |
1270 |
keymap = {} |
1271 |
for line in fin: |
1272 |
matchobj = regexpComm.match(line) |
1273 |
if not matchobj is None: |
1274 |
# Skip comment line |
1275 |
continue |
1276 |
|
1277 |
matchobj = regexp.match(line) |
1278 |
if not(matchobj is None): |
1279 |
# We have a key-value line |
1280 |
key = matchobj.group(1) |
1281 |
val = matchobj.group(2) |
1282 |
keymap[key] = val |
1283 |
except OSError: |
1284 |
sys.stderr.write('Unable to read configuration map-file ' + NET_CFGMAP + '.') |
1285 |
rv = bool(1) |
1286 |
|
1287 |
# We also need to set the UID of the SUMS manager. We have the name of the |
1288 |
# SUMS manager (it is in the configuration file) |
1289 |
configureNet(NET_CFG, cfile, mfile, pfile, pyfile, shfile, pCfile, pMfile, pRfile, pTfile, optD['base'], keymap, 'server' in optD) |
1290 |
else: |
1291 |
# A Stanford user can override the parameters in configsdp.txt by copying that file to config.local, |
1292 |
# and then editing config.local. So, if config.local exists, use that. |
1293 |
if os.path.isfile(cdir + '/' + NET_CFG): |
1294 |
configureSdp(NET_CFG, cfile, mfile, pfile, pyfile, shfile, pCfile, pMfile, pRfile, pTfile, optD['base']) |
1295 |
else: |
1296 |
configureSdp(SDP_CFG, cfile, mfile, pfile, pyfile, shfile, pCfile, pMfile, pRfile, pTfile, optD['base']) |