xcodeproj 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 58c9efc19e5ebe6d1e236953a4ba523bd76284aa
4
- data.tar.gz: 265bccb8aef4feda776f3161a2b7144d04092199
3
+ metadata.gz: 06c48b7bd46aeb7eb795a2ec7ec6e5ae9df37873
4
+ data.tar.gz: 61e02524ef77d19d327a31a198823db5f2c8a8ee
5
5
  SHA512:
6
- metadata.gz: 2f600fece068a72b186a2e4fbe2a62a96129256cd7c4356d1fce4e945ac2150e5f646acaae768fc534d968b5426a440e5dd0b245aaa473bffa853fc3e1eaa154
7
- data.tar.gz: 0d36f633574ac627ed5737ebd6f963c2918f68fbf1afbd26d4b20e9f4e2989326aa548add0c3fa1910b1bbdeb55f9b4dcdd8dab45d7eabc8a51aa5c09c155aff
6
+ metadata.gz: 6d3bcde97af5710149529b4225a666a45ad092f1525e610f07930ff8e48bfd032034f58dce7462fe4c2b3e34618a5400c9fad9d96443121b9e85e2dfdc8c6a29
7
+ data.tar.gz: a703e835b631554b38738a1ec248f6fb9e25c29dc07b58f54f576569a7f1ce939bed45b4709919b336b72a357893df7ef27c6913541b778af072175f603e0f96
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Xcodeproj
2
2
 
3
- [![Build Status](https://travis-ci.org/CocoaPods/Xcodeproj.svg?branch=master)](https://travis-ci.org/CocoaPods/Xcodeproj)
4
- [![Coverage Status](https://img.shields.io/coveralls/CocoaPods/Xcodeproj.svg)](https://coveralls.io/r/CocoaPods/Xcodeproj)
5
- [![Code Climate](https://img.shields.io/codeclimate/github/CocoaPods/Xcodeproj.svg)](https://codeclimate.com/github/CocoaPods/Xcodeproj)
3
+ [![Build Status](https://img.shields.io/travis/CocoaPods/Xcodeproj/master.svg?style=flat)](https://travis-ci.org/CocoaPods/Xcodeproj)
4
+ [![Coverage](https://img.shields.io/codeclimate/coverage/github/CocoaPods/Xcodeproj.svg?style=flat)](https://codeclimate.com/github/CocoaPods/Xcodeproj)
5
+ [![Code Climate](https://img.shields.io/codeclimate/github/CocoaPods/Xcodeproj.svg?style=flat)](https://codeclimate.com/github/CocoaPods/Xcodeproj)
6
6
 
7
7
  Xcodeproj lets you create and modify Xcode projects from [Ruby][ruby].
8
8
  Script boring management tasks or build Xcode-friendly libraries. Also includes
@@ -39,4 +39,4 @@ for more info.
39
39
  [ruby]: http://www.ruby-lang.org/en/
40
40
  [xcodeproj]: https://github.com/cocoapods/xcodeproj
41
41
  [tickets]: https://github.com/cocoapods/xcodeproj/issues
42
- [license]: xcodeproj/blob/master/LICENSE
42
+ [license]: LICENSE
data/lib/xcodeproj.rb CHANGED
@@ -16,15 +16,19 @@ module Xcodeproj
16
16
  autoload :Constants, 'xcodeproj/constants'
17
17
  autoload :Differ, 'xcodeproj/differ'
18
18
  autoload :Helper, 'xcodeproj/helper'
19
+ autoload :PlistHelper, 'xcodeproj/plist_helper'
19
20
  autoload :Project, 'xcodeproj/project'
20
21
  autoload :Workspace, 'xcodeproj/workspace'
21
22
  autoload :XCScheme, 'xcodeproj/scheme'
22
23
  autoload :XcodebuildHelper, 'xcodeproj/xcodebuild_helper'
23
- end
24
24
 
25
- # TODO It appears that loading the C ext from xcodeproj/project while it's
26
- # being autoloaded doesn't actually define the singleton methods. Ruby bug?
27
- #
28
- # This leads to `NoMethodError: undefined method write_plist for Xcodeproj:Module`
29
- # working around it by always loading the ext ASAP.
30
- require 'xcodeproj/ext'
25
+
26
+ # TODO: Delete me (compatibility with CocoaPods 0.33.1)
27
+ def self.read_plist(path)
28
+ PlistHelper.read(path)
29
+ end
30
+
31
+ def self.write_plist(hash, path)
32
+ PlistHelper.write(hash, path)
33
+ end
34
+ end
@@ -57,7 +57,7 @@ module Xcodeproj
57
57
  # ['--silent', 'Print nothing'],
58
58
  # ['--no-color', 'Print output without color'],
59
59
  # ['--verbose', 'Print more information while working'],
60
- ['--version', 'Prints the version of CocoaPods'],
60
+ ['--version', 'Prints the version of Xcodeproj'],
61
61
  ]
62
62
  end
63
63
 
@@ -81,9 +81,11 @@ module Xcodeproj
81
81
  'xcdatamodel' => 'wrapper.xcdatamodel',
82
82
  'xib' => 'file.xib',
83
83
  'sh' => 'text.script.sh',
84
+ 'swift' => 'sourcecode.swift',
84
85
  'plist' => 'text.plist.xml',
85
86
  'markdown' => 'text',
86
- 'xcassets' => 'folder.assetcatalog'
87
+ 'xcassets' => 'folder.assetcatalog',
88
+ 'xctest' => 'wrapper.cfbundle'
87
89
  }.freeze
88
90
 
89
91
  # @return [Hash] The uniform type identifier of various product types.
@@ -111,13 +113,11 @@ module Xcodeproj
111
113
  #
112
114
  COMMON_BUILD_SETTINGS = {
113
115
  :all => {
114
- 'GCC_VERSION' => 'com.apple.compilers.llvm.clang.1_0',
115
116
  'GCC_PRECOMPILE_PREFIX_HEADER' => 'YES',
116
117
  'PRODUCT_NAME' => '$(TARGET_NAME)',
117
118
  'SKIP_INSTALL' => 'YES',
118
119
  'DSTROOT' => '/tmp/xcodeproj.dst',
119
120
  'ALWAYS_SEARCH_USER_PATHS' => 'NO',
120
- 'GCC_C_LANGUAGE_STANDARD' => 'gnu99',
121
121
  'INSTALL_PATH' => "$(BUILT_PRODUCTS_DIR)",
122
122
  'OTHER_LDFLAGS' => '',
123
123
  'COPY_PHASE_STRIP' => 'YES',
data/lib/xcodeproj/ext.rb CHANGED
@@ -1,7 +1 @@
1
- # In case a binary built for the current Ruby exists, use that, otherwise see
2
- # if a prebuilt binary exists for the current platform and Ruby version.
3
- begin
4
- require 'xcodeproj/xcodeproj_ext'
5
- rescue LoadError
6
- require "xcodeproj/prebuilt/#{RUBY_PLATFORM}-#{RUBY_VERSION}/xcodeproj_ext"
7
- end
1
+ # TODO: Delete me
@@ -1,6 +1,6 @@
1
1
  module Xcodeproj
2
2
  # The version of the xcodeproj gem.
3
3
  #
4
- VERSION = '0.17.0' unless defined? Xcodeproj::VERSION
4
+ VERSION = '0.18.0' unless defined? Xcodeproj::VERSION
5
5
  end
6
6
 
@@ -0,0 +1,96 @@
1
+ begin
2
+ require 'libxml'
3
+ rescue LoadError
4
+ Xcodeproj::UI.warn "Xcodeproj is using a fall back solution for parsing " \
5
+ "XML. To use a faster alternative install libxml:\n" \
6
+ "`$ gem install libxml-ruby`"
7
+ end
8
+ require 'cfpropertylist'
9
+
10
+ module Xcodeproj
11
+ # Provides support for loading and serializing property list files.
12
+ #
13
+ module PlistHelper
14
+ class << self
15
+ # Serializes a hash as an XML property list file.
16
+ #
17
+ # @param [#to_hash] hash
18
+ # The hash to store.
19
+ #
20
+ # @param [#to_s] path
21
+ # The path of the file.
22
+ #
23
+ def write(hash, path)
24
+ unless hash.is_a?(Hash)
25
+ if hash.respond_to?(:to_hash)
26
+ hash = hash.to_hash
27
+ else
28
+ raise TypeError, "The given `#{hash}`, must be a hash or " \
29
+ "respond to to_hash"
30
+ end
31
+ end
32
+ plist = CFPropertyList::List.new
33
+ options = { :convert_unknown_to_string => true }
34
+ plist.value = CFPropertyList.guess(hash, options)
35
+ plist.save(path, CFPropertyList::List::FORMAT_XML)
36
+ end
37
+
38
+ # @return [String] Returns the native objects loaded from a property list
39
+ # file.
40
+ #
41
+ # @param [#to_s] path
42
+ # The path of the file.
43
+ #
44
+ def read(path)
45
+ unless File.exist?(path)
46
+ raise ArgumentError, "The file `#{path}` doesn't exists"
47
+ end
48
+ xml = plist_xml_contents(path)
49
+ plist = CFPropertyList::List.new
50
+ plist.load_xml_str(xml)
51
+ CFPropertyList.native_types(plist.value)
52
+ end
53
+
54
+ private
55
+
56
+ # @!group Private Helpers
57
+ #-----------------------------------------------------------------------#
58
+
59
+ # @return [String] Returns the contents of a property list file with
60
+ # Converting it to XML using the `plutil` tool if needed and
61
+ # available.
62
+ #
63
+ # @param [#to_s] path
64
+ # The path of the file.
65
+ #
66
+ def plist_xml_contents(path)
67
+ contents = File.read(path)
68
+ if contents.include?('?xml')
69
+ contents
70
+ elsif plutil_available?
71
+ plutil_contents(path)
72
+ else
73
+ raise "Unable to convert the `#{path}` plist file to XML"
74
+ end
75
+ end
76
+
77
+ # @return [String] The contents of plist file normalized to XML via
78
+ # `plutil` tool.
79
+ #
80
+ # @param [#to_s] path
81
+ # The path of the file.
82
+ #
83
+ # @note This method was extracted to simplify testing.
84
+ #
85
+ def plutil_contents(path)
86
+ `plutil -convert xml1 "#{path}" -o -`
87
+ end
88
+
89
+ # @return [Bool] Whether the `plutil` tool is available.
90
+ #
91
+ def plutil_available?
92
+ system('which plutil > /dev/null 2>&1')
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,5 +1,6 @@
1
1
  require 'fileutils'
2
2
  require 'pathname'
3
+ require 'securerandom'
3
4
 
4
5
  require 'xcodeproj/project/object'
5
6
  require 'xcodeproj/project/project_helper'
@@ -169,7 +170,7 @@ module Xcodeproj
169
170
  #
170
171
  def initialize_from_file
171
172
  pbxproj_path = path + 'project.pbxproj'
172
- plist = Xcodeproj.read_plist(pbxproj_path.to_s)
173
+ plist = Xcodeproj::PlistHelper.read(pbxproj_path.to_s)
173
174
  root_object_uuid = plist['rootObject']
174
175
  root_object.remove_referrer(self) if root_object
175
176
  @root_object = new_from_plist(root_object_uuid, plist['objects'], self)
@@ -300,7 +301,7 @@ module Xcodeproj
300
301
  save_path ||= path
301
302
  FileUtils.mkdir_p(save_path)
302
303
  file = File.join(save_path, 'project.pbxproj')
303
- Xcodeproj.write_plist(to_hash, file)
304
+ Xcodeproj::PlistHelper.write(to_hash, file)
304
305
  fix_encoding(file)
305
306
  XCProjHelper.touch(save_path) unless disable_xcproj
306
307
  end
@@ -371,7 +372,7 @@ module Xcodeproj
371
372
  # @note Implementation detail: as objects usually are created serially
372
373
  # this method creates a batch of UUID and stores the not colliding
373
374
  # ones, so the search for collisions with known UUIDS (a
374
- # performance bottleneck) is performed is performed less often.
375
+ # performance bottleneck) is performed less often.
375
376
  #
376
377
  # @return [String] A UUID unique to the project.
377
378
  #
@@ -404,7 +405,7 @@ module Xcodeproj
404
405
  # @return [void]
405
406
  #
406
407
  def generate_available_uuid_list(count = 100)
407
- new_uuids = (0..count).map { Xcodeproj.generate_uuid }
408
+ new_uuids = (0..count).map { SecureRandom.hex(12).upcase }
408
409
  uniques = (new_uuids - (@generated_uuids + uuids))
409
410
  @generated_uuids += uniques
410
411
  @available_uuids += uniques
@@ -480,7 +481,7 @@ module Xcodeproj
480
481
  #
481
482
  def reference_for_path(absolute_path)
482
483
  absolute_pathname = Pathname.new(absolute_path)
483
-
484
+
484
485
  unless absolute_pathname.absolute?
485
486
  raise ArgumentError, "Paths must be absolute #{absolute_path}"
486
487
  end
@@ -582,10 +583,10 @@ module Xcodeproj
582
583
  # `:static_library`.
583
584
  #
584
585
  # @param [String] name
585
- # the name of the static library product.
586
+ # the name of the target product.
586
587
  #
587
588
  # @param [Symbol] platform
588
- # the platform of the static library. Can be `:ios` or `:osx`.
589
+ # the platform of the target. Can be `:ios` or `:osx`.
589
590
  #
590
591
  # @param [String] deployment_target
591
592
  # the deployment target for the platform.
@@ -702,7 +703,7 @@ module Xcodeproj
702
703
  end
703
704
 
704
705
  xcschememanagement_path = schemes_dir + 'xcschememanagement.plist'
705
- Xcodeproj.write_plist(xcschememanagement, xcschememanagement_path)
706
+ Xcodeproj::PlistHelper.write(xcschememanagement, xcschememanagement_path)
706
707
  end
707
708
 
708
709
  #-------------------------------------------------------------------------#
@@ -199,8 +199,8 @@ module Xcodeproj
199
199
  end
200
200
 
201
201
  # Informs the object that another object stopped referencing it. If the
202
- # object has no other references it is removed form project UUIDs hash
203
- # because it is unreachable.
202
+ # object has no other references it is removed from the project UUIDs
203
+ # hash because it is unreachable.
204
204
  #
205
205
  # @return [void]
206
206
  #
@@ -38,6 +38,7 @@ module Xcodeproj
38
38
  # If this assumption is incorrect, there could be loss of
39
39
  # information opening and saving an existing project.
40
40
  #
41
+ # TODO this is the external reference that 'contains' other proxy items
41
42
  attribute :container_portal, String
42
43
 
43
44
  # @return [String] the type of the proxy.
@@ -225,6 +225,8 @@ module Xcodeproj
225
225
  end
226
226
  end
227
227
 
228
+ #---------------------------------------------------------------------#
229
+
228
230
  # Checks whether the reference is a proxy.
229
231
  #
230
232
  # @return [Bool] always false for this ISA.
@@ -233,6 +235,90 @@ module Xcodeproj
233
235
  false
234
236
  end
235
237
 
238
+ # If this file reference represents an external Xcode project reference
239
+ # then this will return metadata about it which includes the reference
240
+ # to the 'Products' group that's created in this project (the project
241
+ # that includes the external project).
242
+ #
243
+ # @return [ObjectDictionary, nil] The external project metadata for
244
+ # this file reference or `nil` if it's not an external project.
245
+ #
246
+ def project_reference_metadata
247
+ project.root_object.project_references.find do |project_reference|
248
+ project_reference['ProjectRef'] == self
249
+ end
250
+ end
251
+
252
+ # If this file reference represents an external Xcode project reference
253
+ # then this will return the objects that are 'containers' for items
254
+ # contained in the external Xcode project.
255
+ #
256
+ # @return [Array<PBXContainerItemProxy>] The containers for items in
257
+ # the external Xcode project.
258
+ #
259
+ def proxy_containers
260
+ project.objects.select do |object|
261
+ object.isa == 'PBXContainerItemProxy' &&
262
+ object.container_portal == self.uuid
263
+ end
264
+ end
265
+
266
+ # If this file reference represents an external Xcode project reference
267
+ # then this will return proxies for file references contained in the
268
+ # external Xcode project.
269
+ #
270
+ # @return [Array<PBXReferenceProxy>] The file reference proxies for
271
+ # items located in the external Xcode project.
272
+ #
273
+ def file_reference_proxies
274
+ containers = proxy_containers
275
+ if containers.empty?
276
+ []
277
+ else
278
+ project.objects.select do |object|
279
+ object.isa == 'PBXReferenceProxy' &&
280
+ containers.include?(object.remote_ref)
281
+ end
282
+ end
283
+ end
284
+
285
+ # If this file reference represents an external Xcode project reference
286
+ # then this will return dependencies on targets contained in the
287
+ # external Xcode project.
288
+ #
289
+ # @return [Array<PBXTargetDependency>] The dependencies on targets
290
+ # located in the external Xcode project.
291
+ #
292
+ def target_dependency_proxies
293
+ containers = proxy_containers
294
+ if containers.empty?
295
+ []
296
+ else
297
+ project.objects.select do |object|
298
+ object.isa == 'PBXTargetDependency' &&
299
+ containers.include?(object.target_proxy)
300
+ end
301
+ end
302
+ end
303
+
304
+ # In addition to removing the file reference, this will also remove any
305
+ # items related to this reference in case it represents an external
306
+ # Xcode project.
307
+ #
308
+ # @see AbstractObject#remove_from_project
309
+ #
310
+ # @return [void]
311
+ #
312
+ def remove_from_project
313
+ if project_reference = project_reference_metadata
314
+ file_reference_proxies.each(&:remove_from_project)
315
+ target_dependency_proxies.each(&:remove_from_project)
316
+ project_reference['ProductGroup'].remove_from_project
317
+ project.root_object.project_references.delete(project_reference)
318
+ end
319
+ super
320
+ end
321
+
236
322
  #---------------------------------------------------------------------#
237
323
 
238
324
  end
@@ -139,7 +139,7 @@ module Xcodeproj
139
139
  last_child_ref = child_ref
140
140
  elsif File.basename(child_path) == '.xccurrentversion'
141
141
  full_path = path + File.basename(child_path)
142
- xccurrentversion = Xcodeproj.read_plist(full_path)
142
+ xccurrentversion = Xcodeproj::PlistHelper.read(full_path)
143
143
  current_version_name = xccurrentversion['_XCCurrentVersionName']
144
144
  end
145
145
  end
@@ -44,9 +44,9 @@ module Xcodeproj
44
44
  # the class that owns the attribute.
45
45
  #
46
46
  def initialize(type, name, owner)
47
- @type = type
48
- @name = name
49
- @owner = owner
47
+ @type = type
48
+ @name = name
49
+ @owner = owner
50
50
  end
51
51
 
52
52
  # @return[String] The name of the attribute in camel case.
@@ -65,7 +65,7 @@ module Xcodeproj
65
65
  end
66
66
  end
67
67
 
68
- # @return [Hash] a shared store which cahces the plist name of the
68
+ # @return [Hash] a shared store which caches the plist name of the
69
69
  # attributes.
70
70
  #
71
71
  def self.plist_name_store
@@ -25,10 +25,10 @@ module Xcodeproj
25
25
  # `:static_library`.
26
26
  #
27
27
  # @param [String] name
28
- # the name of the static library product.
28
+ # the name of the target product.
29
29
  #
30
30
  # @param [Symbol] platform
31
- # the platform of the static library. Can be `:ios` or `:osx`.
31
+ # the platform of the target. Can be `:ios` or `:osx`.
32
32
  #
33
33
  # @param [String] deployment_target
34
34
  # the deployment target for the platform.
@@ -3,8 +3,7 @@ module Xcodeproj
3
3
  module XCProjHelper
4
4
  class << self
5
5
 
6
- # @return [Bool] Whether the xcproj tool is available in the path of
7
- # the user.
6
+ # @return [Bool] Whether the xcproj tool is available.
8
7
  #
9
8
  def available?
10
9
  `which xcproj`
@@ -199,7 +199,7 @@ module Xcodeproj
199
199
  # @return [String] the XML string value of the current state of the object.
200
200
  #
201
201
  def to_s
202
- formatter = XML_Fromatter.new(2)
202
+ formatter = XML_Formatter.new(2)
203
203
  formatter.compact = false
204
204
  out = ''
205
205
  formatter.write(@doc, out)
@@ -242,7 +242,7 @@ module Xcodeproj
242
242
 
243
243
  # XML formatter which closely mimics the output generated by Xcode.
244
244
  #
245
- class XML_Fromatter < REXML::Formatters::Pretty
245
+ class XML_Formatter < REXML::Formatters::Pretty
246
246
  def write_element(node, output)
247
247
  @indentation = 3
248
248
  output << ' '*@level
@@ -71,7 +71,8 @@ module Xcodeproj
71
71
  # @return [void]
72
72
  #
73
73
  def <<(projpath)
74
- @file_references << projpath
74
+ project_file_reference = Xcodeproj::Workspace::FileReference.new(projpath)
75
+ @file_references << project_file_reference
75
76
  load_schemes_from_project File.expand_path(projpath)
76
77
  end
77
78
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcodeproj
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eloy Duran
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-19 00:00:00.000000000 Z
11
+ date: 2014-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -38,24 +38,32 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: CFPropertyList
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.2'
41
55
  description: Xcodeproj lets you create and modify Xcode projects from Ruby. Script
42
56
  boring management tasks or build Xcode-friendly libraries. Also includes support
43
57
  for Xcode workspaces (.xcworkspace) and configuration files (.xcconfig).
44
58
  email: eloy.de.enige@gmail.com
45
59
  executables:
46
60
  - xcodeproj
47
- extensions:
48
- - ext/xcodeproj/Rakefile
61
+ extensions: []
49
62
  extra_rdoc_files: []
50
63
  files:
51
64
  - LICENSE
52
65
  - README.md
53
66
  - bin/xcodeproj
54
- - ext/xcodeproj/Rakefile
55
- - ext/xcodeproj/extconf.rb
56
- - ext/xcodeproj/prebuilt/universal-darwin12.0-1.8.7/xcodeproj_ext.bundle
57
- - ext/xcodeproj/prebuilt/universal.x86_64-darwin13-2.0.0/xcodeproj_ext.bundle
58
- - ext/xcodeproj/xcodeproj_ext.c
59
67
  - lib/xcodeproj.rb
60
68
  - lib/xcodeproj/command.rb
61
69
  - lib/xcodeproj/command/project_diff.rb
@@ -68,6 +76,7 @@ files:
68
76
  - lib/xcodeproj/ext.rb
69
77
  - lib/xcodeproj/gem_version.rb
70
78
  - lib/xcodeproj/helper.rb
79
+ - lib/xcodeproj/plist_helper.rb
71
80
  - lib/xcodeproj/project.rb
72
81
  - lib/xcodeproj/project/object.rb
73
82
  - lib/xcodeproj/project/object/build_configuration.rb
@@ -99,11 +108,8 @@ licenses:
99
108
  - MIT
100
109
  metadata: {}
101
110
  post_install_message:
102
- rdoc_options:
103
- - "-x"
104
- - ext/.+\.(o|bundle)
111
+ rdoc_options: []
105
112
  require_paths:
106
- - ext
107
113
  - lib
108
114
  required_ruby_version: !ruby/object:Gem::Requirement
109
115
  requirements:
@@ -1,42 +0,0 @@
1
- desc 'Creates a Makefile only if needed. (Explicitly control with XCODEPROJ_BUILD)'
2
- task :ext do
3
- use_prebuilt = case ENV['XCODEPROJ_BUILD']
4
- when '1'
5
- false
6
- when '0'
7
- true
8
- else
9
- require 'rbconfig'
10
- if RbConfig::CONFIG['prefix'] =~ %r{^/System/Library/Frameworks/Ruby.framework/}
11
- prebuilt_ext = File.join('prebuilt', "#{RUBY_PLATFORM}-#{RUBY_VERSION}", 'xcodeproj_ext.bundle')
12
- File.exist?(prebuilt_ext)
13
- else
14
- false
15
- end
16
- end
17
-
18
- if use_prebuilt
19
- # It’s important that we communicate this, so we can differentiate between
20
- # types of installations when people paste output, but there is
21
- # unfortunately no other way than this hack.
22
- #
23
- # By the time we decide wether prebuilt binaries should be used we can't
24
- # change the spec anymore to have a post install message nor can we output
25
- # to stdout/stderr, because RubyGems catches all output and only shows it
26
- # in case of a build failure.
27
- #
28
- begin
29
- if File.writable?('/dev/tty')
30
- File.open('/dev/tty', 'w') do |out|
31
- out.puts "[!] You are using the prebuilt binary version of the xcodeproj gem."
32
- end
33
- end
34
- rescue Errno::ENXIO
35
- end
36
- else
37
- ruby 'extconf.rb'
38
- sh 'make'
39
- end
40
- end
41
-
42
- task :default => :ext
@@ -1,61 +0,0 @@
1
- require 'mkmf'
2
-
3
- # backport from 1.9.x
4
- unless defined?(have_framework) == "method"
5
- def have_framework(fw, &b)
6
- checking_for fw do
7
- src = cpp_include("#{fw}/#{fw}.h") << "\n" "int main(void){return 0;}"
8
- if try_link(src, opt = "-ObjC -framework #{fw}", &b)
9
- $defs.push(format("-DHAVE_FRAMEWORK_%s", fw.tr_cpp))
10
- $LDFLAGS << " " << opt
11
- true
12
- else
13
- false
14
- end
15
- end
16
- end
17
- end
18
-
19
- # Ensure that we can actually set the -std flag
20
- $CFLAGS = $CFLAGS.sub('$(cflags) ', '')
21
- $CFLAGS += ' ' + ENV['CFLAGS'] if ENV['CFLAGS']
22
-
23
- checking_for "-std=c99 option to compiler" do
24
- $CFLAGS += " -std=c99" if try_compile '', '-std=c99'
25
- end
26
-
27
- # From `man ld`:
28
- #
29
- # -Z Do not search the standard directories when searching for libraries and frameworks.
30
- #
31
- # This is typically used when you want compilation against Xcode SDK as opposed to the frameworks installed
32
- # in the running system, which is our use case.
33
- $LDFLAGS.gsub!(/\s-Z\s/,' ')
34
-
35
- # Fix Apple's mess. They built Ruby in a custom way that has lead to these
36
- # options not containing the original commas anymore [1], which when combined
37
- # with the change they made to clang (in Xcode 5.1) to error out on unrecognized
38
- # options [2] leads to failing builds.
39
- #
40
- # [1]: https://bugs.ruby-lang.org/issues/9624#note-11
41
- # [2]: https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Introduction/Introduction.html
42
- $DLDFLAGS.sub!('-undefineddynamic_lookup', '-undefined dynamic_lookup')
43
- $DLDFLAGS.sub!('-multiply_definedsuppress', '-multiply_defined suppress')
44
-
45
- unless have_framework('CoreFoundation')
46
- if have_library('CoreFoundation')
47
- # this is needed for opencflite, assume it's on linux
48
- $defs << '-DTARGET_OS_LINUX'
49
- else
50
- $stderr.puts "CoreFoundation is needed to build the Xcodeproj C extension."
51
- exit -1
52
- end
53
- end
54
-
55
- have_header('CoreFoundation/CoreFoundation.h')
56
- have_header('CoreFoundation/CFStream.h')
57
- have_header('CoreFoundation/CFPropertyList.h')
58
- have_header('ruby/st.h') || have_header('st.h') || abort('xcodeproj currently requires the (ruby/)st.h header')
59
-
60
- create_header
61
- create_makefile 'xcodeproj_ext'
@@ -1,284 +0,0 @@
1
- // TODO
2
- // * free memory when raising
3
-
4
- #include "extconf.h"
5
-
6
- #include "ruby.h"
7
- #if HAVE_RUBY_ST_H
8
- #include "ruby/st.h"
9
- #elif HAVE_ST_H
10
- #include "st.h"
11
- #endif
12
-
13
- #include "CoreFoundation/CoreFoundation.h"
14
- #include "CoreFoundation/CFStream.h"
15
- #include "CoreFoundation/CFPropertyList.h"
16
-
17
- VALUE Xcodeproj = Qnil;
18
-
19
-
20
- static VALUE
21
- cfstr_to_str(const void *cfstr) {
22
- CFDataRef data = CFStringCreateExternalRepresentation(NULL, cfstr, kCFStringEncodingUTF8, 0);
23
- assert(data != NULL);
24
- long len = (long)CFDataGetLength(data);
25
- char *buf = (char *)CFDataGetBytePtr(data);
26
-
27
- register VALUE str = rb_str_new(buf, len);
28
-
29
- // force UTF-8 encoding in Ruby 1.9+
30
- ID forceEncodingId = rb_intern("force_encoding");
31
- if (rb_respond_to(str, forceEncodingId)) {
32
- rb_funcall(str, forceEncodingId, 1, rb_str_new("UTF-8", 5));
33
- }
34
-
35
- CFRelease(data);
36
- return str;
37
- }
38
-
39
- // Coerces to String as well.
40
- static CFStringRef
41
- str_to_cfstr(VALUE str) {
42
- return CFStringCreateWithCString(NULL, RSTRING_PTR(rb_String(str)), kCFStringEncodingUTF8);
43
- }
44
-
45
- /* Generates a UUID. The original version is truncated, so this is not 100%
46
- * guaranteed to be unique. However, the `PBXObject#generate_uuid` method
47
- * checks that the UUID does not exist yet, in the project, before using it.
48
- *
49
- * @note Meant for internal use only.
50
- *
51
- * @return [String] A 24 characters long UUID.
52
- */
53
- static VALUE
54
- generate_uuid(void) {
55
- CFUUIDRef uuid = CFUUIDCreate(NULL);
56
- CFStringRef strRef = CFUUIDCreateString(NULL, uuid);
57
- CFRelease(uuid);
58
-
59
- CFArrayRef components = CFStringCreateArrayBySeparatingStrings(NULL, strRef, CFSTR("-"));
60
- CFRelease(strRef);
61
- strRef = CFStringCreateByCombiningStrings(NULL, components, CFSTR(""));
62
- CFRelease(components);
63
-
64
- UniChar buffer[24];
65
- CFStringGetCharacters(strRef, CFRangeMake(0, 24), buffer);
66
- CFStringRef strRef2 = CFStringCreateWithCharacters(NULL, buffer, 24);
67
-
68
- VALUE str = cfstr_to_str(strRef2);
69
- CFRelease(strRef);
70
- CFRelease(strRef2);
71
- return str;
72
- }
73
-
74
-
75
- static void
76
- hash_set(const void *keyRef, const void *valueRef, void *hash) {
77
- VALUE key = cfstr_to_str(keyRef);
78
- register VALUE value = Qnil;
79
-
80
- CFTypeID valueType = CFGetTypeID(valueRef);
81
- if (valueType == CFStringGetTypeID()) {
82
- value = cfstr_to_str(valueRef);
83
- } else if (valueRef == kCFBooleanTrue) {
84
- value = Qtrue;
85
- } else if (valueRef == kCFBooleanFalse) {
86
- value = Qfalse;
87
- } else if (valueType == CFDictionaryGetTypeID()) {
88
- value = rb_hash_new();
89
- CFDictionaryApplyFunction(valueRef, hash_set, (void *)value);
90
-
91
- } else if (valueType == CFArrayGetTypeID()) {
92
- value = rb_ary_new();
93
- CFIndex i, count = CFArrayGetCount(valueRef);
94
- for (i = 0; i < count; i++) {
95
- CFTypeRef elementRef = CFArrayGetValueAtIndex(valueRef, i);
96
- CFTypeID elementType = CFGetTypeID(elementRef);
97
- if (elementType == CFStringGetTypeID()) {
98
- rb_ary_push(value, cfstr_to_str(elementRef));
99
-
100
- } else if (elementType == CFDictionaryGetTypeID()) {
101
- VALUE hashElement = rb_hash_new();
102
- CFDictionaryApplyFunction(elementRef, hash_set, (void *)hashElement);
103
- rb_ary_push(value, hashElement);
104
-
105
- } else {
106
- CFStringRef descriptionRef = CFCopyDescription(elementRef);
107
- // obviously not optimal, but we're raising here, so it doesn't really matter
108
- VALUE description = cfstr_to_str(descriptionRef);
109
- rb_raise(rb_eTypeError, "Plist array value contains a object type unsupported by Xcodeproj. In: `%s'", RSTRING_PTR(description));
110
- CFRelease(descriptionRef);
111
- }
112
- }
113
-
114
- } else {
115
- rb_raise(rb_eTypeError, "Plist contains a hash value object type unsupported by Xcodeproj.");
116
- }
117
-
118
- rb_hash_aset((VALUE)hash, key, value);
119
- }
120
-
121
- static int
122
- dictionary_set(st_data_t key, st_data_t value, CFMutableDictionaryRef dict) {
123
- CFStringRef keyRef = str_to_cfstr(key);
124
-
125
- CFTypeRef valueRef = NULL;
126
- if (TYPE(value) == T_HASH) {
127
- valueRef = CFDictionaryCreateMutable(NULL,
128
- 0,
129
- &kCFTypeDictionaryKeyCallBacks,
130
- &kCFTypeDictionaryValueCallBacks);
131
- rb_hash_foreach(value, dictionary_set, (st_data_t)valueRef);
132
-
133
- } else if (TYPE(value) == T_ARRAY) {
134
- long i, count = RARRAY_LEN(value);
135
- valueRef = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
136
- for (i = 0; i < count; i++) {
137
- VALUE element = RARRAY_PTR(value)[i];
138
- CFTypeRef elementRef = NULL;
139
- if (TYPE(element) == T_HASH) {
140
- elementRef = CFDictionaryCreateMutable(NULL,
141
- 0,
142
- &kCFTypeDictionaryKeyCallBacks,
143
- &kCFTypeDictionaryValueCallBacks);
144
- rb_hash_foreach(element, dictionary_set, (st_data_t)elementRef);
145
- } else {
146
- // otherwise coerce to string
147
- elementRef = str_to_cfstr(element);
148
- }
149
- CFArrayAppendValue((CFMutableArrayRef)valueRef, elementRef);
150
- CFRelease(elementRef);
151
- }
152
- } else if (value == Qtrue) {
153
- valueRef = kCFBooleanTrue;
154
- } else if (value == Qfalse) {
155
- valueRef = kCFBooleanFalse;
156
- } else {
157
- valueRef = str_to_cfstr(value);
158
- }
159
-
160
- if (valueRef == NULL) {
161
- rb_raise(rb_eTypeError, "Unable to convert value of key `%s'.", RSTRING_PTR(rb_inspect(key)));
162
- }
163
-
164
- CFDictionaryAddValue(dict, keyRef, valueRef);
165
- CFRelease(keyRef);
166
- CFRelease(valueRef);
167
- return ST_CONTINUE;
168
- }
169
-
170
- static CFURLRef
171
- str_to_url(VALUE path) {
172
- #ifdef FilePathValue
173
- VALUE p = FilePathValue(path);
174
- #else
175
- VALUE p = rb_String(path);
176
- #endif
177
- CFURLRef fileURL = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)RSTRING_PTR(p), RSTRING_LEN(p), false);
178
- if (!fileURL) {
179
- rb_raise(rb_eArgError, "Unable to create CFURL from `%s'.", RSTRING_PTR(rb_inspect(path)));
180
- }
181
- return fileURL;
182
- }
183
-
184
- #pragma GCC diagnostic push
185
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
186
-
187
- /* @overload read_plist(path)
188
- *
189
- * Reads from the specified path and de-serializes the property list.
190
- *
191
- * @note This does not yet support all possible types that can exist in a valid property list.
192
- *
193
- * @note This currently only assumes to be given an Xcode project document.
194
- * This means that it only accepts dictionaries, arrays, and strings in
195
- * the document.
196
- *
197
- * @param [String] path The path to the property list file.
198
- * @return [Hash] The dictionary contents of the document.
199
- */
200
- static VALUE
201
- read_plist(VALUE self, VALUE path) {
202
- CFPropertyListRef dict;
203
- CFStringRef errorString;
204
- CFDataRef resourceData;
205
- SInt32 errorCode;
206
-
207
- CFURLRef fileURL = str_to_url(path);
208
- if (CFURLCreateDataAndPropertiesFromResource(NULL, fileURL, &resourceData, NULL, NULL, &errorCode)) {
209
- CFRelease(fileURL);
210
- }
211
- if (!resourceData) {
212
- rb_raise(rb_eArgError, "Unable to read data from `%s'", RSTRING_PTR(rb_inspect(path)));
213
- }
214
-
215
- dict = CFPropertyListCreateFromXMLData(NULL, resourceData, kCFPropertyListImmutable, &errorString);
216
- if (!dict) {
217
- rb_raise(rb_eArgError, "Unable to read plist data from `%s': %s", RSTRING_PTR(rb_inspect(path)), RSTRING_PTR(cfstr_to_str(errorString)));
218
- }
219
- CFRelease(resourceData);
220
-
221
- register VALUE hash = rb_hash_new();
222
- CFDictionaryApplyFunction(dict, hash_set, (void *)hash);
223
- CFRelease(dict);
224
-
225
- return hash;
226
- }
227
-
228
- /* @overload write_plist(hash, path)
229
- *
230
- * Writes the serialized contents of a property list to the specified path.
231
- *
232
- * @note This does not yet support all possible types that can exist in a valid property list.
233
- *
234
- * @note This currently only assumes to be given an Xcode project document.
235
- * This means that it only accepts dictionaries, arrays, and strings in
236
- * the document.
237
- *
238
- * @param [Hash] hash The property list to serialize.
239
- * @param [String] path The path to the property list file.
240
- * @return [true, false] Wether or not saving was successful.
241
- */
242
- static VALUE
243
- write_plist(VALUE self, VALUE hash, VALUE path) {
244
- VALUE h = rb_check_convert_type(hash, T_HASH, "Hash", "to_hash");
245
- if (NIL_P(h)) {
246
- rb_raise(rb_eTypeError, "%s can't be coerced to Hash", rb_obj_classname(hash));
247
- }
248
-
249
- CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL,
250
- 0,
251
- &kCFTypeDictionaryKeyCallBacks,
252
- &kCFTypeDictionaryValueCallBacks);
253
-
254
- rb_hash_foreach(h, dictionary_set, (st_data_t)dict);
255
-
256
- CFURLRef fileURL = str_to_url(path);
257
- CFWriteStreamRef stream = CFWriteStreamCreateWithFile(NULL, fileURL);
258
- CFRelease(fileURL);
259
-
260
- CFIndex success = 0;
261
- if (CFWriteStreamOpen(stream)) {
262
- CFStringRef errorString;
263
- success = CFPropertyListWriteToStream(dict, stream, kCFPropertyListXMLFormat_v1_0, &errorString);
264
- if (!success) {
265
- CFShow(errorString);
266
- }
267
- CFWriteStreamClose(stream);
268
- } else {
269
- printf("Unable to open stream!\n");
270
- }
271
-
272
- CFRelease(stream);
273
- CFRelease(dict);
274
- return success ? Qtrue : Qfalse;
275
- }
276
-
277
- #pragma GCC diagnostic pop
278
-
279
- void Init_xcodeproj_ext() {
280
- Xcodeproj = rb_define_module("Xcodeproj");
281
- rb_define_singleton_method(Xcodeproj, "generate_uuid", generate_uuid, 0);
282
- rb_define_singleton_method(Xcodeproj, "read_plist", read_plist, 1);
283
- rb_define_singleton_method(Xcodeproj, "write_plist", write_plist, 2);
284
- }