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