bundler-maglev- 1.0.21

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.
Files changed (144) hide show
  1. data/.gitignore +22 -0
  2. data/.travis.yml +32 -0
  3. data/CHANGELOG.md +805 -0
  4. data/ISSUES.md +62 -0
  5. data/LICENSE +23 -0
  6. data/README.md +29 -0
  7. data/Rakefile +212 -0
  8. data/UPGRADING.md +103 -0
  9. data/bin/bundle +22 -0
  10. data/bundler.gemspec +30 -0
  11. data/lib/bundler.rb +286 -0
  12. data/lib/bundler/capistrano.rb +11 -0
  13. data/lib/bundler/cli.rb +520 -0
  14. data/lib/bundler/definition.rb +438 -0
  15. data/lib/bundler/dependency.rb +134 -0
  16. data/lib/bundler/deployment.rb +58 -0
  17. data/lib/bundler/dsl.rb +257 -0
  18. data/lib/bundler/environment.rb +47 -0
  19. data/lib/bundler/gem_helper.rb +151 -0
  20. data/lib/bundler/gem_installer.rb +9 -0
  21. data/lib/bundler/gem_tasks.rb +2 -0
  22. data/lib/bundler/graph.rb +130 -0
  23. data/lib/bundler/index.rb +138 -0
  24. data/lib/bundler/installer.rb +97 -0
  25. data/lib/bundler/lazy_specification.rb +74 -0
  26. data/lib/bundler/lockfile_parser.rb +108 -0
  27. data/lib/bundler/remote_specification.rb +59 -0
  28. data/lib/bundler/resolver.rb +464 -0
  29. data/lib/bundler/rubygems_ext.rb +237 -0
  30. data/lib/bundler/rubygems_integration.rb +349 -0
  31. data/lib/bundler/runtime.rb +152 -0
  32. data/lib/bundler/settings.rb +115 -0
  33. data/lib/bundler/setup.rb +23 -0
  34. data/lib/bundler/shared_helpers.rb +71 -0
  35. data/lib/bundler/source.rb +708 -0
  36. data/lib/bundler/spec_set.rb +135 -0
  37. data/lib/bundler/templates/Executable +16 -0
  38. data/lib/bundler/templates/Gemfile +4 -0
  39. data/lib/bundler/templates/newgem/Gemfile.tt +4 -0
  40. data/lib/bundler/templates/newgem/Rakefile.tt +1 -0
  41. data/lib/bundler/templates/newgem/bin/newgem.tt +3 -0
  42. data/lib/bundler/templates/newgem/gitignore.tt +4 -0
  43. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +9 -0
  44. data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +7 -0
  45. data/lib/bundler/templates/newgem/newgem.gemspec.tt +24 -0
  46. data/lib/bundler/ui.rb +73 -0
  47. data/lib/bundler/vendor/thor.rb +358 -0
  48. data/lib/bundler/vendor/thor/actions.rb +314 -0
  49. data/lib/bundler/vendor/thor/actions/create_file.rb +105 -0
  50. data/lib/bundler/vendor/thor/actions/create_link.rb +57 -0
  51. data/lib/bundler/vendor/thor/actions/directory.rb +93 -0
  52. data/lib/bundler/vendor/thor/actions/empty_directory.rb +134 -0
  53. data/lib/bundler/vendor/thor/actions/file_manipulation.rb +270 -0
  54. data/lib/bundler/vendor/thor/actions/inject_into_file.rb +109 -0
  55. data/lib/bundler/vendor/thor/base.rb +576 -0
  56. data/lib/bundler/vendor/thor/core_ext/file_binary_read.rb +9 -0
  57. data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  58. data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +100 -0
  59. data/lib/bundler/vendor/thor/error.rb +30 -0
  60. data/lib/bundler/vendor/thor/group.rb +273 -0
  61. data/lib/bundler/vendor/thor/invocation.rb +168 -0
  62. data/lib/bundler/vendor/thor/parser.rb +4 -0
  63. data/lib/bundler/vendor/thor/parser/argument.rb +67 -0
  64. data/lib/bundler/vendor/thor/parser/arguments.rb +161 -0
  65. data/lib/bundler/vendor/thor/parser/option.rb +120 -0
  66. data/lib/bundler/vendor/thor/parser/options.rb +175 -0
  67. data/lib/bundler/vendor/thor/rake_compat.rb +66 -0
  68. data/lib/bundler/vendor/thor/runner.rb +309 -0
  69. data/lib/bundler/vendor/thor/shell.rb +88 -0
  70. data/lib/bundler/vendor/thor/shell/basic.rb +302 -0
  71. data/lib/bundler/vendor/thor/shell/color.rb +108 -0
  72. data/lib/bundler/vendor/thor/shell/html.rb +121 -0
  73. data/lib/bundler/vendor/thor/task.rb +113 -0
  74. data/lib/bundler/vendor/thor/util.rb +229 -0
  75. data/lib/bundler/vendor/thor/version.rb +3 -0
  76. data/lib/bundler/vendored_thor.rb +7 -0
  77. data/lib/bundler/version.rb +6 -0
  78. data/lib/bundler/vlad.rb +11 -0
  79. data/man/bundle-config.ronn +90 -0
  80. data/man/bundle-exec.ronn +111 -0
  81. data/man/bundle-install.ronn +317 -0
  82. data/man/bundle-package.ronn +59 -0
  83. data/man/bundle-update.ronn +176 -0
  84. data/man/bundle.ronn +80 -0
  85. data/man/gemfile.5.ronn +284 -0
  86. data/man/index.txt +6 -0
  87. data/spec/bundler/gem_helper_spec.rb +143 -0
  88. data/spec/cache/gems_spec.rb +230 -0
  89. data/spec/cache/git_spec.rb +12 -0
  90. data/spec/cache/path_spec.rb +27 -0
  91. data/spec/cache/platform_spec.rb +57 -0
  92. data/spec/install/deploy_spec.rb +197 -0
  93. data/spec/install/deprecated_spec.rb +37 -0
  94. data/spec/install/gems/c_ext_spec.rb +48 -0
  95. data/spec/install/gems/env_spec.rb +107 -0
  96. data/spec/install/gems/flex_spec.rb +313 -0
  97. data/spec/install/gems/groups_spec.rb +259 -0
  98. data/spec/install/gems/packed_spec.rb +84 -0
  99. data/spec/install/gems/platform_spec.rb +192 -0
  100. data/spec/install/gems/resolving_spec.rb +72 -0
  101. data/spec/install/gems/simple_case_spec.rb +770 -0
  102. data/spec/install/gems/sudo_spec.rb +74 -0
  103. data/spec/install/gems/win32_spec.rb +26 -0
  104. data/spec/install/gemspec_spec.rb +125 -0
  105. data/spec/install/git_spec.rb +570 -0
  106. data/spec/install/invalid_spec.rb +35 -0
  107. data/spec/install/path_spec.rb +405 -0
  108. data/spec/install/upgrade_spec.rb +26 -0
  109. data/spec/lock/git_spec.rb +35 -0
  110. data/spec/lock/lockfile_spec.rb +739 -0
  111. data/spec/other/check_spec.rb +221 -0
  112. data/spec/other/config_spec.rb +40 -0
  113. data/spec/other/console_spec.rb +54 -0
  114. data/spec/other/exec_spec.rb +248 -0
  115. data/spec/other/ext_spec.rb +37 -0
  116. data/spec/other/help_spec.rb +39 -0
  117. data/spec/other/init_spec.rb +40 -0
  118. data/spec/other/newgem_spec.rb +46 -0
  119. data/spec/other/open_spec.rb +35 -0
  120. data/spec/other/show_spec.rb +82 -0
  121. data/spec/quality_spec.rb +62 -0
  122. data/spec/resolver/basic_spec.rb +20 -0
  123. data/spec/resolver/platform_spec.rb +82 -0
  124. data/spec/runtime/executable_spec.rb +110 -0
  125. data/spec/runtime/load_spec.rb +107 -0
  126. data/spec/runtime/platform_spec.rb +90 -0
  127. data/spec/runtime/require_spec.rb +231 -0
  128. data/spec/runtime/setup_spec.rb +730 -0
  129. data/spec/runtime/with_clean_env_spec.rb +15 -0
  130. data/spec/spec_helper.rb +92 -0
  131. data/spec/support/builders.rb +597 -0
  132. data/spec/support/helpers.rb +239 -0
  133. data/spec/support/indexes.rb +112 -0
  134. data/spec/support/matchers.rb +77 -0
  135. data/spec/support/path.rb +71 -0
  136. data/spec/support/platforms.rb +53 -0
  137. data/spec/support/ruby_ext.rb +20 -0
  138. data/spec/support/rubygems_ext.rb +37 -0
  139. data/spec/support/rubygems_hax/platform.rb +11 -0
  140. data/spec/support/sudo.rb +21 -0
  141. data/spec/update/gems_spec.rb +122 -0
  142. data/spec/update/git_spec.rb +196 -0
  143. data/spec/update/source_spec.rb +51 -0
  144. metadata +296 -0
@@ -0,0 +1,58 @@
1
+ module Bundler
2
+ class Deployment
3
+ def self.define_task(context, task_method = :task, opts = {})
4
+ if defined?(Capistrano) && context.is_a?(Capistrano::Configuration)
5
+ context_name = "capistrano"
6
+ role_default = "{:except => {:no_release => true}}"
7
+ error_type = ::Capistrano::CommandError
8
+ else
9
+ context_name = "vlad"
10
+ role_default = "[:app]"
11
+ error_type = ::Rake::CommandFailedError
12
+ end
13
+
14
+ roles = context.fetch(:bundle_roles, false)
15
+ opts[:roles] = roles if roles
16
+
17
+ context.send :namespace, :bundle do
18
+ send :desc, <<-DESC
19
+ Install the current Bundler environment. By default, gems will be \
20
+ installed to the shared/bundle path. Gems in the development and \
21
+ test group will not be installed. The install command is executed \
22
+ with the --deployment and --quiet flags. If the bundle cmd cannot \
23
+ be found then you can override the bundle_cmd variable to specifiy \
24
+ which one it should use.
25
+
26
+ You can override any of these defaults by setting the variables shown below.
27
+
28
+ N.B. bundle_roles must be defined before you require 'bundler/#{context_name}' \
29
+ in your deploy.rb file.
30
+
31
+ set :bundle_gemfile, "Gemfile"
32
+ set :bundle_dir, File.join(fetch(:shared_path), 'bundle')
33
+ set :bundle_flags, "--deployment --quiet"
34
+ set :bundle_without, [:development, :test]
35
+ set :bundle_cmd, "bundle" # e.g. "/opt/ruby/bin/bundle"
36
+ set :bundle_roles, #{role_default} # e.g. [:app, :batch]
37
+ DESC
38
+ send task_method, :install, opts do
39
+ bundle_cmd = context.fetch(:bundle_cmd, "bundle")
40
+ bundle_flags = context.fetch(:bundle_flags, "--deployment --quiet")
41
+ bundle_dir = context.fetch(:bundle_dir, File.join(context.fetch(:shared_path), 'bundle'))
42
+ bundle_gemfile = context.fetch(:bundle_gemfile, "Gemfile")
43
+ bundle_without = [*context.fetch(:bundle_without, [:development, :test])].compact
44
+ current_release = context.fetch(:current_release)
45
+ if current_release.to_s.empty?
46
+ raise error_type.new("Cannot detect current release path - make sure you have deployed at least once.")
47
+ end
48
+ args = ["--gemfile #{File.join(current_release, bundle_gemfile)}"]
49
+ args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty?
50
+ args << bundle_flags.to_s
51
+ args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty?
52
+
53
+ run "cd #{current_release} && #{bundle_cmd} install #{args.join(' ')}"
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,257 @@
1
+ require 'bundler/dependency'
2
+
3
+ module Bundler
4
+ class Dsl
5
+ def self.evaluate(gemfile, lockfile, unlock)
6
+ builder = new
7
+ builder.instance_eval(Bundler.read_file(gemfile.to_s), gemfile.to_s, 1)
8
+ builder.to_definition(lockfile, unlock)
9
+ end
10
+
11
+ VALID_PLATFORMS = Bundler::Dependency::PLATFORM_MAP.keys.freeze
12
+
13
+ def initialize
14
+ @rubygems_source = Source::Rubygems.new
15
+ @source = nil
16
+ @sources = []
17
+ @dependencies = []
18
+ @groups = []
19
+ @platforms = []
20
+ @env = nil
21
+ end
22
+
23
+ def gemspec(opts = nil)
24
+ path = opts && opts[:path] || '.'
25
+ name = opts && opts[:name] || '{,*}'
26
+ development_group = opts && opts[:development_group] || :development
27
+ path = File.expand_path(path, Bundler.default_gemfile.dirname)
28
+ gemspecs = Dir[File.join(path, "#{name}.gemspec")]
29
+
30
+ case gemspecs.size
31
+ when 1
32
+ spec = Bundler.load_gemspec(gemspecs.first)
33
+ raise InvalidOption, "There was an error loading the gemspec at #{gemspecs.first}." unless spec
34
+ gem spec.name, :path => path
35
+ group(development_group) do
36
+ spec.development_dependencies.each do |dep|
37
+ gem dep.name, *(dep.requirement.as_list + [:type => :development])
38
+ end
39
+ end
40
+ when 0
41
+ raise InvalidOption, "There are no gemspecs at #{path}."
42
+ else
43
+ raise InvalidOption, "There are multiple gemspecs at #{path}. Please use the :name option to specify which one."
44
+ end
45
+ end
46
+
47
+ def gem(name, *args)
48
+ if name.is_a?(Symbol)
49
+ raise GemfileError, %{You need to specify gem names as Strings. Use 'gem "#{name.to_s}"' instead.}
50
+ end
51
+
52
+ options = Hash === args.last ? args.pop : {}
53
+ version = args || [">= 0"]
54
+
55
+ _deprecated_options(options)
56
+ _normalize_options(name, version, options)
57
+
58
+ dep = Dependency.new(name, version, options)
59
+
60
+ # if there's already a dependency with this name we try to prefer one
61
+ if current = @dependencies.find { |d| d.name == dep.name }
62
+ if current.requirement != dep.requirement
63
+ if current.type == :development
64
+ @dependencies.delete current
65
+ elsif dep.type == :development
66
+ return
67
+ else
68
+ raise DslError, "You cannot specify the same gem twice with different version requirements. " \
69
+ "You specified: #{current.name} (#{current.requirement}) and " \
70
+ "#{dep.name} (#{dep.requirement})"
71
+ end
72
+ end
73
+
74
+ if current.source != dep.source
75
+ if current.type == :development
76
+ @dependencies.delete current
77
+ elsif dep.type == :development
78
+ return
79
+ else
80
+ raise DslError, "You cannot specify the same gem twice coming from different sources. You " \
81
+ "specified that #{dep.name} (#{dep.requirement}) should come from " \
82
+ "#{current.source || 'an unspecfied source'} and #{dep.source}"
83
+ end
84
+ end
85
+ end
86
+
87
+ @dependencies << dep
88
+ end
89
+
90
+ def source(source, options = {})
91
+ case source
92
+ when :gemcutter, :rubygems, :rubyforge then
93
+ rubygems_source "http://rubygems.org"
94
+ return
95
+ when String
96
+ rubygems_source source
97
+ return
98
+ end
99
+
100
+ @source = source
101
+ options[:prepend] ? @sources.unshift(@source) : @sources << @source
102
+
103
+ yield if block_given?
104
+ @source
105
+ ensure
106
+ @source = nil
107
+ end
108
+
109
+ def path(path, options = {}, source_options = {}, &blk)
110
+ source Source::Path.new(_normalize_hash(options).merge("path" => Pathname.new(path))), source_options, &blk
111
+ end
112
+
113
+ def git(uri, options = {}, source_options = {}, &blk)
114
+ unless block_given?
115
+ msg = "You can no longer specify a git source by itself. Instead, \n" \
116
+ "either use the :git option on a gem, or specify the gems that \n" \
117
+ "bundler should find in the git source by passing a block to \n" \
118
+ "the git method, like: \n\n" \
119
+ " git 'git://github.com/rails/rails.git' do\n" \
120
+ " gem 'rails'\n" \
121
+ " end"
122
+ raise DeprecatedError, msg
123
+ end
124
+
125
+ source Source::Git.new(_normalize_hash(options).merge("uri" => uri)), source_options, &blk
126
+ end
127
+
128
+ def to_definition(lockfile, unlock)
129
+ @sources << @rubygems_source
130
+ @sources.uniq!
131
+ Definition.new(lockfile, @dependencies, @sources, unlock)
132
+ end
133
+
134
+ def group(*args, &blk)
135
+ @groups.concat args
136
+ yield
137
+ ensure
138
+ args.each { @groups.pop }
139
+ end
140
+
141
+ def platforms(*platforms)
142
+ @platforms.concat platforms
143
+ yield
144
+ ensure
145
+ platforms.each { @platforms.pop }
146
+ end
147
+ alias_method :platform, :platforms
148
+
149
+ def env(name)
150
+ @env, old = name, @env
151
+ yield
152
+ ensure
153
+ @env = old
154
+ end
155
+
156
+ # Deprecated methods
157
+
158
+ def self.deprecate(name, replacement = nil)
159
+ define_method(name) do |*|
160
+ message = "'#{name}' has been removed from the Gemfile DSL, "
161
+ if replacement
162
+ message << "and has been replaced with '#{replacement}'."
163
+ else
164
+ message << "and is no longer supported."
165
+ end
166
+ message << "\nSee the README for more information on upgrading from Bundler 0.8."
167
+ raise DeprecatedError, message
168
+ end
169
+ end
170
+
171
+ deprecate :only, :group
172
+ deprecate :except
173
+ deprecate :disable_system_gems
174
+ deprecate :disable_rubygems
175
+ deprecate :clear_sources
176
+ deprecate :bundle_path
177
+ deprecate :bin_path
178
+
179
+ private
180
+
181
+ def rubygems_source(source)
182
+ @rubygems_source.add_remote source
183
+ @sources << @rubygems_source
184
+ end
185
+
186
+ def _normalize_hash(opts)
187
+ # Cannot modify a hash during an iteration in 1.9
188
+ opts.keys.each do |k|
189
+ next if String === k
190
+ v = opts[k]
191
+ opts.delete(k)
192
+ opts[k.to_s] = v
193
+ end
194
+ opts
195
+ end
196
+
197
+ def _normalize_options(name, version, opts)
198
+ _normalize_hash(opts)
199
+
200
+ invalid_keys = opts.keys - %w(group groups git path name branch ref tag require submodules platform platforms type)
201
+ if invalid_keys.any?
202
+ plural = invalid_keys.size > 1
203
+ message = "You passed #{invalid_keys.map{|k| ':'+k }.join(", ")} "
204
+ if plural
205
+ message << "as options for gem '#{name}', but they are invalid."
206
+ else
207
+ message << "as an option for gem '#{name}', but it is invalid."
208
+ end
209
+ raise InvalidOption, message
210
+ end
211
+
212
+ groups = @groups.dup
213
+ opts["group"] = opts.delete("groups") || opts["group"]
214
+ groups.concat Array(opts.delete("group"))
215
+ groups = [:default] if groups.empty?
216
+
217
+ platforms = @platforms.dup
218
+ opts["platforms"] = opts["platform"] || opts["platforms"]
219
+ platforms.concat Array(opts.delete("platforms"))
220
+ platforms.map! { |p| p.to_sym }
221
+ platforms.each do |p|
222
+ next if VALID_PLATFORMS.include?(p)
223
+ raise DslError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}"
224
+ end
225
+
226
+ # Normalize git and path options
227
+ ["git", "path"].each do |type|
228
+ if param = opts[type]
229
+ if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/
230
+ options = opts.merge("name" => name, "version" => $1)
231
+ else
232
+ options = opts.dup
233
+ end
234
+ source = send(type, param, options, :prepend => true) {}
235
+ opts["source"] = source
236
+ end
237
+ end
238
+
239
+ opts["source"] ||= @source
240
+ opts["env"] ||= @env
241
+ opts["platforms"] = platforms.dup
242
+ opts["group"] = groups
243
+ end
244
+
245
+ def _deprecated_options(options)
246
+ if options.include?(:require_as)
247
+ raise DeprecatedError, "Please replace :require_as with :require"
248
+ elsif options.include?(:vendored_at)
249
+ raise DeprecatedError, "Please replace :vendored_at with :path"
250
+ elsif options.include?(:only)
251
+ raise DeprecatedError, "Please replace :only with :group"
252
+ elsif options.include?(:except)
253
+ raise DeprecatedError, "The :except option is no longer supported"
254
+ end
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,47 @@
1
+ module Bundler
2
+ class Environment
3
+ attr_reader :root
4
+
5
+ def initialize(root, definition)
6
+ @root = root
7
+ @definition = definition
8
+
9
+ env_file = Bundler.app_config_path.join('environment.rb')
10
+ env_file.rmtree if env_file.exist?
11
+ end
12
+
13
+ def inspect
14
+ @definition.to_lock.inspect
15
+ end
16
+
17
+ # TODO: Remove this method. It's used in cli.rb still
18
+ def index
19
+ @definition.index
20
+ end
21
+
22
+ def requested_specs
23
+ @definition.requested_specs
24
+ end
25
+
26
+ def specs
27
+ @definition.specs
28
+ end
29
+
30
+ def dependencies
31
+ @definition.dependencies
32
+ end
33
+
34
+ def current_dependencies
35
+ @definition.current_dependencies
36
+ end
37
+
38
+ def lock
39
+ @definition.lock(Bundler.default_lockfile)
40
+ end
41
+
42
+ def update(*gems)
43
+ # Nothing
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,151 @@
1
+ $:.unshift File.expand_path('../vendor', __FILE__)
2
+ require 'thor'
3
+ require 'bundler'
4
+
5
+ module Bundler
6
+ class GemHelper
7
+ include Rake::DSL if defined? Rake::DSL
8
+
9
+ def self.install_tasks(opts = {})
10
+ dir = opts[:dir] || Dir.pwd
11
+ self.new(dir, opts[:name]).install
12
+ end
13
+
14
+ attr_reader :spec_path, :base, :gemspec
15
+
16
+ def initialize(base, name = nil)
17
+ Bundler.ui = UI::Shell.new(Thor::Base.shell.new)
18
+ @base = base
19
+ gemspecs = name ? [File.join(base, "#{name}.gemspec")] : Dir[File.join(base, "{,*}.gemspec")]
20
+ raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1
21
+ @spec_path = gemspecs.first
22
+ @gemspec = Bundler.load_gemspec(@spec_path)
23
+ end
24
+
25
+ def install
26
+ desc "Build #{name}-#{version}.gem into the pkg directory"
27
+ task 'build' do
28
+ build_gem
29
+ end
30
+
31
+ desc "Build and install #{name}-#{version}.gem into system gems"
32
+ task 'install' do
33
+ install_gem
34
+ end
35
+
36
+ desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to Rubygems"
37
+ task 'release' do
38
+ release_gem
39
+ end
40
+ end
41
+
42
+ def build_gem
43
+ file_name = nil
44
+ sh("gem build -V '#{spec_path}'") { |out, code|
45
+ raise out unless out[/Successfully/]
46
+ file_name = File.basename(built_gem_path)
47
+ FileUtils.mkdir_p(File.join(base, 'pkg'))
48
+ FileUtils.mv(built_gem_path, 'pkg')
49
+ Bundler.ui.confirm "#{name} #{version} built to pkg/#{file_name}"
50
+ }
51
+ File.join(base, 'pkg', file_name)
52
+ end
53
+
54
+ def install_gem
55
+ built_gem_path = build_gem
56
+ out, _ = sh_with_code("gem install '#{built_gem_path}'")
57
+ raise "Couldn't install gem, run `gem install #{built_gem_path}' for more detailed output" unless out[/Successfully installed/]
58
+ Bundler.ui.confirm "#{name} (#{version}) installed"
59
+ end
60
+
61
+ def release_gem
62
+ guard_clean
63
+ guard_already_tagged
64
+ built_gem_path = build_gem
65
+ tag_version {
66
+ git_push
67
+ rubygem_push(built_gem_path)
68
+ }
69
+ end
70
+
71
+ protected
72
+ def rubygem_push(path)
73
+ if Pathname.new("~/.gem/credentials").expand_path.exist?
74
+ sh("gem push '#{path}'")
75
+ Bundler.ui.confirm "Pushed #{name} #{version} to rubygems.org"
76
+ else
77
+ raise "Your rubygems.org credentials aren't set. Run `gem push` to set them."
78
+ end
79
+ end
80
+
81
+ def built_gem_path
82
+ Dir[File.join(base, "#{name}-*.gem")].sort_by{|f| File.mtime(f)}.last
83
+ end
84
+
85
+ def git_push
86
+ perform_git_push
87
+ perform_git_push ' --tags'
88
+ Bundler.ui.confirm "Pushed git commits and tags"
89
+ end
90
+
91
+ def perform_git_push(options = '')
92
+ cmd = "git push #{options}"
93
+ out, code = sh_with_code(cmd)
94
+ raise "Couldn't git push. `#{cmd}' failed with the following output:\n\n#{out}\n" unless code == 0
95
+ end
96
+
97
+ def guard_already_tagged
98
+ if sh('git tag').split(/\n/).include?(version_tag)
99
+ raise("This tag has already been committed to the repo.")
100
+ end
101
+ end
102
+
103
+ def guard_clean
104
+ clean? or raise("There are files that need to be committed first.")
105
+ end
106
+
107
+ def clean?
108
+ sh_with_code("git diff --exit-code")[1] == 0
109
+ end
110
+
111
+ def tag_version
112
+ sh "git tag -a -m \"Version #{version}\" #{version_tag}"
113
+ Bundler.ui.confirm "Tagged #{version_tag}"
114
+ yield if block_given?
115
+ rescue
116
+ Bundler.ui.error "Untagged #{version_tag} due to error"
117
+ sh_with_code "git tag -d #{version_tag}"
118
+ raise
119
+ end
120
+
121
+ def version
122
+ gemspec.version
123
+ end
124
+
125
+ def version_tag
126
+ "v#{version}"
127
+ end
128
+
129
+ def name
130
+ gemspec.name
131
+ end
132
+
133
+ def sh(cmd, &block)
134
+ out, code = sh_with_code(cmd, &block)
135
+ code == 0 ? out : raise(out.empty? ? "Running `#{cmd}' failed. Run this command directly for more detailed output." : out)
136
+ end
137
+
138
+ def sh_with_code(cmd, &block)
139
+ cmd << " 2>&1"
140
+ outbuf = ''
141
+ Bundler.ui.debug(cmd)
142
+ Dir.chdir(base) {
143
+ outbuf = `#{cmd}`
144
+ if $? == 0
145
+ block.call(outbuf) if block
146
+ end
147
+ }
148
+ [outbuf, $?]
149
+ end
150
+ end
151
+ end