| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 | 
							- #!/usr/bin/python
 
- ###############################################################################
 
- # Name:         build/osx/fix_xcode_ids.py
 
- # Author:       Dimitri Schoolwerth
 
- # Created:      2010-09-08
 
- # Copyright:    (c) 2010 wxWidgets team
 
- # Licence:      wxWindows licence
 
- ###############################################################################
 
- testFixStage = False
 
- import os
 
- import sys
 
- import re
 
- USAGE = """fix_xcode_ids - Modifies an Xcode project in-place to use the same identifiers (based on name) instead of being different on each regeneration"
 
- Usage: fix_xcode_ids xcode_proj_dir"""
 
- if not testFixStage:
 
-     if len(sys.argv) < 2:
 
-         print USAGE
 
-         sys.exit(1)
 
-     projectFile = sys.argv[1] + "/project.pbxproj"
 
-     fin = open(projectFile, "r")
 
-     strIn = fin.read()
 
-     fin.close()
 
- # Xcode identifiers (IDs) consist of 24 hexadecimal digits
 
- idMask = "[A-Fa-f0-9]{24}"
 
- idDict = {}
 
- # convert a name to an identifier for Xcode
 
- def toUuid(name):
 
-     from uuid import uuid3, UUID
 
-     id = uuid3(UUID("349f853c-91f8-4eba-b9b9-5e9f882e693c"), name).hex[:24].upper()
 
-     # Some names can appear twice or even more (depending on number of
 
-     # targets), make them unique
 
-     while id in idDict.values() :
 
-         id = "%024X" % (int(id, 16) + 1)
 
-     return id
 
- def insertBuildFileEntry(filePath, fileRefId):
 
-     global strIn
 
-     print "\tInsert PBXBuildFile for '%s'..." % filePath,
 
-     matchBuildFileSection = re.search("/\* Begin PBXBuildFile section \*/\n", strIn)
 
-     dirName, fileName = os.path.split(filePath)
 
-     fileInSources = fileName + " in Sources"
 
-     id = toUuid(fileInSources)
 
-     idDict[id] = id
 
-     insert = "\t\t%s /* %s */ = {isa = PBXBuildFile; fileRef = %s /* %s */; };\n" % (id, fileInSources, fileRefId, fileName)
 
-     strIn = strIn[:matchBuildFileSection.end()] + insert + strIn[matchBuildFileSection.end():]
 
-     print "OK"
 
-     return id
 
- def insertFileRefEntry(filePath, id = 0):
 
-     global strIn
 
-     print "\tInsert PBXFileReference for '%s'..." % filePath,
 
-     matchFileRefSection = re.search("/\* Begin PBXFileReference section \*/\n", strIn)
 
-     dirName, fileName = os.path.split(filePath)
 
-     if id == 0:
 
-         id = toUuid(fileName)
 
-         idDict[id] = id
 
-     insert = "\t\t%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = file; name = %s; path = %s; sourceTree = \"<group>\"; };\n" % (id, fileName, fileName, filePath)
 
-     strIn = strIn[:matchFileRefSection.end()] + insert + strIn[matchFileRefSection.end():]
 
-     print "OK"
 
-     return id
 
- def insertSourcesBuildPhaseEntry(id, fileName, insertBeforeFileName, startSearchPos = 0):
 
-     global strIn
 
-     print "\tInsert PBXSourcesBuildPhase for '%s'..." % fileName,
 
-     matchBuildPhase = re.compile(".+ /\* " + insertBeforeFileName + " in Sources \*/,") \
 
-         .search(strIn, startSearchPos)
 
-     insert = "\t\t\t\t%s /* %s in Sources */,\n" % (id, fileName)
 
-     strIn = strIn[:matchBuildPhase.start()] \
 
-         + insert \
 
-         + strIn[matchBuildPhase.start():]
 
-     print "OK"
 
-     return matchBuildPhase.start() + len(insert) + len(matchBuildPhase.group(0))
 
- # Detect and fix errors in the project file that might have been introduced.
 
- # Sometimes two source files are concatenated. These are spottable by
 
- # looking for patterns such as "filename.cppsrc/html/"
 
- # Following is a stripped Xcode project containing several problems that
 
- # are solved after finding the error.
 
- strTest = \
 
- """/* Begin PBXBuildFile section */
 
-         95DE8BAB1238EE1800B43069 /* m_fonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */; };
 
-         95DE8BAC1238EE1800B43069 /* m_fonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */; };
 
- /* End PBXBuildFile section */
 
- /* Begin PBXFileReference section */
 
-         95DE8BAA1238EE1700B43069 /* m_fonts.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = m_fonts.cpp; path = ../../src/html/m_dflist.cppsrc/html/m_fonts.cpp; sourceTree = "<group>"; };
 
- /* End PBXFileReference section */
 
- /* Begin PBXGroup section */
 
-         95DE8B831238EE1000B43069 /* html */ = {
 
-             isa = PBXGroup;
 
-             children = (
 
-                 95DE8B841238EE1000B43069 /* src/html */,
 
-                 95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */,
 
-                 95DE8BCE1238EE1F00B43069 /* src/generic */,
 
-             );
 
-             name = html;
 
-             sourceTree = "<group>";
 
-         };
 
-         95DE8B841238EE1000B43069 /* src/html */ = {
 
-             isa = PBXGroup;
 
-             children = (
 
-                 95DE8B851238EE1000B43069 /* chm.cpp */,
 
-                 95DE8BAD1238EE1800B43069 /* m_hline.cpp */,
 
-             );
 
-             name = src/html;
 
-             sourceTree = "<group>";
 
-         };
 
-         95DE8BA91238EE1700B43069 /* src/html/m_dflist.cppsrc/html */ = {
 
-             isa = PBXGroup;
 
-             children = (
 
-                 95DE8BAA1238EE1700B43069 /* m_fonts.cpp */,
 
-             );
 
-             name = src/html/m_dflist.cppsrc/html;
 
-             sourceTree = "<group>";
 
-         };
 
- /* End PBXGroup section */
 
- /* Begin PBXSourcesBuildPhase section */
 
-         404BEE5E10EC83280080E2B8 /* Sources */ = {
 
-             files = (
 
-                 95DE8BAC1238EE1800B43069 /* m_fonts.cpp in Sources */,
 
-             );
 
-             runOnlyForDeploymentPostprocessing = 0;
 
-         };
 
-         D2AAC0C405546C1D00DB518D /* Sources */ = {
 
-             files = (
 
-                 95DE8BAB1238EE1800B43069 /* m_fonts.cpp in Sources */,
 
-             );
 
-             runOnlyForDeploymentPostprocessing = 0;
 
-         };
 
- /* End PBXSourcesBuildPhase section */"""
 
- if testFixStage:
 
-     strIn = strTest
 
- rc = re.compile(".+ (?P<path1>[\w/.]+(\.cpp|\.cxx|\.c))(?P<path2>\w+/[\w/.]+).+")
 
- matchLine = rc.search(strIn)
 
- while matchLine:
 
-     line = matchLine.group(0)
 
-     # is it a line from the PBXFileReference section containing 2 mixed paths?
 
-     # example:
 
-     # FEDCBA9876543210FEDCBA98 /* file2.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = file2.cpp; path = ../../src/html/file1.cppsrc/html/file2.cpp; sourceTree = "<group>"; };
 
-     if line.endswith("};") :
 
-         path1 = matchLine.group('path1')
 
-         path2 = matchLine.group('path2')
 
-         print "Correcting mixed paths '%s' and '%s' at '%s':" % (path1, path2, line)
 
-         # if so, make note of the ID used (belongs to path2), remove the line
 
-         # and split the 2 paths inserting 2 new entries inside PBXFileReference
 
-         fileRefId2 = re.search(idMask, line).group(0)
 
-         print "\tDelete the offending PBXFileReference line...",
 
-         # delete the PBXFileReference line that was found and which contains 2 mixed paths
 
-         strIn = strIn[:matchLine.start()] + strIn[matchLine.end()+1:]
 
-         print "OK"
 
-         # insert corrected path1 entry in PBXFileReference
 
-         fileRefId1 = insertFileRefEntry(path1)
 
-         # do the same for path2 (which already had a ID)
 
-         path2Corrected = path2
 
-         if path2Corrected.startswith('src') :
 
-             path2Corrected = '../../' + path2Corrected
 
-         insertFileRefEntry(path2Corrected, fileRefId2)
 
-         buildPhaseId = {}
 
-         # insert a PBXBuildFile entry, 1 for each target
 
-         # path2 already has correct PBXBuildFile entries
 
-         targetCount = strIn.count("isa = PBXSourcesBuildPhase")
 
-         for i in range(0, targetCount):
 
-             buildPhaseId[i] = insertBuildFileEntry(path1, fileRefId1)
 
-         fileName1 = os.path.split(path1)[1]
 
-         dir2, fileName2 = os.path.split(path2)
 
-         # refer to each PBXBuildFile in each PBXSourcesBuildPhase
 
-         startSearchIndex = 0
 
-         for i in range(0, targetCount):
 
-             startSearchIndex = insertSourcesBuildPhaseEntry(buildPhaseId[i], fileName1, fileName2, startSearchIndex)
 
-         # insert both paths in the group they belong to
 
-         matchGroupStart = re.search("/\* %s \*/ = {" % dir2, strIn)
 
-         endGroupIndex = strIn.find("};", matchGroupStart.start())
 
-         for matchGroupLine in re.compile(".+" + idMask + " /\* (.+) \*/,").finditer(strIn, matchGroupStart.start(), endGroupIndex) :
 
-             if matchGroupLine.group(1) > fileName1:
 
-                 print "\tInsert paths in PBXGroup '%s', just before '%s'..." % (dir2, matchGroupLine.group(1)),
 
-                 strIn = strIn[:matchGroupLine.start()] \
 
-                     + "\t\t\t\t%s /* %s */,\n" % (fileRefId1, fileName1) \
 
-                     + "\t\t\t\t%s /* %s */,\n" % (fileRefId2, fileName2) \
 
-                     + strIn[matchGroupLine.start():]
 
-                 print "OK"
 
-                 break
 
-     elif line.endswith("*/ = {") :
 
-         print "Delete invalid PBXGroup starting at '%s'..." % line,
 
-         find = "};\n"
 
-         endGroupIndex = strIn.find(find, matchLine.start()) + len(find)
 
-         strIn = strIn[:matchLine.start()] + strIn[endGroupIndex:]
 
-         print "OK"
 
-     elif line.endswith(" */,") :
 
-         print "Delete invalid PBXGroup child '%s'..." % line,
 
-         strIn = strIn[:matchLine.start()] + strIn[matchLine.end()+1:]
 
-         print "OK"
 
-     matchLine = rc.search(strIn)
 
- if testFixStage:
 
-     print "------------------------------------------"
 
-     print strIn
 
-     exit(1)
 
- # key = original ID found in project
 
- # value = ID it will be replaced by
 
- idDict = {}
 
- # some of the strings to match to find definitions of Xcode IDs:
 
- # from PBXBuildFile section:
 
- # 0123456789ABCDEF01234567 /* filename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEDCBA9876543210FEDCBA98 /* filename.cpp */; };
 
- # from PBXFileReference section:
 
- # FEDCBA9876543210FEDCBA98 /* filename.cpp */ = {isa = PBXFileReference; lastKnownFileType = file; name = any.cpp; path = ../../src/common/filename.cpp; sourceTree = "<group>"; };
 
- # from remaining sections:
 
- # 890123456789ABCDEF012345 /* Name */ = {
 
- # Capture the first comment between /* and */ (file/section name) as a group
 
- rc = re.compile("\s+(" + idMask + ") /\* (.+) \*/ = {.*$", re.MULTILINE)
 
- dict = rc.findall(strIn)
 
- for s in dict:
 
-     # s[0] is the original ID, s[1] is the name
 
-     assert(not s[0] in idDict)
 
-     idDict[s[0]] = toUuid(s[1])
 
- # replace all found identifiers with the new ones
 
- def repl(match):
 
-     return idDict[match.group(0)]
 
- strOut = re.sub(idMask, repl, strIn)
 
- fout = open(projectFile, "w")
 
- fout.write(strOut)
 
- fout.close()
 
 
  |