bundler_package_git 1.1.pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. data/.gitignore +22 -0
  2. data/.rvmrc +1 -0
  3. data/CHANGELOG.md +659 -0
  4. data/ISSUES.md +47 -0
  5. data/LICENSE +23 -0
  6. data/README.md +29 -0
  7. data/Rakefile +167 -0
  8. data/UPGRADING.md +103 -0
  9. data/bin/bundle +22 -0
  10. data/bundler.gemspec +30 -0
  11. data/lib/bundler.rb +283 -0
  12. data/lib/bundler/capistrano.rb +11 -0
  13. data/lib/bundler/cli.rb +490 -0
  14. data/lib/bundler/definition.rb +429 -0
  15. data/lib/bundler/dependency.rb +130 -0
  16. data/lib/bundler/deployment.rb +53 -0
  17. data/lib/bundler/dsl.rb +243 -0
  18. data/lib/bundler/environment.rb +47 -0
  19. data/lib/bundler/fetcher.rb +101 -0
  20. data/lib/bundler/gem_helper.rb +146 -0
  21. data/lib/bundler/graph.rb +130 -0
  22. data/lib/bundler/index.rb +131 -0
  23. data/lib/bundler/installer.rb +117 -0
  24. data/lib/bundler/lazy_specification.rb +71 -0
  25. data/lib/bundler/lockfile_parser.rb +108 -0
  26. data/lib/bundler/remote_specification.rb +57 -0
  27. data/lib/bundler/resolver.rb +470 -0
  28. data/lib/bundler/rubygems_ext.rb +226 -0
  29. data/lib/bundler/runtime.rb +201 -0
  30. data/lib/bundler/settings.rb +117 -0
  31. data/lib/bundler/setup.rb +16 -0
  32. data/lib/bundler/shared_helpers.rb +167 -0
  33. data/lib/bundler/source.rb +675 -0
  34. data/lib/bundler/spec_set.rb +134 -0
  35. data/lib/bundler/templates/Executable +16 -0
  36. data/lib/bundler/templates/Gemfile +4 -0
  37. data/lib/bundler/templates/newgem/Gemfile.tt +4 -0
  38. data/lib/bundler/templates/newgem/Rakefile.tt +2 -0
  39. data/lib/bundler/templates/newgem/bin/newgem.tt +3 -0
  40. data/lib/bundler/templates/newgem/gitignore.tt +4 -0
  41. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +7 -0
  42. data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +7 -0
  43. data/lib/bundler/templates/newgem/newgem.gemspec.tt +21 -0
  44. data/lib/bundler/ui.rb +73 -0
  45. data/lib/bundler/vendor/net/http/faster.rb +27 -0
  46. data/lib/bundler/vendor/net/http/persistent.rb +464 -0
  47. data/lib/bundler/vendor/thor.rb +319 -0
  48. data/lib/bundler/vendor/thor/actions.rb +297 -0
  49. data/lib/bundler/vendor/thor/actions/create_file.rb +105 -0
  50. data/lib/bundler/vendor/thor/actions/directory.rb +93 -0
  51. data/lib/bundler/vendor/thor/actions/empty_directory.rb +134 -0
  52. data/lib/bundler/vendor/thor/actions/file_manipulation.rb +229 -0
  53. data/lib/bundler/vendor/thor/actions/inject_into_file.rb +104 -0
  54. data/lib/bundler/vendor/thor/base.rb +556 -0
  55. data/lib/bundler/vendor/thor/core_ext/file_binary_read.rb +9 -0
  56. data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  57. data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +100 -0
  58. data/lib/bundler/vendor/thor/error.rb +30 -0
  59. data/lib/bundler/vendor/thor/invocation.rb +168 -0
  60. data/lib/bundler/vendor/thor/parser.rb +4 -0
  61. data/lib/bundler/vendor/thor/parser/argument.rb +67 -0
  62. data/lib/bundler/vendor/thor/parser/arguments.rb +161 -0
  63. data/lib/bundler/vendor/thor/parser/option.rb +120 -0
  64. data/lib/bundler/vendor/thor/parser/options.rb +174 -0
  65. data/lib/bundler/vendor/thor/shell.rb +88 -0
  66. data/lib/bundler/vendor/thor/shell/basic.rb +275 -0
  67. data/lib/bundler/vendor/thor/shell/color.rb +108 -0
  68. data/lib/bundler/vendor/thor/shell/html.rb +121 -0
  69. data/lib/bundler/vendor/thor/task.rb +114 -0
  70. data/lib/bundler/vendor/thor/util.rb +229 -0
  71. data/lib/bundler/vendor/thor/version.rb +3 -0
  72. data/lib/bundler/version.rb +6 -0
  73. data/lib/bundler/vlad.rb +9 -0
  74. data/man/bundle-config.ronn +90 -0
  75. data/man/bundle-exec.ronn +111 -0
  76. data/man/bundle-install.ronn +314 -0
  77. data/man/bundle-package.ronn +59 -0
  78. data/man/bundle-update.ronn +176 -0
  79. data/man/bundle.ronn +80 -0
  80. data/man/gemfile.5.ronn +279 -0
  81. data/man/index.txt +6 -0
  82. data/spec/cache/gems_spec.rb +219 -0
  83. data/spec/cache/git_spec.rb +9 -0
  84. data/spec/cache/path_spec.rb +27 -0
  85. data/spec/cache/platform_spec.rb +57 -0
  86. data/spec/install/deploy_spec.rb +197 -0
  87. data/spec/install/deprecated_spec.rb +37 -0
  88. data/spec/install/gems/c_ext_spec.rb +48 -0
  89. data/spec/install/gems/dependency_api_spec.rb +85 -0
  90. data/spec/install/gems/env_spec.rb +107 -0
  91. data/spec/install/gems/flex_spec.rb +313 -0
  92. data/spec/install/gems/groups_spec.rb +245 -0
  93. data/spec/install/gems/packed_spec.rb +84 -0
  94. data/spec/install/gems/platform_spec.rb +208 -0
  95. data/spec/install/gems/resolving_spec.rb +72 -0
  96. data/spec/install/gems/simple_case_spec.rb +715 -0
  97. data/spec/install/gems/standalone_spec.rb +162 -0
  98. data/spec/install/gems/sudo_spec.rb +73 -0
  99. data/spec/install/gems/win32_spec.rb +26 -0
  100. data/spec/install/gemspec_spec.rb +108 -0
  101. data/spec/install/git_spec.rb +571 -0
  102. data/spec/install/invalid_spec.rb +17 -0
  103. data/spec/install/path_spec.rb +353 -0
  104. data/spec/install/upgrade_spec.rb +26 -0
  105. data/spec/lock/git_spec.rb +35 -0
  106. data/spec/lock/lockfile_spec.rb +683 -0
  107. data/spec/other/check_spec.rb +221 -0
  108. data/spec/other/clean_spec.rb +202 -0
  109. data/spec/other/config_spec.rb +40 -0
  110. data/spec/other/console_spec.rb +54 -0
  111. data/spec/other/exec_spec.rb +241 -0
  112. data/spec/other/ext_spec.rb +16 -0
  113. data/spec/other/gem_helper_spec.rb +128 -0
  114. data/spec/other/help_spec.rb +38 -0
  115. data/spec/other/init_spec.rb +40 -0
  116. data/spec/other/newgem_spec.rb +24 -0
  117. data/spec/other/open_spec.rb +35 -0
  118. data/spec/other/show_spec.rb +82 -0
  119. data/spec/pack/gems_spec.rb +54 -0
  120. data/spec/quality_spec.rb +58 -0
  121. data/spec/resolver/basic_spec.rb +20 -0
  122. data/spec/resolver/platform_spec.rb +82 -0
  123. data/spec/runtime/executable_spec.rb +110 -0
  124. data/spec/runtime/load_spec.rb +107 -0
  125. data/spec/runtime/platform_spec.rb +90 -0
  126. data/spec/runtime/require_spec.rb +231 -0
  127. data/spec/runtime/setup_spec.rb +688 -0
  128. data/spec/runtime/with_clean_env_spec.rb +15 -0
  129. data/spec/spec_helper.rb +85 -0
  130. data/spec/support/artifice/endpoint.rb +50 -0
  131. data/spec/support/artifice/endpoint_fallback.rb +22 -0
  132. data/spec/support/artifice/endpoint_marshal_fail.rb +11 -0
  133. data/spec/support/artifice/endpoint_redirect.rb +11 -0
  134. data/spec/support/builders.rb +574 -0
  135. data/spec/support/fakeweb/rack-1.0.0.marshal +2 -0
  136. data/spec/support/fakeweb/windows.rb +23 -0
  137. data/spec/support/helpers.rb +246 -0
  138. data/spec/support/indexes.rb +112 -0
  139. data/spec/support/matchers.rb +89 -0
  140. data/spec/support/path.rb +73 -0
  141. data/spec/support/platforms.rb +53 -0
  142. data/spec/support/ruby_ext.rb +20 -0
  143. data/spec/support/rubygems_ext.rb +35 -0
  144. data/spec/support/rubygems_hax/platform.rb +11 -0
  145. data/spec/support/sudo.rb +21 -0
  146. data/spec/update/gems_spec.rb +121 -0
  147. data/spec/update/git_spec.rb +196 -0
  148. data/spec/update/source_spec.rb +51 -0
  149. metadata +294 -0
@@ -0,0 +1,53 @@
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
+ else
8
+ context_name = "vlad"
9
+ role_default = "[:app]"
10
+ end
11
+
12
+ roles = context.fetch(:bundle_roles, false)
13
+ opts[:roles] = roles if roles
14
+
15
+ context.send :namespace, :bundle do
16
+ send :desc, <<-DESC
17
+ Install the current Bundler environment. By default, gems will be \
18
+ installed to the shared/bundle path. Gems in the development and \
19
+ test group will not be installed. The install command is executed \
20
+ with the --deployment and --quiet flags. If the bundle cmd cannot \
21
+ be found then you can override the bundle_cmd variable to specifiy \
22
+ which one it should use.
23
+
24
+ You can override any of these defaults by setting the variables shown below.
25
+
26
+ N.B. bundle_roles must be defined before you require 'bundler/#{context_name}' \
27
+ in your deploy.rb file.
28
+
29
+ set :bundle_gemfile, "Gemfile"
30
+ set :bundle_dir, File.join(fetch(:shared_path), 'bundle')
31
+ set :bundle_flags, "--deployment --quiet"
32
+ set :bundle_without, [:development, :test]
33
+ set :bundle_cmd, "bundle" # e.g. "/opt/ruby/bin/bundle"
34
+ set :bundle_roles, #{role_default} # e.g. [:app, :batch]
35
+ DESC
36
+ send task_method, :install, opts do
37
+ bundle_cmd = context.fetch(:bundle_cmd, "bundle")
38
+ bundle_flags = context.fetch(:bundle_flags, "--deployment --quiet")
39
+ bundle_dir = context.fetch(:bundle_dir, File.join(context.fetch(:shared_path), 'bundle'))
40
+ bundle_gemfile = context.fetch(:bundle_gemfile, "Gemfile")
41
+ bundle_without = [*context.fetch(:bundle_without, [:development, :test])].compact
42
+
43
+ args = ["--gemfile #{File.join(context.fetch(:current_release), bundle_gemfile)}"]
44
+ args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty?
45
+ args << bundle_flags.to_s
46
+ args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty?
47
+
48
+ run "#{bundle_cmd} install #{args.join(' ')}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,243 @@
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
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 current = @dependencies.find { |d| d.name == dep.name }
61
+ if current.requirement != dep.requirement
62
+ raise DslError, "You cannot specify the same gem twice with different version requirements. " \
63
+ "You specified: #{current.name} (#{current.requirement}) and " \
64
+ "#{dep.name} (#{dep.requirement})"
65
+ end
66
+
67
+ if current.source != dep.source
68
+ raise DslError, "You cannot specify the same gem twice coming from different sources. You " \
69
+ "specified that #{dep.name} (#{dep.requirement}) should come from " \
70
+ "#{current.source || 'an unspecfied source'} and #{dep.source}"
71
+ end
72
+ end
73
+ @dependencies << Dependency.new(name, version, options)
74
+ end
75
+
76
+ def source(source, options = {})
77
+ case source
78
+ when :gemcutter, :rubygems, :rubyforge then
79
+ rubygems_source "http://rubygems.org"
80
+ return
81
+ when String
82
+ rubygems_source source
83
+ return
84
+ end
85
+
86
+ @source = source
87
+ options[:prepend] ? @sources.unshift(@source) : @sources << @source
88
+
89
+ yield if block_given?
90
+ @source
91
+ ensure
92
+ @source = nil
93
+ end
94
+
95
+ def path(path, options = {}, source_options = {}, &blk)
96
+ source Source::Path.new(_normalize_hash(options).merge("path" => Pathname.new(path))), source_options, &blk
97
+ end
98
+
99
+ def git(uri, options = {}, source_options = {}, &blk)
100
+ unless block_given?
101
+ msg = "You can no longer specify a git source by itself. Instead, \n" \
102
+ "either use the :git option on a gem, or specify the gems that \n" \
103
+ "bundler should find in the git source by passing a block to \n" \
104
+ "the git method, like: \n\n" \
105
+ " git 'git://github.com/rails/rails.git' do\n" \
106
+ " gem 'rails'\n" \
107
+ " end"
108
+ raise DeprecatedError, msg
109
+ end
110
+
111
+ source Source::Git.new(_normalize_hash(options).merge("uri" => uri)), source_options, &blk
112
+ end
113
+
114
+ def to_definition(lockfile, unlock)
115
+ @sources << @rubygems_source
116
+ @sources.uniq!
117
+ Definition.new(lockfile, @dependencies, @sources, unlock)
118
+ end
119
+
120
+ def group(*args, &blk)
121
+ @groups.concat args
122
+ yield
123
+ ensure
124
+ args.each { @groups.pop }
125
+ end
126
+
127
+ def platforms(*platforms)
128
+ @platforms.concat platforms
129
+ yield
130
+ ensure
131
+ platforms.each { @platforms.pop }
132
+ end
133
+ alias_method :platform, :platforms
134
+
135
+ def env(name)
136
+ @env, old = name, @env
137
+ yield
138
+ ensure
139
+ @env = old
140
+ end
141
+
142
+ # Deprecated methods
143
+
144
+ def self.deprecate(name, replacement = nil)
145
+ define_method(name) do |*|
146
+ message = "'#{name}' has been removed from the Gemfile DSL, "
147
+ if replacement
148
+ message << "and has been replaced with '#{replacement}'."
149
+ else
150
+ message << "and is no longer supported."
151
+ end
152
+ message << "\nSee the README for more information on upgrading from Bundler 0.8."
153
+ raise DeprecatedError, message
154
+ end
155
+ end
156
+
157
+ deprecate :only, :group
158
+ deprecate :except
159
+ deprecate :disable_system_gems
160
+ deprecate :disable_rubygems
161
+ deprecate :clear_sources
162
+ deprecate :bundle_path
163
+ deprecate :bin_path
164
+
165
+ private
166
+
167
+ def rubygems_source(source)
168
+ @rubygems_source.add_remote source
169
+ @sources << @rubygems_source
170
+ end
171
+
172
+ def _normalize_hash(opts)
173
+ # Cannot modify a hash during an iteration in 1.9
174
+ opts.keys.each do |k|
175
+ next if String === k
176
+ v = opts[k]
177
+ opts.delete(k)
178
+ opts[k.to_s] = v
179
+ end
180
+ opts
181
+ end
182
+
183
+ def _normalize_options(name, version, opts)
184
+ _normalize_hash(opts)
185
+
186
+ invalid_keys = opts.keys - %w(group groups git path name branch ref tag require submodules platform platforms)
187
+ if invalid_keys.any?
188
+ plural = invalid_keys.size > 1
189
+ message = "You passed #{invalid_keys.map{|k| ':'+k }.join(", ")} "
190
+ if plural
191
+ message << "as options for gem '#{name}', but they are invalid."
192
+ else
193
+ message << "as an option for gem '#{name}', but it is invalid."
194
+ end
195
+ raise InvalidOption, message
196
+ end
197
+
198
+ groups = @groups.dup
199
+ opts["group"] = opts.delete("groups") || opts["group"]
200
+ groups.concat Array(opts.delete("group"))
201
+ groups = [:default] if groups.empty?
202
+
203
+ platforms = @platforms.dup
204
+ opts["platforms"] = opts["platform"] || opts["platforms"]
205
+ platforms.concat Array(opts.delete("platforms"))
206
+ platforms.map! { |p| p.to_sym }
207
+ platforms.each do |p|
208
+ next if VALID_PLATFORMS.include?(p)
209
+ raise DslError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}"
210
+ end
211
+
212
+ # Normalize git and path options
213
+ ["git", "path"].each do |type|
214
+ if param = opts[type]
215
+ if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/
216
+ options = opts.merge("name" => name, "version" => $1)
217
+ else
218
+ options = opts.dup
219
+ end
220
+ source = send(type, param, options, :prepend => true) {}
221
+ opts["source"] = source
222
+ end
223
+ end
224
+
225
+ opts["source"] ||= @source
226
+ opts["env"] ||= @env
227
+ opts["platforms"] = platforms.dup
228
+ opts["group"] = groups
229
+ end
230
+
231
+ def _deprecated_options(options)
232
+ if options.include?(:require_as)
233
+ raise DeprecatedError, "Please replace :require_as with :require"
234
+ elsif options.include?(:vendored_at)
235
+ raise DeprecatedError, "Please replace :vendored_at with :path"
236
+ elsif options.include?(:only)
237
+ raise DeprecatedError, "Please replace :only with :group"
238
+ elsif options.include?(:except)
239
+ raise DeprecatedError, "The :except option is no longer supported"
240
+ end
241
+ end
242
+ end
243
+ 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,101 @@
1
+ require 'uri'
2
+ require 'net/http/persistent'
3
+
4
+ module Bundler
5
+ class Fetcher
6
+ REDIRECT_LIMIT = 5
7
+
8
+ def initialize(remote_uri)
9
+ @remote_uri = remote_uri
10
+ @@connection ||= Net::HTTP::Persistent.new
11
+ end
12
+
13
+ # fetch a gem specification
14
+ def fetch_spec(spec)
15
+ spec = spec - [nil, 'ruby', '']
16
+ spec_file_name = "#{spec.join '-'}.gemspec.rz"
17
+
18
+ uri = URI.parse("#{@remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}")
19
+
20
+ spec_rz = (uri.scheme == "file") ? Gem.read_binary(uri.path) : fetch(uri)
21
+ Marshal.load Gem.inflate(spec_rz)
22
+ end
23
+
24
+ # fetch index
25
+ def fetch_remote_specs(gem_names, full_dependency_list = [], last_spec_list = [], &blk)
26
+ return fetch_all_remote_specs(&blk) unless gem_names && @remote_uri.scheme != "file"
27
+
28
+ query_list = gem_names - full_dependency_list
29
+ Bundler.ui.debug "Query List: #{query_list.inspect}"
30
+ return {@remote_uri => last_spec_list}.each(&blk) if query_list.empty?
31
+
32
+ spec_list, deps_list = fetch_dependency_remote_specs(query_list, &blk)
33
+ returned_gems = spec_list.map {|spec| spec.first }.uniq
34
+
35
+ fetch_remote_specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list, &blk)
36
+ # fall back to the legacy index in the following cases
37
+ # 1.) Gemcutter Endpoint doesn't return a 200
38
+ # 2.) Marshal blob doesn't load properly
39
+ rescue HTTPError, TypeError => e
40
+ Bundler.ui.debug "Error #{e.class} from Gemcutter Dependency Endpoint API: #{e.message}"
41
+ Bundler.ui.debug e.backtrace
42
+ fetch_all_remote_specs(&blk)
43
+ end
44
+
45
+ private
46
+
47
+ def fetch(uri, counter = 0)
48
+ raise HTTPError, "Too many redirects" if counter >= REDIRECT_LIMIT
49
+
50
+ Bundler.ui.debug "Fetching from: #{uri}"
51
+ response = @@connection.request(uri)
52
+ case response
53
+ when Net::HTTPRedirection
54
+ Bundler.ui.debug("HTTP Redirection")
55
+ uri = URI.parse(response["location"])
56
+ fetch(uri, counter + 1)
57
+ when Net::HTTPSuccess
58
+ Bundler.ui.debug("HTTP Success")
59
+ response.body
60
+ else
61
+ Bundler.ui.debug("HTTP Error")
62
+ raise HTTPError
63
+ end
64
+ end
65
+
66
+ # fetch from Gemcutter Dependency Endpoint API
67
+ def fetch_dependency_remote_specs(gem_names, &blk)
68
+ Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(' ')}"
69
+ uri = URI.parse("#{@remote_uri}api/v1/dependencies?gems=#{gem_names.join(",")}")
70
+ marshalled_deps = fetch(uri)
71
+ gem_list = Marshal.load(marshalled_deps)
72
+
73
+ spec_list = gem_list.map do |s|
74
+ [s[:name], Gem::Version.new(s[:number]), s[:platform]]
75
+ end
76
+ deps_list = gem_list.map do |s|
77
+ s[:dependencies].collect {|d| d.first }
78
+ end.flatten.uniq
79
+
80
+ [spec_list, deps_list]
81
+ end
82
+
83
+ # fetch from modern index: specs.4.8.gz
84
+ def fetch_all_remote_specs(&blk)
85
+ Bundler.ui.debug "Fetching modern index"
86
+ Gem.sources = ["#{@remote_uri}"]
87
+ begin
88
+ # Fetch all specs, minus prerelease specs
89
+ Gem::SpecFetcher.new.list(true, false).each(&blk)
90
+ # Then fetch the prerelease specs
91
+ begin
92
+ Gem::SpecFetcher.new.list(false, true).each(&blk)
93
+ rescue Gem::RemoteFetcher::FetchError
94
+ Bundler.ui.warn "Could not fetch prerelease specs from #{self}"
95
+ end
96
+ rescue Gem::RemoteFetcher::FetchError
97
+ Bundler.ui.warn "Could not reach #{self}"
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,146 @@
1
+ $:.unshift File.expand_path('../vendor', __FILE__)
2
+ require 'thor'
3
+ require 'bundler'
4
+
5
+ module Bundler
6
+ class GemHelper
7
+ def self.install_tasks(opts = {})
8
+ dir = opts[:dir] || Dir.pwd
9
+ self.new(dir, opts[:name]).install
10
+ end
11
+
12
+ attr_reader :spec_path, :base, :gemspec
13
+
14
+ def initialize(base, name = nil)
15
+ Bundler.ui = UI::Shell.new(Thor::Base.shell.new)
16
+ @base = base
17
+ gemspecs = name ? [File.join(base, "#{name}.gemspec")] : Dir[File.join(base, "*.gemspec")]
18
+ raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1
19
+ @spec_path = gemspecs.first
20
+ @gemspec = Bundler.load_gemspec(@spec_path)
21
+ end
22
+
23
+ def install
24
+ desc "Build #{name}-#{version}.gem into the pkg directory"
25
+ task 'build' do
26
+ build_gem
27
+ end
28
+
29
+ desc "Build and install #{name}-#{version}.gem into system gems"
30
+ task 'install' do
31
+ install_gem
32
+ end
33
+
34
+ desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to Rubygems"
35
+ task 'release' do
36
+ release_gem
37
+ end
38
+ end
39
+
40
+ def build_gem
41
+ file_name = nil
42
+ sh("gem build #{spec_path}") { |out, code|
43
+ raise out unless out[/Successfully/]
44
+ file_name = File.basename(built_gem_path)
45
+ FileUtils.mkdir_p(File.join(base, 'pkg'))
46
+ FileUtils.mv(built_gem_path, 'pkg')
47
+ Bundler.ui.confirm "#{name} #{version} built to pkg/#{file_name}"
48
+ }
49
+ File.join(base, 'pkg', file_name)
50
+ end
51
+
52
+ def install_gem
53
+ built_gem_path = build_gem
54
+ out, _ = sh_with_code("gem install #{built_gem_path}")
55
+ raise "Couldn't install gem, run `gem install #{built_gem_path}' for more detailed output" unless out[/Successfully installed/]
56
+ Bundler.ui.confirm "#{name} (#{version}) installed"
57
+ end
58
+
59
+ def release_gem
60
+ guard_clean
61
+ guard_already_tagged
62
+ built_gem_path = build_gem
63
+ tag_version {
64
+ git_push
65
+ rubygem_push(built_gem_path)
66
+ }
67
+ end
68
+
69
+ protected
70
+ def rubygem_push(path)
71
+ out, _ = sh("gem push #{path}")
72
+ raise "Gem push failed due to lack of RubyGems.org credentials." if out[/Enter your RubyGems.org credentials/]
73
+ Bundler.ui.confirm "Pushed #{name} #{version} to rubygems.org"
74
+ end
75
+
76
+ def built_gem_path
77
+ Dir[File.join(base, "#{name}-*.gem")].sort_by{|f| File.mtime(f)}.last
78
+ end
79
+
80
+ def git_push
81
+ perform_git_push
82
+ perform_git_push ' --tags'
83
+ Bundler.ui.confirm "Pushed git commits and tags"
84
+ end
85
+
86
+ def perform_git_push(options = '')
87
+ cmd = "git push #{options}"
88
+ out, code = sh_with_code(cmd)
89
+ raise "Couldn't git push. `#{cmd}' failed with the following output:\n\n#{out}\n" unless code == 0
90
+ end
91
+
92
+ def guard_already_tagged
93
+ if sh('git tag').split(/\n/).include?(version_tag)
94
+ raise("This tag has already been committed to the repo.")
95
+ end
96
+ end
97
+
98
+ def guard_clean
99
+ clean? or raise("There are files that need to be committed first.")
100
+ end
101
+
102
+ def clean?
103
+ sh_with_code("git diff --exit-code")[1] == 0
104
+ end
105
+
106
+ def tag_version
107
+ sh "git tag -a -m \"Version #{version}\" #{version_tag}"
108
+ Bundler.ui.confirm "Tagged #{version_tag}"
109
+ yield if block_given?
110
+ rescue
111
+ Bundler.ui.error "Untagged #{version_tag} due to error"
112
+ sh_with_code "git tag -d #{version_tag}"
113
+ raise
114
+ end
115
+
116
+ def version
117
+ gemspec.version
118
+ end
119
+
120
+ def version_tag
121
+ "v#{version}"
122
+ end
123
+
124
+ def name
125
+ gemspec.name
126
+ end
127
+
128
+ def sh(cmd, &block)
129
+ out, code = sh_with_code(cmd, &block)
130
+ code == 0 ? out : raise(out.empty? ? "Running `#{cmd}' failed. Run this command directly for more detailed output." : out)
131
+ end
132
+
133
+ def sh_with_code(cmd, &block)
134
+ cmd << " 2>&1"
135
+ outbuf = ''
136
+ Bundler.ui.debug(cmd)
137
+ Dir.chdir(base) {
138
+ outbuf = `#{cmd}`
139
+ if $? == 0
140
+ block.call(outbuf) if block
141
+ end
142
+ }
143
+ [outbuf, $?]
144
+ end
145
+ end
146
+ end