xcodeproj 0.28.2 → 1.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|