rubygems-update 2.0.17 → 2.1.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -0
  4. data/.autotest +1 -1
  5. data/History.txt +82 -153
  6. data/Manifest.txt +35 -9
  7. data/Rakefile +35 -36
  8. data/lib/rubygems.rb +106 -18
  9. data/lib/rubygems/available_set.rb +68 -0
  10. data/lib/rubygems/basic_specification.rb +139 -0
  11. data/lib/rubygems/command_manager.rb +37 -40
  12. data/lib/rubygems/commands/cert_command.rb +78 -29
  13. data/lib/rubygems/commands/cleanup_command.rb +2 -2
  14. data/lib/rubygems/commands/contents_command.rb +101 -58
  15. data/lib/rubygems/commands/dependency_command.rb +94 -53
  16. data/lib/rubygems/commands/environment_command.rb +70 -53
  17. data/lib/rubygems/commands/fetch_command.rb +1 -2
  18. data/lib/rubygems/commands/help_command.rb +85 -55
  19. data/lib/rubygems/commands/install_command.rb +84 -42
  20. data/lib/rubygems/commands/outdated_command.rb +2 -12
  21. data/lib/rubygems/commands/owner_command.rb +6 -0
  22. data/lib/rubygems/commands/pristine_command.rb +26 -16
  23. data/lib/rubygems/commands/sources_command.rb +85 -70
  24. data/lib/rubygems/commands/uninstall_command.rb +32 -2
  25. data/lib/rubygems/commands/update_command.rb +111 -75
  26. data/lib/rubygems/config_file.rb +15 -3
  27. data/lib/rubygems/core_ext/kernel_require.rb +9 -31
  28. data/lib/rubygems/defaults.rb +8 -0
  29. data/lib/rubygems/dependency.rb +4 -2
  30. data/lib/rubygems/dependency_installer.rb +180 -170
  31. data/lib/rubygems/dependency_resolver.rb +191 -526
  32. data/lib/rubygems/dependency_resolver/activation_request.rb +109 -0
  33. data/lib/rubygems/dependency_resolver/api_set.rb +65 -0
  34. data/lib/rubygems/dependency_resolver/api_specification.rb +36 -0
  35. data/lib/rubygems/dependency_resolver/composed_set.rb +18 -0
  36. data/lib/rubygems/dependency_resolver/current_set.rb +16 -0
  37. data/lib/rubygems/dependency_resolver/dependency_conflict.rb +85 -0
  38. data/lib/rubygems/dependency_resolver/dependency_request.rb +51 -0
  39. data/lib/rubygems/dependency_resolver/index_set.rb +59 -0
  40. data/lib/rubygems/dependency_resolver/index_specification.rb +53 -0
  41. data/lib/rubygems/dependency_resolver/installed_specification.rb +38 -0
  42. data/lib/rubygems/dependency_resolver/installer_set.rb +130 -0
  43. data/lib/rubygems/exceptions.rb +88 -1
  44. data/lib/rubygems/ext/builder.rb +1 -1
  45. data/lib/rubygems/gem_runner.rb +17 -9
  46. data/lib/rubygems/gemcutter_utilities.rb +72 -42
  47. data/lib/rubygems/install_default_message.rb +12 -0
  48. data/lib/rubygems/install_update_options.rb +3 -0
  49. data/lib/rubygems/installer.rb +55 -30
  50. data/lib/rubygems/name_tuple.rb +18 -7
  51. data/lib/rubygems/package.rb +50 -25
  52. data/lib/rubygems/package/tar_test_case.rb +9 -9
  53. data/lib/rubygems/package/tar_writer.rb +35 -12
  54. data/lib/rubygems/package_task.rb +2 -5
  55. data/lib/rubygems/path_support.rb +10 -0
  56. data/lib/rubygems/platform.rb +9 -3
  57. data/lib/rubygems/psych_additions.rb +1 -1
  58. data/lib/rubygems/remote_fetcher.rb +9 -276
  59. data/lib/rubygems/request.rb +267 -0
  60. data/lib/rubygems/request_set.rb +123 -125
  61. data/lib/rubygems/request_set/gem_dependency_api.rb +39 -0
  62. data/lib/rubygems/security.rb +32 -23
  63. data/lib/rubygems/security/policy.rb +35 -9
  64. data/lib/rubygems/security/signer.rb +2 -2
  65. data/lib/rubygems/server.rb +8 -16
  66. data/lib/rubygems/source.rb +25 -14
  67. data/lib/rubygems/source/installed.rb +28 -0
  68. data/lib/rubygems/source/local.rb +122 -0
  69. data/lib/rubygems/source/specific_file.rb +28 -0
  70. data/lib/rubygems/source_local.rb +2 -89
  71. data/lib/rubygems/source_specific_file.rb +2 -26
  72. data/lib/rubygems/spec_fetcher.rb +11 -11
  73. data/lib/rubygems/specification.rb +186 -198
  74. data/lib/rubygems/ssl_certs/AddTrustExternalCARoot.pem +88 -30
  75. data/lib/rubygems/ssl_certs/Entrust_net-Secure-Server-Certification-Authority.pem +90 -0
  76. data/lib/rubygems/ssl_certs/{GeoTrustGlobalCA.pem → GeoTrust_Global_CA.pem} +20 -20
  77. data/lib/rubygems/ssl_certs/VerisignClass3PublicPrimaryCertificationAuthority-G2.pem +57 -0
  78. data/lib/rubygems/stub_specification.rb +119 -0
  79. data/lib/rubygems/test_case.rb +117 -49
  80. data/lib/rubygems/uninstaller.rb +14 -9
  81. data/lib/rubygems/uri_formatter.rb +39 -0
  82. data/lib/rubygems/util/list.rb +44 -0
  83. data/lib/rubygems/version.rb +15 -5
  84. data/lib/rubygems/version_option.rb +8 -2
  85. data/test/rubygems/ca_cert.pem +23 -0
  86. data/test/rubygems/client.pem +49 -0
  87. data/test/rubygems/encrypted_private_key.pem +30 -0
  88. data/test/rubygems/invalid_client.pem +49 -0
  89. data/test/rubygems/specifications/bar-0.0.2.gemspec +9 -0
  90. data/test/rubygems/specifications/foo-0.0.1.gemspec +0 -0
  91. data/test/rubygems/test_gem.rb +76 -454
  92. data/test/rubygems/test_gem_command_manager.rb +23 -21
  93. data/test/rubygems/test_gem_commands_cert_command.rb +154 -14
  94. data/test/rubygems/test_gem_commands_cleanup_command.rb +15 -0
  95. data/test/rubygems/test_gem_commands_contents_command.rb +32 -4
  96. data/test/rubygems/test_gem_commands_environment_command.rb +9 -1
  97. data/test/rubygems/test_gem_commands_fetch_command.rb +2 -28
  98. data/test/rubygems/test_gem_commands_help_command.rb +6 -3
  99. data/test/rubygems/test_gem_commands_install_command.rb +2 -65
  100. data/test/rubygems/test_gem_commands_owner_command.rb +49 -0
  101. data/test/rubygems/test_gem_commands_pristine_command.rb +30 -0
  102. data/test/rubygems/test_gem_commands_sources_command.rb +1 -1
  103. data/test/rubygems/test_gem_commands_uninstall_command.rb +33 -0
  104. data/test/rubygems/test_gem_commands_update_command.rb +2 -1
  105. data/test/rubygems/test_gem_config_file.rb +12 -0
  106. data/test/rubygems/test_gem_dependency_installer.rb +58 -65
  107. data/test/rubygems/test_gem_dependency_resolver.rb +6 -3
  108. data/test/rubygems/test_gem_dependency_resolver_dependency_conflict.rb +36 -0
  109. data/test/rubygems/test_gem_ext_builder.rb +2 -4
  110. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +7 -2
  111. data/test/rubygems/test_gem_gem_runner.rb +17 -13
  112. data/test/rubygems/test_gem_gemcutter_utilities.rb +6 -19
  113. data/test/rubygems/test_gem_impossible_dependencies_error.rb +41 -0
  114. data/test/rubygems/test_gem_install_update_options.rb +4 -1
  115. data/test/rubygems/test_gem_installer.rb +31 -2
  116. data/test/rubygems/test_gem_name_tuple.rb +22 -0
  117. data/test/rubygems/test_gem_package.rb +122 -11
  118. data/test/rubygems/test_gem_package_old.rb +8 -0
  119. data/test/rubygems/test_gem_package_tar_reader.rb +9 -8
  120. data/test/rubygems/test_gem_package_tar_reader_entry.rb +1 -1
  121. data/test/rubygems/test_gem_package_tar_writer.rb +78 -56
  122. data/test/rubygems/test_gem_package_task.rb +2 -23
  123. data/test/rubygems/test_gem_path_support.rb +17 -0
  124. data/test/rubygems/test_gem_platform.rb +18 -0
  125. data/test/rubygems/test_gem_remote_fetcher.rb +106 -385
  126. data/test/rubygems/test_gem_request.rb +239 -0
  127. data/test/rubygems/test_gem_requirement.rb +9 -11
  128. data/test/rubygems/test_gem_security.rb +58 -2
  129. data/test/rubygems/test_gem_security_policy.rb +42 -1
  130. data/test/rubygems/test_gem_security_signer.rb +13 -1
  131. data/test/rubygems/test_gem_security_trust_dir.rb +5 -1
  132. data/test/rubygems/test_gem_server.rb +1 -105
  133. data/test/rubygems/test_gem_source.rb +4 -14
  134. data/test/rubygems/test_gem_source_local.rb +4 -4
  135. data/test/rubygems/test_gem_source_specific_file.rb +1 -1
  136. data/test/rubygems/test_gem_spec_fetcher.rb +0 -12
  137. data/test/rubygems/test_gem_specification.rb +452 -28
  138. data/test/rubygems/test_gem_stub_specification.rb +30 -0
  139. data/test/rubygems/test_gem_uninstaller.rb +14 -0
  140. data/test/rubygems/test_gem_uri_formatter.rb +20 -0
  141. data/test/rubygems/test_gem_version.rb +23 -13
  142. data/test/rubygems/test_gem_version_option.rb +63 -1
  143. data/test/rubygems/test_require.rb +0 -12
  144. data/util/create_encrypted_key.rb +16 -0
  145. metadata +161 -23
  146. metadata.gz.sig +0 -0
  147. data/CVE-2013-4287.txt +0 -36
  148. data/CVE-2013-4363.txt +0 -45
  149. data/lib/rubygems/ssl_certs/AddTrustExternalCARoot-2048.pem +0 -25
  150. data/lib/rubygems/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +0 -14
  151. data/lib/rubygems/ssl_certs/DigiCertHighAssuranceEVRootCA.pem +0 -23
  152. data/lib/rubygems/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +0 -28
  153. data/test/rubygems/test_bundled_ca.rb +0 -59
  154. data/util/update_bundled_ca_certificates.rb +0 -103
@@ -0,0 +1,53 @@
1
+ ##
2
+ # Represents a possible Specification object returned
3
+ # from IndexSet. Used to delay needed to download full
4
+ # Specification objects when only the +name+ and +version+
5
+ # are needed.
6
+
7
+ class Gem::DependencyResolver::IndexSpecification
8
+
9
+ attr_reader :name
10
+
11
+ attr_reader :source
12
+
13
+ attr_reader :version
14
+
15
+ def initialize set, name, version, source, plat
16
+ @set = set
17
+ @name = name
18
+ @version = version
19
+ @source = source
20
+ @platform = plat
21
+
22
+ @spec = nil
23
+ end
24
+
25
+ def dependencies
26
+ spec.dependencies
27
+ end
28
+
29
+ def full_name
30
+ "#{@name}-#{@version}"
31
+ end
32
+
33
+ def inspect # :nodoc:
34
+ '#<%s %s source %s>' % [self.class, full_name, @source]
35
+ end
36
+
37
+ def pretty_print q # :nodoc:
38
+ q.group 2, '[Index specification', ']' do
39
+ q.breakable
40
+ q.text full_name
41
+
42
+ q.breakable
43
+ q.text ' source '
44
+ q.pp @source
45
+ end
46
+ end
47
+
48
+ def spec
49
+ @spec ||= @set.load_spec(@name, @version, @source)
50
+ end
51
+
52
+ end
53
+
@@ -0,0 +1,38 @@
1
+ class Gem::DependencyResolver::InstalledSpecification
2
+
3
+ attr_reader :spec
4
+
5
+ def initialize set, spec, source=nil
6
+ @set = set
7
+ @source = source
8
+ @spec = spec
9
+ end
10
+
11
+ def == other # :nodoc:
12
+ self.class === other and
13
+ @set == other.set and
14
+ @spec == other.spec
15
+ end
16
+
17
+ def dependencies
18
+ @spec.dependencies
19
+ end
20
+
21
+ def full_name
22
+ "#{@spec.name}-#{@spec.version}"
23
+ end
24
+
25
+ def name
26
+ @spec.name
27
+ end
28
+
29
+ def source
30
+ @source ||= Gem::Source::Installed.new
31
+ end
32
+
33
+ def version
34
+ @spec.version
35
+ end
36
+
37
+ end
38
+
@@ -0,0 +1,130 @@
1
+ class Gem::DependencyResolver::InstallerSet
2
+
3
+ ##
4
+ # List of Gem::Specification objects that must always be installed.
5
+
6
+ attr_reader :always_install
7
+
8
+ ##
9
+ # Only install gems in the always_install list
10
+
11
+ attr_accessor :ignore_dependencies
12
+
13
+ ##
14
+ # Do not look in the installed set when finding specifications. This is
15
+ # used by the --install-dir option to `gem install`
16
+
17
+ attr_accessor :ignore_installed
18
+
19
+ def initialize domain
20
+ @domain = domain
21
+
22
+ @f = Gem::SpecFetcher.fetcher
23
+
24
+ @all = Hash.new { |h,k| h[k] = [] }
25
+ @always_install = []
26
+ @ignore_dependencies = false
27
+ @ignore_installed = false
28
+ @loaded_remote_specs = []
29
+ @specs = {}
30
+ end
31
+
32
+ ##
33
+ # Should local gems should be considered?
34
+
35
+ def consider_local?
36
+ @domain == :both or @domain == :local
37
+ end
38
+
39
+ ##
40
+ # Should remote gems should be considered?
41
+
42
+ def consider_remote?
43
+ @domain == :both or @domain == :remote
44
+ end
45
+
46
+ ##
47
+ # Returns an array of IndexSpecification objects matching DependencyRequest
48
+ # +req+.
49
+
50
+ def find_all req
51
+ res = []
52
+
53
+ dep = req.dependency
54
+
55
+ return res if @ignore_dependencies and
56
+ @always_install.none? { |spec| dep.matches_spec? spec }
57
+
58
+ name = dep.name
59
+
60
+ dep.matching_specs.each do |gemspec|
61
+ next if @always_install.include? gemspec
62
+
63
+ res << Gem::DependencyResolver::InstalledSpecification.new(self, gemspec)
64
+ end unless @ignore_installed
65
+
66
+ if consider_local? then
67
+ local_source = Gem::Source::Local.new
68
+
69
+ if spec = local_source.find_gem(name, dep.requirement) then
70
+ res << Gem::DependencyResolver::IndexSpecification.new(
71
+ self, spec.name, spec.version, local_source, spec.platform)
72
+ end
73
+ end
74
+
75
+ if consider_remote? then
76
+ load_remote_specs dep
77
+
78
+ @all[name].each do |remote_source, n|
79
+ if dep.match? n then
80
+ res << Gem::DependencyResolver::IndexSpecification.new(
81
+ self, n.name, n.version, remote_source, n.platform)
82
+ end
83
+ end
84
+ end
85
+
86
+ res
87
+ end
88
+
89
+ def inspect # :nodoc:
90
+ '#<%s domain: %s specs: %p>' % [ self.class, @domain, @specs.keys ]
91
+ end
92
+
93
+ ##
94
+ # Loads remote prerelease specs if +dep+ is a prerelease dependency
95
+
96
+ def load_remote_specs dep
97
+ types = [:released]
98
+ types << :prerelease if dep.prerelease?
99
+
100
+ types.each do |type|
101
+ next if @loaded_remote_specs.include? type
102
+ @loaded_remote_specs << type
103
+
104
+ list, = @f.available_specs type
105
+
106
+ list.each do |uri, specs|
107
+ specs.each do |n|
108
+ @all[n.name] << [uri, n]
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ ##
115
+ # Called from IndexSpecification to get a true Specification
116
+ # object.
117
+
118
+ def load_spec name, ver, source
119
+ key = "#{name}-#{ver}"
120
+ @specs[key] ||= source.fetch_spec Gem::NameTuple.new name, ver
121
+ end
122
+
123
+ ##
124
+ # No prefetching needed since we load the whole index in initially.
125
+
126
+ def prefetch(reqs)
127
+ end
128
+
129
+ end
130
+
@@ -7,7 +7,13 @@
7
7
  # Base exception class for RubyGems. All exception raised by RubyGems are a
8
8
  # subclass of this one.
9
9
  class Gem::Exception < RuntimeError
10
- attr_accessor :source_exception
10
+
11
+ ##
12
+ #--
13
+ # TODO: remove in RubyGems 3, nobody sets this
14
+
15
+ attr_accessor :source_exception # :nodoc:
16
+
11
17
  end
12
18
 
13
19
  class Gem::CommandLineError < Gem::Exception; end
@@ -16,6 +22,28 @@ class Gem::DependencyError < Gem::Exception; end
16
22
 
17
23
  class Gem::DependencyRemovalException < Gem::Exception; end
18
24
 
25
+ ##
26
+ # Raised by Gem::DependencyResolver when a Gem::DependencyConflict reaches the
27
+ # toplevel. Indicates which dependencies were incompatible through #conflict
28
+ # and #conflicting_dependencies
29
+
30
+ class Gem::DependencyResolutionError < Gem::Exception
31
+
32
+ attr_reader :conflict
33
+
34
+ def initialize conflict
35
+ @conflict = conflict
36
+ a, b = conflicting_dependencies
37
+
38
+ super "unable to resolve conflicting dependencies '#{a}' and '#{b}'"
39
+ end
40
+
41
+ def conflicting_dependencies
42
+ @conflict.conflicting_dependencies
43
+ end
44
+
45
+ end
46
+
19
47
  ##
20
48
  # Raised when attempting to uninstall a gem that isn't in GEM_HOME.
21
49
 
@@ -65,6 +93,42 @@ class Gem::SpecificGemNotFoundException < Gem::GemNotFoundException
65
93
  attr_reader :name, :version, :errors
66
94
  end
67
95
 
96
+ ##
97
+ # Raised by Gem::DependencyResolver when dependencies conflict and create the
98
+ # inability to find a valid possible spec for a request.
99
+
100
+ class Gem::ImpossibleDependenciesError < Gem::Exception
101
+
102
+ attr_reader :conflicts
103
+ attr_reader :request
104
+
105
+ def initialize request, conflicts
106
+ @request = request
107
+ @conflicts = conflicts
108
+
109
+ super build_message
110
+ end
111
+
112
+ def build_message # :nodoc:
113
+ requester = @request.requester
114
+ requester = requester ? requester.spec.full_name : 'The user'
115
+ dependency = @request.dependency
116
+
117
+ message = "#{requester} requires #{dependency} but it conflicted:\n"
118
+
119
+ @conflicts.each do |_, conflict|
120
+ message << conflict.explanation
121
+ end
122
+
123
+ message
124
+ end
125
+
126
+ def dependency
127
+ @request.dependency
128
+ end
129
+
130
+ end
131
+
68
132
  class Gem::InstallError < Gem::Exception; end
69
133
 
70
134
  ##
@@ -107,3 +171,26 @@ class Gem::SystemExitException < SystemExit
107
171
 
108
172
  end
109
173
 
174
+ ##
175
+ # Raised by DependencyResolver when a dependency requests a gem for which
176
+ # there is no spec.
177
+
178
+ class Gem::UnsatisfiableDependencyError < Gem::Exception
179
+
180
+ attr_reader :dependency
181
+
182
+ def initialize dep
183
+ requester = dep.requester ? dep.requester.request : '(unknown)'
184
+
185
+ super "Unable to resolve dependency: #{requester} requires #{dep}"
186
+
187
+ @dependency = dep
188
+ end
189
+
190
+ end
191
+
192
+ ##
193
+ # Backwards compatible typo'd exception class for early RubyGems 2.0.x
194
+
195
+ Gem::UnsatisfiableDepedencyError = Gem::UnsatisfiableDependencyError # :nodoc:
196
+
@@ -18,7 +18,7 @@ class Gem::Ext::Builder
18
18
 
19
19
  # try to find make program from Ruby configure arguments first
20
20
  RbConfig::CONFIG['configure_args'] =~ /with-make-prog\=(\w+)/
21
- make_program = $1 || ENV['MAKE'] || ENV['make']
21
+ make_program = ENV['MAKE'] || ENV['make'] || $1
22
22
  unless make_program then
23
23
  make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
24
24
  end
@@ -33,17 +33,11 @@ class Gem::GemRunner
33
33
  ##
34
34
  # Run the gem command with the following arguments.
35
35
 
36
- def run(args)
37
- if args.include?('--')
38
- # We need to preserve the original ARGV to use for passing gem options
39
- # to source gems. If there is a -- in the line, strip all options after
40
- # it...its for the source building process.
41
- # TODO use slice!
42
- build_args = args[args.index("--") + 1...args.length]
43
- args = args[0...args.index("--")]
44
- end
36
+ def run args
37
+ build_args = extract_build_args args
45
38
 
46
39
  do_configuration args
40
+
47
41
  cmd = @command_manager_class.instance
48
42
 
49
43
  cmd.command_names.each do |command_name|
@@ -60,6 +54,20 @@ class Gem::GemRunner
60
54
  cmd.run Gem.configuration.args, build_args
61
55
  end
62
56
 
57
+ ##
58
+ # Separates the build arguments (those following <code>--</code>) from the
59
+ # other arguments in the list.
60
+
61
+ def extract_build_args args # :nodoc:
62
+ return [] unless offset = args.index('--')
63
+
64
+ build_args = args.slice!(offset...args.length)
65
+
66
+ build_args.shift
67
+
68
+ build_args
69
+ end
70
+
63
71
  private
64
72
 
65
73
  def do_configuration(args)
@@ -1,11 +1,17 @@
1
1
  require 'rubygems/remote_fetcher'
2
2
 
3
+ ##
4
+ # Utility methods for using the RubyGems API.
5
+
3
6
  module Gem::GemcutterUtilities
7
+
4
8
  # TODO: move to Gem::Command
5
9
  OptionParser.accept Symbol do |value|
6
10
  value.to_sym
7
11
  end
8
12
 
13
+ attr_writer :host
14
+
9
15
  ##
10
16
  # Add the --key option
11
17
 
@@ -17,6 +23,9 @@ module Gem::GemcutterUtilities
17
23
  end
18
24
  end
19
25
 
26
+ ##
27
+ # The API key from the command options or from the user's configuration.
28
+
20
29
  def api_key
21
30
  if options[:key] then
22
31
  verify_api_key options[:key]
@@ -27,36 +36,10 @@ module Gem::GemcutterUtilities
27
36
  end
28
37
  end
29
38
 
30
- def sign_in sign_in_host = nil
31
- sign_in_host ||= self.host
32
- return if Gem.configuration.rubygems_api_key
33
-
34
- pretty_host = if Gem::DEFAULT_HOST == sign_in_host then
35
- 'RubyGems.org'
36
- else
37
- sign_in_host
38
- end
39
-
40
- say "Enter your #{pretty_host} credentials."
41
- say "Don't have an account yet? " +
42
- "Create one at #{sign_in_host}/sign_up"
43
-
44
- email = ask " Email: "
45
- password = ask_for_password "Password: "
46
- say "\n"
47
-
48
- response = rubygems_api_request(:get, "api/v1/api_key",
49
- sign_in_host) do |request|
50
- request.basic_auth email, password
51
- end
52
-
53
- with_response response do |resp|
54
- say "Signed in."
55
- Gem.configuration.rubygems_api_key = resp.body
56
- end
57
- end
39
+ ##
40
+ # The host to connect to either from the RUBYGEMS_HOST environment variable
41
+ # or from the user's configuration
58
42
 
59
- attr_writer :host
60
43
  def host
61
44
  configured_host = Gem.host unless
62
45
  Gem.configuration.disable_default_gem_server
@@ -71,6 +54,9 @@ module Gem::GemcutterUtilities
71
54
  end
72
55
  end
73
56
 
57
+ ##
58
+ # Creates an RubyGems API to +host+ and +path+ with the given HTTP +method+.
59
+
74
60
  def rubygems_api_request(method, path, host = nil, &block)
75
61
  require 'net/http'
76
62
 
@@ -87,23 +73,42 @@ module Gem::GemcutterUtilities
87
73
  Gem::RemoteFetcher.fetcher.request(uri, request_method, &block)
88
74
  end
89
75
 
90
- def with_response resp, error_prefix = nil
91
- case resp
92
- when Net::HTTPSuccess then
93
- if block_given? then
94
- yield resp
95
- else
96
- say resp.body
97
- end
98
- else
99
- message = resp.body
100
- message = "#{error_prefix}: #{message}" if error_prefix
76
+ ##
77
+ # Signs in with the RubyGems API at +sign_in_host+ and sets the rubygems API
78
+ # key.
101
79
 
102
- say message
103
- terminate_interaction 1 # TODO: question this
80
+ def sign_in sign_in_host = self.host
81
+ return if Gem.configuration.rubygems_api_key
82
+
83
+ pretty_host = if Gem::DEFAULT_HOST == sign_in_host then
84
+ 'RubyGems.org'
85
+ else
86
+ sign_in_host
87
+ end
88
+
89
+ say "Enter your #{pretty_host} credentials."
90
+ say "Don't have an account yet? " +
91
+ "Create one at #{sign_in_host}/sign_up"
92
+
93
+ email = ask " Email: "
94
+ password = ask_for_password "Password: "
95
+ say "\n"
96
+
97
+ response = rubygems_api_request(:get, "api/v1/api_key",
98
+ sign_in_host) do |request|
99
+ request.basic_auth email, password
100
+ end
101
+
102
+ with_response response do |resp|
103
+ say "Signed in."
104
+ Gem.configuration.rubygems_api_key = resp.body
104
105
  end
105
106
  end
106
107
 
108
+ ##
109
+ # Retrieves the pre-configured API key +key+ or terminates interaction with
110
+ # an error.
111
+
107
112
  def verify_api_key(key)
108
113
  if Gem.configuration.api_keys.key? key then
109
114
  Gem.configuration.api_keys[key]
@@ -113,4 +118,29 @@ module Gem::GemcutterUtilities
113
118
  end
114
119
  end
115
120
 
121
+ ##
122
+ # If +response+ is an HTTP Success (2XX) response, yields the response if a
123
+ # block was given or shows the response body to the user.
124
+ #
125
+ # If the response was not successful, shows an error to the user including
126
+ # the +error_prefix+ and the response body.
127
+
128
+ def with_response response, error_prefix = nil
129
+ case response
130
+ when Net::HTTPSuccess then
131
+ if block_given? then
132
+ yield response
133
+ else
134
+ say response.body
135
+ end
136
+ else
137
+ message = response.body
138
+ message = "#{error_prefix}: #{message}" if error_prefix
139
+
140
+ say message
141
+ terminate_interaction 1 # TODO: question this
142
+ end
143
+ end
144
+
116
145
  end
146
+