xcodeproj 0.3.5 → 0.4.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/xcodeproj +13 -0
- data/lib/xcodeproj.rb +13 -1
- data/lib/xcodeproj/command.rb +131 -0
- data/lib/xcodeproj/command/project_diff.rb +53 -0
- data/lib/xcodeproj/command/show.rb +35 -0
- data/lib/xcodeproj/command/target_diff.rb +43 -0
- data/lib/xcodeproj/config.rb +66 -38
- data/lib/xcodeproj/constants.rb +146 -0
- data/lib/xcodeproj/helper.rb +28 -0
- data/lib/xcodeproj/project.rb +462 -156
- data/lib/xcodeproj/project/object.rb +251 -138
- data/lib/xcodeproj/project/object/build_configuration.rb +27 -0
- data/lib/xcodeproj/project/object/build_file.rb +26 -0
- data/lib/xcodeproj/project/object/build_phase.rb +132 -61
- data/lib/xcodeproj/project/object/build_rule.rb +46 -0
- data/lib/xcodeproj/project/object/configuration_list.rb +47 -0
- data/lib/xcodeproj/project/object/container_item_proxy.rb +49 -0
- data/lib/xcodeproj/project/object/file_reference.rb +80 -48
- data/lib/xcodeproj/project/object/group.rb +213 -89
- data/lib/xcodeproj/project/object/native_target.rb +171 -114
- data/lib/xcodeproj/project/object/root_object.rb +66 -0
- data/lib/xcodeproj/project/object/target_dependency.rb +23 -0
- data/lib/xcodeproj/project/object_attributes.rb +382 -0
- data/lib/xcodeproj/project/object_list.rb +64 -118
- data/lib/xcodeproj/project/recursive_diff.rb +116 -0
- data/lib/xcodeproj/workspace.rb +56 -2
- metadata +38 -10
- data/lib/xcodeproj/project/association.rb +0 -54
- data/lib/xcodeproj/project/association/has_many.rb +0 -51
- data/lib/xcodeproj/project/association/has_one.rb +0 -39
- data/lib/xcodeproj/project/association/reflection.rb +0 -86
- data/lib/xcodeproj/project/object/configuration.rb +0 -97
@@ -0,0 +1,66 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
class Project
|
3
|
+
module Object
|
4
|
+
|
5
|
+
# This class represents the root object of a project document.
|
6
|
+
#
|
7
|
+
class PBXProject < AbstractObject
|
8
|
+
|
9
|
+
# @return [ObjectList<PBXNativeTarget>] a list of all the targets in
|
10
|
+
# the project.
|
11
|
+
#
|
12
|
+
has_many :targets, PBXNativeTarget
|
13
|
+
|
14
|
+
# @return [Hash{String => String}] attributes the attributes of the
|
15
|
+
# target.
|
16
|
+
#
|
17
|
+
# The hash might contain the following keys:
|
18
|
+
#
|
19
|
+
# - `CLASSPREFIX`
|
20
|
+
# - `LastUpgradeCheck`
|
21
|
+
# - `ORGANIZATIONNAME`
|
22
|
+
#
|
23
|
+
attribute :attributes, Hash, {'LastUpgradeCheck' => '0450'}
|
24
|
+
|
25
|
+
# @return [XCConfigurationList] the configuration list of the project.
|
26
|
+
#
|
27
|
+
has_one :build_configuration_list, XCConfigurationList
|
28
|
+
|
29
|
+
# @return [String] the compatibility version of the project.
|
30
|
+
#
|
31
|
+
attribute :compatibility_version, String, 'Xcode 3.2'
|
32
|
+
|
33
|
+
# @return [String] the development region of the project.
|
34
|
+
#
|
35
|
+
attribute :development_region, String, 'English'
|
36
|
+
|
37
|
+
# @return [String] whether the project has scanned for encodings.
|
38
|
+
#
|
39
|
+
attribute :has_scanned_for_encodings, String, '0'
|
40
|
+
|
41
|
+
# @return [Array<String>] the list of known regions.
|
42
|
+
#
|
43
|
+
attribute :known_regions, Array, ['en']
|
44
|
+
|
45
|
+
# @return [PBXGroup] the main group of the project. The one displayed
|
46
|
+
# by Xcode in the Project Navigator.
|
47
|
+
#
|
48
|
+
has_one :main_group, PBXGroup
|
49
|
+
|
50
|
+
# @return [PBXGroup] the group containing the references to products of
|
51
|
+
# the project.
|
52
|
+
#
|
53
|
+
has_one :product_ref_group, PBXGroup
|
54
|
+
|
55
|
+
# @return [String] the directory of the project.
|
56
|
+
#
|
57
|
+
attribute :project_dir_path, String
|
58
|
+
|
59
|
+
# @return [String] the root of the project.
|
60
|
+
#
|
61
|
+
attribute :project_root, String
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
class Project
|
3
|
+
module Object
|
4
|
+
|
5
|
+
# Represents a dependency of a target on another one.
|
6
|
+
#
|
7
|
+
class PBXTargetDependency < AbstractObject
|
8
|
+
|
9
|
+
# @return [PBXNativeTarget] the target that needs to be built to
|
10
|
+
# satisfy the dependency.
|
11
|
+
#
|
12
|
+
has_one :target, PBXNativeTarget
|
13
|
+
|
14
|
+
# @return [PBXContainerItemProxy] a proxy for the target that needs to
|
15
|
+
# be built. Apparently to support targets in other projects of the
|
16
|
+
# same workspace.
|
17
|
+
#
|
18
|
+
has_one :targetProxy, PBXContainerItemProxy
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,382 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
class Project
|
3
|
+
module Object
|
4
|
+
|
5
|
+
# This class represents an attribute of {AbstractObject} subclasses.
|
6
|
+
# Attributes are created by the {AbstractObject} DSL methods and allow to
|
7
|
+
# mirror the underlying attributes of the xcodeproj document model.
|
8
|
+
#
|
9
|
+
# Attributes provide support for runtime type checking. They also allow
|
10
|
+
# {AbstractObject} initialization and serialization to plist.
|
11
|
+
#
|
12
|
+
# @todo Add support for a list of required values so objects can be
|
13
|
+
# validated before serialization ?
|
14
|
+
#
|
15
|
+
class AbstractObjectAttribute
|
16
|
+
|
17
|
+
require 'active_support/inflector'
|
18
|
+
|
19
|
+
# @return [Symbol] the type of the attribute. It can be `:simple`,
|
20
|
+
# `:to_one`, `:to_many`.
|
21
|
+
#
|
22
|
+
attr_reader :type
|
23
|
+
|
24
|
+
# @return [Symbol] the name of the attribute.
|
25
|
+
#
|
26
|
+
attr_reader :name
|
27
|
+
|
28
|
+
# @return [Class] the class that owns the attribute.
|
29
|
+
#
|
30
|
+
attr_accessor :owner
|
31
|
+
|
32
|
+
# Creates a new attribute with the given type and name.
|
33
|
+
#
|
34
|
+
# Attributes are expected to be instantiated only by the
|
35
|
+
# {AbstractObject} DSL methods.
|
36
|
+
#
|
37
|
+
# @param [Symbol] type
|
38
|
+
# the type of the attribute.
|
39
|
+
#
|
40
|
+
# @param [Symbol] name
|
41
|
+
# the name of the attribute.
|
42
|
+
#
|
43
|
+
# @param [Class] owner
|
44
|
+
# the class that owns the attribute.
|
45
|
+
#
|
46
|
+
def initialize(type, name, owner)
|
47
|
+
@type = type
|
48
|
+
@name = name
|
49
|
+
@owner = owner
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return[String] The name of the attribute in camel case.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# attribute.new(:simple, project_root)
|
56
|
+
# attribute.plist_name #=> projectRoot
|
57
|
+
#
|
58
|
+
def plist_name
|
59
|
+
case name
|
60
|
+
when :remote_global_id_string
|
61
|
+
# `_id_` would become `Id`
|
62
|
+
'remoteGlobalIDString'
|
63
|
+
else
|
64
|
+
name.to_s.camelize(:lower)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Array<Class>] the list of the classes accepted by the
|
69
|
+
# attribute.
|
70
|
+
#
|
71
|
+
attr_accessor :classes
|
72
|
+
|
73
|
+
# @return [String, Array, Hash] the default value, if any, for simple
|
74
|
+
# attributes.
|
75
|
+
#
|
76
|
+
attr_accessor :default_value
|
77
|
+
|
78
|
+
# Convenience method that returns the value of this attribute for a
|
79
|
+
# given object.
|
80
|
+
#
|
81
|
+
# @param [AbstractObject] object
|
82
|
+
# the object for which the value of this attribute is requested.
|
83
|
+
#
|
84
|
+
# @return [String, Array, Hash, AbstractObject, ObjectList]
|
85
|
+
# the value.
|
86
|
+
#
|
87
|
+
def get_value(object)
|
88
|
+
object.send("#{name}")
|
89
|
+
end
|
90
|
+
|
91
|
+
# Convenience method that sets the value of this attribute for a
|
92
|
+
# given object. It makes sense only for `:simple` or `:to_one`
|
93
|
+
# attributes.
|
94
|
+
#
|
95
|
+
# @raise It the type of this attribute is `:to_many`.
|
96
|
+
#
|
97
|
+
# @param [AbstractObject] object
|
98
|
+
# the object for which to set the value.
|
99
|
+
#
|
100
|
+
# @param [String, Hash, Array, AbstractObject] new_value
|
101
|
+
# the value to set for the attribute.
|
102
|
+
#
|
103
|
+
# @return [void]
|
104
|
+
#
|
105
|
+
def set_value(object, new_value)
|
106
|
+
raise "[Xcodeproj] Set value called for to many attribute" if type == :to_many
|
107
|
+
object.send("#{name}=", new_value)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Convenience method that sets the value of this attribute for a
|
111
|
+
# given object to the default (if any). It makes sense only for
|
112
|
+
# `:simple` attributes.
|
113
|
+
#
|
114
|
+
# @param [AbstractObject] object
|
115
|
+
# the object for which to set the default value.
|
116
|
+
#
|
117
|
+
# @return [void]
|
118
|
+
#
|
119
|
+
def set_default(object)
|
120
|
+
raise "[Xcodeproj] Set value called for to many attribute" unless type == :simple
|
121
|
+
set_value(object, default_value) if default_value
|
122
|
+
end
|
123
|
+
|
124
|
+
# Checks that a given value is compatible with the attribute.
|
125
|
+
#
|
126
|
+
# This method powers the runtime type checking of the {AbstractObject}
|
127
|
+
# and is used its by synthesised methods.
|
128
|
+
#
|
129
|
+
# @raise If the class of the value is not compatible with the attribute.
|
130
|
+
#
|
131
|
+
# @return [void]
|
132
|
+
#
|
133
|
+
def validate_value(object)
|
134
|
+
return unless object
|
135
|
+
acceptable = classes.find { |klass| object.class == klass || object.class < klass }
|
136
|
+
if type == :simple
|
137
|
+
raise "[Xcodeproj] Type checking error: '#{owner.isa}' expected '#{classes.inspect}' got '#{object.class}' for attribute: #{inspect}" unless acceptable
|
138
|
+
else
|
139
|
+
raise "[Xcodeproj] Type checking error: '#{owner.isa}' expected #{classes.map(&:isa)} got #{object.isa} for attribute: #{inspect}" unless acceptable
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def inspect
|
144
|
+
"#<name: '#{name}', type: '#{type}', classes: '#{classes}', owner class: '#{owner.isa}'>"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class AbstractObject
|
149
|
+
|
150
|
+
# The {AbstractObject} DSL methods allow to specify with fidelity the
|
151
|
+
# underlying model of the xcodeproj document format. {AbstractObject}
|
152
|
+
# subclasses should specify their attributes through the following
|
153
|
+
# methods:
|
154
|
+
#
|
155
|
+
# - `{AbstractObject.attribute}`
|
156
|
+
# - `{AbstractObject.has_one}`
|
157
|
+
# - `{AbstractObject.has_many}`
|
158
|
+
#
|
159
|
+
# The subclasses should not interfere with the methods synthesised by
|
160
|
+
# the DSL and should only implement convenience methods in top of them.
|
161
|
+
#
|
162
|
+
# Attributes are typed and are validated at runtime.
|
163
|
+
#
|
164
|
+
class << self
|
165
|
+
|
166
|
+
# @return [Array<AbstractObjectAttribute>] the attributes associated
|
167
|
+
# with the class.
|
168
|
+
#
|
169
|
+
# @note It includes the attributes defined in the superclass and the
|
170
|
+
# list is cleaned for duplicates. Subclasses should not duplicate
|
171
|
+
# an attribute of the superclass but for the method implementation
|
172
|
+
# they will duplicate them.
|
173
|
+
#
|
174
|
+
def attributes
|
175
|
+
unless @full_attributes
|
176
|
+
attributes = @attributes || []
|
177
|
+
super_attributes = superclass.respond_to?(:attributes) ? superclass.attributes : []
|
178
|
+
# The uniqueness of the attributes is very important because the
|
179
|
+
# initialization from plist deletes the values from the dictionary.
|
180
|
+
@full_attributes = attributes.concat(super_attributes).uniq
|
181
|
+
end
|
182
|
+
@full_attributes
|
183
|
+
end
|
184
|
+
|
185
|
+
# @return [Array<AbstractObjectAttribute>] the simple attributes
|
186
|
+
# associated with with the class.
|
187
|
+
#
|
188
|
+
def simple_attributes
|
189
|
+
@simple_attributes ||= attributes.select { |a| a.type == :simple }
|
190
|
+
end
|
191
|
+
|
192
|
+
# @return [Array<AbstractObjectAttribute>] the attributes
|
193
|
+
# representing a to one relationship associated with with the
|
194
|
+
# class.
|
195
|
+
#
|
196
|
+
def to_one_attributes
|
197
|
+
@to_one_attributes ||= attributes.select { |a| a.type == :to_one }
|
198
|
+
end
|
199
|
+
|
200
|
+
# @return [Array<AbstractObjectAttribute>] the attributes
|
201
|
+
# representing a to many relationship associated with with the
|
202
|
+
# class.
|
203
|
+
#
|
204
|
+
def to_many_attributes
|
205
|
+
@to_many_attributes ||= attributes.select { |a| a.type == :to_many }
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
|
210
|
+
# Defines a new simple attribute and synthesises the corresponding
|
211
|
+
# methods.
|
212
|
+
#
|
213
|
+
# @note Simple attributes are directly stored in a hash. They can
|
214
|
+
# contain only a string, array of strings or a hash containing
|
215
|
+
# strings and thus they are not affected by reference counting.
|
216
|
+
# Clients can access the hash directly through the
|
217
|
+
# {AbstractObject#simple_attributes_hash} method.
|
218
|
+
#
|
219
|
+
# @param [Symbol] name
|
220
|
+
# the name of the attribute.
|
221
|
+
#
|
222
|
+
# @param [Class] klass
|
223
|
+
# the accepted {Class} for the values of the attribute.
|
224
|
+
#
|
225
|
+
# @param [String, Array<String>, Hash{String=>String}] default_value
|
226
|
+
# the default value for new objects.
|
227
|
+
#
|
228
|
+
# @example
|
229
|
+
# attribute project_root
|
230
|
+
# #=> leads to the creation of the following methods
|
231
|
+
#
|
232
|
+
# def project_root
|
233
|
+
# @simple_attributes_hash[projectRoot]
|
234
|
+
# end
|
235
|
+
#
|
236
|
+
# def project_root=(value)
|
237
|
+
# attribute.validate_value(value)
|
238
|
+
# @simple_attributes_hash[projectRoot] = value
|
239
|
+
# end
|
240
|
+
#
|
241
|
+
# @macro [attach] attribute
|
242
|
+
# @!attribute [rw] $1
|
243
|
+
#
|
244
|
+
def attribute(name, klass, default_value = nil)
|
245
|
+
attrb = AbstractObjectAttribute.new(:simple, name, self)
|
246
|
+
attrb.classes = [klass]
|
247
|
+
attrb.default_value = default_value
|
248
|
+
add_attribute(attrb)
|
249
|
+
|
250
|
+
define_method(attrb.name) do
|
251
|
+
@simple_attributes_hash ||= {}
|
252
|
+
@simple_attributes_hash[attrb.plist_name]
|
253
|
+
end
|
254
|
+
|
255
|
+
define_method("#{attrb.name}=") do |value|
|
256
|
+
@simple_attributes_hash ||= {}
|
257
|
+
attrb.validate_value(value)
|
258
|
+
@simple_attributes_hash[attrb.plist_name] = value
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Defines a new relationship to a single and synthesises the
|
263
|
+
# corresponding methods.
|
264
|
+
#
|
265
|
+
# @note The synthesised setter takes care of handling reference
|
266
|
+
# counting directly.
|
267
|
+
#
|
268
|
+
# @param [String] singular_name
|
269
|
+
# the name of the relationship.
|
270
|
+
#
|
271
|
+
# @param [Class, Array<Class>] isas
|
272
|
+
# the list of the classes corresponding to the accepted isas for
|
273
|
+
# this relationship.
|
274
|
+
#
|
275
|
+
# @macro [attach] has_one
|
276
|
+
# @!attribute [rw] $1
|
277
|
+
#
|
278
|
+
def has_one(singular_name, isas)
|
279
|
+
isas = [isas] unless isas.is_a?(Array)
|
280
|
+
attrb = AbstractObjectAttribute.new(:to_one, singular_name, self)
|
281
|
+
attrb.classes = isas
|
282
|
+
add_attribute(attrb)
|
283
|
+
|
284
|
+
attr_reader(attrb.name)
|
285
|
+
|
286
|
+
define_method("#{attrb.name}=") do |value|
|
287
|
+
attrb.validate_value(value)
|
288
|
+
|
289
|
+
previous_value = send(attrb.name)
|
290
|
+
previous_value.remove_referrer(self) if previous_value
|
291
|
+
instance_variable_set("@#{attrb.name}", value)
|
292
|
+
value.add_referrer(self) if value
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# Defines a new ordered relationship to many.
|
297
|
+
#
|
298
|
+
# @note This attribute only generates the reader method. Clients are
|
299
|
+
# not supposed to create {ObjectList} objects which are created
|
300
|
+
# by the methods synthesised by this attribute on demand.
|
301
|
+
# Clients, however can mutate the list according to its
|
302
|
+
# interface. The list is responsible to manage the reference
|
303
|
+
# counting for its values.
|
304
|
+
#
|
305
|
+
# @param [String] plural_name
|
306
|
+
# the name of the relationship.
|
307
|
+
#
|
308
|
+
# @param [Class, Array<Class>] isas
|
309
|
+
# the list of the classes corresponding to the accepted isas for
|
310
|
+
# this relationship.
|
311
|
+
#
|
312
|
+
# @macro [attach] has_many
|
313
|
+
# @!attribute [r] $1
|
314
|
+
#
|
315
|
+
def has_many(plural_name, isas)
|
316
|
+
isas = [isas] unless isas.is_a?(Array)
|
317
|
+
|
318
|
+
attrb = AbstractObjectAttribute.new(:to_many, plural_name, self)
|
319
|
+
attrb.classes = isas
|
320
|
+
add_attribute(attrb)
|
321
|
+
|
322
|
+
define_method(attrb.name) do
|
323
|
+
# Here we are in the context of the instance
|
324
|
+
list = instance_variable_get("@#{attrb.name}")
|
325
|
+
unless list
|
326
|
+
list = ObjectList.new(attrb, self)
|
327
|
+
instance_variable_set("@#{attrb.name}", list)
|
328
|
+
end
|
329
|
+
list
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
protected
|
334
|
+
|
335
|
+
# Adds an attribute to the list of attributes of the class.
|
336
|
+
#
|
337
|
+
# @note This method is intended to be invoked only by the
|
338
|
+
# {AbstractObject} meta programming methods
|
339
|
+
#
|
340
|
+
# @return [void]
|
341
|
+
#
|
342
|
+
def add_attribute(attribute)
|
343
|
+
raise "[Xcodeproj] BUG - missing classes for #{attribute.inspect}" unless attribute.classes
|
344
|
+
raise "[Xcodeproj] BUG - classes:#{attribute.classes} for #{attribute.inspect}" unless attribute.classes.all? { |klass| klass.is_a?(Class) }
|
345
|
+
@attributes ||= []
|
346
|
+
@attributes << attribute
|
347
|
+
end
|
348
|
+
end # AbstractObject << self
|
349
|
+
|
350
|
+
# @return [Hash] the simple attributes hash.
|
351
|
+
#
|
352
|
+
attr_reader :simple_attributes_hash
|
353
|
+
|
354
|
+
# @!group xcodeproj format attributes
|
355
|
+
|
356
|
+
# @return (see AbstractObject.attributes)
|
357
|
+
#
|
358
|
+
def attributes
|
359
|
+
self.class.attributes
|
360
|
+
end
|
361
|
+
|
362
|
+
# @return (see AbstractObject.simple_attributes)
|
363
|
+
#
|
364
|
+
def simple_attributes
|
365
|
+
self.class.simple_attributes
|
366
|
+
end
|
367
|
+
|
368
|
+
# @return (see AbstractObject.to_one_attributes)
|
369
|
+
#
|
370
|
+
def to_one_attributes
|
371
|
+
self.class.to_one_attributes
|
372
|
+
end
|
373
|
+
|
374
|
+
# @return (see AbstractObject.to_many_attributes)
|
375
|
+
#
|
376
|
+
def to_many_attributes
|
377
|
+
self.class.to_many_attributes
|
378
|
+
end
|
379
|
+
end # AbstractObject
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|