-
Notifications
You must be signed in to change notification settings - Fork 0
/
xcode_project.py
168 lines (124 loc) · 5.23 KB
/
xcode_project.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import plistlib
import subprocess
import os.path
class XCodeProjectReadException(Exception):
pass
class XCodeConfiguration(object):
@classmethod
def from_list(cls, configurations_dict, objects_dict):
configurations = {}
for configuration_id in configurations_dict['buildConfigurations']:
configuration = cls(objects_dict[configuration_id])
configurations[configuration.name] = configuration
return configurations
def __init__(self, configuration_dict=None):
self.name = ''
self.build_settings = {}
if configuration_dict:
self.set_from_dict(configuration_dict)
def set_from_dict(self, configuration_dict):
self.name = configuration_dict['name']
self.build_settings = configuration_dict['buildSettings']
class XCodeTarget(object):
def __init__(self, target_dict=None, objects_dict=None):
self.name = ''
self.product_name = ''
self.configurations = {}
if target_dict and objects_dict:
self.set_from_dict(target_dict, objects_dict)
def set_from_dict(self, target_dict, objects_dict):
self.name = target_dict['name']
self.product_name = target_dict['productName']
configurations_dict = objects_dict[
target_dict['buildConfigurationList']
]
self.configurations = XCodeConfiguration.from_list(
configurations_dict, objects_dict
)
def get_build_setting(self, setting, configuration='Release'):
build_settings = self.configurations.get(
configuration, XCodeConfiguration()
).build_settings
return build_settings.get(setting, None)
class XCodeProject(object):
def __init__(self, project_file_path=None):
self.configurations = {}
self.targets = {}
if project_file_path:
self.set_from_project_file(project_file_path)
def set_from_project_file(self, project_file_path):
pbxproj_file_path = os.path.join(project_file_path, 'project.pbxproj')
if not os.path.exists(pbxproj_file_path):
raise XCodeProjectReadException(
'Could not find the XCode project file: %s does not exist' %
pbxproj_file_path
)
arguments = 'plutil -convert xml1 -o -'.split(' ')
arguments.append(pbxproj_file_path)
process = subprocess.Popen(arguments, stdout=subprocess.PIPE)
stdoutdata = process.communicate()[0]
if process.returncode != 0:
raise XCodeProjectReadException(
'Could not read the project file: %s' % stdoutdata
)
objects_dict = plistlib.readPlistFromString(stdoutdata)['objects']
for item_dict in objects_dict.itervalues():
isa = item_dict['isa']
if isa == 'PBXNativeTarget':
target = XCodeTarget(item_dict, objects_dict)
self.targets[target.name] = target
if isa in ('PBXProject'):
configurations_dict = objects_dict[
item_dict['buildConfigurationList']
]
self.configurations = XCodeConfiguration.from_list(
configurations_dict, objects_dict
)
def get_build_setting(self, setting, configuration='Release', target=None):
build_settings = self.configurations.get(
configuration, XCodeConfiguration()
).build_settings
value = build_settings.get(setting, None)
if not target or value:
return value
else:
target = self.targets.get(target, XCodeTarget())
return target.get_build_setting(setting, configuration)
def main():
logging.basicConfig(format='%(message)s', level=logging.DEBUG)
if len(sys.argv) < 2:
logging.error('Please specify an XCode project file')
logging.error('usage: %s app.xcodeproj', sys.argv[0])
return 1
project_file_path = sys.argv[1]
logging.info('Scanning file %s', project_file_path)
try:
project = XCodeProject(project_file_path)
except XCodeProjectReadException, exc:
logging.error(exc)
return 2
logging.debug('Project settings:')
for configuration in project.configurations.itervalues():
logging.debug(' * %s:', configuration.name)
for key, value in configuration.build_settings.iteritems():
logging.debug(' > %s = %s', key, value)
for target in project.targets.itervalues():
logging.debug('Target %s (%s):', target.name, target.product_name)
for configuration in target.configurations.itervalues():
logging.debug(' * %s:', configuration.name)
for key, value in configuration.build_settings.iteritems():
logging.debug(' > %s = %s', key, value)
first_target_name = project.targets.iterkeys().next()
logging.debug(
'%s Info.plist file: %s',
first_target_name,
project.get_build_setting('INFOPLIST_FILE', target=first_target_name)
)
logging.debug('Main SDK: %s', project.get_build_setting('SDKROOT'))
return 0
if __name__ == '__main__':
import logging
import sys
sys.exit(main())