~hjd/ubuntu/wily/gyp/debian-merged

« back to all changes in this revision

Viewing changes to pylib/gyp/xcodeproj_file.py

  • Committer: Hans Joachim Desserud
  • Date: 2015-10-31 12:46:59 UTC
  • mfrom: (6.2.6 sid)
  • Revision ID: hans_joachim_desserud-20151031124659-lzxekr6woskh4k0b
Merge latest Debian version

Show diffs side-by-side

added added

removed removed

Lines of Context:
173
173
 
174
174
 
175
175
# Used by SourceTreeAndPathFromPath
176
 
_path_leading_variable = re.compile('^\$\((.*?)\)(/(.*))?$')
 
176
_path_leading_variable = re.compile(r'^\$\((.*?)\)(/(.*))?$')
177
177
 
178
178
def SourceTreeAndPathFromPath(input_path):
179
179
  """Given input_path, returns a tuple with sourceTree and path values.
196
196
  return (source_tree, output_path)
197
197
 
198
198
def ConvertVariablesToShellSyntax(input_string):
199
 
  return re.sub('\$\((.*?)\)', '${\\1}', input_string)
 
199
  return re.sub(r'\$\((.*?)\)', '${\\1}', input_string)
200
200
 
201
201
class XCObject(object):
202
202
  """The abstract base of all class types used in Xcode project files.
341
341
      elif isinstance(value, dict):
342
342
        # dicts are never strong.
343
343
        if is_strong:
344
 
          raise TypeError, 'Strong dict for key ' + key + ' in ' + \
345
 
                           self.__class__.__name__
 
344
          raise TypeError('Strong dict for key ' + key + ' in ' + \
 
345
                          self.__class__.__name__)
346
346
        else:
347
347
          that._properties[key] = value.copy()
348
348
      else:
349
 
        raise TypeError, 'Unexpected type ' + value.__class__.__name__ + \
350
 
                         ' for key ' + key + ' in ' + self.__class__.__name__
 
349
        raise TypeError('Unexpected type ' + value.__class__.__name__ + \
 
350
                        ' for key ' + key + ' in ' + self.__class__.__name__)
351
351
 
352
352
    return that
353
353
 
366
366
        ('name' in self._schema and self._schema['name'][3]):
367
367
      return self._properties['name']
368
368
 
369
 
    raise NotImplementedError, \
370
 
          self.__class__.__name__ + ' must implement Name'
 
369
    raise NotImplementedError(self.__class__.__name__ + ' must implement Name')
371
370
 
372
371
  def Comment(self):
373
372
    """Return a comment string for the object.
466
465
    for descendant in descendants:
467
466
      if descendant.id in ids:
468
467
        other = ids[descendant.id]
469
 
        raise KeyError, \
 
468
        raise KeyError(
470
469
              'Duplicate ID %s, objects "%s" and "%s" in "%s"' % \
471
470
              (descendant.id, str(descendant._properties),
472
 
               str(other._properties), self._properties['rootObject'].Name())
 
471
               str(other._properties), self._properties['rootObject'].Name()))
473
472
      ids[descendant.id] = descendant
474
473
 
475
474
  def Children(self):
630
629
            sep
631
630
      printable += end_tabs + '}'
632
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
634
    if comment != None:
636
635
      printable += ' ' + self._EncodeComment(comment)
756
755
    for property, value in properties.iteritems():
757
756
      # Make sure the property is in the schema.
758
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
760
      # Make sure the property conforms to the schema.
762
761
      (is_list, property_type, is_strong) = self._schema[property][0:3]
763
762
      if is_list:
764
763
        if value.__class__ != list:
765
 
          raise TypeError, \
 
764
          raise TypeError(
766
765
                property + ' of ' + self.__class__.__name__ + \
767
 
                ' must be list, not ' + value.__class__.__name__
 
766
                ' must be list, not ' + value.__class__.__name__)
768
767
        for item in value:
769
768
          if not isinstance(item, property_type) and \
770
769
             not (item.__class__ == unicode and property_type == str):
771
770
            # Accept unicode where str is specified.  str is treated as
772
771
            # UTF-8-encoded.
773
 
            raise TypeError, \
 
772
            raise TypeError(
774
773
                  'item of ' + property + ' of ' + self.__class__.__name__ + \
775
774
                  ' must be ' + property_type.__name__ + ', not ' + \
776
 
                  item.__class__.__name__
 
775
                  item.__class__.__name__)
777
776
      elif not isinstance(value, property_type) and \
778
777
           not (value.__class__ == unicode and property_type == str):
779
778
        # Accept unicode where str is specified.  str is treated as
780
779
        # UTF-8-encoded.
781
 
        raise TypeError, \
 
780
        raise TypeError(
782
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
784
      # Checks passed, perform the assignment.
786
785
      if do_copy:
804
803
        elif isinstance(value, dict):
805
804
          self._properties[property] = value.copy()
806
805
        else:
807
 
          raise TypeError, "Don't know how to copy a " + \
808
 
                           value.__class__.__name__ + ' object for ' + \
809
 
                           property + ' in ' + self.__class__.__name__
 
806
          raise TypeError("Don't know how to copy a " + \
 
807
                          value.__class__.__name__ + ' object for ' + \
 
808
                          property + ' in ' + self.__class__.__name__)
810
809
      else:
811
810
        self._properties[property] = value
812
811
 
837
836
 
838
837
    # Schema validation.
839
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
841
    (is_list, property_type, is_strong) = self._schema[key][0:3]
843
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
844
    if not isinstance(value, property_type):
846
 
      raise TypeError, 'item of ' + key + ' of ' + self.__class__.__name__ + \
847
 
                       ' must be ' + property_type.__name__ + ', not ' + \
848
 
                       value.__class__.__name__
 
845
      raise TypeError('item of ' + key + ' of ' + self.__class__.__name__ + \
 
846
                      ' must be ' + property_type.__name__ + ', not ' + \
 
847
                      value.__class__.__name__)
849
848
 
850
849
    # If the property doesn't exist yet, create a new empty list to receive the
851
850
    # item.
869
868
    for property, attributes in self._schema.iteritems():
870
869
      (is_list, property_type, is_strong, is_required) = attributes[0:4]
871
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
873
  def _SetDefaultsFromSchema(self):
875
874
    """Assign object default values according to the schema.  This will not
1143
1142
    child_path = child.PathFromSourceTreeAndPath()
1144
1143
    if child_path:
1145
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
1146
      self._children_by_path[child_path] = child
1148
1147
 
1149
1148
    if isinstance(child, PBXVariantGroup):
1150
1149
      child_name = child._properties.get('name', None)
1151
1150
      key = (child_name, child_path)
1152
1151
      if key in self._variant_children_by_name_and_path:
1153
 
        raise ValueError, 'Found multiple PBXVariantGroup children with ' + \
1154
 
                          'name ' + str(child_name) + ' and path ' + \
1155
 
                          str(child_path)
 
1152
        raise ValueError('Found multiple PBXVariantGroup children with ' + \
 
1153
                         'name ' + str(child_name) + ' and path ' + \
 
1154
                         str(child_path))
1156
1155
      self._variant_children_by_name_and_path[key] = child
1157
1156
 
1158
1157
  def AppendChild(self, child):
1483
1482
        'cpp':         'sourcecode.cpp.cpp',
1484
1483
        'css':         'text.css',
1485
1484
        'cxx':         'sourcecode.cpp.cpp',
 
1485
        'dart':        'sourcecode',
1486
1486
        'dylib':       'compiled.mach-o.dylib',
1487
1487
        'framework':   'wrapper.framework',
 
1488
        'gyp':         'sourcecode',
 
1489
        'gypi':        'sourcecode',
1488
1490
        'h':           'sourcecode.c.h',
1489
1491
        'hxx':         'sourcecode.cpp.h',
1490
1492
        'icns':        'image.icns',
1505
1507
        's':           'sourcecode.asm',
1506
1508
        'storyboard':  'file.storyboard',
1507
1509
        'strings':     'text.plist.strings',
 
1510
        'swift':       'sourcecode.swift',
1508
1511
        'ttf':         'file',
 
1512
        'xcassets':    'folder.assetcatalog',
1509
1513
        'xcconfig':    'text.xcconfig',
1510
1514
        'xcdatamodel': 'wrapper.xcdatamodel',
 
1515
        'xcdatamodeld':'wrapper.xcdatamodeld',
1511
1516
        'xib':         'file.xib',
1512
1517
        'y':           'sourcecode.yacc',
1513
1518
      }
1514
1519
 
 
1520
      prop_map = {
 
1521
        'dart':        'explicitFileType',
 
1522
        'gyp':         'explicitFileType',
 
1523
        'gypi':        'explicitFileType',
 
1524
      }
 
1525
 
1515
1526
      if is_dir:
1516
1527
        file_type = 'folder'
 
1528
        prop_name = 'lastKnownFileType'
1517
1529
      else:
1518
1530
        basename = posixpath.basename(self._properties['path'])
1519
1531
        (root, ext) = posixpath.splitext(basename)
1528
1540
        # for unrecognized files not containing text.  Xcode seems to choose
1529
1541
        # based on content.
1530
1542
        file_type = extension_map.get(ext, 'text')
 
1543
        prop_name = prop_map.get(ext, 'lastKnownFileType')
1531
1544
 
1532
 
      self._properties['lastKnownFileType'] = file_type
 
1545
      self._properties[prop_name] = file_type
1533
1546
 
1534
1547
 
1535
1548
class PBXVariantGroup(PBXGroup, XCFileLikeElement):
1594
1607
      if configuration._properties['name'] == name:
1595
1608
        return configuration
1596
1609
 
1597
 
    raise KeyError, name
 
1610
    raise KeyError(name)
1598
1611
 
1599
1612
  def DefaultConfiguration(self):
1600
1613
    """Convenience accessor to obtain the default XCBuildConfiguration."""
1651
1664
        value = configuration_value
1652
1665
      else:
1653
1666
        if value != configuration_value:
1654
 
          raise ValueError, 'Variant values for ' + key
 
1667
          raise ValueError('Variant values for ' + key)
1655
1668
 
1656
1669
    return value
1657
1670
 
1758
1771
    # added, either as a child or deeper descendant.  The second item should
1759
1772
    # be a boolean indicating whether files should be added into hierarchical
1760
1773
    # groups or one single flat group.
1761
 
    raise NotImplementedError, \
1762
 
          self.__class__.__name__ + ' must implement FileGroup'
 
1774
    raise NotImplementedError(
 
1775
          self.__class__.__name__ + ' must implement FileGroup')
1763
1776
 
1764
1777
  def _AddPathToDict(self, pbxbuildfile, path):
1765
1778
    """Adds path to the dict tracking paths belonging to this build phase.
1768
1781
    """
1769
1782
 
1770
1783
    if path in self._files_by_path:
1771
 
      raise ValueError, 'Found multiple build files with path ' + path
 
1784
      raise ValueError('Found multiple build files with path ' + path)
1772
1785
    self._files_by_path[path] = pbxbuildfile
1773
1786
 
1774
1787
  def _AddBuildFileToDicts(self, pbxbuildfile, path=None):
1823
1836
    # problem.
1824
1837
    if xcfilelikeelement in self._files_by_xcfilelikeelement and \
1825
1838
       self._files_by_xcfilelikeelement[xcfilelikeelement] != pbxbuildfile:
1826
 
      raise ValueError, 'Found multiple build files for ' + \
1827
 
                        xcfilelikeelement.Name()
 
1839
      raise ValueError('Found multiple build files for ' + \
 
1840
                       xcfilelikeelement.Name())
1828
1841
    self._files_by_xcfilelikeelement[xcfilelikeelement] = pbxbuildfile
1829
1842
 
1830
1843
  def AppendBuildFile(self, pbxbuildfile, path=None):
1988
2001
      subfolder = 0
1989
2002
      relative_path = path[1:]
1990
2003
    else:
1991
 
      raise ValueError, 'Can\'t use path %s in a %s' % \
1992
 
                        (path, self.__class__.__name__)
 
2004
      raise ValueError('Can\'t use path %s in a %s' % \
 
2005
                       (path, self.__class__.__name__))
1993
2006
 
1994
2007
    self._properties['dstPath'] = relative_path
1995
2008
    self._properties['dstSubfolderSpec'] = subfolder
2225
2238
  # Mapping from Xcode product-types to settings.  The settings are:
2226
2239
  #  filetype : used for explicitFileType in the project file
2227
2240
  #  prefix : the prefix for the file name
2228
 
  #  suffix : the suffix for the filen ame
 
2241
  #  suffix : the suffix for the file name
2229
2242
  _product_filetypes = {
2230
 
    'com.apple.product-type.application':     ['wrapper.application',
2231
 
                                               '', '.app'],
2232
 
    'com.apple.product-type.bundle':          ['wrapper.cfbundle',
2233
 
                                               '', '.bundle'],
2234
 
    'com.apple.product-type.framework':       ['wrapper.framework',
2235
 
                                               '', '.framework'],
2236
 
    'com.apple.product-type.library.dynamic': ['compiled.mach-o.dylib',
2237
 
                                               'lib', '.dylib'],
2238
 
    'com.apple.product-type.library.static':  ['archive.ar',
2239
 
                                               'lib', '.a'],
2240
 
    'com.apple.product-type.tool':            ['compiled.mach-o.executable',
2241
 
                                               '', ''],
2242
 
    'com.googlecode.gyp.xcode.bundle':        ['compiled.mach-o.dylib',
2243
 
                                               '', '.so'],
 
2243
    'com.apple.product-type.application':           ['wrapper.application',
 
2244
                                                     '', '.app'],
 
2245
    'com.apple.product-type.application.watchapp':  ['wrapper.application',
 
2246
                                                     '', '.app'],
 
2247
    'com.apple.product-type.watchkit-extension':    ['wrapper.app-extension',
 
2248
                                                     '', '.appex'],
 
2249
    'com.apple.product-type.app-extension':         ['wrapper.app-extension',
 
2250
                                                     '', '.appex'],
 
2251
    'com.apple.product-type.bundle':            ['wrapper.cfbundle',
 
2252
                                                 '', '.bundle'],
 
2253
    'com.apple.product-type.framework':         ['wrapper.framework',
 
2254
                                                 '', '.framework'],
 
2255
    'com.apple.product-type.library.dynamic':   ['compiled.mach-o.dylib',
 
2256
                                                 'lib', '.dylib'],
 
2257
    'com.apple.product-type.library.static':    ['archive.ar',
 
2258
                                                 'lib', '.a'],
 
2259
    'com.apple.product-type.tool':              ['compiled.mach-o.executable',
 
2260
                                                 '', ''],
 
2261
    'com.apple.product-type.bundle.unit-test':  ['wrapper.cfbundle',
 
2262
                                                 '', '.xctest'],
 
2263
    'com.googlecode.gyp.xcode.bundle':          ['compiled.mach-o.dylib',
 
2264
                                                 '', '.so'],
2244
2265
  }
2245
2266
 
2246
2267
  def __init__(self, properties=None, id=None, parent=None,
2292
2313
          if force_extension is None:
2293
2314
            force_extension = suffix[1:]
2294
2315
 
 
2316
        if self._properties['productType'] == \
 
2317
           'com.apple.product-type-bundle.unit.test':
 
2318
          if force_extension is None:
 
2319
            force_extension = suffix[1:]
 
2320
 
2295
2321
        if force_extension is not None:
2296
2322
          # If it's a wrapper (bundle), set WRAPPER_EXTENSION.
 
2323
          # Extension override.
 
2324
          suffix = '.' + force_extension
2297
2325
          if filetype.startswith('wrapper.'):
2298
2326
            self.SetBuildSetting('WRAPPER_EXTENSION', force_extension)
2299
2327
          else:
2300
 
            # Extension override.
2301
 
            suffix = '.' + force_extension
2302
2328
            self.SetBuildSetting('EXECUTABLE_EXTENSION', force_extension)
2303
2329
 
2304
2330
          if filetype.startswith('compiled.mach-o.executable'):
2714
2740
 
2715
2741
    self._SetUpProductReferences(other_pbxproject, product_group, project_ref)
2716
2742
 
 
2743
    inherit_unique_symroot = self._AllSymrootsUnique(other_pbxproject, False)
 
2744
    targets = other_pbxproject.GetProperty('targets')
 
2745
    if all(self._AllSymrootsUnique(t, inherit_unique_symroot) for t in targets):
 
2746
      dir_path = project_ref._properties['path']
 
2747
      product_group._hashables.extend(dir_path)
 
2748
 
2717
2749
    return [product_group, project_ref]
2718
2750
 
 
2751
  def _AllSymrootsUnique(self, target, inherit_unique_symroot):
 
2752
    # Returns True if all configurations have a unique 'SYMROOT' attribute.
 
2753
    # The value of inherit_unique_symroot decides, if a configuration is assumed
 
2754
    # to inherit a unique 'SYMROOT' attribute from its parent, if it doesn't
 
2755
    # define an explicit value for 'SYMROOT'.
 
2756
    symroots = self._DefinedSymroots(target)
 
2757
    for s in self._DefinedSymroots(target):
 
2758
      if (s is not None and not self._IsUniqueSymrootForTarget(s) or
 
2759
          s is None and not inherit_unique_symroot):
 
2760
        return False
 
2761
    return True if symroots else inherit_unique_symroot
 
2762
 
 
2763
  def _DefinedSymroots(self, target):
 
2764
    # Returns all values for the 'SYMROOT' attribute defined in all
 
2765
    # configurations for this target. If any configuration doesn't define the
 
2766
    # 'SYMROOT' attribute, None is added to the returned set. If all
 
2767
    # configurations don't define the 'SYMROOT' attribute, an empty set is
 
2768
    # returned.
 
2769
    config_list = target.GetProperty('buildConfigurationList')
 
2770
    symroots = set()
 
2771
    for config in config_list.GetProperty('buildConfigurations'):
 
2772
      setting = config.GetProperty('buildSettings')
 
2773
      if 'SYMROOT' in setting:
 
2774
        symroots.add(setting['SYMROOT'])
 
2775
      else:
 
2776
        symroots.add(None)
 
2777
    if len(symroots) == 1 and None in symroots:
 
2778
      return set()
 
2779
    return symroots
 
2780
 
 
2781
  def _IsUniqueSymrootForTarget(self, symroot):
 
2782
    # This method returns True if all configurations in target contain a
 
2783
    # 'SYMROOT' attribute that is unique for the given target. A value is
 
2784
    # unique, if the Xcode macro '$SRCROOT' appears in it in any form.
 
2785
    uniquifier = ['$SRCROOT', '$(SRCROOT)']
 
2786
    if any(x in symroot for x in uniquifier):
 
2787
      return True
 
2788
    return False
 
2789
 
2719
2790
  def _SetUpProductReferences(self, other_pbxproject, product_group,
2720
2791
                              project_ref):
2721
2792
    # TODO(mark): This only adds references to products in other_pbxproject
2784
2855
      product_group = ref_dict['ProductGroup']
2785
2856
      product_group._properties['children'] = sorted(
2786
2857
          product_group._properties['children'],
2787
 
          cmp=lambda x, y: CompareProducts(x, y, remote_products))
 
2858
          cmp=lambda x, y, rp=remote_products: CompareProducts(x, y, rp))
2788
2859
 
2789
2860
 
2790
2861
class XCProjectFile(XCObject):
2792
2863
  _schema.update({
2793
2864
    'archiveVersion': [0, int,        0, 1, 1],
2794
2865
    'classes':        [0, dict,       0, 1, {}],
2795
 
    'objectVersion':  [0, int,        0, 1, 45],
 
2866
    'objectVersion':  [0, int,        0, 1, 46],
2796
2867
    'rootObject':     [0, PBXProject, 1, 1],
2797
2868
  })
2798
2869
 
2799
 
  def SetXcodeVersion(self, version):
2800
 
    version_to_object_version = {
2801
 
      '2.4': 45,
2802
 
      '3.0': 45,
2803
 
      '3.1': 45,
2804
 
      '3.2': 46,
2805
 
    }
2806
 
    if not version in version_to_object_version:
2807
 
      supported_str = ', '.join(sorted(version_to_object_version.keys()))
2808
 
      raise Exception(
2809
 
          'Unsupported Xcode version %s (supported: %s)' %
2810
 
          ( version, supported_str ) )
2811
 
    compatibility_version = 'Xcode %s' % version
2812
 
    self._properties['rootObject'].SetProperty('compatibilityVersion',
2813
 
                                               compatibility_version)
2814
 
    self.SetProperty('objectVersion', version_to_object_version[version]);
2815
 
 
2816
2870
  def ComputeIDs(self, recursive=True, overwrite=True, hash=None):
2817
2871
    # Although XCProjectFile is implemented here as an XCObject, it's not a
2818
2872
    # proper object in the Xcode sense, and it certainly doesn't have its own