Changeset 3e828ea in mainline for tools/config.py
- Timestamp:
- 2019-09-23T12:49:29Z (6 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 9be2358
- Parents:
- 9259d20 (diff), 1a4ec93f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - git-author:
- Jiri Svoboda <jiri@…> (2019-09-22 12:49:07)
- git-committer:
- Jiri Svoboda <jiri@…> (2019-09-23 12:49:29)
- File:
-
- 1 edited
-
tools/config.py (modified) (16 diffs)
Legend:
- Unmodified
- Added
- Removed
-
tools/config.py
r9259d20 r3e828ea 42 42 import random 43 43 44 RULES_FILE = sys.argv[1] 44 ARGPOS_RULES = 1 45 ARGPOS_PRESETS_DIR = 2 46 ARGPOS_CHOICE = 3 47 ARGPOS_PRESET = 4 48 ARGPOS_MASK_PLATFORM = 3 49 50 RULES_FILE = sys.argv[ARGPOS_RULES] 45 51 MAKEFILE = 'Makefile.config' 46 52 MACROS = 'config.h' 47 PRESETS_DIR = 'defaults' 53 PRESETS_DIR = sys.argv[ARGPOS_PRESETS_DIR] 54 55 class BinaryOp: 56 def __init__(self, operator, left, right): 57 assert operator in ('&', '|', '=', '!=') 58 59 self._operator = operator 60 self._left = left 61 self._right = right 62 63 def evaluate(self, config): 64 if self._operator == '&': 65 return self._left.evaluate(config) and \ 66 self._right.evaluate(config) 67 if self._operator == '|': 68 return self._left.evaluate(config) or \ 69 self._right.evaluate(config) 70 71 # '=' or '!=' 72 if not self._left in config: 73 config_val = '' 74 else: 75 config_val = config[self._left] 76 if config_val == '*': 77 config_val = 'y' 78 79 if self._operator == '=': 80 return self._right == config_val 81 return self._right != config_val 82 83 # Expression parser 84 class CondParser: 85 TOKEN_EOE = 0 86 TOKEN_SPECIAL = 1 87 TOKEN_STRING = 2 88 89 def __init__(self, text): 90 self._text = text 91 92 def parse(self): 93 self._position = -1 94 self._next_char() 95 self._next_token() 96 97 res = self._parse_expr() 98 if self._token_type != self.TOKEN_EOE: 99 self._error("Expected end of expression") 100 return res 101 102 def _next_char(self): 103 self._position += 1 104 if self._position >= len(self._text): 105 self._char = None 106 else: 107 self._char = self._text[self._position] 108 self._is_special_char = self._char in \ 109 ('&', '|', '=', '!', '(', ')') 110 111 def _error(self, msg): 112 raise RuntimeError("Error parsing expression: %s:\n%s\n%s^" % 113 (msg, self._text, " " * self._token_position)) 114 115 def _next_token(self): 116 self._token_position = self._position 117 118 # End of expression 119 if self._char == None: 120 self._token = None 121 self._token_type = self.TOKEN_EOE 122 return 123 124 # '&', '|', '=', '!=', '(', ')' 125 if self._is_special_char: 126 self._token = self._char 127 self._next_char() 128 if self._token == '!': 129 if self._char != '=': 130 self._error("Expected '='") 131 self._token += self._char 132 self._next_char() 133 self._token_type = self.TOKEN_SPECIAL 134 return 135 136 # <var> or <val> 137 self._token = '' 138 self._token_type = self.TOKEN_STRING 139 while True: 140 self._token += self._char 141 self._next_char() 142 if self._is_special_char or self._char == None: 143 break 144 145 def _parse_expr(self): 146 """ <expr> ::= <or_expr> ('&' <or_expr>)* """ 147 148 left = self._parse_or_expr() 149 while self._token == '&': 150 self._next_token() 151 left = BinaryOp('&', left, self._parse_or_expr()) 152 return left 153 154 def _parse_or_expr(self): 155 """ <or_expr> ::= <factor> ('|' <factor>)* """ 156 157 left = self._parse_factor() 158 while self._token == '|': 159 self._next_token() 160 left = BinaryOp('|', left, self._parse_factor()) 161 return left 162 163 def _parse_factor(self): 164 """ <factor> ::= <var> <cond> | '(' <expr> ')' """ 165 166 if self._token == '(': 167 self._next_token() 168 res = self._parse_expr() 169 if self._token != ')': 170 self._error("Expected ')'") 171 self._next_token() 172 return res 173 174 if self._token_type == self.TOKEN_STRING: 175 var = self._token 176 self._next_token() 177 return self._parse_cond(var) 178 179 self._error("Expected '(' or <var>") 180 181 def _parse_cond(self, var): 182 """ <cond> ::= '=' <val> | '!=' <val> """ 183 184 if self._token not in ('=', '!='): 185 self._error("Expected '=' or '!='") 186 187 oper = self._token 188 self._next_token() 189 190 if self._token_type != self.TOKEN_STRING: 191 self._error("Expected <val>") 192 193 val = self._token 194 self._next_token() 195 196 return BinaryOp(oper, var, val) 48 197 49 198 def read_config(fname, config): … … 59 208 inf.close() 60 209 61 def check_condition(text, config, rules):62 "Check that the condition specified on input line is True (only CNF and DNF is supported)"63 64 ctype = 'cnf'65 66 if (')|' in text) or ('|(' in text):67 ctype = 'dnf'68 69 if ctype == 'cnf':70 conds = text.split('&')71 else:72 conds = text.split('|')73 74 for cond in conds:75 if cond.startswith('(') and cond.endswith(')'):76 cond = cond[1:-1]77 78 inside = check_inside(cond, config, ctype)79 80 if (ctype == 'cnf') and (not inside):81 return False82 83 if (ctype == 'dnf') and inside:84 return True85 86 if ctype == 'cnf':87 return True88 89 return False90 91 def check_inside(text, config, ctype):92 "Check for condition"93 94 if ctype == 'cnf':95 conds = text.split('|')96 else:97 conds = text.split('&')98 99 for cond in conds:100 res = re.match(r'^(.*?)(!?=)(.*)$', cond)101 if not res:102 raise RuntimeError("Invalid condition: %s" % cond)103 104 condname = res.group(1)105 oper = res.group(2)106 condval = res.group(3)107 108 if not condname in config:109 varval = ''110 else:111 varval = config[condname]112 if (varval == '*'):113 varval = 'y'114 115 if ctype == 'cnf':116 if (oper == '=') and (condval == varval):117 return True118 119 if (oper == '!=') and (condval != varval):120 return True121 else:122 if (oper == '=') and (condval != varval):123 return False124 125 if (oper == '!=') and (condval == varval):126 return False127 128 if ctype == 'cnf':129 return False130 131 return True132 133 210 def parse_rules(fname, rules): 134 211 "Parse rules file" … … 149 226 150 227 cond = res.group(1) 228 if cond: 229 cond = CondParser(cond).parse() 151 230 varname = res.group(2) 152 231 vartype = res.group(3) … … 232 311 varname, vartype, name, choices, cond = rule 233 312 234 if cond and (not check_condition(cond, config, rules)):313 if cond and not cond.evaluate(config): 235 314 continue 236 315 … … 279 358 280 359 # First check that this rule would make sense 281 if cond: 282 if not check_condition(cond, config, rules): 283 return random_choices(config, rules, start_index + 1) 360 if cond and not cond.evaluate(config): 361 return random_choices(config, rules, start_index + 1) 284 362 285 363 # Remember previous choices for backtracking … … 460 538 461 539 try: 462 version = subprocess.Popen(['git', ' log', '-1', '--pretty=%h'], stdout = subprocess.PIPE).communicate()[0].decode().strip()540 version = subprocess.Popen(['git', '-C', os.path.dirname(RULES_FILE), 'log', '-1', '--pretty=%h'], stdout = subprocess.PIPE).communicate()[0].decode().strip() 463 541 sys.stderr.write("ok\n") 464 542 except: … … 487 565 488 566 for varname, vartype, name, choices, cond in rules: 489 if cond and (not check_condition(cond, config, rules)):567 if cond and not cond.evaluate(config): 490 568 continue 491 569 … … 514 592 outmk.write('TIMESTAMP_UNIX = %d\n' % timestamp_unix) 515 593 outmc.write('#define TIMESTAMP_UNIX %d\n' % timestamp_unix) 516 defs += ' "-DTIMESTAMP_UNIX=%d" \n' % timestamp_unix594 defs += ' "-DTIMESTAMP_UNIX=%d"' % timestamp_unix 517 595 518 596 outmk.write('TIMESTAMP = %s\n' % timestamp) 519 597 outmc.write('#define TIMESTAMP %s\n' % timestamp) 520 defs += ' "-DTIMESTAMP=%s" \n' % timestamp521 522 outmk.write( defs)598 defs += ' "-DTIMESTAMP=%s"' % timestamp 599 600 outmk.write('%s\n' % defs) 523 601 524 602 outmk.close() … … 604 682 parse_rules(RULES_FILE, rules) 605 683 684 if len(sys.argv) > ARGPOS_CHOICE: 685 choice = sys.argv[ARGPOS_CHOICE] 686 else: 687 choice = None 688 689 if len(sys.argv) > ARGPOS_PRESET: 690 preset = sys.argv[ARGPOS_PRESET] 691 else: 692 preset = None 693 694 mask_platform = (len(sys.argv) > ARGPOS_MASK_PLATFORM and sys.argv[ARGPOS_MASK_PLATFORM] == "--mask-platform") 695 606 696 # Input configuration file can be specified on command line 607 697 # otherwise configuration from previous run is used. 608 if len(sys.argv) >= 4:609 profile = parse_profile_name( sys.argv[3])698 if preset is not None: 699 profile = parse_profile_name(preset) 610 700 read_presets(profile, config) 611 701 elif os.path.exists(MAKEFILE): … … 613 703 614 704 # Default mode: check values and regenerate configuration files 615 if (len(sys.argv) >= 3) and (sys.argv[2] == 'default'):705 if choice == 'default': 616 706 if (infer_verify_choices(config, rules)): 617 707 preprocess_config(config, rules) … … 621 711 # Hands-off mode: check values and regenerate configuration files, 622 712 # but no interactive fallback 623 if (len(sys.argv) >= 3) and (sys.argv[2] == 'hands-off'):624 # We deliberately test sys.argv >= 4because we do not want713 if choice == 'hands-off': 714 # We deliberately test this because we do not want 625 715 # to read implicitly any possible previous run configuration 626 if len(sys.argv) < 4:716 if preset is None: 627 717 sys.stderr.write("Configuration error: No presets specified\n") 628 718 return 2 … … 637 727 638 728 # Check mode: only check configuration 639 if (len(sys.argv) >= 3) and (sys.argv[2] == 'check'):729 if choice == 'check': 640 730 if infer_verify_choices(config, rules): 641 731 return 0 … … 643 733 644 734 # Random mode 645 if (len(sys.argv) == 3) and (sys.argv[2] == 'random'):735 if choice == 'random': 646 736 ok = random_choices(config, rules, 0) 647 737 if not ok: … … 669 759 options = [] 670 760 opt2row = {} 671 cnt = 1 672 673 options.append(" --- Load preconfigured defaults ... ") 761 cnt = 0 762 763 if not mask_platform: 764 cnt += 1 765 options.append(" --- Load preconfigured defaults ... ") 674 766 675 767 for rule in rules: 676 768 varname, vartype, name, choices, cond = rule 677 769 678 if cond and (not check_condition(cond, config, rules)):770 if cond and not cond.evaluate(config): 679 771 continue 772 773 if mask_platform and (varname == "PLATFORM" or varname == "MACHINE" or varname == "COMPILER"): 774 rule = varname, vartype, "(locked) " + name, choices, cond 680 775 681 776 if varname == selname: … … 725 820 continue 726 821 727 if value == 0 :822 if value == 0 and not mask_platform: 728 823 profile = choose_profile(PRESETS_DIR, MAKEFILE, screen, config) 729 824 if profile != None: … … 742 837 else: 743 838 value = config[selname] 839 840 if mask_platform and (selname == "PLATFORM" or selname == "MACHINE" or selname == "COMPILER"): 841 continue 744 842 745 843 if seltype == 'choice':
Note:
See TracChangeset
for help on using the changeset viewer.
