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
@@ -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
|