bundler 1.12.6 → 1.13.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bundler might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +15 -13
- data/.travis.yml +2 -2
- data/CHANGELOG.md +40 -3
- data/CONTRIBUTING.md +9 -5
- data/DEVELOPMENT.md +30 -18
- data/ISSUES.md +26 -22
- data/Rakefile +15 -4
- data/bin/rubocop +1 -1
- data/bundler.gemspec +2 -2
- data/exe/bundle +7 -0
- data/lib/bundler.rb +6 -3
- data/lib/bundler/capistrano.rb +1 -1
- data/lib/bundler/cli.rb +27 -10
- data/lib/bundler/cli/binstubs.rb +2 -0
- data/lib/bundler/cli/exec.rb +1 -1
- data/lib/bundler/cli/install.rb +87 -56
- data/lib/bundler/cli/lock.rb +5 -0
- data/lib/bundler/cli/open.rb +3 -1
- data/lib/bundler/cli/outdated.rb +8 -8
- data/lib/bundler/cli/plugin.rb +23 -0
- data/lib/bundler/cli/update.rb +2 -2
- data/lib/bundler/cli/viz.rb +3 -0
- data/lib/bundler/definition.rb +72 -16
- data/lib/bundler/dsl.rb +19 -7
- data/lib/bundler/endpoint_specification.rb +2 -2
- data/lib/bundler/env.rb +2 -2
- data/lib/bundler/errors.rb +15 -1
- data/lib/bundler/fetcher.rb +5 -2
- data/lib/bundler/fetcher/compact_index.rb +2 -2
- data/lib/bundler/fetcher/dependency.rb +8 -4
- data/lib/bundler/fetcher/downloader.rb +1 -1
- data/lib/bundler/friendly_errors.rb +1 -1
- data/lib/bundler/index.rb +29 -36
- data/lib/bundler/inline.rb +14 -4
- data/lib/bundler/installer.rb +22 -3
- data/lib/bundler/installer/gem_installer.rb +1 -1
- data/lib/bundler/installer/standalone.rb +1 -1
- data/lib/bundler/mirror.rb +4 -4
- data/lib/bundler/plugin.rb +156 -0
- data/lib/bundler/plugin/api.rb +56 -0
- data/lib/bundler/plugin/dsl.rb +29 -0
- data/lib/bundler/plugin/index.rb +88 -0
- data/lib/bundler/plugin/installer.rb +99 -0
- data/lib/bundler/plugin/installer/git.rb +38 -0
- data/lib/bundler/plugin/installer/rubygems.rb +27 -0
- data/lib/bundler/plugin/source_list.rb +24 -0
- data/lib/bundler/postit_trampoline.rb +54 -0
- data/lib/bundler/psyched_yaml.rb +1 -1
- data/lib/bundler/remote_specification.rb +5 -5
- data/lib/bundler/resolver.rb +27 -29
- data/lib/bundler/ruby_version.rb +29 -3
- data/lib/bundler/rubygems_ext.rb +3 -1
- data/lib/bundler/rubygems_integration.rb +10 -4
- data/lib/bundler/runtime.rb +1 -16
- data/lib/bundler/settings.rb +19 -15
- data/lib/bundler/setup.rb +1 -0
- data/lib/bundler/shared_helpers.rb +3 -0
- data/lib/bundler/source.rb +4 -3
- data/lib/bundler/source/gemspec.rb +13 -0
- data/lib/bundler/source/git.rb +4 -3
- data/lib/bundler/source/git/git_proxy.rb +9 -5
- data/lib/bundler/source/path.rb +11 -2
- data/lib/bundler/source/rubygems.rb +28 -15
- data/lib/bundler/source_list.rb +5 -1
- data/lib/bundler/spec_set.rb +3 -3
- data/lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem +21 -0
- data/lib/bundler/ssl_certs/rubygems.org/{AddTrustExternalCARoot-2048.pem → AddTrustExternalCARoot.pem} +0 -0
- data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +54 -29
- data/lib/bundler/templates/newgem/newgem.gemspec.tt +5 -2
- data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +3 -3
- data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +2 -2
- data/lib/bundler/ui/shell.rb +4 -0
- data/lib/bundler/ui/silent.rb +3 -0
- data/lib/bundler/uri_credentials_filter.rb +36 -0
- data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb +1 -1
- data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +50 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +80 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +56 -144
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +35 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +58 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +61 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +53 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +114 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +45 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +35 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +123 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +1 -1
- data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +46 -51
- data/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +4 -2
- data/lib/bundler/vendor/postit/lib/postit.rb +15 -0
- data/lib/bundler/vendor/postit/lib/postit/environment.rb +44 -0
- data/lib/bundler/vendor/postit/lib/postit/installer.rb +28 -0
- data/lib/bundler/vendor/postit/lib/postit/parser.rb +21 -0
- data/lib/bundler/vendor/postit/lib/postit/setup.rb +12 -0
- data/lib/bundler/vendor/postit/lib/postit/version.rb +3 -0
- data/lib/bundler/version.rb +1 -1
- data/lib/bundler/vlad.rb +1 -1
- data/lib/bundler/yaml_serializer.rb +67 -0
- data/man/bundle-install.ronn +10 -5
- data/man/bundle-package.ronn +7 -6
- data/man/bundle-platform.ronn +1 -1
- data/man/bundle-update.ronn +5 -2
- data/man/bundle.ronn +5 -5
- data/man/gemfile.5.ronn +32 -28
- metadata +37 -12
- data/lib/bundler/ssl_certs/Fastly.pem +0 -82
- data/lib/bundler/ssl_certs/GlobalSignOrganizationValidationCA.pem +0 -26
- data/lib/bundler/ssl_certs/GlobalSignRoot.pem +0 -18
- data/lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRoot.pem +0 -18
@@ -58,7 +58,7 @@ module Bundler
|
|
58
58
|
raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \
|
59
59
|
"connection and try again."
|
60
60
|
else
|
61
|
-
raise HTTPError, "Network error while fetching #{uri}"
|
61
|
+
raise HTTPError, "Network error while fetching #{URICredentialsFilter.credential_filtered_uri(uri)}"
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
data/lib/bundler/index.rb
CHANGED
@@ -21,15 +21,14 @@ module Bundler
|
|
21
21
|
@sources = []
|
22
22
|
@cache = {}
|
23
23
|
@specs = Hash.new {|h, k| h[k] = {} }
|
24
|
-
@all_specs = Hash.new {|h, k| h[k] =
|
24
|
+
@all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH }
|
25
25
|
end
|
26
26
|
|
27
27
|
def initialize_copy(o)
|
28
|
-
|
29
|
-
@sources = @sources.dup
|
28
|
+
@sources = o.sources.dup
|
30
29
|
@cache = {}
|
31
30
|
@specs = Hash.new {|h, k| h[k] = {} }
|
32
|
-
@all_specs = Hash.new {|h, k| h[k] =
|
31
|
+
@all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH }
|
33
32
|
|
34
33
|
o.specs.each do |name, hash|
|
35
34
|
@specs[name] = hash.dup
|
@@ -49,7 +48,7 @@ module Bundler
|
|
49
48
|
end
|
50
49
|
|
51
50
|
def search_all(name)
|
52
|
-
all_matches = @all_specs[name]
|
51
|
+
all_matches = local_search(name) + @all_specs[name]
|
53
52
|
@sources.each do |source|
|
54
53
|
all_matches.concat(source.search_all(name))
|
55
54
|
end
|
@@ -60,19 +59,18 @@ module Bundler
|
|
60
59
|
# about, returning all of the results.
|
61
60
|
def search(query, base = nil)
|
62
61
|
results = local_search(query, base)
|
63
|
-
seen =
|
62
|
+
seen = results.map(&:full_name).to_set
|
64
63
|
|
65
64
|
@sources.each do |source|
|
66
65
|
source.search(query, base).each do |spec|
|
67
|
-
|
68
|
-
unless seen.include?(lookup)
|
69
|
-
results << spec
|
70
|
-
seen << lookup
|
71
|
-
end
|
66
|
+
results << spec if seen.add?(spec.full_name)
|
72
67
|
end
|
73
68
|
end
|
74
69
|
|
75
|
-
results.sort_by
|
70
|
+
results.sort_by do |s|
|
71
|
+
platform_string = s.platform.to_s
|
72
|
+
[s.version, platform_string == RUBY ? NULL : platform_string]
|
73
|
+
end
|
76
74
|
end
|
77
75
|
|
78
76
|
def local_search(query, base = nil)
|
@@ -90,14 +88,15 @@ module Bundler
|
|
90
88
|
|
91
89
|
def <<(spec)
|
92
90
|
@specs[spec.name][spec.full_name] = spec
|
93
|
-
|
94
91
|
spec
|
95
92
|
end
|
96
93
|
|
97
94
|
def each(&blk)
|
95
|
+
return enum_for(:each) unless blk
|
98
96
|
specs.values.each do |spec_sets|
|
99
97
|
spec_sets.values.each(&blk)
|
100
98
|
end
|
99
|
+
sources.each {|s| s.each(&blk) }
|
101
100
|
end
|
102
101
|
|
103
102
|
# returns a list of the dependencies
|
@@ -109,17 +108,17 @@ module Bundler
|
|
109
108
|
|
110
109
|
def dependency_names
|
111
110
|
names = []
|
112
|
-
each {|s| names.
|
111
|
+
each {|s| names.concat(s.dependencies.map(&:name)) }
|
113
112
|
names.uniq
|
114
113
|
end
|
115
114
|
|
116
115
|
def use(other, override_dupes = false)
|
117
116
|
return unless other
|
118
117
|
other.each do |s|
|
119
|
-
if (dupes = search_by_spec(s)) && dupes.
|
120
|
-
|
118
|
+
if (dupes = search_by_spec(s)) && !dupes.empty?
|
119
|
+
# safe to << since it's a new array when it has contents
|
120
|
+
@all_specs[s.name] = dupes << s
|
121
121
|
next unless override_dupes
|
122
|
-
self << s
|
123
122
|
end
|
124
123
|
self << s
|
125
124
|
end
|
@@ -135,10 +134,16 @@ module Bundler
|
|
135
134
|
def ==(other)
|
136
135
|
all? do |spec|
|
137
136
|
other_spec = other[spec].first
|
138
|
-
other_spec && (spec
|
137
|
+
other_spec && dependencies_eql?(spec, other_spec) && spec.source == other_spec.source
|
139
138
|
end
|
140
139
|
end
|
141
140
|
|
141
|
+
def dependencies_eql?(spec, other_spec)
|
142
|
+
deps = spec.dependencies.select {|d| d.type != :development }
|
143
|
+
other_deps = other_spec.dependencies.select {|d| d.type != :development }
|
144
|
+
Set.new(deps) == Set.new(other_deps)
|
145
|
+
end
|
146
|
+
|
142
147
|
def add_source(index)
|
143
148
|
raise ArgumentError, "Source must be an index, not #{index.class}" unless index.is_a?(Index)
|
144
149
|
@sources << index
|
@@ -154,8 +159,10 @@ module Bundler
|
|
154
159
|
def search_by_dependency(dependency, base = nil)
|
155
160
|
@cache[base || false] ||= {}
|
156
161
|
@cache[base || false][dependency] ||= begin
|
157
|
-
specs = specs_by_name(dependency.name)
|
162
|
+
specs = specs_by_name(dependency.name)
|
163
|
+
specs += base if base
|
158
164
|
found = specs.select do |spec|
|
165
|
+
next true if spec.source.is_a?(Source::Gemspec)
|
159
166
|
if base # allow all platforms when searching from a lockfile
|
160
167
|
dependency.matches_spec?(spec)
|
161
168
|
else
|
@@ -174,25 +181,11 @@ module Bundler
|
|
174
181
|
end
|
175
182
|
end
|
176
183
|
|
184
|
+
EMPTY_SEARCH = [].freeze
|
185
|
+
|
177
186
|
def search_by_spec(spec)
|
178
187
|
spec = @specs[spec.name][spec.full_name]
|
179
|
-
spec ? [spec] :
|
180
|
-
end
|
181
|
-
|
182
|
-
if RUBY_VERSION < "1.9"
|
183
|
-
def same_version?(a, b)
|
184
|
-
regex = /^(.*?)(?:\.0)*$/
|
185
|
-
a.to_s[regex, 1] == b.to_s[regex, 1]
|
186
|
-
end
|
187
|
-
else
|
188
|
-
def same_version?(a, b)
|
189
|
-
a == b
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def spec_satisfies_dependency?(spec, dep)
|
194
|
-
return false unless dep.name == spec.name
|
195
|
-
dep.requirement.satisfied_by?(spec.version)
|
188
|
+
spec ? [spec] : EMPTY_SEARCH
|
196
189
|
end
|
197
190
|
end
|
198
191
|
end
|
data/lib/bundler/inline.rb
CHANGED
@@ -41,6 +41,7 @@ def gemfile(install = false, options = {}, &gemfile)
|
|
41
41
|
end
|
42
42
|
ENV["BUNDLE_GEMFILE"] ||= "Gemfile"
|
43
43
|
|
44
|
+
Bundler::Plugin.gemfile_install(&gemfile) if Bundler.settings[:plugins]
|
44
45
|
builder = Bundler::Dsl.new
|
45
46
|
builder.instance_eval(&gemfile)
|
46
47
|
|
@@ -48,8 +49,17 @@ def gemfile(install = false, options = {}, &gemfile)
|
|
48
49
|
def definition.lock(*); end
|
49
50
|
definition.validate_ruby!
|
50
51
|
|
51
|
-
|
52
|
-
|
52
|
+
missing_specs = proc do
|
53
|
+
begin
|
54
|
+
!definition.missing_specs.empty?
|
55
|
+
rescue Bundler::GemNotFound, Bundler::GitError
|
56
|
+
definition.instance_variable_set(:@index, nil)
|
57
|
+
true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Bundler.ui = ui if install
|
62
|
+
if install || missing_specs.call
|
53
63
|
Bundler::Installer.install(Bundler.root, definition, :system => true)
|
54
64
|
Bundler::Installer.post_install_messages.each do |name, message|
|
55
65
|
Bundler.ui.info "Post-install message from #{name}:\n#{message}"
|
@@ -58,7 +68,7 @@ def gemfile(install = false, options = {}, &gemfile)
|
|
58
68
|
|
59
69
|
runtime = Bundler::Runtime.new(nil, definition)
|
60
70
|
runtime.setup.require
|
61
|
-
|
71
|
+
ensure
|
62
72
|
bundler_module = class << Bundler; self; end
|
63
|
-
bundler_module.send(:define_method, :root, old_root)
|
73
|
+
bundler_module.send(:define_method, :root, old_root) if old_root
|
64
74
|
end
|
data/lib/bundler/installer.rb
CHANGED
@@ -68,6 +68,7 @@ module Bundler
|
|
68
68
|
end
|
69
69
|
|
70
70
|
resolve_if_need(options)
|
71
|
+
ensure_specs_are_compatible!
|
71
72
|
install(options)
|
72
73
|
|
73
74
|
lock unless Bundler.settings[:frozen]
|
@@ -146,9 +147,9 @@ module Bundler
|
|
146
147
|
private
|
147
148
|
|
148
149
|
# the order that the resolver provides is significant, since
|
149
|
-
# dependencies might
|
150
|
+
# dependencies might affect the installation of a gem.
|
150
151
|
# that said, it's a rare situation (other than rake), and parallel
|
151
|
-
# installation is
|
152
|
+
# installation is SO MUCH FASTER. so we let people opt in.
|
152
153
|
def install(options)
|
153
154
|
force = options["force"]
|
154
155
|
jobs = 1
|
@@ -156,6 +157,24 @@ module Bundler
|
|
156
157
|
install_in_parallel jobs, options[:standalone], force
|
157
158
|
end
|
158
159
|
|
160
|
+
def ensure_specs_are_compatible!
|
161
|
+
system_ruby = Bundler::RubyVersion.system
|
162
|
+
rubygems_version = Gem::Version.create(Gem::VERSION)
|
163
|
+
specs.each do |spec|
|
164
|
+
if required_ruby_version = spec.required_ruby_version
|
165
|
+
unless required_ruby_version.satisfied_by?(system_ruby.gem_version)
|
166
|
+
raise InstallError, "#{spec.full_name} requires ruby version #{required_ruby_version}, " \
|
167
|
+
"which is incompatible with the current version, #{system_ruby}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
next unless required_rubygems_version = spec.required_rubygems_version
|
171
|
+
unless required_rubygems_version.satisfied_by?(rubygems_version)
|
172
|
+
raise InstallError, "#{spec.full_name} requires rubygems version #{required_rubygems_version}, " \
|
173
|
+
"which is incompatible with the current version, #{rubygems_version}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
159
178
|
def can_install_in_parallel?
|
160
179
|
if Bundler.rubygems.provides?(">= 2.1.0")
|
161
180
|
true
|
@@ -185,7 +204,7 @@ module Bundler
|
|
185
204
|
local = Bundler.ui.silence do
|
186
205
|
begin
|
187
206
|
tmpdef = Definition.build(Bundler.default_gemfile, Bundler.default_lockfile, nil)
|
188
|
-
true unless tmpdef.new_platform? || tmpdef.
|
207
|
+
true unless tmpdef.new_platform? || tmpdef.missing_dependencies.any?
|
189
208
|
rescue BundlerError
|
190
209
|
end
|
191
210
|
end
|
@@ -39,7 +39,7 @@ module Bundler
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def handle_exception(e)
|
42
|
-
# if install hook failed or gem signature is bad
|
42
|
+
# Die if install hook failed or gem signature is bad.
|
43
43
|
raise e if e.is_a?(Bundler::InstallHookError) || e.is_a?(Bundler::SecurityError)
|
44
44
|
# other failure, likely a native extension build failure
|
45
45
|
Bundler.ui.info ""
|
data/lib/bundler/mirror.rb
CHANGED
@@ -32,10 +32,10 @@ module Bundler
|
|
32
32
|
|
33
33
|
def parse(key, value)
|
34
34
|
config = MirrorConfig.new(key, value)
|
35
|
-
if config.all?
|
36
|
-
|
35
|
+
mirror = if config.all?
|
36
|
+
@all
|
37
37
|
else
|
38
|
-
|
38
|
+
(@mirrors[config.uri] = @mirrors[config.uri] || Mirror.new)
|
39
39
|
end
|
40
40
|
config.update_mirror(mirror)
|
41
41
|
end
|
@@ -177,7 +177,7 @@ module Bundler
|
|
177
177
|
# a given mirror.
|
178
178
|
#
|
179
179
|
# One mirror may correspond to many different addresses, both
|
180
|
-
# because of it having many dns entries or
|
180
|
+
# because of it having many dns entries or because
|
181
181
|
# the network interface is both ipv4 and ipv5
|
182
182
|
class MirrorSockets
|
183
183
|
def initialize(mirror)
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
module Plugin
|
5
|
+
autoload :API, "bundler/plugin/api"
|
6
|
+
autoload :DSL, "bundler/plugin/dsl"
|
7
|
+
autoload :Index, "bundler/plugin/index"
|
8
|
+
autoload :Installer, "bundler/plugin/installer"
|
9
|
+
autoload :SourceList, "bundler/plugin/source_list"
|
10
|
+
|
11
|
+
class MalformattedPlugin < PluginError; end
|
12
|
+
class UndefinedCommandError < PluginError; end
|
13
|
+
|
14
|
+
PLUGIN_FILE_NAME = "plugins.rb".freeze
|
15
|
+
|
16
|
+
module_function
|
17
|
+
|
18
|
+
@commands = {}
|
19
|
+
|
20
|
+
# Installs a new plugin by the given name
|
21
|
+
#
|
22
|
+
# @param [Array<String>] names the name of plugin to be installed
|
23
|
+
# @param [Hash] options various parameters as described in description
|
24
|
+
# @option options [String] :source rubygems source to fetch the plugin gem from
|
25
|
+
# @option options [String] :version (optional) the version of the plugin to install
|
26
|
+
def install(names, options)
|
27
|
+
paths = Installer.new.install(names, options)
|
28
|
+
|
29
|
+
save_plugins paths
|
30
|
+
rescue PluginError => e
|
31
|
+
paths.values.map {|path| Bundler.rm_rf(path) } if paths
|
32
|
+
Bundler.ui.error "Failed to install plugin #{name}: #{e.message}\n #{e.backtrace.join("\n ")}"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Evaluates the Gemfile with a limited DSL and installs the plugins
|
36
|
+
# specified by plugin method
|
37
|
+
#
|
38
|
+
# @param [Pathname] gemfile path
|
39
|
+
def gemfile_install(gemfile = nil, &inline)
|
40
|
+
if block_given?
|
41
|
+
builder = DSL.new
|
42
|
+
builder.instance_eval(&inline)
|
43
|
+
definition = builder.to_definition(nil, true)
|
44
|
+
else
|
45
|
+
definition = DSL.evaluate(gemfile, nil, {})
|
46
|
+
end
|
47
|
+
return unless definition.dependencies.any?
|
48
|
+
|
49
|
+
plugins = Installer.new.install_definition(definition)
|
50
|
+
|
51
|
+
save_plugins plugins
|
52
|
+
end
|
53
|
+
|
54
|
+
# The index object used to store the details about the plugin
|
55
|
+
def index
|
56
|
+
@index ||= Index.new
|
57
|
+
end
|
58
|
+
|
59
|
+
# The directory root to all plugin related data
|
60
|
+
def root
|
61
|
+
@root ||= Bundler.user_bundle_path.join("plugin")
|
62
|
+
end
|
63
|
+
|
64
|
+
# The cache directory for plugin stuffs
|
65
|
+
def cache
|
66
|
+
@cache ||= root.join("cache")
|
67
|
+
end
|
68
|
+
|
69
|
+
# To be called via the API to register to handle a command
|
70
|
+
def add_command(command, cls)
|
71
|
+
@commands[command] = cls
|
72
|
+
end
|
73
|
+
|
74
|
+
# Checks if any plugins handles the command
|
75
|
+
def command?(command)
|
76
|
+
!index.command_plugin(command).nil?
|
77
|
+
end
|
78
|
+
|
79
|
+
# To be called from Cli class to pass the command and argument to
|
80
|
+
# approriate plugin class
|
81
|
+
def exec_command(command, args)
|
82
|
+
raise UndefinedCommandError, "Command #{command} not found" unless command? command
|
83
|
+
|
84
|
+
load_plugin index.command_plugin(command) unless @commands.key? command
|
85
|
+
|
86
|
+
@commands[command].new.exec(command, args)
|
87
|
+
end
|
88
|
+
|
89
|
+
# currently only intended for specs
|
90
|
+
#
|
91
|
+
# @return [String, nil] installed path
|
92
|
+
def installed?(plugin)
|
93
|
+
Index.new.installed?(plugin)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Post installation processing and registering with index
|
97
|
+
#
|
98
|
+
# @param [Hash] plugins mapped to their installtion path
|
99
|
+
def save_plugins(plugins)
|
100
|
+
plugins.each do |name, path|
|
101
|
+
path = Pathname.new path
|
102
|
+
validate_plugin! path
|
103
|
+
register_plugin name, path
|
104
|
+
Bundler.ui.info "Installed plugin #{name}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Checks if the gem is good to be a plugin
|
109
|
+
#
|
110
|
+
# At present it only checks whether it contains plugins.rb file
|
111
|
+
#
|
112
|
+
# @param [Pathname] plugin_path the path plugin is installed at
|
113
|
+
# @raise [Error] if plugins.rb file is not found
|
114
|
+
def validate_plugin!(plugin_path)
|
115
|
+
plugin_file = plugin_path.join(PLUGIN_FILE_NAME)
|
116
|
+
raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin!" unless plugin_file.file?
|
117
|
+
end
|
118
|
+
|
119
|
+
# Runs the plugins.rb file in an isolated namespace, records the plugin
|
120
|
+
# actions it registers for and then passes the data to index to be stored.
|
121
|
+
#
|
122
|
+
# @param [String] name the name of the plugin
|
123
|
+
# @param [Pathname] path the path where the plugin is installed at
|
124
|
+
def register_plugin(name, path)
|
125
|
+
commands = @commands
|
126
|
+
|
127
|
+
@commands = {}
|
128
|
+
|
129
|
+
begin
|
130
|
+
load path.join(PLUGIN_FILE_NAME), true
|
131
|
+
rescue StandardError => e
|
132
|
+
raise MalformattedPlugin, "#{e.class}: #{e.message}"
|
133
|
+
end
|
134
|
+
|
135
|
+
index.register_plugin name, path.to_s, @commands.keys
|
136
|
+
ensure
|
137
|
+
@commands = commands
|
138
|
+
end
|
139
|
+
|
140
|
+
# Executes the plugins.rb file
|
141
|
+
#
|
142
|
+
# @param [String] name of the plugin
|
143
|
+
def load_plugin(name)
|
144
|
+
# Need to ensure before this that plugin root where the rest of gems
|
145
|
+
# are installed to be on load path to support plugin deps. Currently not
|
146
|
+
# done to avoid conflicts
|
147
|
+
path = index.plugin_path(name)
|
148
|
+
|
149
|
+
load path.join(PLUGIN_FILE_NAME)
|
150
|
+
end
|
151
|
+
|
152
|
+
class << self
|
153
|
+
private :load_plugin, :register_plugin, :save_plugins, :validate_plugin!
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|