Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Merges multiple OS-specific gyp dependency lists into one that works on all | 6 """Merges multiple OS-specific gyp dependency lists into one that works on all |
| 7 of them. | 7 of them. |
| 8 | 8 |
| 9 | 9 |
| 10 The logic is relatively simple. Takes the current conditions, add more | 10 The logic is relatively simple. Takes the current conditions, add more |
| 11 condition, find the strict subset. Done. | 11 condition, find the strict subset. Done. |
| 12 """ | 12 """ |
| 13 | 13 |
| 14 import copy | 14 import copy |
| 15 import logging | 15 import logging |
| 16 import optparse | 16 import optparse |
| 17 import re | 17 import re |
| 18 import sys | 18 import sys |
| 19 | 19 |
| 20 import trace_inputs | 20 import trace_inputs |
| 21 # Create shortcuts. | |
| 22 from trace_inputs import KEY_TRACKED, KEY_UNTRACKED | |
| 21 | 23 |
| 22 | 24 |
| 23 def union(lhs, rhs): | 25 def union(lhs, rhs): |
| 24 """Merges two compatible datastructures composed of dict/list/set.""" | 26 """Merges two compatible datastructures composed of dict/list/set.""" |
| 25 assert lhs is not None or rhs is not None | 27 assert lhs is not None or rhs is not None |
| 26 if lhs is None: | 28 if lhs is None: |
| 27 return copy.deepcopy(rhs) | 29 return copy.deepcopy(rhs) |
| 28 if rhs is None: | 30 if rhs is None: |
| 29 return copy.deepcopy(lhs) | 31 return copy.deepcopy(lhs) |
| 30 assert type(lhs) == type(rhs), (lhs, rhs) | 32 assert type(lhs) == type(rhs), (lhs, rhs) |
| 33 if hasattr(lhs, 'union'): | |
| 34 # Includes set, OSSettings and Configs. | |
| 35 return lhs.union(rhs) | |
| 31 if isinstance(lhs, dict): | 36 if isinstance(lhs, dict): |
| 32 return dict((k, union(lhs.get(k), rhs.get(k))) for k in set(lhs).union(rhs)) | 37 return dict((k, union(lhs.get(k), rhs.get(k))) for k in set(lhs).union(rhs)) |
| 33 elif isinstance(lhs, set): | |
| 34 # Do not go inside the set. | |
| 35 return lhs.union(rhs) | |
| 36 elif isinstance(lhs, list): | 38 elif isinstance(lhs, list): |
| 37 # Do not go inside the list. | 39 # Do not go inside the list. |
| 38 return lhs + rhs | 40 return lhs + rhs |
| 39 assert False, type(lhs) | 41 assert False, type(lhs) |
| 40 | 42 |
| 41 | 43 |
| 42 def process_variables(for_os, variables): | |
| 43 """Extracts files and dirs from the |variables| dict. | |
| 44 | |
| 45 Returns a list of exactly two items. Each item is a dict that maps a string | |
| 46 to a set (of strings). | |
| 47 | |
| 48 In the first item, the keys are file names, and the values are sets of OS | |
| 49 names, like "win" or "mac". In the second item, the keys are directory names, | |
| 50 and the values are sets of OS names too. | |
| 51 """ | |
| 52 VALID_VARIABLES = ['isolate_files', 'isolate_dirs'] | |
| 53 | |
| 54 # Verify strictness. | |
| 55 assert isinstance(variables, dict), variables | |
| 56 assert set(VALID_VARIABLES).issuperset(set(variables)), variables.keys() | |
| 57 for items in variables.itervalues(): | |
| 58 assert isinstance(items, list), items | |
| 59 assert all(isinstance(i, basestring) for i in items), items | |
| 60 | |
| 61 # Returns [files, dirs] | |
| 62 return [ | |
| 63 dict((name, set([for_os])) for name in variables.get(var, [])) | |
| 64 for var in VALID_VARIABLES | |
| 65 ] | |
| 66 | |
| 67 | |
| 68 def eval_content(content): | 44 def eval_content(content): |
| 69 """Evaluates a GYP file and return the value defined in it.""" | 45 """Evaluates a GYP file and return the value defined in it.""" |
| 70 globs = {'__builtins__': None} | 46 globs = {'__builtins__': None} |
| 71 locs = {} | 47 locs = {} |
| 72 value = eval(content, globs, locs) | 48 value = eval(content, globs, locs) |
| 73 assert locs == {}, locs | 49 assert locs == {}, locs |
| 74 assert globs == {'__builtins__': None}, globs | 50 assert globs == {'__builtins__': None}, globs |
| 75 return value | 51 return value |
| 76 | 52 |
| 77 | 53 |
| 78 def _process_inner(for_os, inner, old_files, old_dirs, old_os): | 54 def verify_variables(variables): |
| 79 """Processes the variables inside a condition. | 55 """Verifies the |variables| dictionary is in the expected format.""" |
| 80 | 56 VALID_VARIABLES = [ |
| 81 Only meant to be called by parse_gyp_dict(). | 57 KEY_TRACKED, |
| 82 | 58 KEY_UNTRACKED, |
| 83 Args: | 59 'command', |
| 84 - for_os: OS where the references are tracked for. | 60 'read_only', |
| 85 - inner: Inner dictionary to process. | 61 ] |
| 86 - old_files: Previous list of files to union with. | 62 assert isinstance(variables, dict), variables |
| 87 - old_dirs: Previous list of directories to union with. | 63 assert set(VALID_VARIABLES).issuperset(set(variables)), variables.keys() |
| 88 - old_os: Previous list of OSes referenced to union with. | 64 for name, value in variables.iteritems(): |
| 89 | 65 if name == 'read_only': |
| 90 Returns: | 66 assert value in (True, False, None), value |
| 91 - A tuple of (files, dirs, os) where each list is a union of the new | 67 else: |
| 92 dependencies found for this OS, as referenced by for_os, and the previous | 68 assert isinstance(value, list), value |
| 93 list. | 69 assert all(isinstance(i, basestring) for i in value), value |
| 70 | |
| 71 | |
| 72 def verify_condition(condition): | |
| 73 """Verifies the |condition| dictionary is in the expected format.""" | |
| 74 VALID_INSIDE_CONDITION = ['variables'] | |
| 75 assert isinstance(condition, list), condition | |
| 76 assert 2 <= len(condition) <= 3, condition | |
| 77 assert re.match(r'OS==\"([a-z]+)\"', condition[0]), condition[0] | |
| 78 for c in condition[1:]: | |
| 79 assert isinstance(c, dict), c | |
| 80 assert set(VALID_INSIDE_CONDITION).issuperset(set(c)), c.keys() | |
| 81 verify_variables(c.get('variables', {})) | |
| 82 | |
| 83 | |
| 84 def verify_root(value): | |
| 85 VALID_ROOTS = ['variables', 'conditions'] | |
| 86 assert isinstance(value, dict), value | |
| 87 assert set(VALID_ROOTS).issuperset(set(value)), value.keys() | |
| 88 verify_variables(value.get('variables', {})) | |
| 89 | |
| 90 conditions = value.get('conditions', []) | |
| 91 assert isinstance(conditions, list), conditions | |
| 92 for condition in conditions: | |
| 93 verify_condition(condition) | |
| 94 | |
| 95 | |
| 96 class OSSettings(object): | |
| 97 """Represents the dependencies for an OS. The structure is immutable.""" | |
| 98 def __init__(self, name, values): | |
| 99 self.name = name | |
| 100 verify_variables(values) | |
| 101 self.tracked = sorted(values.get(KEY_TRACKED, [])) | |
| 102 self.untracked = sorted(values.get(KEY_UNTRACKED, [])) | |
| 103 self.command = values.get('command', [])[:] | |
| 104 self.read_only = values.get('read_only') | |
| 105 | |
| 106 def union(self, rhs): | |
| 107 assert self.name == rhs.name | |
| 108 assert not (self.command and rhs.command) | |
| 109 var = { | |
| 110 KEY_TRACKED: sorted(self.tracked + rhs.tracked), | |
| 111 KEY_UNTRACKED: sorted(self.untracked + rhs.untracked), | |
| 112 'command': self.command or rhs.command, | |
| 113 'read_only': rhs.read_only if self.read_only is None else self.read_only, | |
| 114 } | |
| 115 return OSSettings(self.name, var) | |
| 116 | |
| 117 def flatten(self): | |
| 118 out = {} | |
| 119 if self.command: | |
| 120 out['command'] = self.command | |
| 121 if self.tracked: | |
| 122 out[KEY_TRACKED] = self.tracked | |
| 123 if self.untracked: | |
| 124 out[KEY_UNTRACKED] = self.untracked | |
| 125 if self.read_only is not None: | |
| 126 out['read_only'] = self.read_only | |
| 127 return out | |
| 128 | |
| 129 | |
| 130 class Configs(object): | |
| 131 """Represents all the OS-specific configurations. | |
| 132 | |
| 133 The self.per_os[None] member contains all the 'else' clauses plus the default | |
| 134 values. It is not included in the flatten() result. | |
| 94 """ | 135 """ |
| 95 assert isinstance(inner, dict), inner | 136 def __init__(self, oses): |
| 96 assert set(['variables']).issuperset(set(inner)), inner.keys() | 137 self.per_os = { |
| 97 new_files, new_dirs = process_variables(for_os, inner.get('variables', {})) | 138 None: OSSettings(None, {}), |
| 98 if new_files or new_dirs: | 139 } |
| 99 old_os = old_os.union([for_os.lstrip('!')]) | 140 self.per_os.update(dict((name, OSSettings(name, {})) for name in oses)) |
| 100 return union(old_files, new_files), union(old_dirs, new_dirs), old_os | 141 |
| 101 | 142 def union(self, rhs): |
| 102 | 143 out = Configs(list(set(self.per_os.keys() + rhs.per_os.keys()))) |
| 103 def parse_gyp_dict(value): | 144 for value in self.per_os.itervalues(): |
| 104 """Parses a gyp dict as returned by eval_content(). | 145 # TODO(maruel): FAIL |
| 146 out = out.union(value) | |
| 147 for value in rhs.per_os.itervalues(): | |
| 148 out = out.union(value) | |
| 149 return out | |
| 150 | |
| 151 def add_globals(self, values): | |
| 152 for key in self.per_os: | |
| 153 self.per_os[key] = self.per_os[key].union(OSSettings(key, values)) | |
| 154 | |
| 155 def add_values(self, for_os, values): | |
| 156 self.per_os[for_os] = self.per_os[for_os].union(OSSettings(for_os, values)) | |
| 157 | |
| 158 def add_negative_values(self, for_os, values): | |
| 159 """Includes the variables to all OSes except |for_os|. | |
| 160 | |
| 161 This includes 'None' so unknown OSes gets it too. | |
| 162 """ | |
| 163 for key in self.per_os: | |
| 164 if key != for_os: | |
| 165 self.per_os[key] = self.per_os[key].union(OSSettings(key, values)) | |
| 166 | |
| 167 def flatten(self): | |
| 168 """Returns a flat dictionary representation of the configuration. | |
| 169 | |
| 170 Skips None pseudo-OS. | |
| 171 """ | |
| 172 return dict( | |
| 173 (k, v.flatten()) for k, v in self.per_os.iteritems() if k is not None) | |
| 174 | |
| 175 | |
| 176 def invert_map(variables): | |
| 177 """Converts a dict(OS, dict(deptype, list(dependencies)) to | |
| 178 dict(deptype, dict(dependency, set(OSes)) for easier processing. | |
|
Roger Tawa OOO till Jul 10th
2012/04/11 15:15:03
also returns 'OSes' key in dict. maybe the return
| |
| 179 """ | |
| 180 KEYS = ( | |
| 181 KEY_TRACKED, | |
| 182 KEY_UNTRACKED, | |
| 183 'command', | |
| 184 'read_only', | |
| 185 ) | |
| 186 out = dict((key, {}) for key in KEYS) | |
| 187 out['OSes'] = set(variables) | |
| 188 for os_name, values in variables.iteritems(): | |
| 189 for key in (KEY_TRACKED, KEY_UNTRACKED): | |
| 190 for item in values.get(key, []): | |
| 191 out[key].setdefault(item, set()).add(os_name) | |
| 192 | |
| 193 # command needs special handling. | |
| 194 command = tuple(values.get('command', [])) | |
| 195 out['command'].setdefault(command, set()).add(os_name) | |
| 196 | |
| 197 # read_only needs special handling. | |
| 198 out['read_only'].setdefault(values.get('read_only'), set()).add(os_name) | |
| 199 return out | |
| 200 | |
| 201 | |
| 202 def reduce_inputs(values): | |
| 203 """Reduces the invert_map() output to the strictest minimum list.""" | |
| 204 # Construct the inverse map first. | |
| 205 # Look at each individual file and directory, map where they are used and | |
| 206 # reconstruct the inverse dictionary. | |
| 207 # Do not convert back to negative if only 2 OSes were merged. | |
| 208 KEYS = ( | |
| 209 KEY_TRACKED, | |
| 210 KEY_UNTRACKED, | |
| 211 'command', | |
| 212 'read_only', | |
| 213 ) | |
| 214 out = dict((key, {}) for key in KEYS) | |
| 215 oses = out['OSes'] = set(values['OSes']) | |
| 216 assert None not in oses, oses | |
| 217 if len(oses) > 2: | |
| 218 for key in KEYS: | |
| 219 for item, item_oses in values.get(key, {}).iteritems(): | |
| 220 # Converts all oses.difference('foo') to '!foo'. | |
| 221 assert None not in item_oses, item_oses | |
| 222 missing = oses.difference(item_oses) | |
| 223 if len(missing) == 1: | |
| 224 # Replace it with a negative. | |
| 225 out[key][item] = set(['!' + tuple(missing)[0]]) | |
| 226 elif not missing: | |
| 227 out[key][item] = set([None]) | |
| 228 else: | |
| 229 out[key][item] = set(item_oses) | |
| 230 return out | |
| 231 | |
| 232 | |
| 233 def convert_map_to_gyp(values): | |
| 234 """Regenerates back a gyp-like configuration dict from files and dirs | |
| 235 mappings generated from reduce_inputs().""" | |
| 236 # First, inverse the mapping to make it dict first. | |
| 237 oses = values['OSes'] | |
| 238 config = {} | |
| 239 for key in values: | |
| 240 if key == 'OSes': | |
| 241 continue | |
| 242 for item, oses in values[key].iteritems(): | |
| 243 if item is None: | |
| 244 # For read_only default. | |
| 245 continue | |
| 246 for cond_os in oses: | |
| 247 cond_key = None if cond_os is None else cond_os.lstrip('!') | |
| 248 # Insert the if/else dicts. | |
| 249 condition_values = config.setdefault(cond_key, [{}, {}]) | |
| 250 # If condition is negative, use index 1, else use index 0. | |
| 251 cond_value = condition_values[int((cond_os or '').startswith('!'))] | |
| 252 variables = cond_value.setdefault('variables', {}) | |
| 253 | |
| 254 if item in (True, False): | |
| 255 # One-off for read_only. | |
| 256 variables[key] = item | |
| 257 else: | |
| 258 if isinstance(item, tuple): | |
| 259 # One-off for command. | |
| 260 # Do not merge lists and do not sort! | |
| 261 # Note that item is a tuple. | |
| 262 assert key not in variables | |
| 263 variables[key] = list(item) | |
| 264 else: | |
| 265 # The list of items (files or dirs). Append the new item and keep | |
| 266 # the list sorted. | |
| 267 l = variables.setdefault(key, []) | |
| 268 l.append(item) | |
| 269 l.sort() | |
| 270 | |
| 271 out = {} | |
| 272 for o in sorted(config): | |
| 273 d = config[o] | |
| 274 if o is None: | |
| 275 assert not d[1] | |
| 276 out = union(out, d[0]) | |
| 277 else: | |
| 278 c = out.setdefault('conditions', []) | |
| 279 if d[1]: | |
| 280 c.append(['OS=="%s"' % o] + d) | |
| 281 else: | |
| 282 c.append(['OS=="%s"' % o] + d[0:1]) | |
| 283 return out | |
| 284 | |
| 285 | |
| 286 def load_gyp(value): | |
| 287 """Parses one gyp skeleton and returns a Configs() instance. | |
| 105 | 288 |
| 106 |value| is the loaded dictionary that was defined in the gyp file. | 289 |value| is the loaded dictionary that was defined in the gyp file. |
| 107 | 290 |
| 108 Returns a 3-tuple, where the first two items are the same as the items | |
| 109 returned by process_variable() in the same order, and the last item is a set | |
| 110 of strings of all OSs seen in the input dict. | |
| 111 | |
| 112 The expected format is strict, anything diverting from the format below will | 291 The expected format is strict, anything diverting from the format below will |
| 113 fail: | 292 throw an assert: |
| 114 { | 293 { |
| 115 'variables': { | 294 'variables': { |
| 116 'isolate_files': [ | 295 'command': [ |
| 117 ... | 296 ... |
| 118 ], | 297 ], |
| 119 'isolate_dirs: [ | 298 'isolate_dependency_tracked': [ |
| 120 ... | 299 ... |
| 121 ], | 300 ], |
| 301 'isolate_dependency_untracked': [ | |
| 302 ... | |
| 303 ], | |
| 304 'read_only': False, | |
| 122 }, | 305 }, |
| 123 'conditions': [ | 306 'conditions': [ |
| 124 ['OS=="<os>"', { | 307 ['OS=="<os>"', { |
| 125 'variables': { | 308 'variables': { |
| 126 ... | 309 ... |
| 127 }, | 310 }, |
| 128 }, { # else | 311 }, { # else |
| 129 'variables': { | 312 'variables': { |
| 130 ... | 313 ... |
| 131 }, | 314 }, |
| 132 }], | 315 }], |
| 133 ... | 316 ... |
| 134 ], | 317 ], |
| 135 } | 318 } |
| 136 """ | 319 """ |
| 137 assert isinstance(value, dict), value | 320 verify_root(value) |
| 138 VALID_ROOTS = ['variables', 'conditions'] | 321 |
| 139 assert set(VALID_ROOTS).issuperset(set(value)), value.keys() | 322 # Scan to get the list of OSes. |
| 323 conditions = value.get('conditions', []) | |
| 324 oses = set(re.match(r'OS==\"([a-z]+)\"', c[0]).group(1) for c in conditions) | |
| 325 configs = Configs(oses) | |
| 140 | 326 |
| 141 # Global level variables. | 327 # Global level variables. |
| 142 oses = set() | 328 configs.add_globals(value.get('variables', {})) |
| 143 files, dirs = process_variables(None, value.get('variables', {})) | |
| 144 | 329 |
| 145 # OS specific variables. | 330 # OS specific variables. |
| 146 conditions = value.get('conditions', []) | |
| 147 assert isinstance(conditions, list), conditions | |
| 148 for condition in conditions: | 331 for condition in conditions: |
| 149 assert isinstance(condition, list), condition | 332 condition_os = re.match(r'OS==\"([a-z]+)\"', condition[0]).group(1) |
| 150 assert 2 <= len(condition) <= 3, condition | 333 configs.add_values(condition_os, condition[1].get('variables', {})) |
| 151 m = re.match(r'OS==\"([a-z]+)\"', condition[0]) | 334 if len(condition) > 2: |
| 152 assert m, condition[0] | 335 configs.add_negative_values( |
| 153 condition_os = m.group(1) | 336 condition_os, condition[2].get('variables', {})) |
| 154 | 337 return configs |
| 155 files, dirs, oses = _process_inner( | |
| 156 condition_os, condition[1], files, dirs, oses) | |
| 157 | |
| 158 if len(condition) == 3: | |
| 159 files, dirs, oses = _process_inner( | |
| 160 '!' + condition_os, condition[2], files, dirs, oses) | |
| 161 | |
| 162 # TODO(maruel): _expand_negative() should be called here, because otherwise | |
| 163 # the OSes the negative condition represents is lost once the gyps are merged. | |
| 164 # This cause an invalid expansion in reduce_inputs() call. | |
| 165 return files, dirs, oses | |
| 166 | 338 |
| 167 | 339 |
| 168 def parse_gyp_dicts(gyps): | 340 def load_gyps(items): |
| 169 """Parses each gyp file and returns the merged results. | 341 """Parses each gyp file and returns the merged results. |
| 170 | 342 |
| 171 It only loads what parse_gyp_dict() can process. | 343 It only loads what load_gyp() can process. |
| 172 | 344 |
| 173 Return values: | 345 Return values: |
| 174 files: dict(filename, set(OS where this filename is a dependency)) | 346 files: dict(filename, set(OS where this filename is a dependency)) |
| 175 dirs: dict(dirame, set(OS where this dirname is a dependency)) | 347 dirs: dict(dirame, set(OS where this dirname is a dependency)) |
| 176 oses: set(all the OSes referenced) | 348 oses: set(all the OSes referenced) |
| 177 """ | 349 """ |
| 178 files = {} | 350 configs = Configs([]) |
| 179 dirs = {} | 351 for item in items: |
| 180 oses = set() | 352 configs = configs.union(load_gyp(eval_content(open(item, 'rb').read()))) |
| 181 for gyp in gyps: | 353 return configs |
| 182 with open(gyp, 'rb') as gyp_file: | |
| 183 content = gyp_file.read() | |
| 184 gyp_files, gyp_dirs, gyp_oses = parse_gyp_dict(eval_content(content)) | |
| 185 files = union(gyp_files, files) | |
| 186 dirs = union(gyp_dirs, dirs) | |
| 187 oses |= gyp_oses | |
| 188 return files, dirs, oses | |
| 189 | 354 |
| 190 | 355 |
| 191 def _expand_negative(items, oses): | 356 def main(args=None): |
| 192 """Converts all '!foo' value in the set by oses.difference('foo').""" | |
| 193 assert None not in oses and len(oses) >= 2, oses | |
| 194 for name in items: | |
| 195 if None in items[name]: | |
| 196 # Shortcut any item having None in their set. An item listed in None means | |
| 197 # the item is a dependency on all OSes. As such, there is no need to list | |
| 198 # any OS. | |
| 199 items[name] = set([None]) | |
| 200 continue | |
| 201 for neg in [o for o in items[name] if o.startswith('!')]: | |
| 202 # Replace it with the inverse. | |
| 203 items[name] = items[name].union(oses.difference([neg[1:]])) | |
| 204 items[name].remove(neg) | |
| 205 if items[name] == oses: | |
| 206 items[name] = set([None]) | |
| 207 | |
| 208 | |
| 209 def _compact_negative(items, oses): | |
| 210 """Converts all oses.difference('foo') to '!foo'. | |
| 211 | |
| 212 It is doing the reverse of _expand_negative(). | |
| 213 """ | |
| 214 assert None not in oses and len(oses) >= 3, oses | |
| 215 for name in items: | |
| 216 missing = oses.difference(items[name]) | |
| 217 if len(missing) == 1: | |
| 218 # Replace it with a negative. | |
| 219 items[name] = set(['!' + tuple(missing)[0]]) | |
| 220 | |
| 221 | |
| 222 def reduce_inputs(files, dirs, oses): | |
| 223 """Reduces the variables to their strictest minimum.""" | |
| 224 # Construct the inverse map first. | |
| 225 # Look at each individual file and directory, map where they are used and | |
| 226 # reconstruct the inverse dictionary. | |
| 227 # First, expands all '!' builders into the reverse. | |
| 228 # TODO(maruel): This is too late to call _expand_negative(). The exact list | |
| 229 # negative OSes condition it represents is lost at that point. | |
| 230 _expand_negative(files, oses) | |
| 231 _expand_negative(dirs, oses) | |
| 232 | |
| 233 # Do not convert back to negative if only 2 OSes were merged. It is easier to | |
| 234 # read this way. | |
| 235 if len(oses) > 2: | |
| 236 _compact_negative(files, oses) | |
| 237 _compact_negative(dirs, oses) | |
| 238 | |
| 239 return files, dirs | |
| 240 | |
| 241 | |
| 242 def convert_to_gyp(files, dirs): | |
| 243 """Regenerates back a gyp-like configuration dict from files and dirs | |
| 244 mappings. | |
| 245 | |
| 246 Sort the lists. | |
| 247 """ | |
| 248 # First, inverse the mapping to make it dict first. | |
| 249 config = {} | |
| 250 def to_cond(items, name): | |
| 251 for item, oses in items.iteritems(): | |
| 252 for cond_os in oses: | |
| 253 condition_values = config.setdefault( | |
| 254 None if cond_os is None else cond_os.lstrip('!'), | |
| 255 [{}, {}]) | |
| 256 # If condition is negative, use index 1, else use index 0. | |
| 257 condition_value = condition_values[int((cond_os or '').startswith('!'))] | |
| 258 # The list of items (files or dirs). Append the new item and keep the | |
| 259 # list sorted. | |
| 260 l = condition_value.setdefault('variables', {}).setdefault(name, []) | |
| 261 l.append(item) | |
| 262 l.sort() | |
| 263 | |
| 264 to_cond(files, 'isolate_files') | |
| 265 to_cond(dirs, 'isolate_dirs') | |
| 266 | |
| 267 out = {} | |
| 268 for o in sorted(config): | |
| 269 d = config[o] | |
| 270 if o is None: | |
| 271 assert not d[1] | |
| 272 out = union(out, d[0]) | |
| 273 else: | |
| 274 c = out.setdefault('conditions', []) | |
| 275 if d[1]: | |
| 276 c.append(['OS=="%s"' % o] + d) | |
| 277 else: | |
| 278 c.append(['OS=="%s"' % o] + d[0:1]) | |
| 279 return out | |
| 280 | |
| 281 | |
| 282 def main(): | |
| 283 parser = optparse.OptionParser( | 357 parser = optparse.OptionParser( |
| 284 usage='%prog <options> [file1] [file2] ...') | 358 usage='%prog <options> [file1] [file2] ...') |
| 285 parser.add_option( | 359 parser.add_option( |
| 286 '-v', '--verbose', action='count', default=0, help='Use multiple times') | 360 '-v', '--verbose', action='count', default=0, help='Use multiple times') |
| 287 | 361 |
| 288 options, args = parser.parse_args() | 362 options, args = parser.parse_args(args) |
| 289 level = [logging.ERROR, logging.INFO, logging.DEBUG][min(2, options.verbose)] | 363 level = [logging.ERROR, logging.INFO, logging.DEBUG][min(2, options.verbose)] |
| 290 logging.basicConfig( | 364 logging.basicConfig( |
| 291 level=level, | 365 level=level, |
| 292 format='%(levelname)5s %(module)15s(%(lineno)3d):%(message)s') | 366 format='%(levelname)5s %(module)15s(%(lineno)3d):%(message)s') |
| 293 | 367 |
| 294 trace_inputs.pretty_print( | 368 trace_inputs.pretty_print( |
| 295 convert_to_gyp(*reduce_inputs(*parse_gyp_dicts(args))), | 369 convert_map_to_gyp(reduce_inputs(invert_map(load_gyps(args).flatten()))), |
| 296 sys.stdout) | 370 sys.stdout) |
| 297 return 0 | 371 return 0 |
| 298 | 372 |
| 299 | 373 |
| 300 if __name__ == '__main__': | 374 if __name__ == '__main__': |
| 301 sys.exit(main()) | 375 sys.exit(main()) |
| OLD | NEW |