bundler08 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.markdown +284 -0
- data/Rakefile +81 -0
- data/lib/bundler08.rb +49 -0
- data/lib/bundler08/bundle.rb +314 -0
- data/lib/bundler08/cli.rb +89 -0
- data/lib/bundler08/commands/bundle_command.rb +83 -0
- data/lib/bundler08/commands/exec_command.rb +36 -0
- data/lib/bundler08/dependency.rb +62 -0
- data/lib/bundler08/dsl.rb +182 -0
- data/lib/bundler08/environment.rb +87 -0
- data/lib/bundler08/finder.rb +51 -0
- data/lib/bundler08/gem_bundle.rb +11 -0
- data/lib/bundler08/gem_ext.rb +34 -0
- data/lib/bundler08/remote_specification.rb +53 -0
- data/lib/bundler08/resolver.rb +250 -0
- data/lib/bundler08/runtime.rb +2 -0
- data/lib/bundler08/source.rb +365 -0
- data/lib/bundler08/templates/Gemfile +72 -0
- data/lib/bundler08/templates/app_script.erb +3 -0
- data/lib/bundler08/templates/environment.erb +156 -0
- data/lib/bundler08/templates/environment_picker.erb +4 -0
- data/lib/rubygems_plugin.rb +6 -0
- metadata +81 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
class CLI
|
5
|
+
def self.run(command, options = {})
|
6
|
+
new(options).run(command)
|
7
|
+
rescue DefaultManifestNotFound => e
|
8
|
+
Bundler.logger.error "Could not find a Gemfile to use"
|
9
|
+
exit 3
|
10
|
+
rescue InvalidEnvironmentName => e
|
11
|
+
Bundler.logger.error "Gemfile error: #{e.message}"
|
12
|
+
exit 4
|
13
|
+
rescue InvalidRepository => e
|
14
|
+
Bundler.logger.error e.message
|
15
|
+
exit 5
|
16
|
+
rescue VersionConflict => e
|
17
|
+
Bundler.logger.error e.message
|
18
|
+
exit 6
|
19
|
+
rescue GemNotFound => e
|
20
|
+
Bundler.logger.error e.message
|
21
|
+
exit 7
|
22
|
+
rescue InvalidCacheArgument => e
|
23
|
+
Bundler.logger.error e.message
|
24
|
+
exit 8
|
25
|
+
rescue SourceNotCached => e
|
26
|
+
Bundler.logger.error e.message
|
27
|
+
exit 9
|
28
|
+
rescue ManifestFileNotFound => e
|
29
|
+
Bundler.logger.error e.message
|
30
|
+
exit 10
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(options)
|
34
|
+
Bundler.mode = options[:cached] ? :local : :readwrite
|
35
|
+
@options = options
|
36
|
+
@bundle = Bundle.load(@options[:manifest])
|
37
|
+
end
|
38
|
+
|
39
|
+
def bundle
|
40
|
+
@bundle.install(@options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def cache
|
44
|
+
gemfile = @options[:cache]
|
45
|
+
|
46
|
+
if File.extname(gemfile) == ".gem"
|
47
|
+
if !File.exist?(gemfile)
|
48
|
+
raise InvalidCacheArgument, "'#{gemfile}' does not exist."
|
49
|
+
end
|
50
|
+
@bundle.cache(gemfile)
|
51
|
+
elsif File.directory?(gemfile) || gemfile.include?('/')
|
52
|
+
if !File.directory?(gemfile)
|
53
|
+
raise InvalidCacheArgument, "'#{gemfile}' does not exist."
|
54
|
+
end
|
55
|
+
gemfiles = Dir["#{gemfile}/*.gem"]
|
56
|
+
if gemfiles.empty?
|
57
|
+
raise InvalidCacheArgument, "'#{gemfile}' contains no gemfiles"
|
58
|
+
end
|
59
|
+
@bundle.cache(*gemfiles)
|
60
|
+
else
|
61
|
+
raise InvalidCacheArgument, "w0t? '#{gemfile}' means nothing to me."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def prune
|
66
|
+
Bundler.mode = :local
|
67
|
+
@bundle.prune(@options)
|
68
|
+
end
|
69
|
+
|
70
|
+
def list
|
71
|
+
@bundle.list(@options)
|
72
|
+
end
|
73
|
+
|
74
|
+
def list_outdated
|
75
|
+
@bundle.list_outdated(@options)
|
76
|
+
end
|
77
|
+
|
78
|
+
def exec
|
79
|
+
@bundle.setup_environment
|
80
|
+
# w0t?
|
81
|
+
super(*$command)
|
82
|
+
end
|
83
|
+
|
84
|
+
def run(command)
|
85
|
+
send(command)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class Gem::Commands::BundleCommand < Gem::Command
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
super('bundle', 'Create a gem bundle based on your Gemfile', {:manifest => nil, :update => false})
|
5
|
+
|
6
|
+
add_option('-i', '--init',"Create a Gemfile") do
|
7
|
+
options[:init] = true
|
8
|
+
end
|
9
|
+
|
10
|
+
add_option('-m', '--manifest MANIFEST', "Specify the path to the manifest file") do |manifest, options|
|
11
|
+
options[:manifest] = manifest
|
12
|
+
end
|
13
|
+
|
14
|
+
add_option('-u', '--update', "Force a remote check for newer gems") do
|
15
|
+
options[:update] = true
|
16
|
+
end
|
17
|
+
|
18
|
+
add_option('--cached', "Only use cached gems when expanding the bundle") do
|
19
|
+
options[:cached] = true
|
20
|
+
end
|
21
|
+
|
22
|
+
add_option('--cache GEM', "Specify a path to a .gem file to add to the bundled gem cache") do |gem, options|
|
23
|
+
options[:cache] = gem
|
24
|
+
end
|
25
|
+
|
26
|
+
add_option('--prune-cache', "Removes all .gem files that are not a part of the bundle from the cache") do
|
27
|
+
options[:prune] = true
|
28
|
+
end
|
29
|
+
|
30
|
+
add_option('--list', "List all gems that are part of the active bundle") do
|
31
|
+
options[:list] = true
|
32
|
+
end
|
33
|
+
|
34
|
+
add_option('--list-outdated', "List all outdated gems that are part of the active bundle") do
|
35
|
+
options[:list_outdated] = true
|
36
|
+
end
|
37
|
+
|
38
|
+
add_option('-b', '--build-options OPTION_FILE', "Specify a path to a yml file with build options for binary gems") do |option_file, options|
|
39
|
+
if File.exist?(option_file)
|
40
|
+
options[:build_options] = YAML.load_file(option_file)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
add_option('--only ENV', "Only expand the given environment. To specify multiple environments, use --only multiple times.") do |env, options|
|
45
|
+
options[:only] ||= []
|
46
|
+
options[:only] << env
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def usage
|
51
|
+
"#{program_name}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def description # :nodoc:
|
55
|
+
<<-EOF
|
56
|
+
Bundle stuff
|
57
|
+
EOF
|
58
|
+
end
|
59
|
+
|
60
|
+
def execute
|
61
|
+
# Prevent the bundler from getting required unless it is actually being used
|
62
|
+
require 'bundler08'
|
63
|
+
if options[:cache]
|
64
|
+
Bundler::CLI.run(:cache, options)
|
65
|
+
elsif options[:prune]
|
66
|
+
Bundler::CLI.run(:prune, options)
|
67
|
+
elsif options[:list]
|
68
|
+
Bundler::CLI.run(:list, options)
|
69
|
+
elsif options[:list_outdated]
|
70
|
+
Bundler::CLI.run(:list_outdated, options)
|
71
|
+
elsif options[:init]
|
72
|
+
if File.exists?("Gemfile")
|
73
|
+
Bundler.logger.error "The Gemfile already exists"
|
74
|
+
else
|
75
|
+
FileUtils.cp File.expand_path("../../templates/Gemfile", __FILE__), "Gemfile"
|
76
|
+
Bundler.logger.info "Initialized Gemfile in #{Dir.pwd}"
|
77
|
+
end
|
78
|
+
else
|
79
|
+
Bundler::CLI.run(:bundle, options)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
if exec = ARGV.index("exec")
|
2
|
+
$command = ARGV[(exec + 1)..-1]
|
3
|
+
ARGV.replace ARGV[0..exec]
|
4
|
+
end
|
5
|
+
|
6
|
+
class Gem::Commands::ExecCommand < Gem::Command
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super('exec', 'Run a command in context of a gem bundle', {:manifest => nil})
|
10
|
+
|
11
|
+
add_option('-m', '--manifest MANIFEST', "Specify the path to the manifest file") do |manifest, options|
|
12
|
+
options[:manifest] = manifest
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def usage
|
17
|
+
"#{program_name} COMMAND"
|
18
|
+
end
|
19
|
+
|
20
|
+
def arguments # :nodoc:
|
21
|
+
"COMMAND command to run in context of the gem bundle"
|
22
|
+
end
|
23
|
+
|
24
|
+
def description # :nodoc:
|
25
|
+
<<-EOF.gsub(' ', '')
|
26
|
+
Run in context of a bundle
|
27
|
+
EOF
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute
|
31
|
+
# Prevent the bundler from getting required unless it is actually being used
|
32
|
+
require 'bundler08'
|
33
|
+
Bundler::CLI.run(:exec, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Bundler
|
2
|
+
class InvalidEnvironmentName < StandardError; end
|
3
|
+
|
4
|
+
class Dependency < Gem::Dependency
|
5
|
+
attr_reader :name, :version, :require_as, :only, :except
|
6
|
+
attr_accessor :source
|
7
|
+
|
8
|
+
def initialize(name, options = {}, &block)
|
9
|
+
options.each do |k, v|
|
10
|
+
options[k.to_s] = v
|
11
|
+
end
|
12
|
+
|
13
|
+
super(name, options["version"] || ">= 0")
|
14
|
+
|
15
|
+
@require_as = options["require_as"]
|
16
|
+
@only = options["only"]
|
17
|
+
@except = options["except"]
|
18
|
+
@source = options["source"]
|
19
|
+
@block = block
|
20
|
+
|
21
|
+
if (@only && @only.include?("rubygems")) || (@except && @except.include?("rubygems"))
|
22
|
+
raise InvalidEnvironmentName, "'rubygems' is not a valid environment name"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def in?(environment)
|
27
|
+
environment = environment.to_s
|
28
|
+
|
29
|
+
return false unless !@only || @only.include?(environment)
|
30
|
+
return false if @except && @except.include?(environment)
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
def require_env(environment)
|
35
|
+
return unless in?(environment)
|
36
|
+
|
37
|
+
if @require_as
|
38
|
+
Array(@require_as).each { |file| require file }
|
39
|
+
else
|
40
|
+
begin
|
41
|
+
require name
|
42
|
+
rescue LoadError
|
43
|
+
# Do nothing
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
@block.call if @block
|
48
|
+
end
|
49
|
+
|
50
|
+
def no_bundle?
|
51
|
+
source == SystemGemSource.instance
|
52
|
+
end
|
53
|
+
|
54
|
+
def ==(o)
|
55
|
+
[name, version, require_as, only, except] ==
|
56
|
+
[o.name, o.version, o.require_as, o.only, o.except]
|
57
|
+
end
|
58
|
+
|
59
|
+
alias version version_requirements
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module Bundler
|
2
|
+
class ManifestFileNotFound < StandardError; end
|
3
|
+
class InvalidKey < StandardError; end
|
4
|
+
class DefaultManifestNotFound < StandardError; end
|
5
|
+
|
6
|
+
class Dsl
|
7
|
+
def self.evaluate(file, bundle, environment)
|
8
|
+
builder = new(bundle, environment)
|
9
|
+
builder.instance_eval(File.read(file.to_s), file.to_s, 1)
|
10
|
+
environment
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(bundle, environment)
|
14
|
+
@bundle = bundle
|
15
|
+
@environment = environment
|
16
|
+
@directory_sources = []
|
17
|
+
@git_sources = {}
|
18
|
+
@only, @except, @directory, @git = nil, nil, nil, nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def bundle_path(path)
|
22
|
+
@bundle.path = Pathname.new(path)
|
23
|
+
end
|
24
|
+
|
25
|
+
def bin_path(path)
|
26
|
+
@bundle.bindir = Pathname.new(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def disable_rubygems
|
30
|
+
@environment.rubygems = false
|
31
|
+
end
|
32
|
+
|
33
|
+
def disable_system_gems
|
34
|
+
@environment.system_gems = false
|
35
|
+
end
|
36
|
+
|
37
|
+
def source(source)
|
38
|
+
source = GemSource.new(@bundle, :uri => source)
|
39
|
+
unless @environment.sources.include?(source)
|
40
|
+
@environment.add_source(source)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def only(*env)
|
45
|
+
old, @only = @only, _combine_only(env)
|
46
|
+
yield
|
47
|
+
@only = old
|
48
|
+
end
|
49
|
+
|
50
|
+
def except(*env)
|
51
|
+
old, @except = @except, _combine_except(env)
|
52
|
+
yield
|
53
|
+
@except = old
|
54
|
+
end
|
55
|
+
|
56
|
+
def directory(path, options = {})
|
57
|
+
raise DirectorySourceError, "cannot nest calls to directory or git" if @directory || @git
|
58
|
+
@directory = DirectorySource.new(@bundle, options.merge(:location => path))
|
59
|
+
@directory_sources << @directory
|
60
|
+
@environment.add_priority_source(@directory)
|
61
|
+
retval = yield if block_given?
|
62
|
+
@directory = nil
|
63
|
+
retval
|
64
|
+
end
|
65
|
+
|
66
|
+
def git(uri, options = {})
|
67
|
+
raise DirectorySourceError, "cannot nest calls to directory or git" if @directory || @git
|
68
|
+
@git = GitSource.new(@bundle, options.merge(:uri => uri))
|
69
|
+
@git_sources[uri] = @git
|
70
|
+
@environment.add_priority_source(@git)
|
71
|
+
retval = yield if block_given?
|
72
|
+
@git = nil
|
73
|
+
retval
|
74
|
+
end
|
75
|
+
|
76
|
+
def clear_sources
|
77
|
+
@environment.clear_sources
|
78
|
+
end
|
79
|
+
|
80
|
+
def gem(name, *args)
|
81
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
82
|
+
version = args.last
|
83
|
+
|
84
|
+
keys = :vendored_at, :path, :only, :except, :git, :path, :bundle, :require_as, :tag, :branch, :ref
|
85
|
+
unless (invalid = options.keys - keys).empty?
|
86
|
+
raise InvalidKey, "Only #{keys.join(", ")} are valid options to #gem. You used #{invalid.join(", ")}"
|
87
|
+
end
|
88
|
+
|
89
|
+
if path = options.delete(:vendored_at)
|
90
|
+
options[:path] = path
|
91
|
+
warn "The :vendored_at option is deprecated. Use :path instead.\nFrom #{caller[0]}"
|
92
|
+
end
|
93
|
+
|
94
|
+
options[:only] = _combine_only(options[:only] || options["only"])
|
95
|
+
options[:except] = _combine_except(options[:except] || options["except"])
|
96
|
+
|
97
|
+
dep = Dependency.new(name, options.merge(:version => version))
|
98
|
+
|
99
|
+
if options.key?(:bundle) && !options[:bundle]
|
100
|
+
dep.source = SystemGemSource.new(@bundle)
|
101
|
+
elsif @git || options[:git]
|
102
|
+
dep.source = _handle_git_option(name, version, options)
|
103
|
+
elsif @directory || options[:path]
|
104
|
+
dep.source = _handle_vendored_option(name, version, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
@environment.dependencies << dep
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def _version?(version)
|
113
|
+
version && Gem::Version.new(version) rescue false
|
114
|
+
end
|
115
|
+
|
116
|
+
def _handle_vendored_option(name, version, options)
|
117
|
+
dir, path = _find_directory_source(options[:path])
|
118
|
+
|
119
|
+
if dir
|
120
|
+
dir.required_specs << name
|
121
|
+
dir.add_spec(path, name, version) if _version?(version)
|
122
|
+
dir
|
123
|
+
else
|
124
|
+
directory options[:path] do
|
125
|
+
_handle_vendored_option(name, version, {})
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def _find_directory_source(path)
|
131
|
+
if @directory
|
132
|
+
return @directory, Pathname.new(path || '')
|
133
|
+
end
|
134
|
+
|
135
|
+
path = @bundle.gemfile.dirname.join(path)
|
136
|
+
|
137
|
+
@directory_sources.each do |s|
|
138
|
+
if s.location.expand_path.to_s < path.expand_path.to_s
|
139
|
+
return s, path.relative_path_from(s.location)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
|
146
|
+
def _handle_git_option(name, version, options)
|
147
|
+
git = options[:git].to_s
|
148
|
+
ref = options[:ref] || options[:tag]
|
149
|
+
branch = options[:branch]
|
150
|
+
|
151
|
+
if source = @git || @git_sources[git]
|
152
|
+
if ref && source.ref != ref
|
153
|
+
raise GitSourceError, "'#{git}' already specified with ref: #{source.ref}"
|
154
|
+
elsif branch && source.branch != branch
|
155
|
+
raise GitSourceError, "'#{git}' already specified with branch: #{source.branch}"
|
156
|
+
end
|
157
|
+
|
158
|
+
source.required_specs << name
|
159
|
+
source.add_spec(Pathname.new(options[:path] || '.'), name, version) if _version?(version)
|
160
|
+
source
|
161
|
+
else
|
162
|
+
git(git, :ref => ref, :branch => branch) do
|
163
|
+
_handle_git_option(name, version, options)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def _combine_only(only)
|
169
|
+
return @only unless only
|
170
|
+
only = Array(only).compact.uniq.map { |o| o.to_s }
|
171
|
+
only &= @only if @only
|
172
|
+
only
|
173
|
+
end
|
174
|
+
|
175
|
+
def _combine_except(except)
|
176
|
+
return @except unless except
|
177
|
+
except = Array(except).compact.uniq.map { |o| o.to_s }
|
178
|
+
except |= @except if @except
|
179
|
+
except
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|