vendor 0.0.4 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,15 +1,20 @@
|
|
1
1
|
# This is a generated version of the vendorspec. Please change the
|
2
|
-
# values to suit your library.
|
3
|
-
# all possible attributes.
|
2
|
+
# values to suit your library.
|
4
3
|
|
5
|
-
|
6
|
-
version "0.1"
|
4
|
+
Vendor::Spec.new do |s|
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
homepage "HOMEPAGE GOES HERE"
|
11
|
-
description "DESCRIPTION GOES HERE"
|
6
|
+
s.name "<%= name %>"
|
7
|
+
s.version "0.1"
|
12
8
|
|
13
|
-
|
9
|
+
s.authors "<%= username %>"
|
10
|
+
s.email "<%= email %>"
|
11
|
+
s.description "DESCRIPTION GOES HERE"
|
14
12
|
|
15
|
-
|
13
|
+
# s.homepage "HOMEPAGE URL GOES HERE"
|
14
|
+
# s.source "SOURCE URL GOES HERE"
|
15
|
+
|
16
|
+
s.files `git ls-files`.split("\n")
|
17
|
+
|
18
|
+
# s.dependency "JSONKit", "0.5"
|
19
|
+
|
20
|
+
end
|
data/lib/vendor/vendor_file.rb
CHANGED
@@ -2,10 +2,11 @@ module Vendor
|
|
2
2
|
|
3
3
|
module VendorFile
|
4
4
|
|
5
|
-
autoload :Source,
|
6
|
-
autoload :Loader,
|
7
|
-
autoload :DSL,
|
8
|
-
autoload :Library,
|
5
|
+
autoload :Source, "vendor/vendor_file/source"
|
6
|
+
autoload :Loader, "vendor/vendor_file/loader"
|
7
|
+
autoload :DSL, "vendor/vendor_file/dsl"
|
8
|
+
autoload :Library, "vendor/vendor_file/library"
|
9
|
+
autoload :DependencyGraph, "vendor/vendor_file/dependency_graph"
|
9
10
|
|
10
11
|
end
|
11
12
|
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Vendor
|
2
|
+
module VendorFile
|
3
|
+
|
4
|
+
class DependencyGraph
|
5
|
+
|
6
|
+
attr_accessor :libraries
|
7
|
+
attr_reader :libraries_to_install
|
8
|
+
|
9
|
+
def initialize(libs = nil)
|
10
|
+
self.libraries = libs
|
11
|
+
end
|
12
|
+
|
13
|
+
def libraries=(value)
|
14
|
+
if value
|
15
|
+
# We want our own array, not a pointer to the old one, but we
|
16
|
+
# can keep the contents, thats fine.
|
17
|
+
@libraries = [ *value ]
|
18
|
+
else
|
19
|
+
@libraries = nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def dependency_graph
|
24
|
+
map = {}
|
25
|
+
_touched = {}
|
26
|
+
graph = []
|
27
|
+
@libraries.each do |lib|
|
28
|
+
if (x = _map(lib, map, _touched))
|
29
|
+
graph << x
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
return graph, map
|
34
|
+
end
|
35
|
+
|
36
|
+
def version_conflicts?
|
37
|
+
graph, map = dependency_graph
|
38
|
+
|
39
|
+
# The version conflict detector is pretty stupid, pretty much if
|
40
|
+
# two libraries are trying to include a lib of different
|
41
|
+
# versions:
|
42
|
+
# a requires b v1.0
|
43
|
+
# c requires b v1.1
|
44
|
+
# Then things will blow up.
|
45
|
+
|
46
|
+
@libraries_to_install = []
|
47
|
+
|
48
|
+
map.keys.sort.each do |name|
|
49
|
+
|
50
|
+
libs = map[name]
|
51
|
+
|
52
|
+
# Only populate the "targets" element if there is a specific
|
53
|
+
# target to add to.
|
54
|
+
found_targets = libs.find_all { |l| l.targets if l.targets }.map &:targets
|
55
|
+
targets = found_targets.empty? ? nil : found_targets.flatten.compact.uniq
|
56
|
+
|
57
|
+
version_to_install = libs.first
|
58
|
+
|
59
|
+
# Check for conflicts and try to resolve
|
60
|
+
if libs.length > 1
|
61
|
+
|
62
|
+
# Sort the versions, starting with the latest version first
|
63
|
+
versions = libs.sort.reverse
|
64
|
+
|
65
|
+
# This code is a little yucky, but what it does, is it tries
|
66
|
+
# to find the best version match for every other version in
|
67
|
+
# the loop. So, lets say we have versions => 0.1 and ~> 0.1,
|
68
|
+
# and we have an array of [ "0.1", "0.1.1" ], try and find
|
69
|
+
# the higest versiont that each likes. Once we know that, we
|
70
|
+
# uniqify the results. If we have more than 1, that means we
|
71
|
+
# have a conflict.
|
72
|
+
vvs = versions.map(&:version)
|
73
|
+
matched_versions = libs.map do |l|
|
74
|
+
l.version_matches_any?(vvs)
|
75
|
+
end.inject([]) do |uniqs, obj|
|
76
|
+
if uniqs.all? { |e| e != obj }
|
77
|
+
uniqs << obj
|
78
|
+
end
|
79
|
+
uniqs
|
80
|
+
end
|
81
|
+
|
82
|
+
if matched_versions.length > 1
|
83
|
+
version_to_install = nil
|
84
|
+
else
|
85
|
+
# Find the version we've recomended and install that one.
|
86
|
+
y = matched_versions.first
|
87
|
+
version_to_install = versions.find do |x|
|
88
|
+
x.version == y.to_s
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
# Are there multiple versions to install?
|
95
|
+
unless version_to_install
|
96
|
+
Vendor.ui.error "Multiple versions detected for #{name} (#{versions.map(&:version).join(', ')})"
|
97
|
+
|
98
|
+
# A semi-meaningfull error
|
99
|
+
libs.each do |v|
|
100
|
+
if v.parent
|
101
|
+
Vendor.ui.error " #{v.description} is required by #{v.parent.description}"
|
102
|
+
else
|
103
|
+
Vendor.ui.error " #{v.description} is required in the Vendorfile"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
exit
|
108
|
+
else
|
109
|
+
@libraries_to_install << [ version_to_install, targets ]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
false
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def _map(library, map, _touched)
|
119
|
+
unless _touched[library.description]
|
120
|
+
# Add the library to the map
|
121
|
+
map[library.name] ||= []
|
122
|
+
map[library.name] << library
|
123
|
+
|
124
|
+
# So we don't traverse this object again
|
125
|
+
_touched[library.description] = true
|
126
|
+
|
127
|
+
# Return the graph
|
128
|
+
[ library.description, library.dependencies.map { |l| _map(l, map, _touched) }.compact ]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
@@ -6,32 +6,51 @@ module Vendor
|
|
6
6
|
|
7
7
|
class Base
|
8
8
|
|
9
|
+
attr_accessor :parent
|
10
|
+
|
9
11
|
attr_accessor :name
|
10
12
|
attr_accessor :targets
|
11
13
|
attr_accessor :require
|
14
|
+
attr_accessor :version
|
12
15
|
|
13
16
|
def initialize(attributes = {})
|
14
17
|
@source_tree = :group
|
18
|
+
@targets = [ :all ]
|
15
19
|
attributes.each { |k, v| self.send("#{k}=", v) }
|
16
20
|
end
|
17
21
|
|
18
22
|
def targets=(value)
|
19
|
-
|
23
|
+
if value
|
24
|
+
@targets = [ *value ]
|
25
|
+
end
|
20
26
|
end
|
21
27
|
|
22
28
|
alias :target= :targets=
|
23
29
|
|
24
30
|
def cache_path
|
25
|
-
|
31
|
+
File.join(Vendor.library_path, self.class.name.split('::').last.downcase, name)
|
26
32
|
end
|
27
33
|
|
28
34
|
def download
|
29
35
|
# Do nothing by default, leave that up to the implementation
|
30
36
|
end
|
31
37
|
|
32
|
-
|
33
|
-
|
38
|
+
# This method sucks. What we should be doing is passing a library to the Xcode project class
|
39
|
+
# to install. We shouldn't be interacting with it like this. Really, VendorFile::Library should
|
40
|
+
# extend Xcode::Library or something. That was its a little more modular.
|
41
|
+
def install(project, options = {})
|
42
|
+
# If the cache doesn't exist, download it
|
43
|
+
download unless cache_exists?
|
34
44
|
|
45
|
+
Vendor.ui.info %{Installing #{display_name}}
|
46
|
+
|
47
|
+
# Combine the local targets, with those targets specified in the options. Also
|
48
|
+
# for sanity reasons, flatten and uniqify them.
|
49
|
+
if @targets || options[:targets]
|
50
|
+
install_targets = [ @targets, options[:targets] ].compact.flatten.uniq
|
51
|
+
end
|
52
|
+
|
53
|
+
# The destination in the XCode project
|
35
54
|
destination = "Vendor/#{name}"
|
36
55
|
|
37
56
|
# Remove the group, and recreate
|
@@ -39,53 +58,183 @@ module Vendor
|
|
39
58
|
|
40
59
|
# Install the files back into the project
|
41
60
|
files.each do |file|
|
42
|
-
|
43
|
-
|
44
|
-
project.add_file :targets => targets, :path => destination,
|
61
|
+
project.add_file :targets => install_targets, :path => destination,
|
45
62
|
:file => file, :source_tree => @source_tree
|
46
63
|
end
|
64
|
+
|
65
|
+
# Add frameworks
|
66
|
+
frameworks.each do |framework|
|
67
|
+
project.add_framework framework, :targets => install_targets
|
68
|
+
end
|
69
|
+
|
70
|
+
# Add compiler flags
|
71
|
+
build_settings.each do |build_setting|
|
72
|
+
project.add_build_setting build_setting[0], build_setting[1], :targets => install_targets, :from => self
|
73
|
+
end
|
47
74
|
end
|
48
75
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
|
76
|
+
def dependencies
|
77
|
+
# If the cache doesn't exist, download it
|
78
|
+
download unless cache_exists?
|
79
|
+
|
80
|
+
# Find the dependencies
|
81
|
+
dependencies = if manifest
|
82
|
+
manifest['dependencies']
|
83
|
+
elsif vendor_spec
|
84
|
+
vendor_spec.dependencies
|
53
85
|
end
|
54
86
|
|
55
|
-
#
|
56
|
-
|
87
|
+
# Create remote objects to represent the dependencies
|
88
|
+
(dependencies || []).map do |d|
|
89
|
+
Vendor::VendorFile::Library::Remote.new(:name => d[0], :version => d[1], :parent => self, :targets => @targets)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def frameworks
|
94
|
+
# If the cache doesn't exist, download it
|
95
|
+
download unless cache_exists?
|
96
|
+
|
97
|
+
# Find the frameworks
|
98
|
+
frameworks = if manifest
|
99
|
+
manifest['frameworks']
|
100
|
+
elsif vendor_spec
|
101
|
+
vendor_spec.frameworks
|
102
|
+
end
|
103
|
+
|
104
|
+
frameworks || []
|
105
|
+
end
|
57
106
|
|
58
|
-
|
59
|
-
|
107
|
+
def build_settings
|
108
|
+
# If the cache doesn't exist, download it
|
109
|
+
download unless cache_exists?
|
110
|
+
|
111
|
+
# Find the build settings
|
112
|
+
build_settings = if manifest
|
113
|
+
manifest['build_settings']
|
114
|
+
elsif vendor_spec
|
115
|
+
vendor_spec.build_settings
|
116
|
+
end
|
117
|
+
|
118
|
+
build_settings || []
|
119
|
+
end
|
120
|
+
|
121
|
+
def files
|
122
|
+
# If the cache doesn't exist, download it
|
123
|
+
download unless cache_exists?
|
60
124
|
|
61
125
|
# Calculate the files we need to add. There are 3 different types
|
62
126
|
# of installation:
|
63
127
|
# 1) Installation from a manifest (a built lib)
|
64
128
|
# 2) Loading the .vendorspec and seeing what files needed to be added
|
65
129
|
# 3) Try to be smart and try and find files to install
|
66
|
-
install_files = if manifest
|
130
|
+
install_files = if manifest
|
131
|
+
manifest['files'].map do |file|
|
132
|
+
File.join(cache_path, "data", file)
|
133
|
+
end
|
134
|
+
elsif vendor_spec
|
135
|
+
vendor_spec.files.map do |file|
|
136
|
+
File.join(cache_path, file)
|
137
|
+
end
|
138
|
+
else
|
139
|
+
location = [ cache_path, self.require, "**/*.*" ].compact
|
140
|
+
Dir[ File.join *location ]
|
141
|
+
end
|
67
142
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
143
|
+
# Remove files that are within folders with a ".", such as ".bundle"
|
144
|
+
# and ".frameworks"
|
145
|
+
install_files.reject do |file|
|
146
|
+
file.gsub(cache_path, "") =~ /\/?[^\/]+\.[^\/]+\//
|
147
|
+
end
|
148
|
+
end
|
72
149
|
|
73
|
-
|
74
|
-
|
75
|
-
|
150
|
+
def version
|
151
|
+
if @version
|
152
|
+
@version
|
153
|
+
elsif manifest
|
154
|
+
manifest['version']
|
155
|
+
elsif vendor_spec
|
156
|
+
vendor_spec.version
|
157
|
+
end
|
158
|
+
end
|
76
159
|
|
77
|
-
|
160
|
+
def version_matches_any?(other_versions)
|
161
|
+
# If we have an equality matcher, we need sort through
|
162
|
+
# the versions, and try and find the best match
|
163
|
+
wants = Vendor::Version.new(version)
|
78
164
|
|
79
|
-
|
80
|
-
|
165
|
+
# Sort them from the latest versions first
|
166
|
+
versions = other_versions.map{|v| Vendor::Version.create(v) }.sort.reverse
|
81
167
|
|
168
|
+
# We don't want to include pre-releases if the wants version
|
169
|
+
# isn't a pre-release itself. If we're after "2.5.alpha", then
|
170
|
+
# we should be able to include that, however if we're asking for
|
171
|
+
# "2.5", then pre-releases shouldn't be included.
|
172
|
+
unless wants.prerelease?
|
173
|
+
versions = versions.reject { |v| v.prerelease? }
|
82
174
|
end
|
83
175
|
|
84
|
-
|
85
|
-
|
86
|
-
|
176
|
+
versions.find { |has| wants == has }
|
177
|
+
end
|
178
|
+
|
179
|
+
def <=>(other)
|
180
|
+
v = other.respond_to?(:version) ? other.version : other
|
181
|
+
Vendor::Version.create(version) <=> Vendor::Version.create(v)
|
182
|
+
end
|
183
|
+
|
184
|
+
def ==(other)
|
185
|
+
other.name == name && other.version == version
|
186
|
+
end
|
187
|
+
|
188
|
+
def display_name
|
189
|
+
description
|
87
190
|
end
|
88
191
|
|
192
|
+
def description
|
193
|
+
[ name, version ].compact.join(" ")
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def cache_exists?
|
199
|
+
File.exist?(cache_path)
|
200
|
+
end
|
201
|
+
|
202
|
+
def vendor_spec
|
203
|
+
# Cache the vendor spec
|
204
|
+
return @vendor_spec if @vendor_spec
|
205
|
+
|
206
|
+
# Try and find a vendorspec in the cached folder
|
207
|
+
if cache_path
|
208
|
+
file = Dir[File.join(cache_path, "*.vendorspec")].first
|
209
|
+
|
210
|
+
if file && File.exist?(file)
|
211
|
+
@vendor_spec = Vendor::Spec.load(file)
|
212
|
+
else
|
213
|
+
false
|
214
|
+
end
|
215
|
+
else
|
216
|
+
false
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def manifest
|
221
|
+
# Cache the manifest
|
222
|
+
return @manifest if @manifest
|
223
|
+
|
224
|
+
# Try and find a manifest (a built vendor file)
|
225
|
+
if cache_path
|
226
|
+
file = File.join(cache_path, "vendor.json")
|
227
|
+
|
228
|
+
if File.exist?(file)
|
229
|
+
@manifest = JSON.parse(File.read(file))
|
230
|
+
else
|
231
|
+
false
|
232
|
+
end
|
233
|
+
else
|
234
|
+
false
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
89
238
|
end
|
90
239
|
|
91
240
|
end
|