diff --git a/Tools/XcodeCapp/XcodeCapp.xcodeproj/project.pbxproj b/Tools/XcodeCapp/XcodeCapp.xcodeproj/project.pbxproj index 078c6f52e..f94f61257 100644 --- a/Tools/XcodeCapp/XcodeCapp.xcodeproj/project.pbxproj +++ b/Tools/XcodeCapp/XcodeCapp.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ E164FDF51720EBC100263CE3 /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = E164FDF41720EBC100263CE3 /* AppController.m */; }; E164FDF71720EBD600263CE3 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E164FDF61720EBD600263CE3 /* Growl.framework */; }; E164FDFF1720EC5B00263CE3 /* XcodeCapp.m in Sources */ = {isa = PBXBuildFile; fileRef = E164FDFB1720EC5B00263CE3 /* XcodeCapp.m */; }; - E164FE001720EC5B00263CE3 /* UserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = E164FDFD1720EC5B00263CE3 /* UserDefaults.m */; }; E164FE061720ED4500263CE3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E164FE041720ED4400263CE3 /* InfoPlist.strings */; }; E164FE181720F44B00263CE3 /* parser.j in Resources */ = {isa = PBXBuildFile; fileRef = E164FE171720F44B00263CE3 /* parser.j */; }; E164FE1A1720F49A00263CE3 /* Growl Registration Ticket.growlRegDict in Resources */ = {isa = PBXBuildFile; fileRef = E164FE191720F49A00263CE3 /* Growl Registration Ticket.growlRegDict */; }; @@ -34,13 +33,14 @@ E17A822D172700B90095CD83 /* XcodeCapp.iconset in Resources */ = {isa = PBXBuildFile; fileRef = E17A822C172700B90095CD83 /* XcodeCapp.iconset */; }; E17B55411732F57700809FFB /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E17B55401732F57700809FFB /* Quartz.framework */; }; E17B55431732F72700809FFB /* help.pdf in Resources */ = {isa = PBXBuildFile; fileRef = E17B55421732F72700809FFB /* help.pdf */; }; - E17B554D17330E2800809FFB /* DDASLLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = E17B554817330E2800809FFB /* DDASLLogger.m */; }; - E17B554E17330E2800809FFB /* DDLog.m in Sources */ = {isa = PBXBuildFile; fileRef = E17B554A17330E2800809FFB /* DDLog.m */; }; - E17B554F17330E2800809FFB /* DDTTYLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = E17B554C17330E2800809FFB /* DDTTYLogger.m */; }; E1A5594A172C5EE20088FB61 /* FindSourceFilesOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = E1A55949172C5EE20088FB61 /* FindSourceFilesOperation.m */; }; E1A5594D172CA8D40088FB61 /* ProcessSourceOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = E1A5594C172CA8D40088FB61 /* ProcessSourceOperation.m */; }; - E1A55954172CBA8E0088FB61 /* Notifications.m in Sources */ = {isa = PBXBuildFile; fileRef = E1A55953172CBA8E0088FB61 /* Notifications.m */; }; - E1E167F1172F3B20003198BA /* DDLogLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E167F0172F3B20003198BA /* DDLogLevel.m */; }; + E1E90C411735D846005C6D5B /* DDLogLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C391735D846005C6D5B /* DDLogLevel.m */; }; + E1E90C421735D846005C6D5B /* Notifications.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C3C1735D846005C6D5B /* Notifications.m */; }; + E1E90C431735D846005C6D5B /* UserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C3F1735D846005C6D5B /* UserDefaults.m */; }; + E1E90C4B1735D8A1005C6D5B /* DDASLLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C461735D8A1005C6D5B /* DDASLLogger.m */; }; + E1E90C4C1735D8A1005C6D5B /* DDLog.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C481735D8A1005C6D5B /* DDLog.m */; }; + E1E90C4D1735D8A1005C6D5B /* DDTTYLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E90C4A1735D8A1005C6D5B /* DDTTYLogger.m */; }; E1ED6B71173414E100641628 /* icon_128x128.png in Resources */ = {isa = PBXBuildFile; fileRef = E1ED6B6F173414E100641628 /* icon_128x128.png */; }; E1ED6B72173414E100641628 /* icon_128x128@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E1ED6B70173414E100641628 /* icon_128x128@2x.png */; }; /* End PBXBuildFile section */ @@ -71,8 +71,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - E132ED991724B71600D870AE /* XcodeCapp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XcodeCapp.h; sourceTree = ""; }; - E132ED9A1724B71D00D870AE /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; E164FDCF1720E77100263CE3 /* XcodeCapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XcodeCapp.app; sourceTree = BUILT_PRODUCTS_DIR; }; E164FDD21720E77100263CE3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; E164FDD51720E77100263CE3 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; @@ -87,7 +85,6 @@ E164FDF41720EBC100263CE3 /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AppController.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; E164FDF61720EBD600263CE3 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = XcodeCapp/Growl.framework; sourceTree = SOURCE_ROOT; }; E164FDFB1720EC5B00263CE3 /* XcodeCapp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = XcodeCapp.m; sourceTree = ""; usesTabs = 0; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - E164FDFD1720EC5B00263CE3 /* UserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = UserDefaults.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; E164FE051720ED4500263CE3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = XcodeCapp/en.lproj/InfoPlist.strings; sourceTree = ""; }; E164FE131720F40400263CE3 /* mod_pbxproj.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = mod_pbxproj.py; sourceTree = ""; }; E164FE141720F40400263CE3 /* pbxprojModifier.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = pbxprojModifier.py; sourceTree = ""; }; @@ -106,21 +103,24 @@ E17A822C172700B90095CD83 /* XcodeCapp.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = XcodeCapp.iconset; path = Resources/XcodeCapp.iconset; sourceTree = ""; }; E17B55401732F57700809FFB /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; }; E17B55421732F72700809FFB /* help.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = help.pdf; path = Resources/help.pdf; sourceTree = ""; }; - E17B554717330E2800809FFB /* DDASLLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDASLLogger.h; sourceTree = ""; }; - E17B554817330E2800809FFB /* DDASLLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDASLLogger.m; sourceTree = ""; }; - E17B554917330E2800809FFB /* DDLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDLog.h; sourceTree = ""; }; - E17B554A17330E2800809FFB /* DDLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDLog.m; sourceTree = ""; }; - E17B554B17330E2800809FFB /* DDTTYLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTTYLogger.h; sourceTree = ""; }; - E17B554C17330E2800809FFB /* DDTTYLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTTYLogger.m; sourceTree = ""; }; - E1A55948172C5EE20088FB61 /* FindSourceFilesOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = FindSourceFilesOperation.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; E1A55949172C5EE20088FB61 /* FindSourceFilesOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FindSourceFilesOperation.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - E1A5594B172CA8D40088FB61 /* ProcessSourceOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessSourceOperation.h; sourceTree = ""; }; E1A5594C172CA8D40088FB61 /* ProcessSourceOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ProcessSourceOperation.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - E1A55952172CBA6E0088FB61 /* Notifications.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Notifications.h; sourceTree = ""; }; - E1A55953172CBA8E0088FB61 /* Notifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Notifications.m; sourceTree = ""; }; - E1DD4DF517282BFC0063C0D7 /* UserDefaults.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = UserDefaults.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - E1E167EF172F3B20003198BA /* DDLogLevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = DDLogLevel.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - E1E167F0172F3B20003198BA /* DDLogLevel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = DDLogLevel.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + E1E90C371735D82B005C6D5B /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; + E1E90C381735D846005C6D5B /* DDLogLevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDLogLevel.h; sourceTree = ""; }; + E1E90C391735D846005C6D5B /* DDLogLevel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDLogLevel.m; sourceTree = ""; }; + E1E90C3A1735D846005C6D5B /* FindSourceFilesOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FindSourceFilesOperation.h; sourceTree = ""; }; + E1E90C3B1735D846005C6D5B /* Notifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Notifications.h; sourceTree = ""; }; + E1E90C3C1735D846005C6D5B /* Notifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Notifications.m; sourceTree = ""; }; + E1E90C3D1735D846005C6D5B /* ProcessSourceOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessSourceOperation.h; sourceTree = ""; }; + E1E90C3E1735D846005C6D5B /* UserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserDefaults.h; sourceTree = ""; }; + E1E90C3F1735D846005C6D5B /* UserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UserDefaults.m; sourceTree = ""; }; + E1E90C401735D846005C6D5B /* XcodeCapp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XcodeCapp.h; sourceTree = ""; }; + E1E90C451735D8A1005C6D5B /* DDASLLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDASLLogger.h; sourceTree = ""; }; + E1E90C461735D8A1005C6D5B /* DDASLLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDASLLogger.m; sourceTree = ""; }; + E1E90C471735D8A1005C6D5B /* DDLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDLog.h; sourceTree = ""; }; + E1E90C481735D8A1005C6D5B /* DDLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDLog.m; sourceTree = ""; }; + E1E90C491735D8A1005C6D5B /* DDTTYLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTTYLogger.h; sourceTree = ""; }; + E1E90C4A1735D8A1005C6D5B /* DDTTYLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTTYLogger.m; sourceTree = ""; }; E1ED6B6F173414E100641628 /* icon_128x128.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon_128x128.png; path = Resources/icon_128x128.png; sourceTree = ""; }; E1ED6B70173414E100641628 /* icon_128x128@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon_128x128@2x.png"; path = "Resources/icon_128x128@2x.png"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -183,17 +183,17 @@ isa = PBXGroup; children = ( E164FDF41720EBC100263CE3 /* AppController.m */, - E132ED9A1724B71D00D870AE /* AppController.h */, + E1E90C371735D82B005C6D5B /* AppController.h */, E164FDFB1720EC5B00263CE3 /* XcodeCapp.m */, - E132ED991724B71600D870AE /* XcodeCapp.h */, + E1E90C401735D846005C6D5B /* XcodeCapp.h */, + E1E90C3C1735D846005C6D5B /* Notifications.m */, + E1E90C3B1735D846005C6D5B /* Notifications.h */, + E1E90C3F1735D846005C6D5B /* UserDefaults.m */, + E1E90C3E1735D846005C6D5B /* UserDefaults.h */, + E1E90C391735D846005C6D5B /* DDLogLevel.m */, + E1E90C381735D846005C6D5B /* DDLogLevel.h */, E1A55947172C5EA80088FB61 /* Operations */, - E164FDFD1720EC5B00263CE3 /* UserDefaults.m */, - E1DD4DF517282BFC0063C0D7 /* UserDefaults.h */, - E1A55952172CBA6E0088FB61 /* Notifications.h */, - E1A55953172CBA8E0088FB61 /* Notifications.m */, - E1E167EF172F3B20003198BA /* DDLogLevel.h */, - E1E167F0172F3B20003198BA /* DDLogLevel.m */, - E17B554617330E2800809FFB /* Lumberjack */, + E1E90C441735D8A1005C6D5B /* Lumberjack */, E164FE121720F3E100263CE3 /* Scripts */, E164FE071720F25400263CE3 /* Resources */, E164FDD91720E77100263CE3 /* Supporting Files */, @@ -246,30 +246,30 @@ path = Scripts; sourceTree = ""; }; - E17B554617330E2800809FFB /* Lumberjack */ = { - isa = PBXGroup; - children = ( - E17B554717330E2800809FFB /* DDASLLogger.h */, - E17B554817330E2800809FFB /* DDASLLogger.m */, - E17B554917330E2800809FFB /* DDLog.h */, - E17B554A17330E2800809FFB /* DDLog.m */, - E17B554B17330E2800809FFB /* DDTTYLogger.h */, - E17B554C17330E2800809FFB /* DDTTYLogger.m */, - ); - path = Lumberjack; - sourceTree = ""; - }; E1A55947172C5EA80088FB61 /* Operations */ = { isa = PBXGroup; children = ( E1A55949172C5EE20088FB61 /* FindSourceFilesOperation.m */, - E1A55948172C5EE20088FB61 /* FindSourceFilesOperation.h */, + E1E90C3A1735D846005C6D5B /* FindSourceFilesOperation.h */, E1A5594C172CA8D40088FB61 /* ProcessSourceOperation.m */, - E1A5594B172CA8D40088FB61 /* ProcessSourceOperation.h */, + E1E90C3D1735D846005C6D5B /* ProcessSourceOperation.h */, ); name = Operations; sourceTree = ""; }; + E1E90C441735D8A1005C6D5B /* Lumberjack */ = { + isa = PBXGroup; + children = ( + E1E90C451735D8A1005C6D5B /* DDASLLogger.h */, + E1E90C461735D8A1005C6D5B /* DDASLLogger.m */, + E1E90C471735D8A1005C6D5B /* DDLog.h */, + E1E90C481735D8A1005C6D5B /* DDLog.m */, + E1E90C491735D8A1005C6D5B /* DDTTYLogger.h */, + E1E90C4A1735D8A1005C6D5B /* DDTTYLogger.m */, + ); + path = Lumberjack; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -353,14 +353,14 @@ E164FDDF1720E77100263CE3 /* main.m in Sources */, E164FDF51720EBC100263CE3 /* AppController.m in Sources */, E164FDFF1720EC5B00263CE3 /* XcodeCapp.m in Sources */, - E164FE001720EC5B00263CE3 /* UserDefaults.m in Sources */, E1A5594A172C5EE20088FB61 /* FindSourceFilesOperation.m in Sources */, E1A5594D172CA8D40088FB61 /* ProcessSourceOperation.m in Sources */, - E1A55954172CBA8E0088FB61 /* Notifications.m in Sources */, - E1E167F1172F3B20003198BA /* DDLogLevel.m in Sources */, - E17B554D17330E2800809FFB /* DDASLLogger.m in Sources */, - E17B554E17330E2800809FFB /* DDLog.m in Sources */, - E17B554F17330E2800809FFB /* DDTTYLogger.m in Sources */, + E1E90C411735D846005C6D5B /* DDLogLevel.m in Sources */, + E1E90C421735D846005C6D5B /* Notifications.m in Sources */, + E1E90C431735D846005C6D5B /* UserDefaults.m in Sources */, + E1E90C4B1735D8A1005C6D5B /* DDASLLogger.m in Sources */, + E1E90C4C1735D8A1005C6D5B /* DDLog.m in Sources */, + E1E90C4D1735D8A1005C6D5B /* DDTTYLogger.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Tools/XcodeCapp/XcodeCapp/Scripts/mod_pbxproj.py b/Tools/XcodeCapp/XcodeCapp/Scripts/mod_pbxproj.py index d79a717de..82eabb686 100755 --- a/Tools/XcodeCapp/XcodeCapp/Scripts/mod_pbxproj.py +++ b/Tools/XcodeCapp/XcodeCapp/Scripts/mod_pbxproj.py @@ -32,14 +32,22 @@ # the pbxproj file. Plutil is available in OS X 10.2 and higher # Plutil can't write OpenStep plists, so I save as XML -import re, uuid, sys, os, shutil, subprocess, datetime, json, types, re, ntpath +import datetime +import json +import ntpath +import os +import plistlib +import re +import shutil +import subprocess +import uuid from UserDict import IterableUserDict from UserList import UserList -from xml.dom.minidom import * regex = '[a-zA-Z0-9\\._/-]*' + class PBXEncoder(json.JSONEncoder): def default(self, obj): @@ -54,7 +62,7 @@ class PBXEncoder(json.JSONEncoder): class PBXDict(IterableUserDict): def __init__(self, d=None): if d: - d = dict([(PBXType.Convert(k),PBXType.Convert(v)) for k,v in d.items()]) + d = dict([(PBXType.Convert(k), PBXType.Convert(v)) for k, v in d.items()]) IterableUserDict.__init__(self, d) @@ -65,7 +73,6 @@ class PBXDict(IterableUserDict): self.data.pop(PBXType.Convert(key), None) - class PBXList(UserList): def __init__(self, l=None): if isinstance(l, basestring): @@ -100,7 +107,7 @@ class PBXType(PBXDict): def __init__(self, d=None): PBXDict.__init__(self, d) - if not self.has_key('isa'): + if 'isa' not in self: self['isa'] = self.__class__.__name__ self.id = None @@ -143,14 +150,14 @@ class PBXFileReference(PBXType): self.build_phase = None types = { - '.a':('archive.ar', 'PBXFrameworksBuildPhase'), + '.a': ('archive.ar', 'PBXFrameworksBuildPhase'), '.app': ('wrapper.application', None), '.s': ('sourcecode.asm', 'PBXSourcesBuildPhase'), '.c': ('sourcecode.c.c', 'PBXSourcesBuildPhase'), '.cpp': ('sourcecode.cpp.cpp', 'PBXSourcesBuildPhase'), - '.framework': ('wrapper.framework','PBXFrameworksBuildPhase'), + '.framework': ('wrapper.framework', 'PBXFrameworksBuildPhase'), '.h': ('sourcecode.c.h', None), - '.icns': ('image.icns','PBXResourcesBuildPhase'), + '.icns': ('image.icns', 'PBXResourcesBuildPhase'), '.m': ('sourcecode.c.objc', 'PBXSourcesBuildPhase'), '.j': ('sourcecode.c.objc', 'PBXSourcesBuildPhase'), '.mm': ('sourcecode.cpp.objcpp', 'PBXSourcesBuildPhase'), @@ -177,13 +184,14 @@ class PBXFileReference(PBXType): 'SOURCE_ROOT', ] - def guess_file_type(self): + def guess_file_type(self, ignore_unknown_type=True): self.remove('explicitFileType') self.remove('lastKnownFileType') if os.path.isdir(self.get('path')): f_type = 'folder' build_phase = None + ext = '' else: ext = os.path.splitext(self.get('name', ''))[1] f_type, build_phase = PBXFileReference.types.get(ext, ('?', None)) @@ -191,7 +199,7 @@ class PBXFileReference(PBXType): self['lastKnownFileType'] = f_type self.build_phase = build_phase - if f_type == '?': + if f_type == '?' and not ignore_unknown_type: print 'unknown file extension: %s' % ext print 'please add extension and Xcode type to PBXFileReference.types' @@ -204,7 +212,7 @@ class PBXFileReference(PBXType): self['explicitFileType'] = ft @classmethod - def Create(cls, os_path, tree='SOURCE_ROOT'): + def Create(cls, os_path, tree='SOURCE_ROOT', ignore_unknown_type=True): if tree not in cls.trees: print 'Not a valid sourceTree type: %s' % tree return None @@ -214,10 +222,11 @@ class PBXFileReference(PBXType): fr['path'] = os_path fr['name'] = os.path.split(os_path)[1] fr['sourceTree'] = '' if os.path.isabs(os_path) else tree - fr.guess_file_type() + fr.guess_file_type(ignore_unknown_type=ignore_unknown_type) return fr + class PBXBuildFile(PBXType): def set_weak_link(self, weak=False): k_settings = 'settings' @@ -227,7 +236,7 @@ class PBXBuildFile(PBXType): if not s: if weak: - self[k_settings] = PBXDict({k_attributes:PBXList(['Weak'])}) + self[k_settings] = PBXDict({k_attributes: PBXList(['Weak'])}) return True @@ -252,10 +261,10 @@ class PBXBuildFile(PBXType): k_settings = 'settings' k_attributes = 'COMPILER_FLAGS' - if not self.has_key(k_settings): + if k_settings not in self: self[k_settings] = PBXDict() - if not self[k_settings].has_key(k_attributes): + if k_attributes not in self[k_settings]: self[k_settings][k_attributes] = flag return True @@ -282,6 +291,7 @@ class PBXBuildFile(PBXType): return bf + class PBXGroup(PBXType): def add_child(self, ref): if not isinstance(ref, PBXDict): @@ -292,7 +302,7 @@ class PBXGroup(PBXType): if isa != 'PBXFileReference' and isa != 'PBXGroup': return None - if not self.has_key('children'): + if 'children' not in self: self['children'] = PBXList() self['children'].add(ref.id) @@ -300,7 +310,7 @@ class PBXGroup(PBXType): return ref.id def remove_child(self, id): - if not self.has_key('children'): + if 'children' not in self: self['children'] = PBXList() return @@ -310,7 +320,7 @@ class PBXGroup(PBXType): self['children'].remove(id) def has_child(self, id): - if not self.has_key('children'): + if 'children' not in self: self['children'] = PBXList() return False @@ -320,7 +330,7 @@ class PBXGroup(PBXType): return id in self['children'] def get_name(self): - path_name = os.path.split(self.get('path',''))[1] + path_name = os.path.split(self.get('path', ''))[1] return self.get('name', path_name) @classmethod @@ -368,7 +378,7 @@ class PBXBuildPhase(PBXType): if bf.get('isa') != 'PBXBuildFile': return False - if not self.has_key('files'): + if 'files' not in self: self['files'] = PBXList() self['files'].add(bf.id) @@ -376,14 +386,14 @@ class PBXBuildPhase(PBXType): return True def remove_build_file(self, id): - if not self.has_key('files'): + if 'files' not in self: self['files'] = PBXList() return self['files'].remove(id) def has_build_file(self, id): - if not self.has_key('files'): + if 'files' not in self: self['files'] = PBXList() return False @@ -420,23 +430,23 @@ class XCBuildConfiguration(PBXType): if not isinstance(paths, list): paths = [paths] - if not self.has_key(base): + if base not in self: self[base] = PBXDict() for path in paths: if recursive and not path.endswith('/**'): path = os.path.join(path, '**') - if not self[base].has_key(key): + if key not in self[base]: self[base][key] = PBXList() elif isinstance(self[base][key], basestring): self[base][key] = PBXList(self[base][key]) - if escape : - if self[base][key].add('\\"%s\\"' % path):#'\\"%s\\"' % path + if escape: + if self[base][key].add('\\"%s\\"' % path): # '\\"%s\\"' % path modified = True else: - if self[base][key].add(path):#'\\"%s\\"' % path + if self[base][key].add(path): # '\\"%s\\"' % path modified = True return modified @@ -448,7 +458,7 @@ class XCBuildConfiguration(PBXType): return self.add_search_paths(paths, 'buildSettings', 'LIBRARY_SEARCH_PATHS', recursive=recursive) def add_framework_search_paths(self, paths, recursive=True): - return self.add_search_paths(paths, 'buildSettings', 'FRAMEWORK_SEARCH_PATHS', recursive=recursive, escape = False) + return self.add_search_paths(paths, 'buildSettings', 'FRAMEWORK_SEARCH_PATHS', recursive=recursive, escape=False) def add_other_cflags(self, flags): modified = False @@ -459,12 +469,11 @@ class XCBuildConfiguration(PBXType): if isinstance(flags, basestring): flags = PBXList(flags) - if not self.has_key(base): + if base not in self: self[base] = PBXDict() for flag in flags: - - if not self[base].has_key(key): + if key not in self[base]: self[base][key] = PBXList() elif isinstance(self[base][key], basestring): self[base][key] = PBXList(self[base][key]) @@ -484,12 +493,11 @@ class XCBuildConfiguration(PBXType): if isinstance(flags, basestring): flags = PBXList(flags) - if not self.has_key(base): + if base not in self: self[base] = PBXDict() for flag in flags: - - if not self[base].has_key(key): + if key not in self[base]: self[base][key] = PBXList() elif isinstance(self[base][key], basestring): self[base][key] = PBXList(self[base][key]) @@ -509,19 +517,20 @@ class XCBuildConfiguration(PBXType): if isinstance(flags, basestring): flags = PBXList(flags) - if self.has_key(base): #there is flags, so we can "remove" something + if base in self: # there are flags, so we can "remove" something for flag in flags: - if not self[base].has_key(key): + if key not in self[base]: return False elif isinstance(self[base][key], basestring): self[base][key] = PBXList(self[base][key]) if self[base][key].remove(flag): self[base][key] = [e for e in self[base][key] if e] - mofified = True + modified = True return modified + class XCConfigurationList(PBXType): pass @@ -544,6 +553,7 @@ class XcodeProject(PBXDict): self.modified = False root_id = self.get('rootObject') + if root_id: self.root_object = self.objects[root_id] root_group_id = self.root_object.get('mainGroup') @@ -553,7 +563,7 @@ class XcodeProject(PBXDict): self.root_object = None self.root_group = None - for k,v in self.objects.iteritems(): + for k, v in self.objects.iteritems(): v.id = k def add_other_cflags(self, flags): @@ -670,7 +680,7 @@ class XcodeProject(PBXDict): path = os.path.abspath(path) groups = [g for g in self.objects.values() if g.get('isa') == 'PBXGroup' - and os.path.abspath(g.get('path','/dev/null')) == path] + and os.path.abspath(g.get('path', '/dev/null')) == path] return groups @@ -709,7 +719,7 @@ class XcodeProject(PBXDict): # assume it's an id parent = self.objects.get(parent, self.root_group) - path_dict = {os.path.split(os_path)[0]:parent} + path_dict = {os.path.split(os_path)[0]: parent} special_list = [] for (grp_path, subdirs, files) in os.walk(os_path): @@ -726,7 +736,6 @@ class XcodeProject(PBXDict): if os.path.splitext(grp_path)[1] in XcodeProject.special_folders: # if this file has a special extension (bundle or framework mainly) treat it as a file special_list.append(grp_path) - new_files = self.verify_files([folder_name], parent=parent) if new_files: @@ -735,7 +744,7 @@ class XcodeProject(PBXDict): continue # create group - grp = self.get_or_create_group(folder_name, path=self.get_relative_path(grp_path) , parent=parent) + grp = self.get_or_create_group(folder_name, path=self.get_relative_path(grp_path), parent=parent) path_dict[grp_path] = grp results.append(grp) @@ -743,7 +752,7 @@ class XcodeProject(PBXDict): file_dict = {} for f in files: - if f[0] == '.' or [m for m in excludes if re.match(m,f)]: + if f[0] == '.' or [m for m in excludes if re.match(m, f)]: continue kwds = { @@ -758,7 +767,7 @@ class XcodeProject(PBXDict): new_files = self.verify_files([n.get('name') for n in file_dict.values()], parent=grp) - add_files = [(k,v) for k,v in file_dict.items() if v.get('name') in new_files] + add_files = [(k, v) for k, v in file_dict.items() if v.get('name') in new_files] for path, kwds in add_files: kwds.pop('name', None) @@ -773,21 +782,20 @@ class XcodeProject(PBXDict): return results - def path_leaf(self,path): + def path_leaf(self, path): head, tail = ntpath.split(path) return tail or ntpath.basename(head) - def add_file_if_doesnt_exist(self, f_path, parent=None, tree='SOURCE_ROOT', create_build_files=True, weak=False): - for obj in self.objects.values() : - if 'path' in obj : + def add_file_if_doesnt_exist(self, f_path, parent=None, tree='SOURCE_ROOT', create_build_files=True, weak=False, ignore_unknown_type=True): + for obj in self.objects.values(): + if 'path' in obj: if self.path_leaf(f_path) == self.path_leaf(obj.get('path')): return [] - return self.add_file(f_path, parent, tree, create_build_files, weak) + return self.add_file(f_path, parent, tree, create_build_files, weak, ignore_unknown_type=ignore_unknown_type) - def add_file(self, f_path, parent=None, tree='SOURCE_ROOT', create_build_files=True, weak=False): + def add_file(self, f_path, parent=None, tree='SOURCE_ROOT', create_build_files=True, weak=False, ignore_unknown_type=True): results = [] - abs_path = '' if os.path.isabs(f_path): @@ -806,9 +814,10 @@ class XcodeProject(PBXDict): # assume it's an id parent = self.objects.get(parent, self.root_group) - file_ref = PBXFileReference.Create(f_path, tree) + file_ref = PBXFileReference.Create(f_path, tree, ignore_unknown_type=ignore_unknown_type) parent.add_child(file_ref) results.append(file_ref) + # create a build file for the file ref if file_ref.build_phase and create_build_files: phases = self.get_build_phases(file_ref.build_phase) @@ -819,16 +828,17 @@ class XcodeProject(PBXDict): phase.add_build_file(build_file) results.append(build_file) - if abs_path and tree == 'SOURCE_ROOT' and os.path.isfile(abs_path)\ - and file_ref.build_phase == 'PBXFrameworksBuildPhase': - library_path = os.path.join('$(SRCROOT)', os.path.split(f_path)[0]) - self.add_library_search_paths([library_path], recursive=False) + if abs_path and tree == 'SOURCE_ROOT' \ + and os.path.isfile(abs_path) \ + and file_ref.build_phase == 'PBXFrameworksBuildPhase': + library_path = os.path.join('$(SRCROOT)', os.path.split(f_path)[0]) + self.add_library_search_paths([library_path], recursive=False) - if abs_path and tree == 'SOURCE_ROOT' and not os.path.isfile(abs_path)\ - and file_ref.build_phase == 'PBXFrameworksBuildPhase': - - framework_path = os.path.join('$(SRCROOT)', os.path.split(f_path)[0]) - self.add_framework_search_paths([framework_path,'$(inherited)'], recursive=False) + if abs_path and tree == 'SOURCE_ROOT' \ + and not os.path.isfile(abs_path) \ + and file_ref.build_phase == 'PBXFrameworksBuildPhase': + framework_path = os.path.join('$(SRCROOT)', os.path.split(f_path)[0]) + self.add_framework_search_paths([framework_path, '$(inherited)'], recursive=False) for r in results: self.objects[r.id] = r @@ -839,23 +849,24 @@ class XcodeProject(PBXDict): return results def check_and_repair_framework(self, base): - name = os.path.basename(base); - if(".framework" in name): + name = os.path.basename(base) + + if ".framework" in name: basename = name[:-len(".framework")] - finalHeaders = os.path.join(base, "Headers"); - finalCurrent = os.path.join(base, "Versions/Current"); - finalLib = os.path.join(base, basename); - srcHeaders = "Versions/A/Headers"; - srcCurrent = "A"; - srcLib = "Versions/A/"+basename; + finalHeaders = os.path.join(base, "Headers") + finalCurrent = os.path.join(base, "Versions/Current") + finalLib = os.path.join(base, basename) + srcHeaders = "Versions/A/Headers" + srcCurrent = "A" + srcLib = "Versions/A/" + basename - if(not os.path.exists(finalHeaders)): - os.symlink(srcHeaders, finalHeaders); - if(not os.path.exists(finalCurrent)): - os.symlink(srcCurrent, finalCurrent); - if(not os.path.exists(finalLib)): - os.symlink(srcLib, finalLib); + if not os.path.exists(finalHeaders): + os.symlink(srcHeaders, finalHeaders) + if not os.path.exists(finalCurrent): + os.symlink(srcCurrent, finalCurrent) + if not os.path.exists(finalLib): + os.symlink(srcLib, finalLib) def remove_group(self, grp): pass @@ -886,7 +897,7 @@ class XcodeProject(PBXDict): print 'applying "%s" to "%s"' % (patch_path, xcode_path) - return subprocess.call(['patch', '-p1', '--forward', '--directory=%s'%xcode_path, '--input=%s'%patch_path]) + return subprocess.call(['patch', '-p1', '--forward', '--directory=%s' % xcode_path, '--input=%s' % patch_path]) def apply_mods(self, mod_dict, default_path=None): if not default_path: @@ -896,7 +907,6 @@ class XcodeProject(PBXDict): for k in keys: v = mod_dict.pop(k) - mod_dict[k.lower()] = v parent = mod_dict.pop('group', None) @@ -911,7 +921,7 @@ class XcodeProject(PBXDict): compiler_flags = mod_dict.pop('compiler_flags', {}) - for k,v in mod_dict.items(): + for k, v in mod_dict.items(): if k == 'patches': for p in v: if not os.path.isabs(p): @@ -958,7 +968,6 @@ class XcodeProject(PBXDict): continue p = self.get_relative_path(p) - paths.append(os.path.join('$(SRCROOT)', p, "**")) if k == 'headerpaths': @@ -985,7 +994,7 @@ class XcodeProject(PBXDict): file_path = os.path.join(default_path, p) search_path, file_name = os.path.split(file_path) - if [m for m in excludes if re.match(m,file_name)]: + if [m for m in excludes if re.match(m, file_name)]: continue try: @@ -997,10 +1006,10 @@ class XcodeProject(PBXDict): file_list = os.listdir(search_path) for f in file_list: - if [m for m in excludes if re.match(m,f)]: + if [m for m in excludes if re.match(m, f)]: continue - if re.search(expr,f): + if re.search(expr, f): kwds['name'] = f paths[os.path.join(search_path, f)] = kwds p = None @@ -1014,10 +1023,10 @@ class XcodeProject(PBXDict): kwds['name'] = file_name if k == 'libs': - p = os.path.join('usr','lib',p) + p = os.path.join('usr', 'lib', p) kwds['tree'] = 'SDKROOT' elif k == 'frameworks': - p = os.path.join('System','Library','Frameworks',p) + p = os.path.join('System', 'Library', 'Frameworks', p) kwds['tree'] = 'SDKROOT' elif k == 'files' and not os.path.exists(file_path): # don't add non-existent files to the project. @@ -1026,26 +1035,24 @@ class XcodeProject(PBXDict): paths[p] = kwds new_files = self.verify_files([n.get('name') for n in paths.values()]) - - add_files = [(k,v) for k,v in paths.items() if v.get('name') in new_files] + add_files = [(k, v) for k, v in paths.items() if v.get('name') in new_files] for path, kwds in add_files: kwds.pop('name', None) - if not kwds.has_key('parent') and parent: + if 'parent' not in kwds and parent: kwds['parent'] = parent self.add_file(path, **kwds) if compiler_flags: - for k,v in compiler_flags.items(): + for k, v in compiler_flags.items(): filerefs = [] for f in v: filerefs.extend([fr.id for fr in self.objects.values() if fr.get('isa') == 'PBXFileReference' and fr.get('name') == f]) - buildfiles = [bf for bf in self.objects.values() if bf.get('isa') == 'PBXBuildFile' and bf.get('fileRef') in filerefs] @@ -1053,48 +1060,54 @@ class XcodeProject(PBXDict): if bf.add_compiler_flag(k): self.modified = True - - def backup(self, file_name=None): + def backup(self, file_name=None, backup_name=None): if not file_name: file_name = self.pbxproj_path - backup_name = "%s.%s.backup" % (file_name, datetime.datetime.now().strftime('%d%m%y-%H%M%S')) + if not backup_name: + backup_name = "%s.%s.backup" % (file_name, datetime.datetime.now().strftime('%d%m%y-%H%M%S')) shutil.copy2(file_name, backup_name) - #old format def save(self, file_name=None): + """Saves in old (xml) format""" if not file_name: file_name = self.pbxproj_path - # JSON serialize the project and convert that json to an xml plist - p = subprocess.Popen([XcodeProject.plutil_path, '-convert', 'xml1', '-o', file_name, '-'], stdin=subprocess.PIPE) - p.communicate(PBXEncoder().encode(self.data)) + # This code is adapted from plistlib.writePlist + with open(file_name, "w") as f: + writer = PBXWriter(f) + writer.writeln("") + writer.writeValue(self.data) + writer.writeln("") - #save Xcode 3.2 compatible format def saveFormat3_2(self, file_name=None): + """Save in Xcode 3.2 compatible (new) format""" if not file_name: file_name = self.pbxproj_path - #process to get the section's info and names - objs = self.data.get('objects'); - sections = dict(); - uuids = dict(); + # process to get the section's info and names + objs = self.data.get('objects') + sections = dict() + uuids = dict() + for key in objs: - l = list(); + l = list() + if objs.get(key).get('isa') in sections: l = sections.get(objs.get(key).get('isa')) - l.append(tuple([key, objs.get(key)])) - sections[objs.get(key).get('isa')] = l; - if('name' in objs.get(key)): + l.append(tuple([key, objs.get(key)])) + sections[objs.get(key).get('isa')] = l + + if 'name' in objs.get(key): uuids[key] = objs.get(key).get('name') - elif('path' in objs.get(key)): + elif 'path' in objs.get(key): uuids[key] = objs.get(key).get('path') else: - if(objs.get(key).get('isa')=='PBXProject'): + if objs.get(key).get('isa') == 'PBXProject': uuids[objs.get(key).get('buildConfigurationList')] = 'Build configuration list for PBXProject "Unity-iPhone"' - elif(objs.get(key).get('isa')[0:3] == 'PBX'): + elif objs.get(key).get('isa')[0:3] == 'PBX': uuids[key] = objs.get(key).get('isa')[3:-10] else: uuids[key] = 'Build configuration list for PBXNativeTarget "TARGET_NAME"' @@ -1103,173 +1116,156 @@ class XcodeProject(PBXDict): uuids[ro] = 'Project Object' for key in objs: - #transitive references (used in the BuildFile section) - if('fileRef' in objs.get(key) and objs.get(key).get('fileRef') in uuids): + # transitive references (used in the BuildFile section) + if 'fileRef' in objs.get(key) and objs.get(key).get('fileRef') in uuids: uuids[key] = uuids[objs.get(key).get('fileRef')] - #transitive reference to the target name (used in the Native target section) - if(objs.get(key).get('isa') == 'PBXNativeTarget'): - uuids[objs.get(key).get('buildConfigurationList')] = uuids[objs.get(key).get('buildConfigurationList')].replace('TARGET_NAME',uuids[key]) - self.uuids = uuids; - self.sections = sections; + # transitive reference to the target name (used in the Native target section) + if objs.get(key).get('isa') == 'PBXNativeTarget': + uuids[objs.get(key).get('buildConfigurationList')] = uuids[objs.get(key).get('buildConfigurationList')].replace('TARGET_NAME', uuids[key]) - out = open(file_name,'w') - out.write('// !$*UTF8*$!\n'); + self.uuids = uuids + self.sections = sections + + out = open(file_name, 'w') + out.write('// !$*UTF8*$!\n') self._printNewXCodeFormat(out, self.data, '', enters=True) out.close() @classmethod - def addslashes(cls,s): - d = {'"':'\\"', "'":"\\'", "\0":"\\\0", "\\":"\\\\"} + def addslashes(cls, s): + d = {'"': '\\"', "'": "\\'", "\0": "\\\0", "\\": "\\\\"} return ''.join(d.get(c, c) for c in s) - def _printNewXCodeFormat(self, out, root, deep, enters = True): - if(isinstance(root,IterableUserDict)): + def _printNewXCodeFormat(self, out, root, deep, enters=True): + if isinstance(root, IterableUserDict): out.write('{') + if enters: out.write('\n') - isa = root.pop('isa','') - if(isa!=''): #keep the isa in the first spot + isa = root.pop('isa', '') + + if isa != '': # keep the isa in the first spot if enters: - out.write('\t'+deep) - out.write('isa = '); - self._printNewXCodeFormat(out,isa,'\t'+deep, enters=enters); + out.write('\t' + deep) + + out.write('isa = ') + self._printNewXCodeFormat(out, isa, '\t' + deep, enters=enters) out.write(';') + if enters: out.write('\n') else: - out.write(' '); + out.write(' ') - for key in sorted(root.iterkeys()): #keep the same order as Apple. + for key in sorted(root.iterkeys()): # keep the same order as Apple. if enters: - out.write('\t'+deep) + out.write('\t' + deep) - if re.match(regex,key).group(0) == key: - out.write(key+' = '); + if re.match(regex, key).group(0) == key: + out.write(key.encode("utf-8") + ' = ') else: - out.write('"'+key+'" = '); + out.write('"' + key.encode("utf-8") + '" = ') if key == 'objects': - out.write('{');#open the objects section + out.write('{') # open the objects section + if enters: out.write('\n') - #root.remove('objects') #remove it to avoid problems + #root.remove('objects') # remove it to avoid problems sections = [ - ('PBXBuildFile',False), - ('PBXCopyFilesBuildPhase',True), - ('PBXFileReference',False), - ('PBXFrameworksBuildPhase',True), - ('PBXGroup',True), - ('PBXNativeTarget',True), - ('PBXProject',True), - ('PBXResourcesBuildPhase',True), - ('PBXShellScriptBuildPhase',True), - ('PBXSourcesBuildPhase',True), - ('XCBuildConfiguration',True), - ('XCConfigurationList',True), + ('PBXBuildFile', False), + ('PBXCopyFilesBuildPhase', True), + ('PBXFileReference', False), + ('PBXFrameworksBuildPhase', True), + ('PBXGroup', True), + ('PBXNativeTarget', True), + ('PBXProject', True), + ('PBXResourcesBuildPhase', True), + ('PBXShellScriptBuildPhase', True), + ('PBXSourcesBuildPhase', True), + ('XCBuildConfiguration', True), + ('XCConfigurationList', True), ('PBXTargetDependency', True), ('PBXVariantGroup', True), ('PBXReferenceProxy', True), ('PBXContainerItemProxy', True)] - for section in sections: #iterate over the sections - if(self.sections.get(section[0]) == None): - continue; + for section in sections: # iterate over the sections + if self.sections.get(section[0]) is None: + continue - out.write('\n/* Begin %s section */'%section[0]); - self.sections.get(section[0]).sort(cmp=lambda x,y: cmp(x[0],y[0])) - #if(self.sections.get(section[0])=='PBXGroup' and ): //add the patch to add the missing but existing files. + out.write('\n/* Begin %s section */' % section[0].encode("utf-8")) + self.sections.get(section[0]).sort(cmp=lambda x, y: cmp(x[0], y[0])) for pair in self.sections.get(section[0]): key = pair[0] value = pair[1] out.write('\n') + if enters: - out.write('\t\t'+deep) - out.write(key); - if(key in self.uuids): - out.write(" /* "+self.uuids[key]+" */"); - out.write(" = "); - self._printNewXCodeFormat(out,value,'\t\t'+deep,enters=section[1]) + out.write('\t\t' + deep) + + out.write(key.encode("utf-8")) + + if key in self.uuids: + out.write(" /* " + self.uuids[key].encode("utf-8") + " */") + + out.write(" = ") + self._printNewXCodeFormat(out, value, '\t\t' + deep, enters=section[1]) out.write(';') - out.write('\n/* End %s section */\n'%section[0]) - out.write(deep+'\t}');#close of the objects section + + out.write('\n/* End %s section */\n' % section[0].encode("utf-8")) + + out.write(deep + '\t}') # close of the objects section else: - self._printNewXCodeFormat(out,root[key],'\t'+deep,enters=enters) + self._printNewXCodeFormat(out, root[key], '\t' + deep, enters=enters) out.write(';') + if enters: out.write('\n') else: out.write(' ') - root['isa']=isa; #restore the isa for further calls + + root['isa'] = isa # restore the isa for further calls if enters: out.write(deep) + out.write('}') - elif isinstance(root,UserList): + + elif isinstance(root, UserList): out.write('(') + if enters: out.write('\n') - for value in (root): + + for value in root: if enters: - out.write('\t'+deep) - self._printNewXCodeFormat(out,value,'\t'+deep,enters=enters) + out.write('\t' + deep) + + self._printNewXCodeFormat(out, value, '\t' + deep, enters=enters) out.write(',') + if enters: out.write('\n') + if enters: out.write(deep) + out.write(')') + else: - if len(root) > 0 and re.match(regex,root).group(0) == root: - out.write(root) + if len(root) > 0 and re.match(regex, root).group(0) == root: + out.write(root.encode("utf-8")) else: - out.write('"'+XcodeProject.addslashes(root)+'"') - if(root in self.uuids): - out.write(" /* "+self.uuids[root]+" */"); - - @classmethod - def getJSONFromXML(cls, root): - result = '' - if(root.nodeName == 'dict'): - result += '{' - i=0; - for child in root.childNodes: - if child.nodeType != Node.ELEMENT_NODE: - continue; - if(child.nodeName=='key' and i>0): - result +=',' - result += XcodeProject.getJSONFromXML(child); - i = i + 1 - result += '}' - elif root.nodeName == 'key': - for node in root.childNodes: - if node.nodeType == node.TEXT_NODE: - result += '"'+node.data+'":' - break - elif root.nodeName == 'array': - result += '[' - i=0; - for child in root.childNodes: - if child.nodeType != Node.ELEMENT_NODE: - continue; - - if(i>0): - result += "," - result += XcodeProject.getJSONFromXML(child); - i = i+1; - result += ']' - elif root.nodeName == 'string': - data = '""' - for node in root.childNodes: - if node.nodeType == node.TEXT_NODE: - data = '"'+XcodeProject.addslashes(node.data).replace('\n','\\n').replace('\\\'', '\'')+'"' - break - result += data - return result; + out.write('"' + XcodeProject.addslashes(root.encode("utf-8")) + '"') + + if root in self.uuids: + out.write(" /* " + self.uuids[root].encode("utf-8") + " */") @classmethod def Load(cls, path): @@ -1278,16 +1274,54 @@ class XcodeProject(PBXDict): if not os.path.isfile(XcodeProject.plutil_path): cls.plutil_path = 'plutil' - if subprocess.call([XcodeProject.plutil_path,'-lint','-s',path]): - print 'ERROR: not a valid .pbxproj file' + # load project by converting to xml and then convert that using plistlib + p = subprocess.Popen([XcodeProject.plutil_path, '-convert', 'xml1', '-o', '-', path], stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + + # If the plist was malformed, returncode will be non-zero + if p.returncode != 0: + print stdout return None - # load project by converting to JSON and parse - p = subprocess.Popen([XcodeProject.plutil_path, '-convert', 'xml1', '-o', '-', path], stdout=subprocess.PIPE) - rawXML = p.communicate()[0] - - xml = parseString(rawXML); - jsonStr = XcodeProject.getJSONFromXML(xml.getElementsByTagName('dict')[0]); - - tree = json.loads(jsonStr) + tree = plistlib.readPlistFromString(stdout) return XcodeProject(tree, path) + + +# The code below was adapted from plistlib.py. + +class PBXWriter(plistlib.PlistWriter): + def writeValue(self, value): + if isinstance(value, (PBXList, PBXDict)): + plistlib.PlistWriter.writeValue(self, value.data) + else: + plistlib.PlistWriter.writeValue(self, value) + + def simpleElement(self, element, value=None): + """ + We have to override this method to deal with Unicode text correctly. + Non-ascii characters have to get encoded as character references. + """ + if value is not None: + value = _escapeAndEncode(value) + self.writeln("<%s>%s" % (element, value, element)) + else: + self.writeln("<%s/>" % element) + + +# Regex to find any control chars, except for \t \n and \r +_controlCharPat = re.compile( + r"[\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f" + r"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f]") + + +def _escapeAndEncode(text): + m = _controlCharPat.search(text) + if m is not None: + raise ValueError("strings can't contains control characters; " + "use plistlib.Data instead") + text = text.replace("\r\n", "\n") # convert DOS line endings + text = text.replace("\r", "\n") # convert Mac line endings + text = text.replace("&", "&") # escape '&' + text = text.replace("<", "<") # escape '<' + text = text.replace(">", ">") # escape '>' + return text.encode("ascii", "xmlcharrefreplace") # encode as ascii with xml character references diff --git a/Tools/XcodeCapp/XcodeCapp/Scripts/pbxprojModifier.py b/Tools/XcodeCapp/XcodeCapp/Scripts/pbxprojModifier.py index dabf75448..cdedb9544 100755 --- a/Tools/XcodeCapp/XcodeCapp/Scripts/pbxprojModifier.py +++ b/Tools/XcodeCapp/XcodeCapp/Scripts/pbxprojModifier.py @@ -9,7 +9,6 @@ class PBXModifier (object): XCODE_SUPPORT_FOLDER = u".XcodeSupport" SLASH_REPLACEMENT = u"∕" # DIVISION SLASH Unicode U+2215 - STRING_RE = re.compile(ur"^\s*(.*)\s*$", re.MULTILINE) FRAMEWORKS_RE = re.compile(ur"^(.+/Frameworks/(?:Debug|Source)/([^/]+))/.+$") XCC_GENERAL_INCLUDE = u"xcc_general_include.h" @@ -93,22 +92,6 @@ class PBXModifier (object): if fileRef: self.project.remove_file(fileRef) - def xml_converter(self, matchObj): - return "{0}".format(matchObj.group(1).encode("ascii", "xmlcharrefreplace")) - - def convert_unicode_to_xml(self): - """ - mod_pbxproj writes unicode data as utf-8, but since it's an xml plist - all non-ascii characters should be converted to xml character references. - So we do that as a post-processing phase. - """ - with open(self.pbxPath, 'rb') as f: - content = f.read().decode('utf-8') - - with open(self.pbxPath, "wb") as f: - content = self.STRING_RE.sub(self.xml_converter, content) - f.write(content) - def add_framework_resources(self, framework, resourcesPath): files = self.project.get_files_by_os_path(resourcesPath, tree="") @@ -186,9 +169,9 @@ class PBXModifier (object): root_ids.insert(0, id) def save_project(self): + self.project.backup(backup_name=self.project.pbxproj_path + ".backup") self.sort_project() - self.project.save() - self.convert_unicode_to_xml() + self.project.saveFormat3_2() def update_project_with_source(self, action, projectSourcePath): relativePath = os.path.relpath(projectSourcePath, self.projectRootPath)