honkster-bundler 1.1.pre
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/.gitignore +14 -0
- data/CHANGELOG.md +547 -0
- data/ISSUES.md +32 -0
- data/LICENSE +20 -0
- data/README.md +29 -0
- data/Rakefile +150 -0
- data/UPGRADING.md +103 -0
- data/bin/bundle +21 -0
- data/bundler.gemspec +30 -0
- data/lib/bundler.rb +268 -0
- data/lib/bundler/capistrano.rb +11 -0
- data/lib/bundler/cli.rb +515 -0
- data/lib/bundler/definition.rb +427 -0
- data/lib/bundler/dependency.rb +114 -0
- data/lib/bundler/deployment.rb +37 -0
- data/lib/bundler/dsl.rb +245 -0
- data/lib/bundler/environment.rb +47 -0
- data/lib/bundler/gem_helper.rb +145 -0
- data/lib/bundler/graph.rb +130 -0
- data/lib/bundler/index.rb +114 -0
- data/lib/bundler/installer.rb +84 -0
- data/lib/bundler/lazy_specification.rb +71 -0
- data/lib/bundler/lockfile_parser.rb +108 -0
- data/lib/bundler/remote_specification.rb +59 -0
- data/lib/bundler/resolver.rb +454 -0
- data/lib/bundler/rubygems_ext.rb +203 -0
- data/lib/bundler/runtime.rb +148 -0
- data/lib/bundler/settings.rb +117 -0
- data/lib/bundler/setup.rb +15 -0
- data/lib/bundler/shared_helpers.rb +151 -0
- data/lib/bundler/source.rb +662 -0
- data/lib/bundler/spec_set.rb +134 -0
- data/lib/bundler/templates/Executable +16 -0
- data/lib/bundler/templates/Gemfile +4 -0
- data/lib/bundler/templates/newgem/Gemfile.tt +4 -0
- data/lib/bundler/templates/newgem/Rakefile.tt +2 -0
- data/lib/bundler/templates/newgem/bin/newgem.tt +3 -0
- data/lib/bundler/templates/newgem/gitignore.tt +3 -0
- data/lib/bundler/templates/newgem/lib/newgem.rb.tt +7 -0
- data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +7 -0
- data/lib/bundler/templates/newgem/newgem.gemspec.tt +21 -0
- data/lib/bundler/ui.rb +60 -0
- data/lib/bundler/vendor/thor.rb +319 -0
- data/lib/bundler/vendor/thor/actions.rb +297 -0
- data/lib/bundler/vendor/thor/actions/create_file.rb +105 -0
- data/lib/bundler/vendor/thor/actions/directory.rb +93 -0
- data/lib/bundler/vendor/thor/actions/empty_directory.rb +134 -0
- data/lib/bundler/vendor/thor/actions/file_manipulation.rb +229 -0
- data/lib/bundler/vendor/thor/actions/inject_into_file.rb +104 -0
- data/lib/bundler/vendor/thor/base.rb +556 -0
- data/lib/bundler/vendor/thor/core_ext/file_binary_read.rb +9 -0
- data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +75 -0
- data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +100 -0
- data/lib/bundler/vendor/thor/error.rb +30 -0
- data/lib/bundler/vendor/thor/invocation.rb +168 -0
- data/lib/bundler/vendor/thor/parser.rb +4 -0
- data/lib/bundler/vendor/thor/parser/argument.rb +67 -0
- data/lib/bundler/vendor/thor/parser/arguments.rb +161 -0
- data/lib/bundler/vendor/thor/parser/option.rb +120 -0
- data/lib/bundler/vendor/thor/parser/options.rb +174 -0
- data/lib/bundler/vendor/thor/shell.rb +88 -0
- data/lib/bundler/vendor/thor/shell/basic.rb +275 -0
- data/lib/bundler/vendor/thor/shell/color.rb +108 -0
- data/lib/bundler/vendor/thor/shell/html.rb +121 -0
- data/lib/bundler/vendor/thor/task.rb +114 -0
- data/lib/bundler/vendor/thor/util.rb +229 -0
- data/lib/bundler/vendor/thor/version.rb +3 -0
- data/lib/bundler/version.rb +6 -0
- data/lib/bundler/vlad.rb +9 -0
- data/man/bundle-config.ronn +90 -0
- data/man/bundle-exec.ronn +98 -0
- data/man/bundle-install.ronn +310 -0
- data/man/bundle-package.ronn +59 -0
- data/man/bundle-update.ronn +176 -0
- data/man/bundle.ronn +77 -0
- data/man/gemfile.5.ronn +273 -0
- data/man/index.txt +6 -0
- data/spec/cache/gems_spec.rb +205 -0
- data/spec/cache/git_spec.rb +9 -0
- data/spec/cache/path_spec.rb +27 -0
- data/spec/cache/platform_spec.rb +57 -0
- data/spec/install/deploy_spec.rb +197 -0
- data/spec/install/deprecated_spec.rb +43 -0
- data/spec/install/gems/c_ext_spec.rb +48 -0
- data/spec/install/gems/env_spec.rb +107 -0
- data/spec/install/gems/flex_spec.rb +272 -0
- data/spec/install/gems/groups_spec.rb +228 -0
- data/spec/install/gems/packed_spec.rb +72 -0
- data/spec/install/gems/platform_spec.rb +195 -0
- data/spec/install/gems/resolving_spec.rb +72 -0
- data/spec/install/gems/simple_case_spec.rb +749 -0
- data/spec/install/gems/sudo_spec.rb +77 -0
- data/spec/install/gems/win32_spec.rb +26 -0
- data/spec/install/gemspec_spec.rb +96 -0
- data/spec/install/git_spec.rb +553 -0
- data/spec/install/invalid_spec.rb +17 -0
- data/spec/install/path_spec.rb +329 -0
- data/spec/install/upgrade_spec.rb +26 -0
- data/spec/lock/flex_spec.rb +650 -0
- data/spec/lock/git_spec.rb +35 -0
- data/spec/other/check_spec.rb +221 -0
- data/spec/other/config_spec.rb +40 -0
- data/spec/other/console_spec.rb +54 -0
- data/spec/other/exec_spec.rb +241 -0
- data/spec/other/ext_spec.rb +16 -0
- data/spec/other/gem_helper_spec.rb +126 -0
- data/spec/other/help_spec.rb +36 -0
- data/spec/other/init_spec.rb +40 -0
- data/spec/other/newgem_spec.rb +24 -0
- data/spec/other/open_spec.rb +35 -0
- data/spec/other/show_spec.rb +82 -0
- data/spec/pack/gems_spec.rb +22 -0
- data/spec/quality_spec.rb +55 -0
- data/spec/resolver/basic_spec.rb +20 -0
- data/spec/resolver/platform_spec.rb +57 -0
- data/spec/runtime/environment_rb_spec.rb +162 -0
- data/spec/runtime/executable_spec.rb +110 -0
- data/spec/runtime/load_spec.rb +102 -0
- data/spec/runtime/platform_spec.rb +90 -0
- data/spec/runtime/require_spec.rb +231 -0
- data/spec/runtime/setup_spec.rb +412 -0
- data/spec/runtime/with_clean_env_spec.rb +15 -0
- data/spec/spec_helper.rb +82 -0
- data/spec/support/builders.rb +566 -0
- data/spec/support/helpers.rb +243 -0
- data/spec/support/indexes.rb +113 -0
- data/spec/support/matchers.rb +89 -0
- data/spec/support/path.rb +71 -0
- data/spec/support/platforms.rb +49 -0
- data/spec/support/ruby_ext.rb +19 -0
- data/spec/support/rubygems_ext.rb +30 -0
- data/spec/support/rubygems_hax/rubygems_plugin.rb +9 -0
- data/spec/support/sudo.rb +21 -0
- data/spec/update/gems_spec.rb +112 -0
- data/spec/update/git_spec.rb +159 -0
- data/spec/update/source_spec.rb +50 -0
- metadata +251 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'bundler/shared_helpers'
|
|
2
|
+
|
|
3
|
+
if Bundler::SharedHelpers.in_bundle?
|
|
4
|
+
require 'bundler'
|
|
5
|
+
begin
|
|
6
|
+
Bundler.setup
|
|
7
|
+
rescue Bundler::BundlerError => e
|
|
8
|
+
puts "\e[31m#{e.message}\e[0m"
|
|
9
|
+
exit e.status_code
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Add bundler to the load path after disabling system gems
|
|
13
|
+
bundler_lib = File.expand_path("../..", __FILE__)
|
|
14
|
+
$LOAD_PATH.unshift(bundler_lib) unless $LOAD_PATH.include?(bundler_lib)
|
|
15
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
Gem.source_index # ensure Rubygems is fully loaded in Ruby 1.9
|
|
4
|
+
|
|
5
|
+
module Gem
|
|
6
|
+
class Dependency
|
|
7
|
+
if !instance_methods.map { |m| m.to_s }.include?("requirement")
|
|
8
|
+
def requirement
|
|
9
|
+
version_requirements
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module Bundler
|
|
16
|
+
module SharedHelpers
|
|
17
|
+
attr_accessor :gem_loaded
|
|
18
|
+
|
|
19
|
+
def default_gemfile
|
|
20
|
+
gemfile = find_gemfile
|
|
21
|
+
gemfile or raise GemfileNotFound, "Could not locate Gemfile"
|
|
22
|
+
Pathname.new(gemfile)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def default_lockfile
|
|
26
|
+
Pathname.new("#{default_gemfile}.lock")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def in_bundle?
|
|
30
|
+
find_gemfile
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def find_gemfile
|
|
36
|
+
return ENV['BUNDLE_GEMFILE'] if ENV['BUNDLE_GEMFILE']
|
|
37
|
+
|
|
38
|
+
previous = nil
|
|
39
|
+
current = File.expand_path(Dir.pwd)
|
|
40
|
+
|
|
41
|
+
until !File.directory?(current) || current == previous
|
|
42
|
+
filename = File.join(current, 'Gemfile')
|
|
43
|
+
return filename if File.file?(filename)
|
|
44
|
+
current, previous = File.expand_path("..", current), current
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def clean_load_path
|
|
49
|
+
# handle 1.9 where system gems are always on the load path
|
|
50
|
+
if defined?(::Gem)
|
|
51
|
+
me = File.expand_path("../../", __FILE__)
|
|
52
|
+
$LOAD_PATH.reject! do |p|
|
|
53
|
+
next if File.expand_path(p).include?(me)
|
|
54
|
+
p != File.dirname(__FILE__) &&
|
|
55
|
+
Gem.path.any? { |gp| p.include?(gp) }
|
|
56
|
+
end
|
|
57
|
+
$LOAD_PATH.uniq!
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def reverse_rubygems_kernel_mixin
|
|
62
|
+
# Disable rubygems' gem activation system
|
|
63
|
+
::Kernel.class_eval do
|
|
64
|
+
if private_method_defined?(:gem_original_require)
|
|
65
|
+
alias rubygems_require require
|
|
66
|
+
alias require gem_original_require
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
undef gem
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def cripple_rubygems(specs)
|
|
74
|
+
reverse_rubygems_kernel_mixin
|
|
75
|
+
|
|
76
|
+
executables = specs.map { |s| s.executables }.flatten
|
|
77
|
+
Gem.source_index # ensure RubyGems is fully loaded
|
|
78
|
+
|
|
79
|
+
::Kernel.send(:define_method, :gem) do |dep, *reqs|
|
|
80
|
+
if executables.include? File.basename(caller.first.split(':').first)
|
|
81
|
+
return
|
|
82
|
+
end
|
|
83
|
+
opts = reqs.last.is_a?(Hash) ? reqs.pop : {}
|
|
84
|
+
|
|
85
|
+
unless dep.respond_to?(:name) && dep.respond_to?(:requirement)
|
|
86
|
+
dep = Gem::Dependency.new(dep, reqs)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
spec = specs.find { |s| s.name == dep.name }
|
|
90
|
+
|
|
91
|
+
if spec.nil?
|
|
92
|
+
e = Gem::LoadError.new "#{dep.name} is not part of the bundle. Add it to Gemfile."
|
|
93
|
+
e.name = dep.name
|
|
94
|
+
e.version_requirement = dep.requirement
|
|
95
|
+
raise e
|
|
96
|
+
elsif dep !~ spec
|
|
97
|
+
e = Gem::LoadError.new "can't activate #{dep}, already activated #{spec.full_name}. " \
|
|
98
|
+
"Make sure all dependencies are added to Gemfile."
|
|
99
|
+
e.name = dep.name
|
|
100
|
+
e.version_requirement = dep.requirement
|
|
101
|
+
raise e
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
true
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# === Following hacks are to improve on the generated bin wrappers ===
|
|
108
|
+
|
|
109
|
+
# Yeah, talk about a hack
|
|
110
|
+
source_index_class = (class << Gem::SourceIndex ; self ; end)
|
|
111
|
+
source_index_class.send(:remove_method, :from_gems_in)
|
|
112
|
+
source_index_class.send(:define_method, :from_gems_in) do |*args|
|
|
113
|
+
source_index = Gem::SourceIndex.new
|
|
114
|
+
source_index.spec_dirs = *args
|
|
115
|
+
source_index.add_specs(*specs)
|
|
116
|
+
source_index
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# OMG more hacks
|
|
120
|
+
gem_class = (class << Gem ; self ; end)
|
|
121
|
+
gem_class.send(:remove_method, :refresh)
|
|
122
|
+
gem_class.send(:define_method, :refresh) { }
|
|
123
|
+
gem_class.send(:remove_method, :bin_path)
|
|
124
|
+
gem_class.send(:define_method, :bin_path) do |name, *args|
|
|
125
|
+
exec_name, *reqs = args
|
|
126
|
+
|
|
127
|
+
if exec_name == 'bundle'
|
|
128
|
+
return ENV['BUNDLE_BIN_PATH']
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
spec = nil
|
|
132
|
+
|
|
133
|
+
if exec_name
|
|
134
|
+
spec = specs.find { |s| s.executables.include?(exec_name) }
|
|
135
|
+
spec or raise Gem::Exception, "can't find executable #{exec_name}"
|
|
136
|
+
else
|
|
137
|
+
spec = specs.find { |s| s.name == name }
|
|
138
|
+
exec_name = spec.default_executable or raise Gem::Exception, "no default executable for #{spec.full_name}"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name)
|
|
142
|
+
gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name)
|
|
143
|
+
File.exist?(gem_bin) ? gem_bin : gem_from_path_bin
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
Gem.clear_paths
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
extend self
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
require "uri"
|
|
2
|
+
require "rubygems/installer"
|
|
3
|
+
require "rubygems/spec_fetcher"
|
|
4
|
+
require "rubygems/format"
|
|
5
|
+
require "digest/sha1"
|
|
6
|
+
require "open3"
|
|
7
|
+
|
|
8
|
+
module Bundler
|
|
9
|
+
module Source
|
|
10
|
+
# TODO: Refactor this class
|
|
11
|
+
class Rubygems
|
|
12
|
+
attr_reader :remotes
|
|
13
|
+
|
|
14
|
+
def initialize(options = {})
|
|
15
|
+
@options = options
|
|
16
|
+
@remotes = (options["remotes"] || []).map { |r| normalize_uri(r) }
|
|
17
|
+
@allow_remote = false
|
|
18
|
+
@allow_cached = false
|
|
19
|
+
# Hardcode the paths for now
|
|
20
|
+
@caches = [ Bundler.app_cache ] + Gem.path.map { |p| File.expand_path("#{p}/cache") }
|
|
21
|
+
@spec_fetch_map = {}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def remote!
|
|
25
|
+
@allow_remote = true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def cached!
|
|
29
|
+
@allow_cached = true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def hash
|
|
33
|
+
Rubygems.hash
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def eql?(o)
|
|
37
|
+
Rubygems === o
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
alias == eql?
|
|
41
|
+
|
|
42
|
+
# Not really needed, but it seems good to implement this method for interface
|
|
43
|
+
# consistency. Source name is mostly used to identify Path & Git sources
|
|
44
|
+
def name
|
|
45
|
+
":gems"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def options
|
|
49
|
+
{ "remotes" => @remotes.map { |r| r.to_s } }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.from_lock(options)
|
|
53
|
+
s = new(options)
|
|
54
|
+
Array(options["remote"]).each { |r| s.add_remote(r) }
|
|
55
|
+
s
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def to_lock
|
|
59
|
+
out = "GEM\n"
|
|
60
|
+
out << remotes.map {|r| " remote: #{r}\n" }.join
|
|
61
|
+
out << " specs:\n"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def to_s
|
|
65
|
+
remotes = self.remotes.map { |r| r.to_s }.join(', ')
|
|
66
|
+
"rubygems repository #{remotes}"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def specs
|
|
70
|
+
@specs ||= fetch_specs
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def fetch(spec)
|
|
74
|
+
spec, uri = @spec_fetch_map[spec.full_name]
|
|
75
|
+
if spec
|
|
76
|
+
path = download_gem_from_uri(spec, uri)
|
|
77
|
+
s = Gem::Format.from_file_by_path(path).spec
|
|
78
|
+
spec.__swap__(s)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def install(spec)
|
|
83
|
+
path = cached_gem(spec)
|
|
84
|
+
|
|
85
|
+
if installed_specs[spec].any?
|
|
86
|
+
Bundler.ui.info "Using #{spec.name} (#{spec.version}) "
|
|
87
|
+
return
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
Bundler.ui.info "Installing #{spec.name} (#{spec.version}) "
|
|
91
|
+
|
|
92
|
+
install_path = Bundler.requires_sudo? ? Bundler.tmp : Gem.dir
|
|
93
|
+
options = { :install_dir => install_path,
|
|
94
|
+
:ignore_dependencies => true,
|
|
95
|
+
:wrappers => true,
|
|
96
|
+
:env_shebang => true }
|
|
97
|
+
options.merge!(:bin_dir => "#{install_path}/bin") unless spec.executables.nil? || spec.executables.empty?
|
|
98
|
+
|
|
99
|
+
installer = Gem::Installer.new path, options
|
|
100
|
+
installer.install
|
|
101
|
+
|
|
102
|
+
# SUDO HAX
|
|
103
|
+
if Bundler.requires_sudo?
|
|
104
|
+
sudo "mkdir -p #{Gem.dir}/gems #{Gem.dir}/specifications"
|
|
105
|
+
sudo "cp -R #{Bundler.tmp}/gems/#{spec.full_name} #{Gem.dir}/gems/"
|
|
106
|
+
sudo "cp -R #{Bundler.tmp}/specifications/#{spec.full_name}.gemspec #{Gem.dir}/specifications/"
|
|
107
|
+
spec.executables.each do |exe|
|
|
108
|
+
sudo "mkdir -p #{Gem.bindir}"
|
|
109
|
+
sudo "cp -R #{Bundler.tmp}/bin/#{exe} #{Gem.bindir}"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
spec.loaded_from = "#{Gem.dir}/specifications/#{spec.full_name}.gemspec"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def sudo(str)
|
|
117
|
+
Bundler.sudo(str)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def cache(spec)
|
|
121
|
+
cached_path = cached_gem(spec)
|
|
122
|
+
raise GemNotFound, "Missing gem file '#{spec.full_name}.gem'." unless cached_path
|
|
123
|
+
return if File.dirname(cached_path) == Bundler.app_cache.to_s
|
|
124
|
+
Bundler.ui.info " * #{File.basename(cached_path)}"
|
|
125
|
+
FileUtils.cp(cached_path, Bundler.app_cache)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def add_remote(source)
|
|
129
|
+
@remotes << normalize_uri(source)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def merge_remotes(source)
|
|
133
|
+
@remotes = []
|
|
134
|
+
source.remotes.each do |r|
|
|
135
|
+
add_remote r.to_s
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
private
|
|
140
|
+
|
|
141
|
+
def cached_gem(spec)
|
|
142
|
+
possibilities = @caches.map { |p| "#{p}/#{spec.full_name}.gem" }
|
|
143
|
+
possibilities.find { |p| File.exist?(p) }
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def normalize_uri(uri)
|
|
147
|
+
uri = uri.to_s
|
|
148
|
+
uri = "#{uri}/" unless uri =~ %r'/$'
|
|
149
|
+
uri = URI(uri)
|
|
150
|
+
raise ArgumentError, "The source must be an absolute URI" unless uri.absolute?
|
|
151
|
+
uri
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def fetch_specs
|
|
155
|
+
Index.build do |idx|
|
|
156
|
+
idx.use installed_specs
|
|
157
|
+
idx.use cached_specs if @allow_cached || @allow_remote
|
|
158
|
+
idx.use remote_specs if @allow_remote
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def installed_specs
|
|
163
|
+
@installed_specs ||= begin
|
|
164
|
+
idx = Index.new
|
|
165
|
+
have_bundler = false
|
|
166
|
+
Gem::SourceIndex.from_installed_gems.to_a.reverse.each do |dont_use_this_var, spec|
|
|
167
|
+
next if spec.name == 'bundler' && spec.version.to_s != VERSION
|
|
168
|
+
have_bundler = true if spec.name == 'bundler'
|
|
169
|
+
spec.source = self
|
|
170
|
+
idx << spec
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Always have bundler locally
|
|
174
|
+
unless have_bundler
|
|
175
|
+
# We're running bundler directly from the source
|
|
176
|
+
# so, let's create a fake gemspec for it (it's a path)
|
|
177
|
+
# gemspec
|
|
178
|
+
bundler = Gem::Specification.new do |s|
|
|
179
|
+
s.name = 'bundler'
|
|
180
|
+
s.version = VERSION
|
|
181
|
+
s.platform = Gem::Platform::RUBY
|
|
182
|
+
s.source = self
|
|
183
|
+
s.loaded_from = File.expand_path("..", __FILE__)
|
|
184
|
+
end
|
|
185
|
+
idx << bundler
|
|
186
|
+
end
|
|
187
|
+
idx
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def cached_specs
|
|
192
|
+
@cached_specs ||= begin
|
|
193
|
+
idx = Index.new
|
|
194
|
+
@caches.each do |path|
|
|
195
|
+
Dir["#{path}/*.gem"].each do |gemfile|
|
|
196
|
+
next if name == 'bundler'
|
|
197
|
+
s = Gem::Format.from_file_by_path(gemfile).spec
|
|
198
|
+
s.source = self
|
|
199
|
+
idx << s
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
idx
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def remote_specs
|
|
207
|
+
@remote_specs ||= begin
|
|
208
|
+
idx = Index.new
|
|
209
|
+
old = Gem.sources
|
|
210
|
+
|
|
211
|
+
remotes.each do |uri|
|
|
212
|
+
Bundler.ui.info "Fetching source index for #{uri}"
|
|
213
|
+
Gem.sources = ["#{uri}"]
|
|
214
|
+
fetch_all_remote_specs do |n,v|
|
|
215
|
+
v.each do |name, version, platform|
|
|
216
|
+
next if name == 'bundler'
|
|
217
|
+
spec = RemoteSpecification.new(name, version, platform, uri)
|
|
218
|
+
spec.source = self
|
|
219
|
+
@spec_fetch_map[spec.full_name] = [spec, uri]
|
|
220
|
+
idx << spec
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
idx
|
|
225
|
+
ensure
|
|
226
|
+
Gem.sources = old
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def fetch_all_remote_specs(&blk)
|
|
231
|
+
begin
|
|
232
|
+
# Fetch all specs, minus prerelease specs
|
|
233
|
+
Gem::SpecFetcher.new.list(true, false).each(&blk)
|
|
234
|
+
# Then fetch the prerelease specs
|
|
235
|
+
begin
|
|
236
|
+
Gem::SpecFetcher.new.list(false, true).each(&blk)
|
|
237
|
+
rescue Gem::RemoteFetcher::FetchError
|
|
238
|
+
Bundler.ui.warn "Could not fetch prerelease specs from #{self}"
|
|
239
|
+
end
|
|
240
|
+
rescue Gem::RemoteFetcher::FetchError
|
|
241
|
+
Bundler.ui.warn "Could not reach #{self}"
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def download_gem_from_uri(spec, uri)
|
|
246
|
+
spec.fetch_platform
|
|
247
|
+
|
|
248
|
+
download_path = Bundler.requires_sudo? ? Bundler.tmp : Gem.dir
|
|
249
|
+
gem_path = "#{Gem.dir}/cache/#{spec.full_name}.gem"
|
|
250
|
+
|
|
251
|
+
FileUtils.mkdir_p("#{download_path}/cache")
|
|
252
|
+
Gem::RemoteFetcher.fetcher.download(spec, uri, download_path)
|
|
253
|
+
|
|
254
|
+
if Bundler.requires_sudo?
|
|
255
|
+
sudo "mkdir -p #{Gem.dir}/cache"
|
|
256
|
+
sudo "mv #{Bundler.tmp}/cache/#{spec.full_name}.gem #{gem_path}"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
gem_path
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
class Path
|
|
264
|
+
attr_reader :path, :options
|
|
265
|
+
# Kind of a hack, but needed for the lock file parser
|
|
266
|
+
attr_writer :name
|
|
267
|
+
attr_accessor :version
|
|
268
|
+
|
|
269
|
+
DEFAULT_GLOB = "{,*/}*.gemspec"
|
|
270
|
+
|
|
271
|
+
def initialize(options)
|
|
272
|
+
@options = options
|
|
273
|
+
@glob = options["glob"] || DEFAULT_GLOB
|
|
274
|
+
|
|
275
|
+
@allow_cached = false
|
|
276
|
+
@allow_remote = false
|
|
277
|
+
|
|
278
|
+
if options["path"]
|
|
279
|
+
@path = Pathname.new(options["path"])
|
|
280
|
+
@path = @path.expand_path(Bundler.root) unless @path.relative?
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
@name = options["name"]
|
|
284
|
+
@version = options["version"]
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def remote!
|
|
288
|
+
@allow_remote = true
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def cached!
|
|
292
|
+
@allow_cached = true
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def self.from_lock(options)
|
|
296
|
+
new(options.merge("path" => options.delete("remote")))
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def to_lock
|
|
300
|
+
out = "PATH\n"
|
|
301
|
+
out << " remote: #{relative_path}\n"
|
|
302
|
+
out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB
|
|
303
|
+
out << " specs:\n"
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def to_s
|
|
307
|
+
"source at #{@path}"
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def hash
|
|
311
|
+
self.class.hash
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def eql?(o)
|
|
315
|
+
o.instance_of?(Path) &&
|
|
316
|
+
path == o.path &&
|
|
317
|
+
name == o.name &&
|
|
318
|
+
version == o.version
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
alias == eql?
|
|
322
|
+
|
|
323
|
+
def name
|
|
324
|
+
File.basename(@path.to_s)
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def load_spec_files
|
|
328
|
+
index = Index.new
|
|
329
|
+
|
|
330
|
+
expanded_path = path.expand_path
|
|
331
|
+
|
|
332
|
+
if File.directory?(expanded_path)
|
|
333
|
+
Dir["#{expanded_path}/#{@glob}"].each do |file|
|
|
334
|
+
spec = Bundler.load_gemspec(file)
|
|
335
|
+
if spec
|
|
336
|
+
spec.loaded_from = file.to_s
|
|
337
|
+
spec.source = self
|
|
338
|
+
index << spec
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
if index.empty? && @name && @version
|
|
343
|
+
index << Gem::Specification.new do |s|
|
|
344
|
+
s.name = @name
|
|
345
|
+
s.source = self
|
|
346
|
+
s.version = Gem::Version.new(@version)
|
|
347
|
+
s.platform = Gem::Platform::RUBY
|
|
348
|
+
s.summary = "Fake gemspec for #{@name}"
|
|
349
|
+
s.relative_loaded_from = "#{@name}.gemspec"
|
|
350
|
+
if expanded_path.join("bin").exist?
|
|
351
|
+
binaries = expanded_path.join("bin").children.map{|c| c.basename.to_s }
|
|
352
|
+
s.executables = binaries
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
else
|
|
357
|
+
raise PathError, "The path `#{expanded_path}` does not exist."
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
index
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def local_specs
|
|
364
|
+
@local_specs ||= load_spec_files
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
class Installer < Gem::Installer
|
|
368
|
+
def initialize(spec, options = {})
|
|
369
|
+
@spec = spec
|
|
370
|
+
@bin_dir = Bundler.requires_sudo? ? "#{Bundler.tmp}/bin" : "#{Gem.dir}/bin"
|
|
371
|
+
@gem_dir = spec.full_gem_path
|
|
372
|
+
@wrappers = options[:wrappers] || true
|
|
373
|
+
@env_shebang = options[:env_shebang] || true
|
|
374
|
+
@format_executable = options[:format_executable] || false
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def generate_bin
|
|
378
|
+
return if spec.executables.nil? || spec.executables.empty?
|
|
379
|
+
|
|
380
|
+
if Bundler.requires_sudo?
|
|
381
|
+
FileUtils.mkdir_p("#{Bundler.tmp}/bin") unless File.exist?("#{Bundler.tmp}/bin")
|
|
382
|
+
end
|
|
383
|
+
super
|
|
384
|
+
if Bundler.requires_sudo?
|
|
385
|
+
Bundler.mkdir_p "#{Gem.dir}/bin"
|
|
386
|
+
spec.executables.each do |exe|
|
|
387
|
+
Bundler.sudo "cp -R #{Bundler.tmp}/bin/#{exe} #{Gem.dir}/bin/"
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def install(spec)
|
|
394
|
+
Bundler.ui.info "Using #{spec.name} (#{spec.version}) from #{to_s} "
|
|
395
|
+
# Let's be honest, when we're working from a path, we can't
|
|
396
|
+
# really expect native extensions to work because the whole point
|
|
397
|
+
# is to just be able to modify what's in that path and go. So, let's
|
|
398
|
+
# not put ourselves through the pain of actually trying to generate
|
|
399
|
+
# the full gem.
|
|
400
|
+
Installer.new(spec).generate_bin
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
alias specs local_specs
|
|
404
|
+
|
|
405
|
+
def cache(spec)
|
|
406
|
+
unless path.to_s.index(Bundler.root.to_s) == 0
|
|
407
|
+
Bundler.ui.warn " * #{spec.name} at `#{path}` will not be cached."
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
private
|
|
412
|
+
|
|
413
|
+
def relative_path
|
|
414
|
+
if path.to_s.include?(Bundler.root.to_s)
|
|
415
|
+
return path.relative_path_from(Bundler.root)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
path
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def generate_bin(spec)
|
|
422
|
+
gem_dir = Pathname.new(spec.full_gem_path)
|
|
423
|
+
|
|
424
|
+
# Some gem authors put absolute paths in their gemspec
|
|
425
|
+
# and we have to save them from themselves
|
|
426
|
+
spec.files = spec.files.map do |p|
|
|
427
|
+
next if File.directory?(p)
|
|
428
|
+
begin
|
|
429
|
+
Pathname.new(p).relative_path_from(gem_dir).to_s
|
|
430
|
+
rescue ArgumentError
|
|
431
|
+
p
|
|
432
|
+
end
|
|
433
|
+
end.compact
|
|
434
|
+
|
|
435
|
+
gem_file = Dir.chdir(gem_dir){ Gem::Builder.new(spec).build }
|
|
436
|
+
|
|
437
|
+
installer = Installer.new(spec, :env_shebang => false)
|
|
438
|
+
installer.build_extensions
|
|
439
|
+
installer.generate_bin
|
|
440
|
+
rescue Gem::InvalidSpecificationException => e
|
|
441
|
+
Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \
|
|
442
|
+
"This prevents bundler from installing bins or native extensions, but " \
|
|
443
|
+
"that may not affect its functionality."
|
|
444
|
+
|
|
445
|
+
if !spec.extensions.empty? && !spec.email.empty?
|
|
446
|
+
Bundler.ui.warn "If you need to use this package without installing it from a gem " \
|
|
447
|
+
"repository, please contact #{spec.email} and ask them " \
|
|
448
|
+
"to modify their .gemspec so it can work with `gem build`."
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
Bundler.ui.warn "The validation message from Rubygems was:\n #{e.message}"
|
|
452
|
+
ensure
|
|
453
|
+
Dir.chdir(gem_dir){ FileUtils.rm_rf(gem_file) if gem_file && File.exist?(gem_file) }
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
class Git < Path
|
|
459
|
+
attr_reader :uri, :ref, :options, :submodules
|
|
460
|
+
|
|
461
|
+
def initialize(options)
|
|
462
|
+
super
|
|
463
|
+
@uri = options["uri"]
|
|
464
|
+
@ref = options["ref"] || options["branch"] || options["tag"] || 'master'
|
|
465
|
+
@revision = options["revision"]
|
|
466
|
+
@submodules = options["submodules"]
|
|
467
|
+
@update = false
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
def self.from_lock(options)
|
|
471
|
+
new(options.merge("uri" => options.delete("remote")))
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
def to_lock
|
|
475
|
+
out = "GIT\n"
|
|
476
|
+
out << " remote: #{@uri}\n"
|
|
477
|
+
out << " revision: #{revision}\n"
|
|
478
|
+
%w(ref branch tag submodules).each do |opt|
|
|
479
|
+
out << " #{opt}: #{options[opt]}\n" if options[opt]
|
|
480
|
+
end
|
|
481
|
+
out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB
|
|
482
|
+
out << " specs:\n"
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
def eql?(o)
|
|
486
|
+
Git === o &&
|
|
487
|
+
uri == o.uri &&
|
|
488
|
+
ref == o.ref &&
|
|
489
|
+
name == o.name &&
|
|
490
|
+
version == o.version &&
|
|
491
|
+
submodules == o.submodules
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
alias == eql?
|
|
495
|
+
|
|
496
|
+
def to_s
|
|
497
|
+
ref = @options["ref"] ? shortref_for_display(@options["ref"]) : @ref
|
|
498
|
+
"#{@uri} (at #{ref})"
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def name
|
|
502
|
+
File.basename(@uri, '.git')
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
def path
|
|
506
|
+
@install_path ||= begin
|
|
507
|
+
git_scope = "#{base_name}-#{shortref_for_path(revision)}"
|
|
508
|
+
|
|
509
|
+
if Bundler.requires_sudo?
|
|
510
|
+
Bundler.user_bundle_path.join(Bundler.ruby_scope).join(git_scope)
|
|
511
|
+
else
|
|
512
|
+
Bundler.install_path.join(git_scope)
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
def unlock!
|
|
518
|
+
@revision = nil
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
# TODO: actually cache git specs
|
|
522
|
+
def specs
|
|
523
|
+
if allow_git_ops? && !@update
|
|
524
|
+
# Start by making sure the git cache is up to date
|
|
525
|
+
cache
|
|
526
|
+
checkout
|
|
527
|
+
@update = true
|
|
528
|
+
end
|
|
529
|
+
local_specs
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
def install(spec)
|
|
533
|
+
Bundler.ui.info "Using #{spec.name} (#{spec.version}) from #{to_s} "
|
|
534
|
+
|
|
535
|
+
unless @installed
|
|
536
|
+
Bundler.ui.debug " * Checking out revision: #{ref}"
|
|
537
|
+
checkout if allow_git_ops?
|
|
538
|
+
@installed = true
|
|
539
|
+
end
|
|
540
|
+
generate_bin(spec)
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
def load_spec_files
|
|
544
|
+
super
|
|
545
|
+
rescue PathError, GitError
|
|
546
|
+
raise GitError, "#{to_s} is not checked out. Please run `bundle install`"
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
private
|
|
550
|
+
|
|
551
|
+
def git(command)
|
|
552
|
+
if allow_git_ops?
|
|
553
|
+
out = %x{git #{command}}
|
|
554
|
+
|
|
555
|
+
if $? != 0
|
|
556
|
+
raise GitError, "An error has occurred in git when running `git #{command}`. Cannot complete bundling."
|
|
557
|
+
end
|
|
558
|
+
out
|
|
559
|
+
else
|
|
560
|
+
raise GitError, "Bundler is trying to run a `git #{command}` at runtime. You probably need to run `bundle install`. However, " \
|
|
561
|
+
"this error message could probably be more useful. Please submit a ticket at http://github.com/carlhuda/bundler/issues " \
|
|
562
|
+
"with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}"
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
def base_name
|
|
567
|
+
File.basename(uri.sub(%r{^(\w+://)?([^/:]+:)},''), ".git")
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
def shortref_for_display(ref)
|
|
571
|
+
ref[0..6]
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
def shortref_for_path(ref)
|
|
575
|
+
ref[0..11]
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
def uri_hash
|
|
579
|
+
if uri =~ %r{^\w+://(\w+@)?}
|
|
580
|
+
# Downcase the domain component of the URI
|
|
581
|
+
# and strip off a trailing slash, if one is present
|
|
582
|
+
input = URI.parse(uri).normalize.to_s.sub(%r{/$},'')
|
|
583
|
+
else
|
|
584
|
+
# If there is no URI scheme, assume it is an ssh/git URI
|
|
585
|
+
input = uri
|
|
586
|
+
end
|
|
587
|
+
Digest::SHA1.hexdigest(input)
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def cache_path
|
|
591
|
+
@cache_path ||= begin
|
|
592
|
+
git_scope = "#{base_name}-#{uri_hash}"
|
|
593
|
+
|
|
594
|
+
if Bundler.requires_sudo?
|
|
595
|
+
Bundler.user_bundle_path.join("cache/git", git_scope)
|
|
596
|
+
else
|
|
597
|
+
Bundler.cache.join("git", git_scope)
|
|
598
|
+
end
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
def cache
|
|
603
|
+
if cached?
|
|
604
|
+
return if has_revision_cached?
|
|
605
|
+
Bundler.ui.info "Updating #{uri}"
|
|
606
|
+
in_cache { git %|fetch --force --quiet --tags "#{uri}" refs/heads/*:refs/heads/*| }
|
|
607
|
+
else
|
|
608
|
+
Bundler.ui.info "Fetching #{uri}"
|
|
609
|
+
FileUtils.mkdir_p(cache_path.dirname)
|
|
610
|
+
git %|clone "#{uri}" "#{cache_path}" --bare --no-hardlinks|
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
def checkout
|
|
615
|
+
unless File.exist?(path.join(".git"))
|
|
616
|
+
FileUtils.mkdir_p(path.dirname)
|
|
617
|
+
git %|clone --no-checkout "#{cache_path}" "#{path}"|
|
|
618
|
+
end
|
|
619
|
+
Dir.chdir(path) do
|
|
620
|
+
git %|fetch --force --quiet --tags "#{cache_path}"|
|
|
621
|
+
git "reset --hard #{revision}"
|
|
622
|
+
|
|
623
|
+
if @submodules
|
|
624
|
+
git "submodule init"
|
|
625
|
+
git "submodule update"
|
|
626
|
+
end
|
|
627
|
+
end
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
def has_revision_cached?
|
|
631
|
+
return unless @revision
|
|
632
|
+
in_cache { git %|cat-file -e #{@revision}| }
|
|
633
|
+
true
|
|
634
|
+
rescue GitError
|
|
635
|
+
false
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
def allow_git_ops?
|
|
639
|
+
@allow_remote || @allow_cached
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
def revision
|
|
643
|
+
@revision ||= begin
|
|
644
|
+
if allow_git_ops?
|
|
645
|
+
in_cache { git("rev-parse #{ref}").strip }
|
|
646
|
+
else
|
|
647
|
+
raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application"
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
def cached?
|
|
653
|
+
cache_path.exist?
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
def in_cache(&blk)
|
|
657
|
+
cache unless cached?
|
|
658
|
+
Dir.chdir(cache_path, &blk)
|
|
659
|
+
end
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
end
|