Changes in tools/config.py [3f1a481:a35b458] in mainline
- File:
-
- 1 edited
-
tools/config.py (modified) (16 diffs)
Legend:
- Unmodified
- Added
- Removed
-
tools/config.py
r3f1a481 ra35b458 42 42 import random 43 43 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] 44 RULES_FILE = sys.argv[1] 51 45 MAKEFILE = 'Makefile.config' 52 46 MACROS = 'config.h' 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) 47 PRESETS_DIR = 'defaults' 197 48 198 49 def read_config(fname, config): … … 208 59 inf.close() 209 60 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 False 82 83 if (ctype == 'dnf') and inside: 84 return True 85 86 if ctype == 'cnf': 87 return True 88 89 return False 90 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 True 118 119 if (oper == '!=') and (condval != varval): 120 return True 121 else: 122 if (oper == '=') and (condval != varval): 123 return False 124 125 if (oper == '!=') and (condval == varval): 126 return False 127 128 if ctype == 'cnf': 129 return False 130 131 return True 132 210 133 def parse_rules(fname, rules): 211 134 "Parse rules file" … … 226 149 227 150 cond = res.group(1) 228 if cond:229 cond = CondParser(cond).parse()230 151 varname = res.group(2) 231 152 vartype = res.group(3) … … 311 232 varname, vartype, name, choices, cond = rule 312 233 313 if cond and not cond.evaluate(config):234 if cond and (not check_condition(cond, config, rules)): 314 235 continue 315 236 … … 358 279 359 280 # First check that this rule would make sense 360 if cond and not cond.evaluate(config): 361 return random_choices(config, rules, start_index + 1) 281 if cond: 282 if not check_condition(cond, config, rules): 283 return random_choices(config, rules, start_index + 1) 362 284 363 285 # Remember previous choices for backtracking … … 538 460 539 461 try: 540 version = subprocess.Popen(['git', ' -C', os.path.dirname(RULES_FILE), 'log', '-1', '--pretty=%h'], stdout = subprocess.PIPE).communicate()[0].decode().strip()462 version = subprocess.Popen(['git', 'log', '-1', '--pretty=%h'], stdout = subprocess.PIPE).communicate()[0].decode().strip() 541 463 sys.stderr.write("ok\n") 542 464 except: … … 565 487 566 488 for varname, vartype, name, choices, cond in rules: 567 if cond and not cond.evaluate(config):489 if cond and (not check_condition(cond, config, rules)): 568 490 continue 569 491 … … 592 514 outmk.write('TIMESTAMP_UNIX = %d\n' % timestamp_unix) 593 515 outmc.write('#define TIMESTAMP_UNIX %d\n' % timestamp_unix) 594 defs += ' "-DTIMESTAMP_UNIX=%d" ' % timestamp_unix516 defs += ' "-DTIMESTAMP_UNIX=%d"\n' % timestamp_unix 595 517 596 518 outmk.write('TIMESTAMP = %s\n' % timestamp) 597 519 outmc.write('#define TIMESTAMP %s\n' % timestamp) 598 defs += ' "-DTIMESTAMP=%s" ' % timestamp599 600 outmk.write( '%s\n' %defs)520 defs += ' "-DTIMESTAMP=%s"\n' % timestamp 521 522 outmk.write(defs) 601 523 602 524 outmk.close() … … 682 604 parse_rules(RULES_FILE, rules) 683 605 684 if len(sys.argv) > ARGPOS_CHOICE:685 choice = sys.argv[ARGPOS_CHOICE]686 else:687 choice = None688 689 if len(sys.argv) > ARGPOS_PRESET:690 preset = sys.argv[ARGPOS_PRESET]691 else:692 preset = None693 694 mask_platform = (len(sys.argv) > ARGPOS_MASK_PLATFORM and sys.argv[ARGPOS_MASK_PLATFORM] == "--mask-platform")695 696 606 # Input configuration file can be specified on command line 697 607 # otherwise configuration from previous run is used. 698 if preset is not None:699 profile = parse_profile_name( preset)608 if len(sys.argv) >= 4: 609 profile = parse_profile_name(sys.argv[3]) 700 610 read_presets(profile, config) 701 611 elif os.path.exists(MAKEFILE): … … 703 613 704 614 # Default mode: check values and regenerate configuration files 705 if choice == 'default':615 if (len(sys.argv) >= 3) and (sys.argv[2] == 'default'): 706 616 if (infer_verify_choices(config, rules)): 707 617 preprocess_config(config, rules) … … 711 621 # Hands-off mode: check values and regenerate configuration files, 712 622 # but no interactive fallback 713 if choice == 'hands-off':714 # We deliberately test thisbecause we do not want623 if (len(sys.argv) >= 3) and (sys.argv[2] == 'hands-off'): 624 # We deliberately test sys.argv >= 4 because we do not want 715 625 # to read implicitly any possible previous run configuration 716 if preset is None:626 if len(sys.argv) < 4: 717 627 sys.stderr.write("Configuration error: No presets specified\n") 718 628 return 2 … … 727 637 728 638 # Check mode: only check configuration 729 if choice == 'check':639 if (len(sys.argv) >= 3) and (sys.argv[2] == 'check'): 730 640 if infer_verify_choices(config, rules): 731 641 return 0 … … 733 643 734 644 # Random mode 735 if choice == 'random':645 if (len(sys.argv) == 3) and (sys.argv[2] == 'random'): 736 646 ok = random_choices(config, rules, 0) 737 647 if not ok: … … 759 669 options = [] 760 670 opt2row = {} 761 cnt = 0 762 763 if not mask_platform: 764 cnt += 1 765 options.append(" --- Load preconfigured defaults ... ") 671 cnt = 1 672 673 options.append(" --- Load preconfigured defaults ... ") 766 674 767 675 for rule in rules: 768 676 varname, vartype, name, choices, cond = rule 769 677 770 if cond and not cond.evaluate(config):678 if cond and (not check_condition(cond, config, rules)): 771 679 continue 772 773 if mask_platform and (varname == "PLATFORM" or varname == "MACHINE" or varname == "COMPILER"):774 rule = varname, vartype, "(locked) " + name, choices, cond775 680 776 681 if varname == selname: … … 820 725 continue 821 726 822 if value == 0 and not mask_platform:727 if value == 0: 823 728 profile = choose_profile(PRESETS_DIR, MAKEFILE, screen, config) 824 729 if profile != None: … … 837 742 else: 838 743 value = config[selname] 839 840 if mask_platform and (selname == "PLATFORM" or selname == "MACHINE" or selname == "COMPILER"):841 continue842 744 843 745 if seltype == 'choice':
Note:
See TracChangeset
for help on using the changeset viewer.
