OLD | NEW |
1 # Copyright (c) 2012 Google Inc. All rights reserved. | 1 # Copyright (c) 2012 Google Inc. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Xcode project file generator. | 5 """Xcode project file generator. |
6 | 6 |
7 This module is both an Xcode project file generator and a documentation of the | 7 This module is both an Xcode project file generator and a documentation of the |
8 Xcode project file format. Knowledge of the project file format was gained | 8 Xcode project file format. Knowledge of the project file format was gained |
9 based on extensive experience with Xcode, and by making changes to projects in | 9 based on extensive experience with Xcode, and by making changes to projects in |
10 Xcode.app and observing the resultant changes in the associated project files. | 10 Xcode.app and observing the resultant changes in the associated project files. |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 # Strings that match this pattern are quoted regardless of what _unquoted says. | 166 # Strings that match this pattern are quoted regardless of what _unquoted says. |
167 # Oddly, Xcode will quote any string with a run of three or more underscores. | 167 # Oddly, Xcode will quote any string with a run of three or more underscores. |
168 _quoted = re.compile('___') | 168 _quoted = re.compile('___') |
169 | 169 |
170 # This pattern should match any character that needs to be escaped by | 170 # This pattern should match any character that needs to be escaped by |
171 # XCObject._EncodeString. See that function. | 171 # XCObject._EncodeString. See that function. |
172 _escaped = re.compile('[\\\\"]|[\x00-\x1f]') | 172 _escaped = re.compile('[\\\\"]|[\x00-\x1f]') |
173 | 173 |
174 | 174 |
175 # Used by SourceTreeAndPathFromPath | 175 # Used by SourceTreeAndPathFromPath |
176 _path_leading_variable = re.compile('^\$\((.*?)\)(/(.*))?$') | 176 _path_leading_variable = re.compile(r'^\$\((.*?)\)(/(.*))?$') |
177 | 177 |
178 def SourceTreeAndPathFromPath(input_path): | 178 def SourceTreeAndPathFromPath(input_path): |
179 """Given input_path, returns a tuple with sourceTree and path values. | 179 """Given input_path, returns a tuple with sourceTree and path values. |
180 | 180 |
181 Examples: | 181 Examples: |
182 input_path (source_tree, output_path) | 182 input_path (source_tree, output_path) |
183 '$(VAR)/path' ('VAR', 'path') | 183 '$(VAR)/path' ('VAR', 'path') |
184 '$(VAR)' ('VAR', None) | 184 '$(VAR)' ('VAR', None) |
185 'path' (None, 'path') | 185 'path' (None, 'path') |
186 """ | 186 """ |
187 | 187 |
188 source_group_match = _path_leading_variable.match(input_path) | 188 source_group_match = _path_leading_variable.match(input_path) |
189 if source_group_match: | 189 if source_group_match: |
190 source_tree = source_group_match.group(1) | 190 source_tree = source_group_match.group(1) |
191 output_path = source_group_match.group(3) # This may be None. | 191 output_path = source_group_match.group(3) # This may be None. |
192 else: | 192 else: |
193 source_tree = None | 193 source_tree = None |
194 output_path = input_path | 194 output_path = input_path |
195 | 195 |
196 return (source_tree, output_path) | 196 return (source_tree, output_path) |
197 | 197 |
198 def ConvertVariablesToShellSyntax(input_string): | 198 def ConvertVariablesToShellSyntax(input_string): |
199 return re.sub('\$\((.*?)\)', '${\\1}', input_string) | 199 return re.sub(r'\$\((.*?)\)', '${\\1}', input_string) |
200 | 200 |
201 class XCObject(object): | 201 class XCObject(object): |
202 """The abstract base of all class types used in Xcode project files. | 202 """The abstract base of all class types used in Xcode project files. |
203 | 203 |
204 Class variables: | 204 Class variables: |
205 _schema: A dictionary defining the properties of this class. The keys to | 205 _schema: A dictionary defining the properties of this class. The keys to |
206 _schema are string property keys as used in project files. Values | 206 _schema are string property keys as used in project files. Values |
207 are a list of four or five elements: | 207 are a list of four or five elements: |
208 [ is_list, property_type, is_strong, is_required, default ] | 208 [ is_list, property_type, is_strong, is_required, default ] |
209 is_list: True if the property described is a list, as opposed | 209 is_list: True if the property described is a list, as opposed |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
334 that._properties[key] = [] | 334 that._properties[key] = [] |
335 for item in value: | 335 for item in value: |
336 new_item = item.Copy() | 336 new_item = item.Copy() |
337 new_item.parent = that | 337 new_item.parent = that |
338 that._properties[key].append(new_item) | 338 that._properties[key].append(new_item) |
339 else: | 339 else: |
340 that._properties[key] = value[:] | 340 that._properties[key] = value[:] |
341 elif isinstance(value, dict): | 341 elif isinstance(value, dict): |
342 # dicts are never strong. | 342 # dicts are never strong. |
343 if is_strong: | 343 if is_strong: |
344 raise TypeError, 'Strong dict for key ' + key + ' in ' + \ | 344 raise TypeError('Strong dict for key ' + key + ' in ' + \ |
345 self.__class__.__name__ | 345 self.__class__.__name__) |
346 else: | 346 else: |
347 that._properties[key] = value.copy() | 347 that._properties[key] = value.copy() |
348 else: | 348 else: |
349 raise TypeError, 'Unexpected type ' + value.__class__.__name__ + \ | 349 raise TypeError('Unexpected type ' + value.__class__.__name__ + \ |
350 ' for key ' + key + ' in ' + self.__class__.__name__ | 350 ' for key ' + key + ' in ' + self.__class__.__name__) |
351 | 351 |
352 return that | 352 return that |
353 | 353 |
354 def Name(self): | 354 def Name(self): |
355 """Return the name corresponding to an object. | 355 """Return the name corresponding to an object. |
356 | 356 |
357 Not all objects necessarily need to be nameable, and not all that do have | 357 Not all objects necessarily need to be nameable, and not all that do have |
358 a "name" property. Override as needed. | 358 a "name" property. Override as needed. |
359 """ | 359 """ |
360 | 360 |
361 # If the schema indicates that "name" is required, try to access the | 361 # If the schema indicates that "name" is required, try to access the |
362 # property even if it doesn't exist. This will result in a KeyError | 362 # property even if it doesn't exist. This will result in a KeyError |
363 # being raised for the property that should be present, which seems more | 363 # being raised for the property that should be present, which seems more |
364 # appropriate than NotImplementedError in this case. | 364 # appropriate than NotImplementedError in this case. |
365 if 'name' in self._properties or \ | 365 if 'name' in self._properties or \ |
366 ('name' in self._schema and self._schema['name'][3]): | 366 ('name' in self._schema and self._schema['name'][3]): |
367 return self._properties['name'] | 367 return self._properties['name'] |
368 | 368 |
369 raise NotImplementedError, \ | 369 raise NotImplementedError(self.__class__.__name__ + ' must implement Name') |
370 self.__class__.__name__ + ' must implement Name' | |
371 | 370 |
372 def Comment(self): | 371 def Comment(self): |
373 """Return a comment string for the object. | 372 """Return a comment string for the object. |
374 | 373 |
375 Most objects just use their name as the comment, but PBXProject uses | 374 Most objects just use their name as the comment, but PBXProject uses |
376 different values. | 375 different values. |
377 | 376 |
378 The returned comment is not escaped and does not have any comment marker | 377 The returned comment is not escaped and does not have any comment marker |
379 strings applied to it. | 378 strings applied to it. |
380 """ | 379 """ |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 | 458 |
460 def EnsureNoIDCollisions(self): | 459 def EnsureNoIDCollisions(self): |
461 """Verifies that no two objects have the same ID. Checks all descendants. | 460 """Verifies that no two objects have the same ID. Checks all descendants. |
462 """ | 461 """ |
463 | 462 |
464 ids = {} | 463 ids = {} |
465 descendants = self.Descendants() | 464 descendants = self.Descendants() |
466 for descendant in descendants: | 465 for descendant in descendants: |
467 if descendant.id in ids: | 466 if descendant.id in ids: |
468 other = ids[descendant.id] | 467 other = ids[descendant.id] |
469 raise KeyError, \ | 468 raise KeyError( |
470 'Duplicate ID %s, objects "%s" and "%s" in "%s"' % \ | 469 'Duplicate ID %s, objects "%s" and "%s" in "%s"' % \ |
471 (descendant.id, str(descendant._properties), | 470 (descendant.id, str(descendant._properties), |
472 str(other._properties), self._properties['rootObject'].Name()) | 471 str(other._properties), self._properties['rootObject'].Name())) |
473 ids[descendant.id] = descendant | 472 ids[descendant.id] = descendant |
474 | 473 |
475 def Children(self): | 474 def Children(self): |
476 """Returns a list of all of this object's owned (strong) children.""" | 475 """Returns a list of all of this object's owned (strong) children.""" |
477 | 476 |
478 children = [] | 477 children = [] |
479 for property, attributes in self._schema.iteritems(): | 478 for property, attributes in self._schema.iteritems(): |
480 (is_list, property_type, is_strong) = attributes[0:3] | 479 (is_list, property_type, is_strong) = attributes[0:3] |
481 if is_strong and property in self._properties: | 480 if is_strong and property in self._properties: |
482 if not is_list: | 481 if not is_list: |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
623 printable += end_tabs + ')' | 622 printable += end_tabs + ')' |
624 elif isinstance(value, dict): | 623 elif isinstance(value, dict): |
625 printable = '{' + sep | 624 printable = '{' + sep |
626 for item_key, item_value in sorted(value.iteritems()): | 625 for item_key, item_value in sorted(value.iteritems()): |
627 printable += element_tabs + \ | 626 printable += element_tabs + \ |
628 self._XCPrintableValue(tabs + 1, item_key, flatten_list) + ' = ' + \ | 627 self._XCPrintableValue(tabs + 1, item_key, flatten_list) + ' = ' + \ |
629 self._XCPrintableValue(tabs + 1, item_value, flatten_list) + ';' + \ | 628 self._XCPrintableValue(tabs + 1, item_value, flatten_list) + ';' + \ |
630 sep | 629 sep |
631 printable += end_tabs + '}' | 630 printable += end_tabs + '}' |
632 else: | 631 else: |
633 raise TypeError, "Can't make " + value.__class__.__name__ + ' printable' | 632 raise TypeError("Can't make " + value.__class__.__name__ + ' printable') |
634 | 633 |
635 if comment != None: | 634 if comment != None: |
636 printable += ' ' + self._EncodeComment(comment) | 635 printable += ' ' + self._EncodeComment(comment) |
637 | 636 |
638 return printable | 637 return printable |
639 | 638 |
640 def _XCKVPrint(self, file, tabs, key, value): | 639 def _XCKVPrint(self, file, tabs, key, value): |
641 """Prints a key and value, members of an XCObject's _properties dictionary, | 640 """Prints a key and value, members of an XCObject's _properties dictionary, |
642 to file. | 641 to file. |
643 | 642 |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
749 strong-owned XCObjects in lists will be copied instead of having their | 748 strong-owned XCObjects in lists will be copied instead of having their |
750 references added. | 749 references added. |
751 """ | 750 """ |
752 | 751 |
753 if properties is None: | 752 if properties is None: |
754 return | 753 return |
755 | 754 |
756 for property, value in properties.iteritems(): | 755 for property, value in properties.iteritems(): |
757 # Make sure the property is in the schema. | 756 # Make sure the property is in the schema. |
758 if not property in self._schema: | 757 if not property in self._schema: |
759 raise KeyError, property + ' not in ' + self.__class__.__name__ | 758 raise KeyError(property + ' not in ' + self.__class__.__name__) |
760 | 759 |
761 # Make sure the property conforms to the schema. | 760 # Make sure the property conforms to the schema. |
762 (is_list, property_type, is_strong) = self._schema[property][0:3] | 761 (is_list, property_type, is_strong) = self._schema[property][0:3] |
763 if is_list: | 762 if is_list: |
764 if value.__class__ != list: | 763 if value.__class__ != list: |
765 raise TypeError, \ | 764 raise TypeError( |
766 property + ' of ' + self.__class__.__name__ + \ | 765 property + ' of ' + self.__class__.__name__ + \ |
767 ' must be list, not ' + value.__class__.__name__ | 766 ' must be list, not ' + value.__class__.__name__) |
768 for item in value: | 767 for item in value: |
769 if not isinstance(item, property_type) and \ | 768 if not isinstance(item, property_type) and \ |
770 not (item.__class__ == unicode and property_type == str): | 769 not (item.__class__ == unicode and property_type == str): |
771 # Accept unicode where str is specified. str is treated as | 770 # Accept unicode where str is specified. str is treated as |
772 # UTF-8-encoded. | 771 # UTF-8-encoded. |
773 raise TypeError, \ | 772 raise TypeError( |
774 'item of ' + property + ' of ' + self.__class__.__name__ + \ | 773 'item of ' + property + ' of ' + self.__class__.__name__ + \ |
775 ' must be ' + property_type.__name__ + ', not ' + \ | 774 ' must be ' + property_type.__name__ + ', not ' + \ |
776 item.__class__.__name__ | 775 item.__class__.__name__) |
777 elif not isinstance(value, property_type) and \ | 776 elif not isinstance(value, property_type) and \ |
778 not (value.__class__ == unicode and property_type == str): | 777 not (value.__class__ == unicode and property_type == str): |
779 # Accept unicode where str is specified. str is treated as | 778 # Accept unicode where str is specified. str is treated as |
780 # UTF-8-encoded. | 779 # UTF-8-encoded. |
781 raise TypeError, \ | 780 raise TypeError( |
782 property + ' of ' + self.__class__.__name__ + ' must be ' + \ | 781 property + ' of ' + self.__class__.__name__ + ' must be ' + \ |
783 property_type.__name__ + ', not ' + value.__class__.__name__ | 782 property_type.__name__ + ', not ' + value.__class__.__name__) |
784 | 783 |
785 # Checks passed, perform the assignment. | 784 # Checks passed, perform the assignment. |
786 if do_copy: | 785 if do_copy: |
787 if isinstance(value, XCObject): | 786 if isinstance(value, XCObject): |
788 if is_strong: | 787 if is_strong: |
789 self._properties[property] = value.Copy() | 788 self._properties[property] = value.Copy() |
790 else: | 789 else: |
791 self._properties[property] = value | 790 self._properties[property] = value |
792 elif isinstance(value, str) or isinstance(value, unicode) or \ | 791 elif isinstance(value, str) or isinstance(value, unicode) or \ |
793 isinstance(value, int): | 792 isinstance(value, int): |
794 self._properties[property] = value | 793 self._properties[property] = value |
795 elif isinstance(value, list): | 794 elif isinstance(value, list): |
796 if is_strong: | 795 if is_strong: |
797 # If is_strong is True, each element is an XCObject, so it's safe | 796 # If is_strong is True, each element is an XCObject, so it's safe |
798 # to call Copy. | 797 # to call Copy. |
799 self._properties[property] = [] | 798 self._properties[property] = [] |
800 for item in value: | 799 for item in value: |
801 self._properties[property].append(item.Copy()) | 800 self._properties[property].append(item.Copy()) |
802 else: | 801 else: |
803 self._properties[property] = value[:] | 802 self._properties[property] = value[:] |
804 elif isinstance(value, dict): | 803 elif isinstance(value, dict): |
805 self._properties[property] = value.copy() | 804 self._properties[property] = value.copy() |
806 else: | 805 else: |
807 raise TypeError, "Don't know how to copy a " + \ | 806 raise TypeError("Don't know how to copy a " + \ |
808 value.__class__.__name__ + ' object for ' + \ | 807 value.__class__.__name__ + ' object for ' + \ |
809 property + ' in ' + self.__class__.__name__ | 808 property + ' in ' + self.__class__.__name__) |
810 else: | 809 else: |
811 self._properties[property] = value | 810 self._properties[property] = value |
812 | 811 |
813 # Set up the child's back-reference to this object. Don't use |value| | 812 # Set up the child's back-reference to this object. Don't use |value| |
814 # any more because it may not be right if do_copy is true. | 813 # any more because it may not be right if do_copy is true. |
815 if is_strong: | 814 if is_strong: |
816 if not is_list: | 815 if not is_list: |
817 self._properties[property].parent = self | 816 self._properties[property].parent = self |
818 else: | 817 else: |
819 for item in self._properties[property]: | 818 for item in self._properties[property]: |
(...skipping 10 matching lines...) Expand all Loading... |
830 | 829 |
831 def DelProperty(self, key): | 830 def DelProperty(self, key): |
832 if key in self._properties: | 831 if key in self._properties: |
833 del self._properties[key] | 832 del self._properties[key] |
834 | 833 |
835 def AppendProperty(self, key, value): | 834 def AppendProperty(self, key, value): |
836 # TODO(mark): Support ExtendProperty too (and make this call that)? | 835 # TODO(mark): Support ExtendProperty too (and make this call that)? |
837 | 836 |
838 # Schema validation. | 837 # Schema validation. |
839 if not key in self._schema: | 838 if not key in self._schema: |
840 raise KeyError, key + ' not in ' + self.__class__.__name__ | 839 raise KeyError(key + ' not in ' + self.__class__.__name__) |
841 | 840 |
842 (is_list, property_type, is_strong) = self._schema[key][0:3] | 841 (is_list, property_type, is_strong) = self._schema[key][0:3] |
843 if not is_list: | 842 if not is_list: |
844 raise TypeError, key + ' of ' + self.__class__.__name__ + ' must be list' | 843 raise TypeError(key + ' of ' + self.__class__.__name__ + ' must be list') |
845 if not isinstance(value, property_type): | 844 if not isinstance(value, property_type): |
846 raise TypeError, 'item of ' + key + ' of ' + self.__class__.__name__ + \ | 845 raise TypeError('item of ' + key + ' of ' + self.__class__.__name__ + \ |
847 ' must be ' + property_type.__name__ + ', not ' + \ | 846 ' must be ' + property_type.__name__ + ', not ' + \ |
848 value.__class__.__name__ | 847 value.__class__.__name__) |
849 | 848 |
850 # If the property doesn't exist yet, create a new empty list to receive the | 849 # If the property doesn't exist yet, create a new empty list to receive the |
851 # item. | 850 # item. |
852 if not key in self._properties: | 851 if not key in self._properties: |
853 self._properties[key] = [] | 852 self._properties[key] = [] |
854 | 853 |
855 # Set up the ownership link. | 854 # Set up the ownership link. |
856 if is_strong: | 855 if is_strong: |
857 value.parent = self | 856 value.parent = self |
858 | 857 |
859 # Store the item. | 858 # Store the item. |
860 self._properties[key].append(value) | 859 self._properties[key].append(value) |
861 | 860 |
862 def VerifyHasRequiredProperties(self): | 861 def VerifyHasRequiredProperties(self): |
863 """Ensure that all properties identified as required by the schema are | 862 """Ensure that all properties identified as required by the schema are |
864 set. | 863 set. |
865 """ | 864 """ |
866 | 865 |
867 # TODO(mark): A stronger verification mechanism is needed. Some | 866 # TODO(mark): A stronger verification mechanism is needed. Some |
868 # subclasses need to perform validation beyond what the schema can enforce. | 867 # subclasses need to perform validation beyond what the schema can enforce. |
869 for property, attributes in self._schema.iteritems(): | 868 for property, attributes in self._schema.iteritems(): |
870 (is_list, property_type, is_strong, is_required) = attributes[0:4] | 869 (is_list, property_type, is_strong, is_required) = attributes[0:4] |
871 if is_required and not property in self._properties: | 870 if is_required and not property in self._properties: |
872 raise KeyError, self.__class__.__name__ + ' requires ' + property | 871 raise KeyError(self.__class__.__name__ + ' requires ' + property) |
873 | 872 |
874 def _SetDefaultsFromSchema(self): | 873 def _SetDefaultsFromSchema(self): |
875 """Assign object default values according to the schema. This will not | 874 """Assign object default values according to the schema. This will not |
876 overwrite properties that have already been set.""" | 875 overwrite properties that have already been set.""" |
877 | 876 |
878 defaults = {} | 877 defaults = {} |
879 for property, attributes in self._schema.iteritems(): | 878 for property, attributes in self._schema.iteritems(): |
880 (is_list, property_type, is_strong, is_required) = attributes[0:4] | 879 (is_list, property_type, is_strong, is_required) = attributes[0:4] |
881 if is_required and len(attributes) >= 5 and \ | 880 if is_required and len(attributes) >= 5 and \ |
882 not property in self._properties: | 881 not property in self._properties: |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1136 def HashablesForChild(self): | 1135 def HashablesForChild(self): |
1137 # To avoid a circular reference the hashables used to compute a child id do | 1136 # To avoid a circular reference the hashables used to compute a child id do |
1138 # not include the child names. | 1137 # not include the child names. |
1139 return XCHierarchicalElement.Hashables(self) | 1138 return XCHierarchicalElement.Hashables(self) |
1140 | 1139 |
1141 def _AddChildToDicts(self, child): | 1140 def _AddChildToDicts(self, child): |
1142 # Sets up this PBXGroup object's dicts to reference the child properly. | 1141 # Sets up this PBXGroup object's dicts to reference the child properly. |
1143 child_path = child.PathFromSourceTreeAndPath() | 1142 child_path = child.PathFromSourceTreeAndPath() |
1144 if child_path: | 1143 if child_path: |
1145 if child_path in self._children_by_path: | 1144 if child_path in self._children_by_path: |
1146 raise ValueError, 'Found multiple children with path ' + child_path | 1145 raise ValueError('Found multiple children with path ' + child_path) |
1147 self._children_by_path[child_path] = child | 1146 self._children_by_path[child_path] = child |
1148 | 1147 |
1149 if isinstance(child, PBXVariantGroup): | 1148 if isinstance(child, PBXVariantGroup): |
1150 child_name = child._properties.get('name', None) | 1149 child_name = child._properties.get('name', None) |
1151 key = (child_name, child_path) | 1150 key = (child_name, child_path) |
1152 if key in self._variant_children_by_name_and_path: | 1151 if key in self._variant_children_by_name_and_path: |
1153 raise ValueError, 'Found multiple PBXVariantGroup children with ' + \ | 1152 raise ValueError('Found multiple PBXVariantGroup children with ' + \ |
1154 'name ' + str(child_name) + ' and path ' + \ | 1153 'name ' + str(child_name) + ' and path ' + \ |
1155 str(child_path) | 1154 str(child_path)) |
1156 self._variant_children_by_name_and_path[key] = child | 1155 self._variant_children_by_name_and_path[key] = child |
1157 | 1156 |
1158 def AppendChild(self, child): | 1157 def AppendChild(self, child): |
1159 # Callers should use this instead of calling | 1158 # Callers should use this instead of calling |
1160 # AppendProperty('children', child) directly because this function | 1159 # AppendProperty('children', child) directly because this function |
1161 # maintains the group's dicts. | 1160 # maintains the group's dicts. |
1162 self.AppendProperty('children', child) | 1161 self.AppendProperty('children', child) |
1163 self._AddChildToDicts(child) | 1162 self._AddChildToDicts(child) |
1164 | 1163 |
1165 def GetChildByName(self, name): | 1164 def GetChildByName(self, name): |
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1601 def Name(self): | 1600 def Name(self): |
1602 return 'Build configuration list for ' + \ | 1601 return 'Build configuration list for ' + \ |
1603 self.parent.__class__.__name__ + ' "' + self.parent.Name() + '"' | 1602 self.parent.__class__.__name__ + ' "' + self.parent.Name() + '"' |
1604 | 1603 |
1605 def ConfigurationNamed(self, name): | 1604 def ConfigurationNamed(self, name): |
1606 """Convenience accessor to obtain an XCBuildConfiguration by name.""" | 1605 """Convenience accessor to obtain an XCBuildConfiguration by name.""" |
1607 for configuration in self._properties['buildConfigurations']: | 1606 for configuration in self._properties['buildConfigurations']: |
1608 if configuration._properties['name'] == name: | 1607 if configuration._properties['name'] == name: |
1609 return configuration | 1608 return configuration |
1610 | 1609 |
1611 raise KeyError, name | 1610 raise KeyError(name) |
1612 | 1611 |
1613 def DefaultConfiguration(self): | 1612 def DefaultConfiguration(self): |
1614 """Convenience accessor to obtain the default XCBuildConfiguration.""" | 1613 """Convenience accessor to obtain the default XCBuildConfiguration.""" |
1615 return self.ConfigurationNamed(self._properties['defaultConfigurationName']) | 1614 return self.ConfigurationNamed(self._properties['defaultConfigurationName']) |
1616 | 1615 |
1617 def HasBuildSetting(self, key): | 1616 def HasBuildSetting(self, key): |
1618 """Determines the state of a build setting in all XCBuildConfiguration | 1617 """Determines the state of a build setting in all XCBuildConfiguration |
1619 child objects. | 1618 child objects. |
1620 | 1619 |
1621 If all child objects have key in their build settings, and the value is the | 1620 If all child objects have key in their build settings, and the value is the |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1658 # TODO(mark): This is wrong for build settings that are lists. The list | 1657 # TODO(mark): This is wrong for build settings that are lists. The list |
1659 # contents should be compared (and a list copy returned?) | 1658 # contents should be compared (and a list copy returned?) |
1660 | 1659 |
1661 value = None | 1660 value = None |
1662 for configuration in self._properties['buildConfigurations']: | 1661 for configuration in self._properties['buildConfigurations']: |
1663 configuration_value = configuration.GetBuildSetting(key) | 1662 configuration_value = configuration.GetBuildSetting(key) |
1664 if value is None: | 1663 if value is None: |
1665 value = configuration_value | 1664 value = configuration_value |
1666 else: | 1665 else: |
1667 if value != configuration_value: | 1666 if value != configuration_value: |
1668 raise ValueError, 'Variant values for ' + key | 1667 raise ValueError('Variant values for ' + key) |
1669 | 1668 |
1670 return value | 1669 return value |
1671 | 1670 |
1672 def SetBuildSetting(self, key, value): | 1671 def SetBuildSetting(self, key, value): |
1673 """Sets the build setting for key to value in all child | 1672 """Sets the build setting for key to value in all child |
1674 XCBuildConfiguration objects. | 1673 XCBuildConfiguration objects. |
1675 """ | 1674 """ |
1676 | 1675 |
1677 for configuration in self._properties['buildConfigurations']: | 1676 for configuration in self._properties['buildConfigurations']: |
1678 configuration.SetBuildSetting(key, value) | 1677 configuration.SetBuildSetting(key, value) |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1765 self._files_by_xcfilelikeelement = {} | 1764 self._files_by_xcfilelikeelement = {} |
1766 for pbxbuildfile in self._properties.get('files', []): | 1765 for pbxbuildfile in self._properties.get('files', []): |
1767 self._AddBuildFileToDicts(pbxbuildfile) | 1766 self._AddBuildFileToDicts(pbxbuildfile) |
1768 | 1767 |
1769 def FileGroup(self, path): | 1768 def FileGroup(self, path): |
1770 # Subclasses must override this by returning a two-element tuple. The | 1769 # Subclasses must override this by returning a two-element tuple. The |
1771 # first item in the tuple should be the PBXGroup to which "path" should be | 1770 # first item in the tuple should be the PBXGroup to which "path" should be |
1772 # added, either as a child or deeper descendant. The second item should | 1771 # added, either as a child or deeper descendant. The second item should |
1773 # be a boolean indicating whether files should be added into hierarchical | 1772 # be a boolean indicating whether files should be added into hierarchical |
1774 # groups or one single flat group. | 1773 # groups or one single flat group. |
1775 raise NotImplementedError, \ | 1774 raise NotImplementedError( |
1776 self.__class__.__name__ + ' must implement FileGroup' | 1775 self.__class__.__name__ + ' must implement FileGroup') |
1777 | 1776 |
1778 def _AddPathToDict(self, pbxbuildfile, path): | 1777 def _AddPathToDict(self, pbxbuildfile, path): |
1779 """Adds path to the dict tracking paths belonging to this build phase. | 1778 """Adds path to the dict tracking paths belonging to this build phase. |
1780 | 1779 |
1781 If the path is already a member of this build phase, raises an exception. | 1780 If the path is already a member of this build phase, raises an exception. |
1782 """ | 1781 """ |
1783 | 1782 |
1784 if path in self._files_by_path: | 1783 if path in self._files_by_path: |
1785 raise ValueError, 'Found multiple build files with path ' + path | 1784 raise ValueError('Found multiple build files with path ' + path) |
1786 self._files_by_path[path] = pbxbuildfile | 1785 self._files_by_path[path] = pbxbuildfile |
1787 | 1786 |
1788 def _AddBuildFileToDicts(self, pbxbuildfile, path=None): | 1787 def _AddBuildFileToDicts(self, pbxbuildfile, path=None): |
1789 """Maintains the _files_by_path and _files_by_xcfilelikeelement dicts. | 1788 """Maintains the _files_by_path and _files_by_xcfilelikeelement dicts. |
1790 | 1789 |
1791 If path is specified, then it is the path that is being added to the | 1790 If path is specified, then it is the path that is being added to the |
1792 phase, and pbxbuildfile must contain either a PBXFileReference directly | 1791 phase, and pbxbuildfile must contain either a PBXFileReference directly |
1793 referencing that path, or it must contain a PBXVariantGroup that itself | 1792 referencing that path, or it must contain a PBXVariantGroup that itself |
1794 contains a PBXFileReference referencing the path. | 1793 contains a PBXFileReference referencing the path. |
1795 | 1794 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1830 # Add the paths first, because if something's going to raise, the | 1829 # Add the paths first, because if something's going to raise, the |
1831 # messages provided by _AddPathToDict are more useful owing to its | 1830 # messages provided by _AddPathToDict are more useful owing to its |
1832 # having access to a real pathname and not just an object's Name(). | 1831 # having access to a real pathname and not just an object's Name(). |
1833 for a_path in paths: | 1832 for a_path in paths: |
1834 self._AddPathToDict(pbxbuildfile, a_path) | 1833 self._AddPathToDict(pbxbuildfile, a_path) |
1835 | 1834 |
1836 # If another PBXBuildFile references this XCFileLikeElement, there's a | 1835 # If another PBXBuildFile references this XCFileLikeElement, there's a |
1837 # problem. | 1836 # problem. |
1838 if xcfilelikeelement in self._files_by_xcfilelikeelement and \ | 1837 if xcfilelikeelement in self._files_by_xcfilelikeelement and \ |
1839 self._files_by_xcfilelikeelement[xcfilelikeelement] != pbxbuildfile: | 1838 self._files_by_xcfilelikeelement[xcfilelikeelement] != pbxbuildfile: |
1840 raise ValueError, 'Found multiple build files for ' + \ | 1839 raise ValueError('Found multiple build files for ' + \ |
1841 xcfilelikeelement.Name() | 1840 xcfilelikeelement.Name()) |
1842 self._files_by_xcfilelikeelement[xcfilelikeelement] = pbxbuildfile | 1841 self._files_by_xcfilelikeelement[xcfilelikeelement] = pbxbuildfile |
1843 | 1842 |
1844 def AppendBuildFile(self, pbxbuildfile, path=None): | 1843 def AppendBuildFile(self, pbxbuildfile, path=None): |
1845 # Callers should use this instead of calling | 1844 # Callers should use this instead of calling |
1846 # AppendProperty('files', pbxbuildfile) directly because this function | 1845 # AppendProperty('files', pbxbuildfile) directly because this function |
1847 # maintains the object's dicts. Better yet, callers can just call AddFile | 1846 # maintains the object's dicts. Better yet, callers can just call AddFile |
1848 # with a pathname and not worry about building their own PBXBuildFile | 1847 # with a pathname and not worry about building their own PBXBuildFile |
1849 # objects. | 1848 # objects. |
1850 self.AppendProperty('files', pbxbuildfile) | 1849 self.AppendProperty('files', pbxbuildfile) |
1851 self._AddBuildFileToDicts(pbxbuildfile, path) | 1850 self._AddBuildFileToDicts(pbxbuildfile, path) |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1995 # The path starts with an unrecognized Xcode variable | 1994 # The path starts with an unrecognized Xcode variable |
1996 # name like $(SRCROOT). Xcode will still handle this | 1995 # name like $(SRCROOT). Xcode will still handle this |
1997 # as an "absolute path" that starts with the variable. | 1996 # as an "absolute path" that starts with the variable. |
1998 subfolder = 0 | 1997 subfolder = 0 |
1999 relative_path = path | 1998 relative_path = path |
2000 elif path.startswith('/'): | 1999 elif path.startswith('/'): |
2001 # Special case. Absolute paths are in dstSubfolderSpec 0. | 2000 # Special case. Absolute paths are in dstSubfolderSpec 0. |
2002 subfolder = 0 | 2001 subfolder = 0 |
2003 relative_path = path[1:] | 2002 relative_path = path[1:] |
2004 else: | 2003 else: |
2005 raise ValueError, 'Can\'t use path %s in a %s' % \ | 2004 raise ValueError('Can\'t use path %s in a %s' % \ |
2006 (path, self.__class__.__name__) | 2005 (path, self.__class__.__name__)) |
2007 | 2006 |
2008 self._properties['dstPath'] = relative_path | 2007 self._properties['dstPath'] = relative_path |
2009 self._properties['dstSubfolderSpec'] = subfolder | 2008 self._properties['dstSubfolderSpec'] = subfolder |
2010 | 2009 |
2011 | 2010 |
2012 class PBXBuildRule(XCObject): | 2011 class PBXBuildRule(XCObject): |
2013 _schema = XCObject._schema.copy() | 2012 _schema = XCObject._schema.copy() |
2014 _schema.update({ | 2013 _schema.update({ |
2015 'compilerSpec': [0, str, 0, 1], | 2014 'compilerSpec': [0, str, 0, 1], |
2016 'filePatterns': [0, str, 0, 0], | 2015 'filePatterns': [0, str, 0, 0], |
(...skipping 783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2800 for target in other_pbxproject._properties['targets']: | 2799 for target in other_pbxproject._properties['targets']: |
2801 if not isinstance(target, PBXNativeTarget): | 2800 if not isinstance(target, PBXNativeTarget): |
2802 continue | 2801 continue |
2803 remote_products.append(target._properties['productReference']) | 2802 remote_products.append(target._properties['productReference']) |
2804 | 2803 |
2805 # Sort the PBXReferenceProxy children according to the list of remote | 2804 # Sort the PBXReferenceProxy children according to the list of remote |
2806 # products. | 2805 # products. |
2807 product_group = ref_dict['ProductGroup'] | 2806 product_group = ref_dict['ProductGroup'] |
2808 product_group._properties['children'] = sorted( | 2807 product_group._properties['children'] = sorted( |
2809 product_group._properties['children'], | 2808 product_group._properties['children'], |
2810 cmp=lambda x, y: CompareProducts(x, y, remote_products)) | 2809 cmp=lambda x, y, rp=remote_products: CompareProducts(x, y, rp)) |
2811 | 2810 |
2812 | 2811 |
2813 class XCProjectFile(XCObject): | 2812 class XCProjectFile(XCObject): |
2814 _schema = XCObject._schema.copy() | 2813 _schema = XCObject._schema.copy() |
2815 _schema.update({ | 2814 _schema.update({ |
2816 'archiveVersion': [0, int, 0, 1, 1], | 2815 'archiveVersion': [0, int, 0, 1, 1], |
2817 'classes': [0, dict, 0, 1, {}], | 2816 'classes': [0, dict, 0, 1, {}], |
2818 'objectVersion': [0, int, 0, 1, 45], | 2817 'objectVersion': [0, int, 0, 1, 45], |
2819 'rootObject': [0, PBXProject, 1, 1], | 2818 'rootObject': [0, PBXProject, 1, 1], |
2820 }) | 2819 }) |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2884 self._XCPrint(file, 0, '/* Begin ' + class_name + ' section */\n') | 2883 self._XCPrint(file, 0, '/* Begin ' + class_name + ' section */\n') |
2885 for object in sorted(objects_by_class[class_name], | 2884 for object in sorted(objects_by_class[class_name], |
2886 cmp=lambda x, y: cmp(x.id, y.id)): | 2885 cmp=lambda x, y: cmp(x.id, y.id)): |
2887 object.Print(file) | 2886 object.Print(file) |
2888 self._XCPrint(file, 0, '/* End ' + class_name + ' section */\n') | 2887 self._XCPrint(file, 0, '/* End ' + class_name + ' section */\n') |
2889 | 2888 |
2890 if self._should_print_single_line: | 2889 if self._should_print_single_line: |
2891 self._XCPrint(file, 0, '}; ') | 2890 self._XCPrint(file, 0, '}; ') |
2892 else: | 2891 else: |
2893 self._XCPrint(file, 1, '};\n') | 2892 self._XCPrint(file, 1, '};\n') |
OLD | NEW |