| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 # Copyright (C) 2013 Google Inc. All rights reserved. |  | 
| 2 # |  | 
| 3 # Redistribution and use in source and binary forms, with or without |  | 
| 4 # modification, are permitted provided that the following conditions are |  | 
| 5 # met: |  | 
| 6 # |  | 
| 7 #     * Redistributions of source code must retain the above copyright |  | 
| 8 # notice, this list of conditions and the following disclaimer. |  | 
| 9 #     * Redistributions in binary form must reproduce the above |  | 
| 10 # copyright notice, this list of conditions and the following disclaimer |  | 
| 11 # in the documentation and/or other materials provided with the |  | 
| 12 # distribution. |  | 
| 13 #     * Neither the name of Google Inc. nor the names of its |  | 
| 14 # contributors may be used to endorse or promote products derived from |  | 
| 15 # this software without specific prior written permission. |  | 
| 16 # |  | 
| 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |  | 
| 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |  | 
| 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |  | 
| 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |  | 
| 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | 
| 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |  | 
| 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |  | 
| 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |  | 
| 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |  | 
| 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |  | 
| 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | 
| 28 |  | 
| 29 import copy |  | 
| 30 import os |  | 
| 31 |  | 
| 32 # NOTE: This has only been used to parse |  | 
| 33 # core/page/RuntimeEnabledFeatures.in and may not be capable |  | 
| 34 # of parsing other .in files correctly. |  | 
| 35 |  | 
| 36 # .in file format is: |  | 
| 37 # // comment |  | 
| 38 # name1 arg=value, arg2=value2, arg2=value3 |  | 
| 39 # |  | 
| 40 # InFile must be passed a dictionary of default values |  | 
| 41 # with which to validate arguments against known names. |  | 
| 42 # Sequence types as default values will produce sequences |  | 
| 43 # as parse results. |  | 
| 44 # Bare arguments (no '=') are treated as names with value True. |  | 
| 45 # The first field will always be labeled 'name'. |  | 
| 46 # |  | 
| 47 # InFile.load_from_files(['file.in'], {'arg': None, 'arg2': []}) |  | 
| 48 # |  | 
| 49 # Parsing produces an array of dictionaries: |  | 
| 50 # [ { 'name' : 'name1', 'arg' :' value', arg2=['value2', 'value3'] } |  | 
| 51 |  | 
| 52 def _is_comment(line): |  | 
| 53     return line.startswith("//") or line.startswith("#") |  | 
| 54 |  | 
| 55 class InFile(object): |  | 
| 56     def __init__(self, lines, defaults, valid_values=None, default_parameters=No
     ne): |  | 
| 57         self.name_dictionaries = [] |  | 
| 58         self.parameters = copy.deepcopy(default_parameters if default_parameters
      else {}) |  | 
| 59         self._defaults = defaults |  | 
| 60         self._valid_values = copy.deepcopy(valid_values if valid_values else {}) |  | 
| 61         self._parse(map(str.strip, lines)) |  | 
| 62 |  | 
| 63     @classmethod |  | 
| 64     def load_from_files(self, file_paths, defaults, valid_values, default_parame
     ters): |  | 
| 65         lines = [] |  | 
| 66         for path in file_paths: |  | 
| 67             with open(os.path.abspath(path)) as in_file: |  | 
| 68                 lines += in_file.readlines() |  | 
| 69         return InFile(lines, defaults, valid_values, default_parameters) |  | 
| 70 |  | 
| 71     def _is_sequence(self, arg): |  | 
| 72         return (not hasattr(arg, "strip") |  | 
| 73                 and hasattr(arg, "__getitem__") |  | 
| 74                 or hasattr(arg, "__iter__")) |  | 
| 75 |  | 
| 76     def _parse(self, lines): |  | 
| 77         parsing_parameters = True |  | 
| 78         indices = {} |  | 
| 79         for line in lines: |  | 
| 80             if _is_comment(line): |  | 
| 81                 continue |  | 
| 82             if not line: |  | 
| 83                 parsing_parameters = False |  | 
| 84                 continue |  | 
| 85             if parsing_parameters: |  | 
| 86                 self._parse_parameter(line) |  | 
| 87             else: |  | 
| 88                 entry = self._parse_line(line) |  | 
| 89                 name = entry['name'] |  | 
| 90                 if name in indices: |  | 
| 91                     entry = self._merge_entries(entry, self.name_dictionaries[in
     dices[name]]) |  | 
| 92                     entry['name'] = name |  | 
| 93                     self.name_dictionaries[indices[name]] = entry |  | 
| 94                 else: |  | 
| 95                     indices[name] = len(self.name_dictionaries) |  | 
| 96                     self.name_dictionaries.append(entry) |  | 
| 97 |  | 
| 98 |  | 
| 99     def _merge_entries(self, one, two): |  | 
| 100         merged = {} |  | 
| 101         for key in one: |  | 
| 102             if key not in two: |  | 
| 103                 self._fatal("Expected key '%s' not found in entry: %s" % (key, t
     wo)) |  | 
| 104             if one[key] and two[key]: |  | 
| 105                 val_one = one[key] |  | 
| 106                 val_two = two[key] |  | 
| 107                 if isinstance(val_one, list) and isinstance(val_two, list): |  | 
| 108                     val = val_one + val_two |  | 
| 109                 elif isinstance(val_one, list): |  | 
| 110                     val = val_one + [val_two] |  | 
| 111                 elif isinstance(val_two, list): |  | 
| 112                     val = [val_one] + val_two |  | 
| 113                 else: |  | 
| 114                     val = [val_one, val_two] |  | 
| 115                 merged[key] = val |  | 
| 116             elif one[key]: |  | 
| 117                 merged[key] = one[key] |  | 
| 118             else: |  | 
| 119                 merged[key] = two[key] |  | 
| 120         return merged |  | 
| 121 |  | 
| 122 |  | 
| 123     def _parse_parameter(self, line): |  | 
| 124         if '=' in line: |  | 
| 125             name, value = line.split('=') |  | 
| 126         else: |  | 
| 127             name, value = line, True |  | 
| 128         if not name in self.parameters: |  | 
| 129             self._fatal("Unknown parameter: '%s' in line:\n%s\nKnown parameters:
      %s" % (name, line, self.parameters.keys())) |  | 
| 130         self.parameters[name] = value |  | 
| 131 |  | 
| 132     def _parse_line(self, line): |  | 
| 133         args = copy.deepcopy(self._defaults) |  | 
| 134         parts = line.split(' ') |  | 
| 135         args['name'] = parts[0] |  | 
| 136         # re-join the rest of the line and split on ',' |  | 
| 137         args_list = ' '.join(parts[1:]).strip().split(',') |  | 
| 138         for arg_string in args_list: |  | 
| 139             arg_string = arg_string.strip() |  | 
| 140             if not arg_string: # Ignore empty args |  | 
| 141                 continue |  | 
| 142             if '=' in arg_string: |  | 
| 143                 arg_name, arg_value = arg_string.split('=') |  | 
| 144             else: |  | 
| 145                 arg_name, arg_value = arg_string, True |  | 
| 146             if arg_name not in self._defaults: |  | 
| 147                 self._fatal("Unknown argument: '%s' in line:\n%s\nKnown argument
     s: %s" % (arg_name, line, self._defaults.keys())) |  | 
| 148             valid_values = self._valid_values.get(arg_name) |  | 
| 149             if valid_values and arg_value not in valid_values: |  | 
| 150                 self._fatal("Unknown value: '%s' in line:\n%s\nKnown values: %s"
      % (arg_value, line, valid_values)) |  | 
| 151             if self._is_sequence(args[arg_name]): |  | 
| 152                 args[arg_name].append(arg_value) |  | 
| 153             else: |  | 
| 154                 args[arg_name] = arg_value |  | 
| 155         return args |  | 
| 156 |  | 
| 157     def _fatal(self, message): |  | 
| 158         # FIXME: This should probably raise instead of exit(1) |  | 
| 159         print message |  | 
| 160         exit(1) |  | 
| OLD | NEW | 
|---|