vendor 0.0.4 → 0.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.
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +9 -1
- data/Guardfile +12 -0
- data/LICENSE +2 -0
- data/Readme.markdown +39 -23
- data/TODO.md +26 -0
- data/VERSION +1 -0
- data/lib/vendor.rb +6 -0
- data/lib/vendor/api.rb +61 -7
- data/lib/vendor/cli/app.rb +4 -4
- data/lib/vendor/cli/console.rb +7 -0
- data/lib/vendor/spec.rb +98 -0
- data/lib/vendor/templates/Vendorfile +3 -1
- data/lib/vendor/templates/vendorspec +15 -10
- data/lib/vendor/vendor_file.rb +5 -4
- data/lib/vendor/vendor_file/dependency_graph.rb +135 -0
- data/lib/vendor/vendor_file/dsl.rb +2 -0
- data/lib/vendor/vendor_file/library/base.rb +178 -29
- data/lib/vendor/vendor_file/library/git.rb +5 -1
- data/lib/vendor/vendor_file/library/local.rb +11 -1
- data/lib/vendor/vendor_file/library/remote.rb +134 -2
- data/lib/vendor/vendor_file/loader.rb +13 -11
- data/lib/vendor/vendor_spec/builder.rb +4 -7
- data/lib/vendor/version.rb +172 -1
- data/lib/vendor/xcode/project.rb +213 -4
- data/lib/vendor/xcode/proxy.rb +1 -0
- data/lib/vendor/xcode/proxy/pbx_frameworks_build_phase.rb +6 -0
- data/lib/vendor/xcode/proxy/pbx_reference_proxy.rb +7 -0
- data/lib/vendor/xcode/proxy/pbx_resources_build_phase.rb +8 -0
- data/lib/vendor/xcode/proxy/pbx_shell_script_build_phase.rb +8 -0
- data/lib/vendor/xcode/proxy/pbx_sources_build_phase.rb +6 -0
- data/spec/lib/vendor/api_spec.rb +54 -0
- data/spec/lib/vendor/spec_spec.rb +121 -0
- data/spec/lib/vendor/vendor_file/dependency_graph_spec.rb +129 -0
- data/spec/lib/vendor/vendor_file/library/base_spec.rb +174 -14
- data/spec/lib/vendor/vendor_file/library/remote_spec.rb +154 -4
- data/spec/lib/vendor/vendor_file/loader_spec.rb +4 -2
- data/spec/lib/vendor/vendor_spec/builder_spec.rb +2 -2
- data/spec/lib/vendor/version_spec.rb +168 -0
- data/spec/lib/vendor/xcode/project_spec.rb +175 -4
- data/spec/lib/vendor_spec.rb +15 -0
- data/spec/spec_helper.rb +3 -2
- data/spec/support/api_stubs.rb +57 -0
- data/spec/support/resources/cache/base/{DKBenchmark-Manifest → DKBenchmark-0.1-Manifest}/data/DKBenchmark.h +0 -0
- data/spec/support/resources/cache/base/{DKBenchmark-Manifest → DKBenchmark-0.1-Manifest}/data/DKBenchmark.m +0 -0
- data/spec/support/resources/cache/base/DKBenchmark-0.1-Manifest/vendor.json +1 -0
- data/spec/support/resources/cache/base/{DKBenchmark-Vendorspec → DKBenchmark-0.1-Nothing}/DKBenchmark.h +0 -0
- data/spec/support/resources/cache/base/{DKBenchmark-Vendorspec → DKBenchmark-0.1-Nothing}/DKBenchmark.m +0 -0
- data/spec/support/resources/cache/base/DKBenchmark-0.1-Nothing/DKBenchmark.vendorspec +16 -0
- data/spec/support/resources/cache/base/DKBenchmark-0.1-Vendorspec/DKBenchmark.h +18 -0
- data/spec/support/resources/cache/base/DKBenchmark-0.1-Vendorspec/DKBenchmark.m +73 -0
- data/spec/support/resources/cache/base/DKBenchmark-0.1-Vendorspec/DKBenchmark.vendorspec +24 -0
- data/spec/support/resources/projects/MultipleTargets/MultipleTargets.xcodeproj/project.pbxproj +624 -0
- data/spec/support/resources/projects/RestKitProject/RestKitProject.xcodeproj/project.pbxproj +479 -0
- data/spec/support/resources/projects/UtilityApplication/UtilityApplication.xcodeproj/project.pbxproj +16 -7
- data/spec/support/resources/vendors/DKBenchmark/DKBenchmark.vendorspec +24 -8
- data/spec/support/resources/vendors/DKBenchmarkUnsafe/DKBenchmark.vendorspec +17 -8
- data/vendor.gemspec +4 -2
- metadata +93 -39
- data/lib/vendor/vendor_spec/dsl.rb +0 -39
- data/lib/vendor/vendor_spec/loader.rb +0 -23
- data/spec/lib/vendor/vendor_spec/dsl_spec.rb +0 -67
- data/spec/lib/vendor/vendor_spec/loader_spec.rb +0 -41
- data/spec/support/resources/cache/base/DKBenchmark-Manifest/vendor.json +0 -1
- data/spec/support/resources/cache/base/DKBenchmark-Vendorspec/DKBenchmark.vendorspec +0 -11
@@ -44,7 +44,11 @@ module Vendor
|
|
44
44
|
# the sources correctly. So instead of using the name, use a hash of
|
45
45
|
# the URI
|
46
46
|
def cache_path
|
47
|
-
|
47
|
+
File.join(Vendor.library_path, "git", Digest::MD5.hexdigest(uri)) if uri
|
48
|
+
end
|
49
|
+
|
50
|
+
def display_name
|
51
|
+
[ name, "(#{uri}##{tag})" ].join(' ')
|
48
52
|
end
|
49
53
|
|
50
54
|
private
|
@@ -12,9 +12,19 @@ module Vendor
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def cache_path
|
15
|
-
|
15
|
+
expanded_path if path
|
16
16
|
end
|
17
17
|
|
18
|
+
def display_name
|
19
|
+
[ name, "(#{expanded_path})" ].join(' ')
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def expanded_path
|
25
|
+
File.expand_path(path)
|
26
|
+
end
|
27
|
+
|
18
28
|
end
|
19
29
|
|
20
30
|
end
|
@@ -4,13 +4,145 @@ module Vendor
|
|
4
4
|
|
5
5
|
class Remote < Base
|
6
6
|
|
7
|
-
|
7
|
+
require 'zip/zip'
|
8
|
+
|
9
|
+
attr_accessor :equality
|
8
10
|
attr_accessor :sources
|
9
11
|
|
12
|
+
def version
|
13
|
+
@version
|
14
|
+
end
|
15
|
+
|
16
|
+
def version=(value)
|
17
|
+
# Matches (some equality matcher, followed by some spaces, then a version)
|
18
|
+
if value
|
19
|
+
if value.match(/^(\<\=|\>\=|\~\>|\>|\<)?\s*([a-zA-Z0-9\.]+)$/)
|
20
|
+
@equality = $1
|
21
|
+
@version = $2
|
22
|
+
else
|
23
|
+
Vendor.ui.error "Invalid version format '#{value}' for '#{name}'"
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
else
|
27
|
+
@equality = nil
|
28
|
+
@version = nil
|
29
|
+
end
|
30
|
+
value
|
31
|
+
end
|
32
|
+
|
33
|
+
def matched_version
|
34
|
+
# If we just have a version, and no equality matcher
|
35
|
+
if version && !equality
|
36
|
+
return version
|
37
|
+
end
|
38
|
+
|
39
|
+
# If we don't have a version, get the latest version
|
40
|
+
# from the remote sources
|
41
|
+
unless version
|
42
|
+
return meta['release']
|
43
|
+
end
|
44
|
+
|
45
|
+
# Try and find a version that matches the lib
|
46
|
+
other_versions = meta['versions'].map { |v| v[0] }
|
47
|
+
found = version_matches_any?(other_versions)
|
48
|
+
|
49
|
+
# Did we actually find something?
|
50
|
+
unless found
|
51
|
+
Vendor.ui.error "Could not find a valid version '#{equality} #{version}' in '#{other_versions}'"
|
52
|
+
exit 1
|
53
|
+
else
|
54
|
+
found
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def version_matches_any?(other_versions)
|
59
|
+
# If we have an equality matcher, we need sort through
|
60
|
+
# the versions, and try and find the best match
|
61
|
+
wants = Vendor::Version.new(version)
|
62
|
+
|
63
|
+
# Sort them from the latest versions first
|
64
|
+
versions = other_versions.map{|v| Vendor::Version.create(v) }.sort.reverse
|
65
|
+
|
66
|
+
# We don't want to include pre-releases if the wants version
|
67
|
+
# isn't a pre-release itself. If we're after "2.5.alpha", then
|
68
|
+
# we should be able to include that, however if we're asking for
|
69
|
+
# "2.5", then pre-releases shouldn't be included.
|
70
|
+
unless wants.prerelease?
|
71
|
+
versions = versions.reject { |v| v.prerelease? }
|
72
|
+
end
|
73
|
+
|
74
|
+
# If this a spermy search, we have a slightly different search mechanism. We use the
|
75
|
+
# version segemets to determine if the version is valid. For example, lets say we're
|
76
|
+
# testing to see if "0.1" is a spermy match to "0.1.5.2", we start by getting the
|
77
|
+
# two segments for each:
|
78
|
+
#
|
79
|
+
# [ 0, 1 ]
|
80
|
+
# [ 0, 1, 5, 2 ]
|
81
|
+
#
|
82
|
+
# We chop the second set of segments to be the same lenth as the first one:
|
83
|
+
#
|
84
|
+
# [ 0, 1, 5, 2 ].slice(0, 2) #=. [ 0, 1 ]
|
85
|
+
#
|
86
|
+
# No we just test to see if they are the same! I think this works...
|
87
|
+
if equality == "~>"
|
88
|
+
segments = wants.segments
|
89
|
+
versions.find do |has|
|
90
|
+
segments == has.segments.slice(0, segments.length)
|
91
|
+
end
|
92
|
+
elsif equality
|
93
|
+
versions.find do |has|
|
94
|
+
wants.send(:"#{equality}", has)
|
95
|
+
end
|
96
|
+
else
|
97
|
+
versions.find do |has|
|
98
|
+
wants == has
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
10
103
|
def download
|
11
|
-
|
104
|
+
# If we haven't already downloaded the vendor
|
105
|
+
unless File.exist?(cache_path)
|
106
|
+
# Download it
|
107
|
+
file = Vendor::API.download(name, matched_version)
|
108
|
+
|
109
|
+
# Unzip the download
|
110
|
+
unzip_file file.path, cache_path
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def cache_path
|
115
|
+
File.join(Vendor.library_path, "remote", name, matched_version.to_s)
|
12
116
|
end
|
13
117
|
|
118
|
+
def ==(other)
|
119
|
+
other.name == @name && other.version == @version && other.equality == @equality
|
120
|
+
end
|
121
|
+
|
122
|
+
def display_name
|
123
|
+
[ name, matched_version ].compact.join(" ")
|
124
|
+
end
|
125
|
+
|
126
|
+
def description
|
127
|
+
[ @name, @equality, @version ].compact.join(" ")
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def meta
|
133
|
+
@meta ||= Vendor::API.meta(name)
|
134
|
+
end
|
135
|
+
|
136
|
+
def unzip_file (file, destination)
|
137
|
+
Zip::ZipFile.open(file) { |zip_file|
|
138
|
+
zip_file.each { |f|
|
139
|
+
f_path = File.join(destination, f.name)
|
140
|
+
FileUtils.mkdir_p(File.dirname(f_path))
|
141
|
+
zip_file.extract(f, f_path) unless File.exist?(f_path)
|
142
|
+
}
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
14
146
|
end
|
15
147
|
|
16
148
|
end
|
@@ -6,27 +6,29 @@ module Vendor
|
|
6
6
|
require 'fileutils'
|
7
7
|
|
8
8
|
attr_reader :dsl
|
9
|
+
attr_reader :libraries
|
9
10
|
|
10
11
|
def initialize
|
11
12
|
@dsl = Vendor::VendorFile::DSL.new
|
13
|
+
@libraries = []
|
12
14
|
end
|
13
15
|
|
14
|
-
def
|
15
|
-
@
|
16
|
+
def libraries=(value)
|
17
|
+
@graph = Vendor::VendorFile::DependencyGraph.new(value)
|
18
|
+
@libraries = value
|
16
19
|
end
|
17
20
|
|
18
|
-
def
|
19
|
-
@dsl.
|
20
|
-
|
21
|
-
lib.sources = @dsl.sources
|
22
|
-
end
|
23
|
-
lib.download
|
24
|
-
end
|
21
|
+
def load(filename)
|
22
|
+
@dsl.instance_eval(File.read(filename), filename)
|
23
|
+
self.libraries = @dsl.libraries
|
25
24
|
end
|
26
25
|
|
27
26
|
def install(project)
|
28
|
-
@
|
29
|
-
|
27
|
+
unless @graph.version_conflicts?
|
28
|
+
@graph.libraries_to_install.each do |lib|
|
29
|
+
library, targets = lib
|
30
|
+
library.install project, :targets => targets
|
31
|
+
end
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
@@ -15,14 +15,11 @@ module Vendor
|
|
15
15
|
attr_reader :vendor_spec
|
16
16
|
|
17
17
|
def initialize(vendor_spec)
|
18
|
-
loader = Vendor::VendorSpec::Loader.new
|
19
|
-
loader.load vendor_spec
|
20
|
-
|
21
18
|
@folder = File.expand_path(File.join(vendor_spec, '..'))
|
22
|
-
@vendor_spec =
|
19
|
+
@vendor_spec = Vendor::Spec.load vendor_spec
|
23
20
|
|
24
|
-
@name = safe_filename(@vendor_spec
|
25
|
-
@version = safe_filename(@vendor_spec
|
21
|
+
@name = safe_filename(@vendor_spec.name)
|
22
|
+
@version = safe_filename(@vendor_spec.version)
|
26
23
|
@filename = "#{@name}-#{@version}.vendor"
|
27
24
|
end
|
28
25
|
|
@@ -49,7 +46,7 @@ module Vendor
|
|
49
46
|
|
50
47
|
# Remove files that are within folders with a ".", such as ".bundle"
|
51
48
|
# and ".frameworks"
|
52
|
-
copy_files = @vendor_spec
|
49
|
+
copy_files = @vendor_spec.files.reject { |file| file =~ /\/?[^\/]+\.[^\/]+\// }
|
53
50
|
|
54
51
|
copy_files.each do |file|
|
55
52
|
dir = File.dirname(file)
|
data/lib/vendor/version.rb
CHANGED
@@ -1,5 +1,176 @@
|
|
1
1
|
module Vendor
|
2
2
|
|
3
|
-
|
3
|
+
class Version
|
4
|
+
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
VERSION_PATTERN = '[0-9]+(\.[0-9a-zA-Z]+)*' # :nodoc:
|
8
|
+
ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})*\s*\z/ # :nodoc:
|
9
|
+
|
10
|
+
##
|
11
|
+
# A string representation of this Version.
|
12
|
+
|
13
|
+
attr_reader :version
|
14
|
+
alias to_s version
|
15
|
+
|
16
|
+
##
|
17
|
+
# True if the +version+ string matches Vendor's requirements.
|
18
|
+
|
19
|
+
def self.correct? version
|
20
|
+
version.to_s =~ ANCHORED_VERSION_PATTERN
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Factory method to create a Version object. Input may be a Version
|
25
|
+
# or a String. Intended to simplify client code.
|
26
|
+
#
|
27
|
+
# ver1 = Version.create('1.3.17') # -> (Version object)
|
28
|
+
# ver2 = Version.create(ver1) # -> (ver1)
|
29
|
+
# ver3 = Version.create(nil) # -> nil
|
30
|
+
|
31
|
+
def self.create input
|
32
|
+
if input === Vendor::Version
|
33
|
+
input
|
34
|
+
elsif input.nil? then
|
35
|
+
nil
|
36
|
+
else
|
37
|
+
new input
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Constructs a Version from the +version+ string. A version string is a
|
43
|
+
# series of digits or ASCII letters separated by dots.
|
44
|
+
|
45
|
+
def initialize version
|
46
|
+
raise ArgumentError, "Malformed version number string #{version}" unless
|
47
|
+
self.class.correct?(version)
|
48
|
+
|
49
|
+
@version = version.to_s
|
50
|
+
@version.strip!
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Return a new version object where the next to the last revision
|
55
|
+
# number is one greater (e.g., 5.3.1 => 5.4).
|
56
|
+
#
|
57
|
+
# Pre-release (alpha) parts, e.g, 5.3.1.b.2 => 5.4, are ignored.
|
58
|
+
|
59
|
+
def bump
|
60
|
+
segments = self.segments.dup
|
61
|
+
segments.pop while segments.any? { |s| String === s }
|
62
|
+
segments.pop if segments.size > 1
|
63
|
+
|
64
|
+
segments[-1] = segments[-1].succ
|
65
|
+
self.class.new segments.join(".")
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# A Version is only eql? to another version if it's specified to the
|
70
|
+
# same precision. Version "1.0" is not the same as version "1".
|
71
|
+
|
72
|
+
def eql? other
|
73
|
+
self.class === other and @version == other.version
|
74
|
+
end
|
75
|
+
|
76
|
+
def inspect # :nodoc:
|
77
|
+
"#<#{self.class} #{version.inspect}>"
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Dump only the raw version string, not the complete object. It's a
|
82
|
+
# string for backwards (RubyGems 1.3.5 and earlier) compatibility.
|
83
|
+
|
84
|
+
def marshal_dump
|
85
|
+
[version]
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Load custom marshal format. It's a string for backwards (RubyGems
|
90
|
+
# 1.3.5 and earlier) compatibility.
|
91
|
+
|
92
|
+
def marshal_load array
|
93
|
+
initialize array[0]
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# A version is considered a prerelease if it contains a letter.
|
98
|
+
|
99
|
+
def prerelease?
|
100
|
+
@prerelease ||= @version =~ /[a-zA-Z]/
|
101
|
+
end
|
102
|
+
|
103
|
+
def pretty_print q # :nodoc:
|
104
|
+
q.text "Vendor::Version.new(#{version.inspect})"
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# The release for this version (e.g. 1.2.0.a -> 1.2.0).
|
109
|
+
# Non-prerelease versions return themselves.
|
110
|
+
|
111
|
+
def release
|
112
|
+
return self unless prerelease?
|
113
|
+
|
114
|
+
segments = self.segments.dup
|
115
|
+
segments.pop while segments.any? { |s| String === s }
|
116
|
+
self.class.new segments.join('.')
|
117
|
+
end
|
118
|
+
|
119
|
+
def segments # :nodoc:
|
120
|
+
|
121
|
+
# segments is lazy so it can pick up version values that come from
|
122
|
+
# old marshaled versions, which don't go through marshal_load.
|
123
|
+
|
124
|
+
@segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s|
|
125
|
+
/^\d+$/ =~ s ? s.to_i : s
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# A recommended version for use with a ~> Requirement.
|
131
|
+
|
132
|
+
def spermy_recommendation
|
133
|
+
segments = self.segments.dup
|
134
|
+
|
135
|
+
segments.pop while segments.any? { |s| String === s }
|
136
|
+
segments.pop while segments.size > 2
|
137
|
+
segments.push 0 while segments.size < 2
|
138
|
+
|
139
|
+
"~> #{segments.join(".")}"
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# Compares this version with +other+ returning -1, 0, or 1 if the
|
144
|
+
# other version is larger, the same, or smaller than this
|
145
|
+
# one. Attempts to compare to something that's not a
|
146
|
+
# <tt>Vendor::Version</tt> return +nil+.
|
147
|
+
|
148
|
+
def <=> other
|
149
|
+
return unless Vendor::Version === other
|
150
|
+
return 0 if @version == other.version
|
151
|
+
|
152
|
+
lhsegments = segments
|
153
|
+
rhsegments = other.segments
|
154
|
+
|
155
|
+
lhsize = lhsegments.size
|
156
|
+
rhsize = rhsegments.size
|
157
|
+
limit = (lhsize > rhsize ? lhsize : rhsize) - 1
|
158
|
+
|
159
|
+
i = 0
|
160
|
+
|
161
|
+
while i <= limit
|
162
|
+
lhs, rhs = lhsegments[i] || 0, rhsegments[i] || 0
|
163
|
+
i += 1
|
164
|
+
|
165
|
+
next if lhs == rhs
|
166
|
+
return -1 if String === lhs && Numeric === rhs
|
167
|
+
return 1 if Numeric === lhs && String === rhs
|
168
|
+
|
169
|
+
return lhs <=> rhs
|
170
|
+
end
|
171
|
+
|
172
|
+
return 0
|
173
|
+
end
|
174
|
+
end
|
4
175
|
|
5
176
|
end
|
data/lib/vendor/xcode/project.rb
CHANGED
@@ -4,6 +4,11 @@ module Vendor::XCode
|
|
4
4
|
|
5
5
|
class Project
|
6
6
|
|
7
|
+
# Build settings and the format that they should be stored in
|
8
|
+
BUILD_SETTING_TYPES = {
|
9
|
+
"OTHER_LDFLAGS" => :array
|
10
|
+
}
|
11
|
+
|
7
12
|
require 'fileutils'
|
8
13
|
|
9
14
|
attr_reader :name
|
@@ -55,8 +60,13 @@ module Vendor::XCode
|
|
55
60
|
@objects_by_id[id]
|
56
61
|
end
|
57
62
|
|
58
|
-
def find_target(
|
59
|
-
|
63
|
+
def find_target(t)
|
64
|
+
# Are we already a target?
|
65
|
+
if t.kind_of?(Vendor::XCode::Proxy::Base)
|
66
|
+
t
|
67
|
+
else
|
68
|
+
root_object.targets.find { |x| x.name == t }
|
69
|
+
end
|
60
70
|
end
|
61
71
|
|
62
72
|
def find_group(path)
|
@@ -105,6 +115,8 @@ module Vendor::XCode
|
|
105
115
|
# If we have the group
|
106
116
|
if group
|
107
117
|
|
118
|
+
ids_to_remove = []
|
119
|
+
|
108
120
|
# Remove the children from the file system
|
109
121
|
group.children.each do |child|
|
110
122
|
if child.group? # Is it a group?
|
@@ -120,13 +132,27 @@ module Vendor::XCode
|
|
120
132
|
Vendor.ui.error "Couldn't remove object: #{child}"
|
121
133
|
end
|
122
134
|
|
135
|
+
# Remove from the targets (if we can)
|
136
|
+
root_object.targets.each { |t| remove_file_from_target(child, t) }
|
137
|
+
|
123
138
|
# Remove the file from the parent
|
124
139
|
child.parent.attributes['children'].delete child.id
|
140
|
+
|
141
|
+
# Add the id to the list of stuff to remove. If we do this
|
142
|
+
# during the loop, bad things happen - not sure why.
|
143
|
+
ids_to_remove << child.id
|
125
144
|
end
|
126
145
|
|
127
146
|
# Remove the group from the parent
|
128
147
|
group.parent.attributes['children'].delete group.id
|
129
148
|
|
149
|
+
# Add to the list of stuff to remove
|
150
|
+
ids_to_remove << group.id
|
151
|
+
|
152
|
+
ids_to_remove.each do |id|
|
153
|
+
@objects_by_id.delete id
|
154
|
+
end
|
155
|
+
|
130
156
|
# Mark as dirty
|
131
157
|
@dirty = true
|
132
158
|
|
@@ -135,11 +161,101 @@ module Vendor::XCode
|
|
135
161
|
end
|
136
162
|
end
|
137
163
|
|
164
|
+
def add_framework(framework, options = {})
|
165
|
+
# Find targets
|
166
|
+
targets = targets_from_options(options)
|
167
|
+
Vendor.ui.debug %{Adding #{framework} to targets "#{targets.map(&:name)}"}
|
168
|
+
|
169
|
+
targets.each do |t|
|
170
|
+
# Does the framework already exist?
|
171
|
+
build_phase = build_phase_for_file("wrapper.framework", t)
|
172
|
+
|
173
|
+
if build_phase
|
174
|
+
# Does a framework already exist?
|
175
|
+
existing_framework = build_phase.files.map(&:file_ref).find do |file|
|
176
|
+
# Some files have names, some done. Framework references
|
177
|
+
# have names...
|
178
|
+
if file.respond_to?(:name)
|
179
|
+
file.name == framework
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# If an existing framework was found, don't add it again
|
184
|
+
unless existing_framework
|
185
|
+
add_file :targets => t, :file => "System/Library/Frameworks/#{framework}", :path => "Frameworks", :source_tree => :sdkroot
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def add_build_setting(name, value, options = {})
|
192
|
+
|
193
|
+
targets_from_options(options).each do |target|
|
194
|
+
|
195
|
+
target.build_configuration_list.build_configurations.each do |config|
|
196
|
+
|
197
|
+
build_settings = config.build_settings
|
198
|
+
|
199
|
+
debug_key = "#{target.name}/#{config.name}".inspect
|
200
|
+
|
201
|
+
# If the build setting already has the key
|
202
|
+
if build_settings.has_key?(name)
|
203
|
+
|
204
|
+
# Is this setting known to have multiple values?
|
205
|
+
if (setting_type = BUILD_SETTING_TYPES[name])
|
206
|
+
|
207
|
+
# If its an array
|
208
|
+
if setting_type == :array
|
209
|
+
# Is it already an array, if so, check to see if
|
210
|
+
# it already exists, and if it doesn't add it.
|
211
|
+
if build_settings[name].kind_of?(Array)
|
212
|
+
unless build_settings[name].include?
|
213
|
+
Vendor.ui.debug(" Added build setting (#{name.inspect} = #{value.inspect}) to #{debug_key}")
|
214
|
+
|
215
|
+
build_settings[name] << value
|
216
|
+
end
|
217
|
+
else
|
218
|
+
Vendor.ui.debug(" Added build setting (#{name.inspect} = #{value.inspect}) to #{debug_key}")
|
219
|
+
|
220
|
+
# Don't add it if the single build value is already there
|
221
|
+
unless build_settings[name].strip == value.strip
|
222
|
+
build_settings[name] = [ build_settings[name], value ]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
else
|
228
|
+
# If its an unknown type, then we should just throw a warning
|
229
|
+
# because we should'nt just change stuff willy, nilly.
|
230
|
+
Vendor.ui.warn(" Build setting #{name.inspect} wanted to change to #{value.inspect}, but it was already #{build_settings[name].inspect} in #{debug_key}")
|
231
|
+
end
|
232
|
+
|
233
|
+
else
|
234
|
+
Vendor.ui.debug(" Added build setting (#{name.inspect} = #{value.inspect}) to #{debug_key}")
|
235
|
+
|
236
|
+
build_settings[name] = value
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
@dirty = true
|
244
|
+
|
245
|
+
end
|
246
|
+
|
138
247
|
def add_file(options)
|
139
248
|
require_options options, :path, :file, :source_tree
|
140
249
|
|
141
|
-
# Ensure file exists
|
142
|
-
|
250
|
+
# Ensure file exists if we'nre not using the sdk root source tree.
|
251
|
+
# The SDKROOT source tree has a virtual file on the system, so
|
252
|
+
# File.exist checks will always return false.
|
253
|
+
unless options[:source_tree] == :sdkroot
|
254
|
+
raise StandardError.new("Could not find file `#{options[:file]}`") unless File.exists?(options[:file])
|
255
|
+
end
|
256
|
+
|
257
|
+
# Find targets
|
258
|
+
targets = targets_from_options(options)
|
143
259
|
|
144
260
|
# Create the group
|
145
261
|
group = create_group(options[:path])
|
@@ -174,6 +290,12 @@ module Vendor::XCode
|
|
174
290
|
attributes['name'] = name
|
175
291
|
attributes['path'] = options[:file]
|
176
292
|
|
293
|
+
elsif options[:source_tree] == :sdkroot
|
294
|
+
|
295
|
+
# Set the path and the name of the framework
|
296
|
+
attributes['path'] = options[:file]
|
297
|
+
attributes['sourceTree'] = "SDKROOT"
|
298
|
+
|
177
299
|
else
|
178
300
|
|
179
301
|
# Could not handle that option
|
@@ -192,6 +314,11 @@ module Vendor::XCode
|
|
192
314
|
# Add the file id to the groups children
|
193
315
|
group.attributes['children'] << file.id
|
194
316
|
|
317
|
+
# Add the file to targets
|
318
|
+
targets.each do |t|
|
319
|
+
add_file_to_target file, t
|
320
|
+
end
|
321
|
+
|
195
322
|
# Mark as dirty
|
196
323
|
@dirty = true
|
197
324
|
|
@@ -199,6 +326,50 @@ module Vendor::XCode
|
|
199
326
|
@objects_by_id[file.id] = file
|
200
327
|
end
|
201
328
|
|
329
|
+
def remove_file_from_target(file, target)
|
330
|
+
|
331
|
+
# Search through all the build phases for references to the file
|
332
|
+
build_files = []
|
333
|
+
target.build_phases.each do |phase|
|
334
|
+
build_files << phase.files.find_all do |build_file|
|
335
|
+
build_file.attributes['fileRef'] == file.id
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
# Remove the build files from the references
|
340
|
+
build_files.flatten.each do |build_file|
|
341
|
+
build_file.parent.attributes['files'].delete build_file.id
|
342
|
+
@objects_by_id.delete build_file.id
|
343
|
+
end
|
344
|
+
|
345
|
+
end
|
346
|
+
|
347
|
+
def add_file_to_target(file, target)
|
348
|
+
|
349
|
+
build_phase = build_phase_for_file(file.last_known_file_type, target)
|
350
|
+
|
351
|
+
if build_phase
|
352
|
+
|
353
|
+
Vendor.ui.debug "Adding #{file.attributes} to #{target.name} (build_phase = #{build_phase.class.name})"
|
354
|
+
|
355
|
+
# Add the file to XCode
|
356
|
+
build_file = Vendor::XCode::Proxy::PBXBuildFile.new(:project => self,
|
357
|
+
:id => Vendor::XCode::Proxy::Base.generate_id,
|
358
|
+
:attributes => { 'fileRef' => file.id })
|
359
|
+
|
360
|
+
# Set the parent
|
361
|
+
build_file.parent = build_phase
|
362
|
+
|
363
|
+
# Add the file to the internal index
|
364
|
+
@objects_by_id[build_file.id] = build_file
|
365
|
+
|
366
|
+
# Add the file to the build phase
|
367
|
+
build_phase.attributes['files'] << build_file.id
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
202
373
|
def to_ascii_plist
|
203
374
|
plist = { :archiveVersion => archive_version,
|
204
375
|
:classes => {},
|
@@ -240,10 +411,48 @@ module Vendor::XCode
|
|
240
411
|
|
241
412
|
private
|
242
413
|
|
414
|
+
def build_phase_for_file(file_type, target)
|
415
|
+
# Which build phase does this file belong?
|
416
|
+
klass = case file_type
|
417
|
+
when "sourcecode.c.objc"
|
418
|
+
Vendor::XCode::Proxy::PBXSourcesBuildPhase
|
419
|
+
when "wrapper.framework"
|
420
|
+
Vendor::XCode::Proxy::PBXFrameworksBuildPhase
|
421
|
+
end
|
422
|
+
|
423
|
+
if klass
|
424
|
+
# Find the build phase
|
425
|
+
build_phase = target.build_phases.find { |phase| phase.kind_of?(klass) }
|
426
|
+
unless build_phase
|
427
|
+
Vendor.ui.error "Could not find '#{klass.name}' build phase for target '#{target.name}'"
|
428
|
+
exit 1
|
429
|
+
end
|
430
|
+
build_phase
|
431
|
+
else
|
432
|
+
false
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
243
436
|
def require_options(options, *keys)
|
244
437
|
keys.each { |k| raise StandardError.new("Missing :#{k} option") unless options[k] }
|
245
438
|
end
|
246
439
|
|
440
|
+
def targets_from_options(options)
|
441
|
+
if options[:targets]
|
442
|
+
[ *options[:targets] ].map do |t|
|
443
|
+
if t == :all
|
444
|
+
root_object.targets
|
445
|
+
else
|
446
|
+
target = find_target(t)
|
447
|
+
raise StandardError.new("Could not find target '#{t}' in project '#{name}'") unless target
|
448
|
+
target
|
449
|
+
end
|
450
|
+
end.flatten.uniq
|
451
|
+
else
|
452
|
+
root_object.targets
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
247
456
|
end
|
248
457
|
|
249
458
|
end
|