xcodeproj 0.28.2 → 1.0.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/xcodeproj.rb +1 -1
- data/lib/xcodeproj/command/config_dump.rb +1 -1
- data/lib/xcodeproj/config.rb +14 -5
- data/lib/xcodeproj/config/other_linker_flags_parser.rb +5 -2
- data/lib/xcodeproj/constants.rb +57 -24
- data/lib/xcodeproj/differ.rb +2 -2
- data/lib/xcodeproj/gem_version.rb +1 -1
- data/lib/xcodeproj/plist.rb +89 -0
- data/lib/xcodeproj/plist/ffi.rb +119 -0
- data/lib/xcodeproj/plist/ffi/core_foundation.rb +441 -0
- data/lib/xcodeproj/plist/ffi/dev_tools_core.rb +186 -0
- data/lib/xcodeproj/plist/plist_gem.rb +27 -0
- data/lib/xcodeproj/project.rb +36 -12
- data/lib/xcodeproj/project/object.rb +15 -2
- data/lib/xcodeproj/project/object/group.rb +28 -0
- data/lib/xcodeproj/project/object/helpers/file_references_factory.rb +1 -1
- data/lib/xcodeproj/project/object/native_target.rb +26 -7
- data/lib/xcodeproj/project/object_attributes.rb +10 -0
- data/lib/xcodeproj/project/object_dictionary.rb +2 -0
- data/lib/xcodeproj/project/object_list.rb +12 -0
- data/lib/xcodeproj/project/uuid_generator.rb +1 -0
- data/lib/xcodeproj/scheme/build_action.rb +2 -1
- data/lib/xcodeproj/scheme/environment_variables.rb +170 -0
- data/lib/xcodeproj/scheme/launch_action.rb +16 -0
- data/lib/xcodeproj/scheme/test_action.rb +18 -0
- data/lib/xcodeproj/workspace.rb +125 -34
- data/lib/xcodeproj/workspace/group_reference.rb +64 -0
- metadata +19 -13
- data/lib/xcodeproj/plist_helper.rb +0 -758
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55e5e01727aa2cef3b7bc6e1682340c8b795adfd
|
4
|
+
data.tar.gz: df9be60720e81d807f9206ef7e1aac6bbf2f47f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e26720ad177f765056a554e514a9c4465aa94b4619fbd8947e0a221704926f8df605e8cc9a1a46c97e87dd4574023834e169144df4d0f4dce5e01460cfd937af
|
7
|
+
data.tar.gz: 72832c119af852d63ae64df30ebda2f7cb5090c83b57684b07b1cb57f3cd3686850c292dd2d66ece72c8ca3960ac54db87885aff33c0f60ea41df37e65da85fb
|
data/lib/xcodeproj.rb
CHANGED
@@ -20,7 +20,7 @@ module Xcodeproj
|
|
20
20
|
autoload :Constants, 'xcodeproj/constants'
|
21
21
|
autoload :Differ, 'xcodeproj/differ'
|
22
22
|
autoload :Helper, 'xcodeproj/helper'
|
23
|
-
autoload :
|
23
|
+
autoload :Plist, 'xcodeproj/plist'
|
24
24
|
autoload :Project, 'xcodeproj/project'
|
25
25
|
autoload :Workspace, 'xcodeproj/workspace'
|
26
26
|
autoload :XCScheme, 'xcodeproj/scheme'
|
data/lib/xcodeproj/config.rb
CHANGED
@@ -82,7 +82,7 @@ module Xcodeproj
|
|
82
82
|
def to_s(prefix = nil)
|
83
83
|
include_lines = includes.map { |path| "#include \"#{normalized_xcconfig_path(path)}\"" }
|
84
84
|
settings = to_hash(prefix).sort_by(&:first).map { |k, v| "#{k} = #{v}".strip }
|
85
|
-
|
85
|
+
(include_lines + settings).join("\n") << "\n"
|
86
86
|
end
|
87
87
|
|
88
88
|
# Writes the serialized representation of the internal data to the given
|
@@ -275,9 +275,17 @@ module Xcodeproj
|
|
275
275
|
#
|
276
276
|
def merge_attributes!(attributes)
|
277
277
|
@attributes.merge!(attributes) do |_, v1, v2|
|
278
|
-
v1
|
279
|
-
|
280
|
-
|
278
|
+
v1 = v1.strip
|
279
|
+
v2 = v2.strip
|
280
|
+
v1_split = v1.shellsplit
|
281
|
+
v2_split = v2.shellsplit
|
282
|
+
if (v2_split - v1_split).empty? || v1_split.first(v2_split.size) == v2_split
|
283
|
+
v1
|
284
|
+
elsif v2_split.first(v1_split.size) == v1_split
|
285
|
+
v2
|
286
|
+
else
|
287
|
+
"#{v1} #{v2}"
|
288
|
+
end
|
281
289
|
end
|
282
290
|
end
|
283
291
|
|
@@ -317,7 +325,8 @@ module Xcodeproj
|
|
317
325
|
def extract_key_value(line)
|
318
326
|
match = line.match(KEY_VALUE_PATTERN)
|
319
327
|
if match
|
320
|
-
key
|
328
|
+
key = match[1]
|
329
|
+
value = match[2]
|
321
330
|
[key.strip, value.strip]
|
322
331
|
else
|
323
332
|
[]
|
@@ -8,7 +8,7 @@ module Xcodeproj
|
|
8
8
|
# @return [Hash{Symbol, Array[String]}] Splits the given
|
9
9
|
# other linker flags value by type.
|
10
10
|
#
|
11
|
-
# @param [String] flags
|
11
|
+
# @param [String, Array] flags
|
12
12
|
# The other linker flags value.
|
13
13
|
#
|
14
14
|
def self.parse(flags)
|
@@ -21,7 +21,10 @@ module Xcodeproj
|
|
21
21
|
}
|
22
22
|
|
23
23
|
key = nil
|
24
|
-
|
24
|
+
if flags.is_a? String
|
25
|
+
flags = split(flags)
|
26
|
+
end
|
27
|
+
flags.each do |token|
|
25
28
|
case token
|
26
29
|
when '-framework'
|
27
30
|
key = :frameworks
|
data/lib/xcodeproj/constants.rb
CHANGED
@@ -4,17 +4,17 @@ module Xcodeproj
|
|
4
4
|
module Constants
|
5
5
|
# @return [String] The last known iOS SDK (stable).
|
6
6
|
#
|
7
|
-
LAST_KNOWN_IOS_SDK = '9.
|
7
|
+
LAST_KNOWN_IOS_SDK = '9.2'
|
8
8
|
|
9
9
|
# @return [String] The last known OS X SDK (stable).
|
10
10
|
#
|
11
|
-
LAST_KNOWN_OSX_SDK
|
11
|
+
LAST_KNOWN_OSX_SDK = '10.11'
|
12
12
|
|
13
|
-
# @return [String] The last known tvOS SDK (
|
14
|
-
LAST_KNOWN_TVOS_SDK = '9.
|
13
|
+
# @return [String] The last known tvOS SDK (stable).
|
14
|
+
LAST_KNOWN_TVOS_SDK = '9.1'
|
15
15
|
|
16
|
-
# @return [String] The last known watchOS SDK.
|
17
|
-
LAST_KNOWN_WATCHOS_SDK = '2.
|
16
|
+
# @return [String] The last known watchOS SDK (stable).
|
17
|
+
LAST_KNOWN_WATCHOS_SDK = '2.1'
|
18
18
|
|
19
19
|
# @return [String] The last known archive version to Xcodeproj.
|
20
20
|
#
|
@@ -25,15 +25,15 @@ module Xcodeproj
|
|
25
25
|
|
26
26
|
# @return [String] The last known object version to Xcodeproj.
|
27
27
|
#
|
28
|
-
LAST_KNOWN_OBJECT_VERSION
|
28
|
+
LAST_KNOWN_OBJECT_VERSION = 47
|
29
29
|
|
30
30
|
# @return [String] The last known object version to Xcodeproj.
|
31
31
|
#
|
32
|
-
LAST_UPGRADE_CHECK
|
32
|
+
LAST_UPGRADE_CHECK = '0700'
|
33
33
|
|
34
34
|
# @return [String] The last known object version to Xcodeproj.
|
35
35
|
#
|
36
|
-
LAST_SWIFT_UPGRADE_CHECK = '
|
36
|
+
LAST_SWIFT_UPGRADE_CHECK = '0720'
|
37
37
|
|
38
38
|
# @return [String] The version of `.xcscheme` files supported by Xcodeproj
|
39
39
|
#
|
@@ -119,6 +119,7 @@ module Xcodeproj
|
|
119
119
|
:watch2_app => 'com.apple.product-type.application.watchapp2',
|
120
120
|
:watch_extension => 'com.apple.product-type.watchkit-extension',
|
121
121
|
:watch2_extension => 'com.apple.product-type.watchkit2-extension',
|
122
|
+
:tv_extension => 'com.apple.product-type.tv-app-extension',
|
122
123
|
}.freeze
|
123
124
|
|
124
125
|
# @return [Hash] The extensions or the various product UTIs.
|
@@ -138,13 +139,16 @@ module Xcodeproj
|
|
138
139
|
#
|
139
140
|
COMMON_BUILD_SETTINGS = {
|
140
141
|
:all => {
|
141
|
-
'PRODUCT_NAME' => '$(TARGET_NAME)',
|
142
142
|
'ENABLE_STRICT_OBJC_MSGSEND' => 'YES',
|
143
|
+
'GCC_NO_COMMON_BLOCKS' => 'YES',
|
144
|
+
'PRODUCT_NAME' => '$(TARGET_NAME)',
|
143
145
|
}.freeze,
|
144
146
|
[:debug] => {
|
147
|
+
'DEBUG_INFORMATION_FORMAT' => 'dwarf',
|
145
148
|
'MTL_ENABLE_DEBUG_INFO' => 'YES',
|
146
149
|
}.freeze,
|
147
150
|
[:release] => {
|
151
|
+
'DEBUG_INFORMATION_FORMAT' => 'dwarf-with-dsym',
|
148
152
|
'MTL_ENABLE_DEBUG_INFO' => 'NO',
|
149
153
|
}.freeze,
|
150
154
|
[:ios] => {
|
@@ -163,23 +167,18 @@ module Xcodeproj
|
|
163
167
|
# Empty?
|
164
168
|
}.freeze,
|
165
169
|
[:release, :osx] => {
|
166
|
-
|
170
|
+
# Empty?
|
167
171
|
}.freeze,
|
168
172
|
[:debug, :ios] => {
|
169
173
|
# Empty?
|
170
174
|
}.freeze,
|
171
175
|
[:debug, :application, :swift] => {
|
172
176
|
'SWIFT_OPTIMIZATION_LEVEL' => '-Onone',
|
173
|
-
'ENABLE_TESTABILITY' => 'YES',
|
174
177
|
}.freeze,
|
175
|
-
[:debug, :
|
176
|
-
'
|
177
|
-
}.freeze,
|
178
|
-
[:debug, :framework, :swift] => {
|
179
|
-
'ENABLE_TESTABILITY' => 'YES',
|
178
|
+
[:debug, :swift] => {
|
179
|
+
'SWIFT_OPTIMIZATION_LEVEL' => '-Onone',
|
180
180
|
}.freeze,
|
181
181
|
[:debug, :static_library, :swift] => {
|
182
|
-
'ENABLE_TESTABILITY' => 'YES',
|
183
182
|
}.freeze,
|
184
183
|
[:framework] => {
|
185
184
|
'VERSION_INFO_PREFIX' => '',
|
@@ -200,25 +199,43 @@ module Xcodeproj
|
|
200
199
|
[:osx, :framework] => {
|
201
200
|
'LD_RUNPATH_SEARCH_PATHS' => ['$(inherited)', '@executable_path/../Frameworks', '@loader_path/Frameworks'],
|
202
201
|
'FRAMEWORK_VERSION' => 'A',
|
202
|
+
'CODE_SIGN_IDENTITY' => '-',
|
203
203
|
'COMBINE_HIDPI_IMAGES' => 'YES',
|
204
204
|
}.freeze,
|
205
|
+
[:watchos, :framework] => {
|
206
|
+
'APPLICATION_EXTENSION_API_ONLY' => 'YES',
|
207
|
+
'LD_RUNPATH_SEARCH_PATHS' => ['$(inherited)', '@executable_path/Frameworks', '@loader_path/Frameworks'],
|
208
|
+
'TARGETED_DEVICE_FAMILY' => '4',
|
209
|
+
}.freeze,
|
210
|
+
[:tvos, :framework] => {
|
211
|
+
'LD_RUNPATH_SEARCH_PATHS' => ['$(inherited)', '@executable_path/Frameworks', '@loader_path/Frameworks'],
|
212
|
+
'TARGETED_DEVICE_FAMILY' => '3',
|
213
|
+
}.freeze,
|
205
214
|
[:framework, :swift] => {
|
206
215
|
'DEFINES_MODULE' => 'YES',
|
207
216
|
}.freeze,
|
208
|
-
[:debug, :framework, :swift] => {
|
209
|
-
'SWIFT_OPTIMIZATION_LEVEL' => '-Onone',
|
210
|
-
}.freeze,
|
211
217
|
[:osx, :static_library] => {
|
218
|
+
'CODE_SIGN_IDENTITY' => '-',
|
212
219
|
'EXECUTABLE_PREFIX' => 'lib',
|
213
220
|
}.freeze,
|
214
221
|
[:ios, :static_library] => {
|
222
|
+
'CODE_SIGN_IDENTITY[sdk=iphoneos*]' => 'iPhone Developer',
|
223
|
+
'OTHER_LDFLAGS' => '-ObjC',
|
224
|
+
'SKIP_INSTALL' => 'YES',
|
225
|
+
}.freeze,
|
226
|
+
[:watchos, :static_library] => {
|
227
|
+
'OTHER_LDFLAGS' => '-ObjC',
|
228
|
+
'SKIP_INSTALL' => 'YES',
|
229
|
+
}.freeze,
|
230
|
+
[:tvos, :static_library] => {
|
215
231
|
'OTHER_LDFLAGS' => '-ObjC',
|
216
232
|
'SKIP_INSTALL' => 'YES',
|
217
233
|
}.freeze,
|
218
234
|
[:osx, :dynamic_library] => {
|
219
|
-
'
|
235
|
+
'CODE_SIGN_IDENTITY' => '-',
|
220
236
|
'DYLIB_COMPATIBILITY_VERSION' => '1',
|
221
237
|
'DYLIB_CURRENT_VERSION' => '1',
|
238
|
+
'EXECUTABLE_PREFIX' => 'lib',
|
222
239
|
}.freeze,
|
223
240
|
[:application] => {
|
224
241
|
'ASSETCATALOG_COMPILER_APPICON_NAME' => 'AppIcon',
|
@@ -226,12 +243,26 @@ module Xcodeproj
|
|
226
243
|
[:ios, :application] => {
|
227
244
|
'CODE_SIGN_IDENTITY[sdk=iphoneos*]' => 'iPhone Developer',
|
228
245
|
'LD_RUNPATH_SEARCH_PATHS' => ['$(inherited)', '@executable_path/Frameworks'],
|
246
|
+
'TARGETED_DEVICE_FAMILY' => '1,2',
|
229
247
|
}.freeze,
|
230
248
|
[:osx, :application] => {
|
231
249
|
'COMBINE_HIDPI_IMAGES' => 'YES',
|
232
250
|
'CODE_SIGN_IDENTITY' => '-',
|
233
251
|
'LD_RUNPATH_SEARCH_PATHS' => ['$(inherited)', '@executable_path/../Frameworks'],
|
234
252
|
}.freeze,
|
253
|
+
[:watchos, :application] => {
|
254
|
+
'SKIP_INSTALL' => 'YES',
|
255
|
+
'TARGETED_DEVICE_FAMILY' => '4',
|
256
|
+
}.freeze,
|
257
|
+
[:watchos, :application, :swift] => {
|
258
|
+
'EMBEDDED_CONTENT_CONTAINS_SWIFT' => 'YES',
|
259
|
+
}.freeze,
|
260
|
+
[:tvos, :application] => {
|
261
|
+
'ASSETCATALOG_COMPILER_APPICON_NAME' => 'App Icon & Top Shelf Image',
|
262
|
+
'ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME' => 'LaunchImage',
|
263
|
+
'TARGETED_DEVICE_FAMILY' => '3',
|
264
|
+
'LD_RUNPATH_SEARCH_PATHS' => ['$(inherited)', '@executable_path/Frameworks'],
|
265
|
+
}.freeze,
|
235
266
|
[:bundle] => {
|
236
267
|
'PRODUCT_NAME' => '$(TARGET_NAME)',
|
237
268
|
'WRAPPER_EXTENSION' => 'bundle',
|
@@ -241,9 +272,10 @@ module Xcodeproj
|
|
241
272
|
'SDKROOT' => 'iphoneos',
|
242
273
|
}.freeze,
|
243
274
|
[:osx, :bundle] => {
|
275
|
+
'CODE_SIGN_IDENTITY' => '-',
|
244
276
|
'COMBINE_HIDPI_IMAGES' => 'YES',
|
245
|
-
'SDKROOT' => 'macosx',
|
246
277
|
'INSTALL_PATH' => '$(LOCAL_LIBRARY_DIR)/Bundles',
|
278
|
+
'SDKROOT' => 'macosx',
|
247
279
|
}.freeze,
|
248
280
|
}.freeze
|
249
281
|
|
@@ -281,6 +313,7 @@ module Xcodeproj
|
|
281
313
|
:debug => {
|
282
314
|
'ONLY_ACTIVE_ARCH' => 'YES',
|
283
315
|
'COPY_PHASE_STRIP' => 'NO',
|
316
|
+
'ENABLE_TESTABILITY' => 'YES',
|
284
317
|
'GCC_DYNAMIC_NO_PIC' => 'NO',
|
285
318
|
'GCC_OPTIMIZATION_LEVEL' => '0',
|
286
319
|
'GCC_PREPROCESSOR_DEFINITIONS' => ['DEBUG=1', '$(inherited)'],
|
@@ -313,6 +346,6 @@ module Xcodeproj
|
|
313
346
|
|
314
347
|
# @return [Array] The extensions which are associated with header files.
|
315
348
|
#
|
316
|
-
HEADER_FILES_EXTENSIONS = %w(.h .hh .hpp .ipp .tpp).freeze
|
349
|
+
HEADER_FILES_EXTENSIONS = %w(.h .hh .hpp .ipp .tpp .hxx .def).freeze
|
317
350
|
end
|
318
351
|
end
|
data/lib/xcodeproj/differ.rb
CHANGED
@@ -43,8 +43,8 @@ module Xcodeproj
|
|
43
43
|
# @return [Nil] if the given values are equal.
|
44
44
|
#
|
45
45
|
def self.diff(value_1, value_2, options = {})
|
46
|
-
options[:key_1]
|
47
|
-
options[:key_2]
|
46
|
+
options[:key_1] ||= 'value_1'
|
47
|
+
options[:key_2] ||= 'value_2'
|
48
48
|
options[:id_key] ||= nil
|
49
49
|
|
50
50
|
if value_1.class == value_2.class
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
# Provides support for loading and serializing property list files.
|
3
|
+
#
|
4
|
+
module Plist
|
5
|
+
autoload :FFI, 'xcodeproj/plist/ffi'
|
6
|
+
autoload :PlistGem, 'xcodeproj/plist/plist_gem'
|
7
|
+
|
8
|
+
# @return [Hash] Returns the native objects loaded from a property list
|
9
|
+
# file.
|
10
|
+
#
|
11
|
+
# @param [#to_s] path
|
12
|
+
# The path of the file.
|
13
|
+
#
|
14
|
+
def self.read_from_path(path)
|
15
|
+
path = path.to_s
|
16
|
+
unless File.exist?(path)
|
17
|
+
raise Informative, "The plist file at path `#{path}` doesn't exist."
|
18
|
+
end
|
19
|
+
if file_in_conflict?(path)
|
20
|
+
raise Informative, "The file `#{path}` is in a merge conflict."
|
21
|
+
end
|
22
|
+
implementation.read_from_path(path)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Serializes a hash as an XML property list file.
|
26
|
+
#
|
27
|
+
# @param [#to_hash] hash
|
28
|
+
# The hash to store.
|
29
|
+
#
|
30
|
+
# @param [#to_s] path
|
31
|
+
# The path of the file.
|
32
|
+
#
|
33
|
+
def self.write_to_path(hash, path)
|
34
|
+
if hash.respond_to?(:to_hash)
|
35
|
+
hash = hash.to_hash
|
36
|
+
else
|
37
|
+
raise TypeError, "The given `#{hash.inspect}` must respond " \
|
38
|
+
"to #to_hash'."
|
39
|
+
end
|
40
|
+
|
41
|
+
unless path.is_a?(String) || path.is_a?(Pathname)
|
42
|
+
raise TypeError, "The given `#{path}` must be a string or 'pathname'."
|
43
|
+
end
|
44
|
+
path = path.to_s
|
45
|
+
raise IOError, 'Empty path.' if path.empty?
|
46
|
+
implementation.write_to_path(hash, path)
|
47
|
+
end
|
48
|
+
|
49
|
+
# The known modules that can serialize plists.
|
50
|
+
#
|
51
|
+
KNOWN_IMPLEMENTATIONS = [:FFI, :PlistGem]
|
52
|
+
|
53
|
+
class << self
|
54
|
+
# @return The module used to implement plist serialization.
|
55
|
+
#
|
56
|
+
attr_accessor :implementation
|
57
|
+
def implementation
|
58
|
+
@implementation ||= autoload_implementation
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Attempts to autoload a known plist implementation.
|
63
|
+
#
|
64
|
+
# @return a successfully loaded plist serialization implementation.
|
65
|
+
#
|
66
|
+
def self.autoload_implementation
|
67
|
+
failures = KNOWN_IMPLEMENTATIONS.map do |impl|
|
68
|
+
begin
|
69
|
+
impl = Plist.const_get(impl)
|
70
|
+
failure = impl.attempt_to_load!
|
71
|
+
return impl if failure.nil?
|
72
|
+
failure
|
73
|
+
rescue NameError, LoadError => e
|
74
|
+
e.message
|
75
|
+
end
|
76
|
+
end.compact
|
77
|
+
raise Informative, "Unable to load a plist implementation:\n\n#{failures.join("\n\n")}"
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Bool] Checks whether there are merge conflicts in the file.
|
81
|
+
#
|
82
|
+
# @param [#to_s] path
|
83
|
+
# The path of the file.
|
84
|
+
#
|
85
|
+
def self.file_in_conflict?(path)
|
86
|
+
File.read(path).match(/^(<|=|>){7}/)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
module Plist
|
3
|
+
# Provides support for loading and serializing property list files via
|
4
|
+
# Fiddle and CoreFoundation / Xcode.
|
5
|
+
#
|
6
|
+
module FFI
|
7
|
+
autoload :CoreFoundation, 'xcodeproj/plist/ffi/core_foundation'
|
8
|
+
autoload :DevToolsCore, 'xcodeproj/plist/ffi/dev_tools_core'
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Attempts to load the `fiddle` and Xcode based plist serializer.
|
12
|
+
#
|
13
|
+
# @return [String,Nil] The loading error message, or `nil` if loading
|
14
|
+
# was successful.
|
15
|
+
#
|
16
|
+
def attempt_to_load!
|
17
|
+
return @attempt_to_load if defined?(@attempt_to_load)
|
18
|
+
@attempt_to_load = begin
|
19
|
+
require 'fiddle'
|
20
|
+
nil
|
21
|
+
rescue LoadError
|
22
|
+
'Xcodeproj relies on a library called `fiddle` to read and write ' \
|
23
|
+
'Xcode project files. Ensure your Ruby installation includes ' \
|
24
|
+
'`fiddle` and try again.'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Serializes a hash as an XML property list file.
|
29
|
+
#
|
30
|
+
# @param [#to_hash] hash
|
31
|
+
# The hash to store.
|
32
|
+
#
|
33
|
+
# @param [#to_s] path
|
34
|
+
# The path of the file.
|
35
|
+
#
|
36
|
+
def write_to_path(hash, path)
|
37
|
+
raise ThreadError, 'Can only write plists from the main thread.' unless Thread.current == Thread.main
|
38
|
+
|
39
|
+
if DevToolsCore.load_xcode_frameworks && path.end_with?('pbxproj')
|
40
|
+
ruby_hash_write_xcode(hash, path)
|
41
|
+
else
|
42
|
+
CoreFoundation.RubyHashPropertyListWrite(hash, path)
|
43
|
+
fix_encoding(path)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Hash] Returns the native objects loaded from a property list
|
48
|
+
# file.
|
49
|
+
#
|
50
|
+
# @param [#to_s] path
|
51
|
+
# The path of the file.
|
52
|
+
#
|
53
|
+
def read_from_path(path)
|
54
|
+
CoreFoundation.RubyHashPropertyListRead(path)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Simple workaround to escape characters which are outside of ASCII
|
60
|
+
# character-encoding. Relies on the fact that there are no XML characters
|
61
|
+
# which would need to be escaped.
|
62
|
+
#
|
63
|
+
# @note This is necessary because Xcode (4.6 currently) uses the MacRoman
|
64
|
+
# encoding unless the `// !$*UTF8*$!` magic comment is present. It
|
65
|
+
# is not possible to serialize a plist using the NeXTSTEP format
|
66
|
+
# without access to the private classes of Xcode and that comment
|
67
|
+
# is not compatible with the XML format. For the complete
|
68
|
+
# discussion see CocoaPods/CocoaPods#926.
|
69
|
+
#
|
70
|
+
#
|
71
|
+
# @note Sadly this hack is not sufficient for supporting Emoji.
|
72
|
+
#
|
73
|
+
# @param [String, Pathname] The path of the file which needs to be fixed.
|
74
|
+
#
|
75
|
+
# @return [void]
|
76
|
+
#
|
77
|
+
def fix_encoding(filename)
|
78
|
+
output = ''
|
79
|
+
input = File.open(filename, 'rb', &:read)
|
80
|
+
input.unpack('U*').each do |codepoint|
|
81
|
+
if codepoint > 127 # ASCII is 7-bit, so 0-127 are valid characters
|
82
|
+
output << "&##{codepoint};"
|
83
|
+
else
|
84
|
+
output << codepoint.chr
|
85
|
+
end
|
86
|
+
end
|
87
|
+
File.open(filename, 'wb') { |file| file.write(output) }
|
88
|
+
end
|
89
|
+
|
90
|
+
# Serializes a hash as an ASCII plist, using Xcode.
|
91
|
+
#
|
92
|
+
# @param [Hash] hash
|
93
|
+
# The hash to store.
|
94
|
+
#
|
95
|
+
# @param [String] path
|
96
|
+
# The path of the file.
|
97
|
+
#
|
98
|
+
def ruby_hash_write_xcode(hash, path)
|
99
|
+
path = File.expand_path(path)
|
100
|
+
success = true
|
101
|
+
|
102
|
+
begin
|
103
|
+
plist = DevToolsCore::CFDictionary.new(CoreFoundation.RubyHashToCFDictionary(hash))
|
104
|
+
data = DevToolsCore::NSData.new(plist.plistDescriptionUTF8Data)
|
105
|
+
success &= data.writeToFileAtomically(path)
|
106
|
+
|
107
|
+
project = DevToolsCore::PBXProject.new(path)
|
108
|
+
success &= project.writeToFileSystemProjectFile
|
109
|
+
project.close
|
110
|
+
rescue Fiddle::DLError
|
111
|
+
success = false
|
112
|
+
end
|
113
|
+
|
114
|
+
CoreFoundation.RubyHashPropertyListWrite(hash, path) unless success
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|