bundler 4.0.21 → 4.1.0.beta1

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 (190) hide show
  1. checksums.yaml +4 -4
  2. data/{lib/bundler/vendor/connection_pool/LICENSE → MIT.txt} +8 -6
  3. data/bundler.gemspec +23 -6
  4. data/lib/bundler/build_metadata.rb +2 -2
  5. data/lib/bundler/checksum.rb +40 -25
  6. data/lib/bundler/ci_detector.rb +1 -1
  7. data/lib/bundler/cli/add.rb +3 -4
  8. data/lib/bundler/cli/cache.rb +4 -0
  9. data/lib/bundler/cli/clean.rb +5 -0
  10. data/lib/bundler/cli/common.rb +37 -1
  11. data/lib/bundler/cli/config.rb +4 -2
  12. data/lib/bundler/cli/gem.rb +0 -17
  13. data/lib/bundler/cli/install.rb +4 -5
  14. data/lib/bundler/cli/lock.rb +1 -2
  15. data/lib/bundler/cli/outdated.rb +8 -3
  16. data/lib/bundler/cli/pristine.rb +2 -1
  17. data/lib/bundler/cli/update.rb +21 -12
  18. data/lib/bundler/cli.rb +14 -11
  19. data/lib/bundler/definition.rb +61 -24
  20. data/lib/bundler/dependency.rb +4 -0
  21. data/lib/bundler/dsl.rb +77 -11
  22. data/lib/bundler/endpoint_specification.rb +51 -14
  23. data/lib/bundler/env.rb +7 -24
  24. data/lib/bundler/errors.rb +34 -5
  25. data/lib/bundler/fetcher/compact_index.rb +14 -5
  26. data/lib/bundler/fetcher/connection_pools.rb +150 -0
  27. data/lib/bundler/fetcher/downloader.rb +31 -16
  28. data/lib/bundler/fetcher.rb +8 -47
  29. data/lib/bundler/injector.rb +3 -3
  30. data/lib/bundler/inline.rb +44 -4
  31. data/lib/bundler/installer/parallel_installer.rb +25 -30
  32. data/lib/bundler/installer.rb +20 -6
  33. data/lib/bundler/lazy_specification.rb +44 -17
  34. data/lib/bundler/lockfile_generator.rb +24 -2
  35. data/lib/bundler/lockfile_parser.rb +43 -5
  36. data/lib/bundler/man/bundle-add.1 +7 -4
  37. data/lib/bundler/man/bundle-add.1.ronn +8 -4
  38. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  39. data/lib/bundler/man/bundle-cache.1 +2 -2
  40. data/lib/bundler/man/bundle-cache.1.ronn +2 -2
  41. data/lib/bundler/man/bundle-check.1 +1 -1
  42. data/lib/bundler/man/bundle-clean.1 +1 -1
  43. data/lib/bundler/man/bundle-config.1 +38 -6
  44. data/lib/bundler/man/bundle-config.1.ronn +143 -10
  45. data/lib/bundler/man/bundle-console.1 +1 -1
  46. data/lib/bundler/man/bundle-doctor.1 +1 -1
  47. data/lib/bundler/man/bundle-env.1 +1 -1
  48. data/lib/bundler/man/bundle-exec.1 +1 -1
  49. data/lib/bundler/man/bundle-fund.1 +1 -1
  50. data/lib/bundler/man/bundle-gem.1 +1 -1
  51. data/lib/bundler/man/bundle-help.1 +1 -1
  52. data/lib/bundler/man/bundle-info.1 +1 -1
  53. data/lib/bundler/man/bundle-init.1 +1 -1
  54. data/lib/bundler/man/bundle-install.1 +2 -2
  55. data/lib/bundler/man/bundle-install.1.ronn +4 -4
  56. data/lib/bundler/man/bundle-issue.1 +1 -1
  57. data/lib/bundler/man/bundle-licenses.1 +1 -1
  58. data/lib/bundler/man/bundle-list.1 +1 -1
  59. data/lib/bundler/man/bundle-lock.1 +3 -3
  60. data/lib/bundler/man/bundle-lock.1.ronn +5 -5
  61. data/lib/bundler/man/bundle-open.1 +1 -1
  62. data/lib/bundler/man/bundle-outdated.1 +1 -1
  63. data/lib/bundler/man/bundle-platform.1 +1 -1
  64. data/lib/bundler/man/bundle-plugin.1 +1 -1
  65. data/lib/bundler/man/bundle-pristine.1 +1 -1
  66. data/lib/bundler/man/bundle-remove.1 +1 -1
  67. data/lib/bundler/man/bundle-show.1 +1 -1
  68. data/lib/bundler/man/bundle-update.1 +3 -3
  69. data/lib/bundler/man/bundle-update.1.ronn +3 -5
  70. data/lib/bundler/man/bundle-version.1 +1 -1
  71. data/lib/bundler/man/bundle.1 +1 -1
  72. data/lib/bundler/man/gemfile.5 +45 -1
  73. data/lib/bundler/man/gemfile.5.ronn +53 -0
  74. data/lib/bundler/match_metadata.rb +20 -0
  75. data/lib/bundler/match_platform.rb +25 -2
  76. data/lib/bundler/match_remote_metadata.rb +21 -6
  77. data/lib/bundler/materialization.rb +2 -1
  78. data/lib/bundler/override.rb +69 -0
  79. data/lib/bundler/plugin/dsl.rb +3 -5
  80. data/lib/bundler/plugin/events.rb +55 -13
  81. data/lib/bundler/plugin/index.rb +87 -11
  82. data/lib/bundler/plugin/installer/path.rb +1 -1
  83. data/lib/bundler/plugin/installer.rb +13 -5
  84. data/lib/bundler/plugin.rb +58 -30
  85. data/lib/bundler/remote_specification.rb +6 -3
  86. data/lib/bundler/resolver/base.rb +2 -1
  87. data/lib/bundler/resolver/incompatibility.rb +1 -1
  88. data/lib/bundler/resolver.rb +73 -23
  89. data/lib/bundler/ruby_version.rb +0 -2
  90. data/lib/bundler/rubygems_ext.rb +71 -1
  91. data/lib/bundler/rubygems_gem_installer.rb +41 -2
  92. data/lib/bundler/rubygems_integration.rb +7 -2
  93. data/lib/bundler/runtime.rb +69 -2
  94. data/lib/bundler/self_manager.rb +9 -15
  95. data/lib/bundler/settings.rb +373 -30
  96. data/lib/bundler/shared_helpers.rb +2 -1
  97. data/lib/bundler/source/git/git_proxy.rb +2 -10
  98. data/lib/bundler/source/git.rb +15 -6
  99. data/lib/bundler/source/path/installer.rb +1 -1
  100. data/lib/bundler/source/rubygems/remote.rb +10 -5
  101. data/lib/bundler/source/rubygems.rb +48 -12
  102. data/lib/bundler/spec_set.rb +16 -4
  103. data/lib/bundler/stub_specification.rb +2 -1
  104. data/lib/bundler/templates/newgem/Gemfile.tt +4 -4
  105. data/lib/bundler/templates/newgem/newgem.gemspec.tt +3 -3
  106. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +1 -1
  107. data/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt +1 -1
  108. data/lib/bundler/ui/shell.rb +0 -4
  109. data/lib/bundler/ui/silent.rb +0 -4
  110. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +35 -2
  111. data/lib/bundler/vendor/thor/lib/thor/base.rb +2 -1
  112. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +14 -6
  113. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +2 -0
  114. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  115. data/lib/bundler/vendor/thor/lib/thor.rb +34 -1
  116. data/lib/bundler/vendored_pub_grub.rb +5 -2
  117. data/lib/bundler/vendored_securerandom.rb +11 -8
  118. data/lib/bundler/vendored_uri.rb +14 -14
  119. data/lib/bundler/version.rb +1 -1
  120. data/lib/bundler/worker.rb +3 -2
  121. data/lib/bundler.rb +1 -1
  122. data/lib/rubygems/compact_index_client/cache.rb +122 -0
  123. data/lib/rubygems/compact_index_client/cache_file.rb +147 -0
  124. data/lib/rubygems/compact_index_client/http_fetcher.rb +88 -0
  125. data/lib/rubygems/compact_index_client/parser.rb +90 -0
  126. data/lib/rubygems/compact_index_client/updater.rb +113 -0
  127. data/lib/rubygems/compact_index_client.rb +111 -0
  128. data/lib/rubygems/cooldown_settings.rb +57 -0
  129. data/lib/rubygems/credential_store/native/linux.rb +97 -0
  130. data/lib/rubygems/credential_store/native/macos.rb +88 -0
  131. data/lib/rubygems/credential_store/native/windows.rb +130 -0
  132. data/lib/rubygems/credential_store.rb +332 -0
  133. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/assignment.rb +1 -1
  134. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +7 -7
  135. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/failure_writer.rb +1 -1
  136. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/incompatibility.rb +4 -4
  137. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/package.rb +1 -1
  138. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/partial_solution.rb +1 -1
  139. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/rubygems.rb +3 -3
  140. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/solve_failure.rb +1 -1
  141. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/static_package_source.rb +3 -3
  142. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/strategy.rb +2 -2
  143. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/term.rb +1 -1
  144. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version.rb +1 -1
  145. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_constraint.rb +3 -3
  146. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_range.rb +1 -1
  147. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_solver.rb +2 -2
  148. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_union.rb +1 -1
  149. data/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb +57 -0
  150. data/lib/{bundler → rubygems}/vendor/securerandom/lib/securerandom.rb +10 -6
  151. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/common.rb +119 -119
  152. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/file.rb +13 -13
  153. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ftp.rb +24 -24
  154. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/generic.rb +132 -132
  155. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/http.rb +18 -18
  156. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/https.rb +4 -4
  157. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ldap.rb +14 -14
  158. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ldaps.rb +4 -4
  159. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/mailto.rb +21 -21
  160. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/rfc2396_parser.rb +39 -39
  161. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/rfc3986_parser.rb +14 -14
  162. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/version.rb +1 -1
  163. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ws.rb +12 -12
  164. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/wss.rb +4 -4
  165. data/lib/{bundler → rubygems}/vendor/uri/lib/uri.rb +35 -31
  166. data/lib/rubygems/yaml_serializer.rb +880 -0
  167. metadata +77 -68
  168. data/CHANGELOG.md +0 -5784
  169. data/LICENSE.md +0 -22
  170. data/README.md +0 -58
  171. data/lib/bundler/compact_index_client/cache.rb +0 -107
  172. data/lib/bundler/compact_index_client/cache_file.rb +0 -148
  173. data/lib/bundler/compact_index_client/parser.rb +0 -87
  174. data/lib/bundler/compact_index_client/updater.rb +0 -105
  175. data/lib/bundler/compact_index_client.rb +0 -92
  176. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +0 -227
  177. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +0 -3
  178. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +0 -56
  179. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +0 -230
  180. data/lib/bundler/vendor/net-http-persistent/README.rdoc +0 -82
  181. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +0 -41
  182. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +0 -65
  183. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +0 -80
  184. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +0 -1153
  185. data/lib/bundler/vendor/pub_grub/lib/pub_grub.rb +0 -31
  186. data/lib/bundler/vendored_persistent.rb +0 -11
  187. data/lib/bundler/yaml_serializer.rb +0 -98
  188. /data/lib/{bundler → rubygems}/vendor/pub_grub/LICENSE.txt +0 -0
  189. /data/lib/{bundler → rubygems}/vendor/securerandom/COPYING +0 -0
  190. /data/lib/{bundler → rubygems}/vendor/uri/COPYING +0 -0
@@ -0,0 +1,332 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Skip reloading when an identical copy (e.g. the one shipped inside the Bundler
4
+ # gem) was already required from a different path, to avoid redefinition warnings.
5
+ return if defined?(Gem::CredentialStore::SERVICE_NAME)
6
+
7
+ ##
8
+ # Gem::CredentialStore is opt-in storage for authentication secrets (API
9
+ # keys, host credentials) in the operating system's native secret store
10
+ # instead of a plain text file:
11
+ #
12
+ # * macOS: Keychain, via the +security+ command line tool.
13
+ # * Linux: the Secret Service API (GNOME Keyring, KWallet, ...), via
14
+ # +secret-tool+.
15
+ # * Windows: Credential Manager, via the +Windows.Security.Credentials.PasswordVault+
16
+ # API from PowerShell.
17
+ #
18
+ # A third party can add another backend (1Password, pass, HashiCorp Vault,
19
+ # ...) by shipping a gem that provides
20
+ # <tt>rubygems/credential_store/backends/<name></tt> and calls
21
+ # .register_backend from it. Users then select it by name instead of +true+
22
+ # (see .resolve_backend).
23
+ #
24
+ # Every public method traps all errors and returns +nil+/+false+ instead of
25
+ # raising, so that callers can transparently fall back to their existing
26
+ # file-based storage when the native store is unavailable or fails (a
27
+ # locked keychain over SSH, a headless Linux session without a keyring
28
+ # daemon, ...).
29
+
30
+ class Gem::CredentialStore
31
+ SERVICE_NAME = "rubygems"
32
+
33
+ ##
34
+ # Returns the store to use for +spec+, or +nil+ when the credential store
35
+ # is off. +spec+ is either +true+ (use this platform's native backend) or
36
+ # the name of a registered backend such as "1password". +service+ names
37
+ # the account namespace within the backend, so RubyGems and Bundler keep
38
+ # separate credentials in one native store. The store is memoized per
39
+ # +spec+ and +service+ for the life of the process, so the read cache and
40
+ # any expensive backend startup are shared across callers. A test may
41
+ # install a stand-in via #instance= that is returned here for any enabled
42
+ # +spec+, or inject a shared backend via #backend=.
43
+
44
+ def self.for(spec, service: SERVICE_NAME)
45
+ return nil unless spec
46
+ return @override if defined?(@override) && @override
47
+
48
+ backend = defined?(@override_backend) && @override_backend ? @override_backend : backend_for(spec)
49
+ (@instances ||= {})[[spec, service]] ||= new(backend: backend, service: service)
50
+ end
51
+
52
+ ##
53
+ # The default-backed store for this platform, i.e. <tt>for(true)</tt>.
54
+ # Kept for callers and tests that only care about the native backend.
55
+
56
+ def self.instance
57
+ self.for(true)
58
+ end
59
+
60
+ ##
61
+ # Installs a stand-in store that .for returns for any enabled setting.
62
+ # Intended for tests that inject a fake backend.
63
+
64
+ def self.instance=(store)
65
+ @override = store
66
+ end
67
+
68
+ ##
69
+ # Installs a shared backend that .for wraps for every spec and service.
70
+ # Intended for tests that need RubyGems and Bundler credentials to land in
71
+ # one backend under their own service names.
72
+
73
+ def self.backend=(backend)
74
+ @override_backend = backend
75
+ end
76
+
77
+ ##
78
+ # Clears the memoized stores, the injected overrides, and the warned
79
+ # messages. Intended for tests only.
80
+
81
+ def self.reset!
82
+ @override = nil
83
+ @override_backend = nil
84
+ @instances = nil
85
+ @warned = nil
86
+ @warn_handler = nil
87
+ end
88
+
89
+ ##
90
+ # Warns once per distinct message. A single flag for every message would
91
+ # let an early warning about, say, a misspelled backend name suppress the
92
+ # later warning that a secret was written in plain text.
93
+
94
+ def self.warn_once(message)
95
+ @warned ||= {}
96
+ return if @warned.key?(message)
97
+
98
+ @warned[message] = true
99
+
100
+ if defined?(@warn_handler) && @warn_handler
101
+ @warn_handler.call(message)
102
+ else
103
+ Gem.ui.alert_warning message
104
+ end
105
+ end
106
+
107
+ ##
108
+ # Sends warnings to +handler+ (anything responding to #call) instead of
109
+ # Gem.ui. Bundler sets this because it replaces Gem.ui with a subclass of
110
+ # Gem::SilentUI, which discards alert_warning entirely, so a credential
111
+ # store failure would otherwise be silent for the whole bundle command.
112
+
113
+ def self.warn_handler=(handler)
114
+ @warn_handler = handler
115
+ end
116
+
117
+ ##
118
+ # Registers +backend+ under +name+ so it can be selected with
119
+ # <tt>credential_store = <name></tt>. A third-party backend gem calls this
120
+ # from the file RubyGems loads for that name (see .resolve_backend).
121
+
122
+ def self.register_backend(name, backend)
123
+ (@backends ||= {})[name.to_s] = backend
124
+ end
125
+
126
+ BACKEND_NAME = /\A[a-z0-9_-]+\z/
127
+
128
+ ##
129
+ # Resolves a registered backend by +name+, requiring
130
+ # <tt>rubygems/credential_store/backends/<name></tt> on first use so a
131
+ # backend shipped as its own gem loads only when actually selected.
132
+ # Returns +nil+ (warning once) when the name is malformed or no gem
133
+ # provides it, which makes callers fall back to file storage. The fixed
134
+ # require prefix and the restricted name charset keep the setting a piece
135
+ # of data, never a path or a command.
136
+
137
+ def self.resolve_backend(name)
138
+ # The setting can carry bytes Regexp#match? would reject. A name that gets
139
+ # past the match is ASCII only, so the require path it builds stays sound.
140
+ name = name.to_s.b
141
+ unless BACKEND_NAME.match?(name)
142
+ warn_once "Ignoring invalid credential store backend name #{name.inspect}."
143
+ return nil
144
+ end
145
+
146
+ return @backends[name] if @backends&.key?(name)
147
+
148
+ begin
149
+ require "rubygems/credential_store/backends/#{name}"
150
+ rescue LoadError
151
+ warn_once "Credential store backend #{name.inspect} is not installed. " \
152
+ "Install a gem that provides rubygems/credential_store/backends/#{name}, " \
153
+ "or unset the credential_store setting. Falling back to file storage."
154
+ return nil
155
+ end
156
+
157
+ @backends && @backends[name]
158
+ end
159
+
160
+ def self.backend_for(spec)
161
+ spec == true ? default_backend : resolve_backend(spec)
162
+ end
163
+ private_class_method :backend_for
164
+
165
+ def self.default_backend
166
+ if Gem.win_platform?
167
+ require_relative "credential_store/native/windows"
168
+ WindowsBackend
169
+ elsif RUBY_PLATFORM.include?("darwin")
170
+ require_relative "credential_store/native/macos"
171
+ MacOSBackend
172
+ elsif RUBY_PLATFORM.include?("linux")
173
+ require_relative "credential_store/native/linux"
174
+ LinuxBackend if LinuxBackend.available?
175
+ end
176
+ end
177
+
178
+ ##
179
+ # +backend+ is only used by tests to inject a fake backend regardless of
180
+ # the platform the test suite happens to run on. +service+ is the account
181
+ # namespace this store reads and writes under.
182
+
183
+ def initialize(backend: self.class.default_backend, service: SERVICE_NAME)
184
+ @backend = backend
185
+ @service = service
186
+ @cache = {}
187
+ end
188
+
189
+ ##
190
+ # True if a native credential backend is usable on this platform.
191
+
192
+ def available?
193
+ !@backend.nil?
194
+ end
195
+
196
+ ##
197
+ # Returns the secret stored for +account+, or +nil+ if there is none or
198
+ # the backend is unavailable/fails.
199
+
200
+ def get(account)
201
+ return nil unless @backend
202
+ return @cache[account] if @cache.key?(account)
203
+
204
+ @cache[account] = @backend.get(@service, account)
205
+ rescue StandardError => e
206
+ warn_failure(:read, e)
207
+ # Retrying means another subprocess and, on some platforms, another
208
+ # authorization prompt. #read_failed? keeps this apart from an absent one.
209
+ (@failed ||= {})[account] = true
210
+ @cache[account] = nil
211
+ end
212
+
213
+ ##
214
+ # True when #get returned +nil+ for +account+ because the backend could not
215
+ # answer, rather than because nothing is stored under it. Callers that would
216
+ # otherwise fall back to a different credential need the difference: a
217
+ # missing entry means "use something else", an unreadable one does not.
218
+
219
+ def read_failed?(account)
220
+ return false unless defined?(@failed) && @failed
221
+
222
+ @failed.key?(account)
223
+ end
224
+
225
+ ##
226
+ # Stores +secret+ for +account+. Returns +true+ on success.
227
+
228
+ def set(account, secret)
229
+ return false unless @backend
230
+
231
+ validate_credential(account, secret)
232
+
233
+ if @backend.set(@service, account, secret)
234
+ @cache[account] = secret
235
+ @failed&.delete(account)
236
+ invalidate_list
237
+ true
238
+ else
239
+ false
240
+ end
241
+ rescue StandardError => e
242
+ warn_failure(:write, e)
243
+ false
244
+ end
245
+
246
+ ##
247
+ # Removes the secret stored for +account+. Returns +true+ if the entry is
248
+ # gone, whether or not it existed beforehand.
249
+
250
+ def delete(account)
251
+ return false unless @backend
252
+
253
+ result = @backend.delete(@service, account)
254
+ @cache.delete(account)
255
+ @failed&.delete(account)
256
+ invalidate_list
257
+ result
258
+ rescue StandardError => e
259
+ warn_failure(:remove, e)
260
+ false
261
+ end
262
+
263
+ ##
264
+ # The accounts this store holds, or +nil+ when the backend cannot
265
+ # enumerate them. Listing is optional in the backend protocol: the native
266
+ # backends implement it, but a third-party backend that only resolves
267
+ # credentials on demand has nothing to enumerate. Callers must treat +nil+
268
+ # as "unknown", not as "empty". Secrets are never returned.
269
+
270
+ def list
271
+ return nil unless @backend.respond_to?(:list)
272
+ return @list if defined?(@list)
273
+
274
+ @list = @backend.list(@service)
275
+ rescue StandardError => e
276
+ warn_failure(:list, e)
277
+ # Remembered for the same reason #get remembers a failed read.
278
+ @list = nil
279
+ end
280
+
281
+ ##
282
+ # Removes every entry this store owns (all accounts under its service).
283
+ # Returns +true+ when the store is now clear. Used by +gem signout+ to end
284
+ # every session at once, mirroring deletion of the whole credentials file.
285
+
286
+ def delete_all
287
+ return false unless @backend
288
+
289
+ result = @backend.delete_all(@service)
290
+ @cache.clear
291
+ @failed = nil
292
+ invalidate_list
293
+ result
294
+ rescue StandardError => e
295
+ warn_failure(:remove, e)
296
+ false
297
+ end
298
+
299
+ private
300
+
301
+ # The listing is memoized, so a write has to drop it.
302
+ def invalidate_list
303
+ remove_instance_variable(:@list) if defined?(@list)
304
+ end
305
+
306
+ # The macOS keychain hands non-printable bytes back as hex through the only
307
+ # read-back its CLI offers. Applied to every backend so the same value is
308
+ # stored, or refused for the same reason, everywhere.
309
+ PRINTABLE_ASCII = /\A[\x20-\x7e]*\z/
310
+
311
+ # What happens after a failure depends on the operation, so the warning has
312
+ # to say the right thing for each.
313
+ OUTCOMES = {
314
+ read: "any copy left in the config file will be used instead",
315
+ write: "falling back to file storage",
316
+ remove: "the credential is still in the store",
317
+ list: "stored credentials will not be listed",
318
+ }.freeze
319
+
320
+ # A newline in an account would start a second command in the macOS batch
321
+ # input. #set turns the raise back into a warning and a false.
322
+ def validate_credential(account, secret)
323
+ raise ArgumentError, "credential secret must be printable ASCII" unless secret.to_s.b.match?(PRINTABLE_ASCII)
324
+ raise ArgumentError, "credential account must not contain a newline" if account.to_s.include?("\n")
325
+ raise ArgumentError, "credential service must not contain a newline" if @service.to_s.include?("\n")
326
+ end
327
+
328
+ def warn_failure(operation, error)
329
+ self.class.warn_once "Credential store #{operation} failed for #{@service}" \
330
+ " (#{error.class}: #{error.message}); #{OUTCOMES[operation]}."
331
+ end
332
+ end
@@ -1,4 +1,4 @@
1
- module Bundler::PubGrub
1
+ module Gem::PubGrub
2
2
  class Assignment
3
3
  attr_reader :term, :cause, :decision_level, :index
4
4
  def initialize(term, cause, decision_level, index)
@@ -1,10 +1,10 @@
1
1
  require_relative 'version_constraint'
2
2
  require_relative 'incompatibility'
3
3
 
4
- module Bundler::PubGrub
4
+ module Gem::PubGrub
5
5
  # Types:
6
6
  #
7
- # Where possible, Bundler::PubGrub will accept user-defined types, so long as they quack.
7
+ # Where possible, Gem::PubGrub will accept user-defined types, so long as they quack.
8
8
  #
9
9
  # ## "Package":
10
10
  #
@@ -32,7 +32,7 @@ module Bundler::PubGrub
32
32
  #
33
33
  # This class represents the requirement one package has on another. It is
34
34
  # returned by dependencies_for(package, version) and will be passed to
35
- # parse_dependency to convert it to a format Bundler::PubGrub understands.
35
+ # parse_dependency to convert it to a format Gem::PubGrub understands.
36
36
  #
37
37
  # It must also have a reasonable definition of #==
38
38
  #
@@ -59,13 +59,13 @@ module Bundler::PubGrub
59
59
 
60
60
  # Override me!
61
61
  #
62
- # Convert a (user-defined) dependency into a format Bundler::PubGrub understands.
62
+ # Convert a (user-defined) dependency into a format Gem::PubGrub understands.
63
63
  #
64
64
  # Package is passed to this method but for many implementations is not
65
65
  # needed.
66
66
  #
67
- # Returns: either a Bundler::PubGrub::VersionRange, Bundler::PubGrub::VersionUnion, or a
68
- # Bundler::PubGrub::VersionConstraint
67
+ # Returns: either a Gem::PubGrub::VersionRange, Gem::PubGrub::VersionUnion, or a
68
+ # Gem::PubGrub::VersionConstraint
69
69
  def parse_dependency(package, dependency)
70
70
  raise NotImplementedError
71
71
  end
@@ -155,7 +155,7 @@ module Bundler::PubGrub
155
155
  dep_constraint = parse_dependency(dep_package, dep_constraint_name)
156
156
  if !dep_constraint
157
157
  # falsey indicates this dependency was invalid
158
- cause = Bundler::PubGrub::Incompatibility::InvalidDependency.new(dep_package, dep_constraint_name)
158
+ cause = Gem::PubGrub::Incompatibility::InvalidDependency.new(dep_package, dep_constraint_name)
159
159
  return [Incompatibility.new([Term.new(self_constraint, true)], cause: cause)]
160
160
  elsif !dep_constraint.is_a?(VersionConstraint)
161
161
  # Upgrade range/union to VersionConstraint
@@ -1,4 +1,4 @@
1
- module Bundler::PubGrub
1
+ module Gem::PubGrub
2
2
  class FailureWriter
3
3
  def initialize(root)
4
4
  @root = root
@@ -1,4 +1,4 @@
1
- module Bundler::PubGrub
1
+ module Gem::PubGrub
2
2
  class Incompatibility
3
3
  ConflictCause = Struct.new(:incompatibility, :satisfier) do
4
4
  alias_method :conflict, :incompatibility
@@ -61,11 +61,11 @@ module Bundler::PubGrub
61
61
  "(root dependency)"
62
62
  when :dependency
63
63
  "#{terms[0].to_s(allow_every: true)} depends on #{terms[1].invert}"
64
- when Bundler::PubGrub::Incompatibility::InvalidDependency
64
+ when Gem::PubGrub::Incompatibility::InvalidDependency
65
65
  "#{terms[0].to_s(allow_every: true)} depends on unknown package #{cause.package}"
66
- when Bundler::PubGrub::Incompatibility::NoVersions
66
+ when Gem::PubGrub::Incompatibility::NoVersions
67
67
  "no versions satisfy #{cause.constraint}"
68
- when Bundler::PubGrub::Incompatibility::ConflictCause
68
+ when Gem::PubGrub::Incompatibility::ConflictCause
69
69
  if failure?
70
70
  "version solving has failed"
71
71
  elsif terms.length == 1
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Bundler::PubGrub
3
+ module Gem::PubGrub
4
4
  class Package
5
5
 
6
6
  attr_reader :name
@@ -1,6 +1,6 @@
1
1
  require_relative 'assignment'
2
2
 
3
- module Bundler::PubGrub
3
+ module Gem::PubGrub
4
4
  class PartialSolution
5
5
  attr_reader :assignments, :decisions
6
6
  attr_reader :attempted_solutions
@@ -1,4 +1,4 @@
1
- module Bundler::PubGrub
1
+ module Gem::PubGrub
2
2
  module RubyGems
3
3
  extend self
4
4
 
@@ -30,7 +30,7 @@ module Bundler::PubGrub
30
30
  end
31
31
 
32
32
  def requirement_to_constraint(package, requirement)
33
- Bundler::PubGrub::VersionConstraint.new(package, range: requirement_to_range(requirement))
33
+ Gem::PubGrub::VersionConstraint.new(package, range: requirement_to_range(requirement))
34
34
  end
35
35
 
36
36
  def parse_range(dep)
@@ -39,7 +39,7 @@ module Bundler::PubGrub
39
39
 
40
40
  def parse_constraint(package, dep)
41
41
  range = parse_range(dep)
42
- Bundler::PubGrub::VersionConstraint.new(package, range: range)
42
+ Gem::PubGrub::VersionConstraint.new(package, range: range)
43
43
  end
44
44
  end
45
45
  end
@@ -1,6 +1,6 @@
1
1
  require_relative 'failure_writer'
2
2
 
3
- module Bundler::PubGrub
3
+ module Gem::PubGrub
4
4
  class SolveFailure < StandardError
5
5
  attr_reader :incompatibility
6
6
 
@@ -4,7 +4,7 @@ require_relative 'version_constraint'
4
4
  require_relative 'incompatibility'
5
5
  require_relative 'basic_package_source'
6
6
 
7
- module Bundler::PubGrub
7
+ module Gem::PubGrub
8
8
  class StaticPackageSource < BasicPackageSource
9
9
  class DSL
10
10
  def initialize(packages, root_deps)
@@ -27,7 +27,7 @@ module Bundler::PubGrub
27
27
 
28
28
  # Exclude redundant self-referencing dependencies
29
29
  def clean_deps(name, version, deps)
30
- deps.reject {|dep_name, req| name == dep_name && Bundler::PubGrub::RubyGems.parse_range(req).include?(version) }
30
+ deps.reject {|dep_name, req| name == dep_name && Gem::PubGrub::RubyGems.parse_range(req).include?(version) }
31
31
  end
32
32
  end
33
33
 
@@ -55,7 +55,7 @@ module Bundler::PubGrub
55
55
  def parse_dependency(package, dependency)
56
56
  return false unless @packages.key?(package)
57
57
 
58
- Bundler::PubGrub::RubyGems.parse_constraint(package, dependency)
58
+ Gem::PubGrub::RubyGems.parse_constraint(package, dependency)
59
59
  end
60
60
  end
61
61
  end
@@ -1,4 +1,4 @@
1
- module Bundler::PubGrub
1
+ module Gem::PubGrub
2
2
  class Strategy
3
3
  def initialize(source)
4
4
  @source = source
@@ -27,7 +27,7 @@ module Bundler::PubGrub
27
27
  versions = @source.versions_for(package, range)
28
28
 
29
29
  indexes = @version_indexes[package]
30
- versions.min_by { |version| indexes[version] }
30
+ versions.min_by { |version| indexes[version] || Float::INFINITY }
31
31
  end
32
32
 
33
33
  def next_term_to_try_from(unsatisfied)
@@ -1,4 +1,4 @@
1
- module Bundler::PubGrub
1
+ module Gem::PubGrub
2
2
  class Term
3
3
  attr_reader :package, :constraint, :positive
4
4
 
@@ -1,3 +1,3 @@
1
- module Bundler::PubGrub
1
+ module Gem::PubGrub
2
2
  VERSION = "0.5.0"
3
3
  end
@@ -1,11 +1,11 @@
1
1
  require_relative 'version_range'
2
2
 
3
- module Bundler::PubGrub
3
+ module Gem::PubGrub
4
4
  class VersionConstraint
5
5
  attr_reader :package, :range
6
6
 
7
- # @param package [Bundler::PubGrub::Package]
8
- # @param range [Bundler::PubGrub::VersionRange]
7
+ # @param package [Gem::PubGrub::Package]
8
+ # @param range [Gem::PubGrub::VersionRange]
9
9
  def initialize(package, range: nil)
10
10
  @package = package
11
11
  @range = range
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Bundler::PubGrub
3
+ module Gem::PubGrub
4
4
  class VersionRange
5
5
  attr_reader :min, :max, :include_min, :include_max
6
6
 
@@ -4,14 +4,14 @@ require_relative 'incompatibility'
4
4
  require_relative 'solve_failure'
5
5
  require_relative 'strategy'
6
6
 
7
- module Bundler::PubGrub
7
+ module Gem::PubGrub
8
8
  class VersionSolver
9
9
  attr_reader :logger
10
10
  attr_reader :source
11
11
  attr_reader :solution
12
12
  attr_reader :strategy
13
13
 
14
- def initialize(source:, root: Package.root, strategy: Strategy.new(source), logger: Bundler::PubGrub.logger)
14
+ def initialize(source:, root: Package.root, strategy: Strategy.new(source), logger: Gem::PubGrub.logger)
15
15
  @logger = logger
16
16
 
17
17
  @source = source
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Bundler::PubGrub
3
+ module Gem::PubGrub
4
4
  class VersionUnion
5
5
  attr_reader :ranges
6
6
 
@@ -0,0 +1,57 @@
1
+ # Skip reloading when an identical copy (e.g. the one shipped inside the Bundler
2
+ # gem) was already required from a different path, to avoid redefinition warnings.
3
+ return if defined?(Gem::PubGrub::VERSION)
4
+
5
+ require_relative "pub_grub/package"
6
+ require_relative "pub_grub/static_package_source"
7
+ require_relative "pub_grub/term"
8
+ require_relative "pub_grub/version_range"
9
+ require_relative "pub_grub/version_constraint"
10
+ require_relative "pub_grub/version_union"
11
+ require_relative "pub_grub/version_solver"
12
+ require_relative "pub_grub/incompatibility"
13
+ require_relative 'pub_grub/solve_failure'
14
+ require_relative 'pub_grub/failure_writer'
15
+ require_relative 'pub_grub/version'
16
+
17
+ module Gem::PubGrub
18
+ # Minimal logger that doesn't require the 'logger' gem
19
+ class NullLogger
20
+ def info(&block); end
21
+ def debug(&block); end
22
+ def warn(&block); end
23
+ def error(&block); end
24
+ end
25
+
26
+ class StderrLogger
27
+ def info(&block)
28
+ $stderr.puts "INFO: #{block.call}" if block
29
+ end
30
+
31
+ def debug(&block)
32
+ $stderr.puts "DEBUG: #{block.call}" if block
33
+ end
34
+
35
+ def warn(&block)
36
+ $stderr.puts "WARN: #{block.call}" if block
37
+ end
38
+
39
+ def error(&block)
40
+ $stderr.puts "ERROR: #{block.call}" if block
41
+ end
42
+ end
43
+
44
+ class << self
45
+ attr_writer :logger
46
+
47
+ def logger
48
+ @logger || default_logger
49
+ end
50
+
51
+ private
52
+
53
+ def default_logger
54
+ @logger = $DEBUG ? StderrLogger.new : NullLogger.new
55
+ end
56
+ end
57
+ end
@@ -10,7 +10,7 @@ require 'random/formatter'
10
10
  #
11
11
  # You can use this library in your application by requiring it:
12
12
  #
13
- # require 'bundler/vendor/securerandom/lib/securerandom'
13
+ # require 'rubygems/vendor/securerandom/lib/securerandom'
14
14
  #
15
15
  # It supports the following secure random number generators:
16
16
  #
@@ -18,7 +18,7 @@ require 'random/formatter'
18
18
  # * /dev/urandom
19
19
  # * Win32
20
20
  #
21
- # Bundler::SecureRandom is extended by the Random::Formatter module which
21
+ # Gem::SecureRandom is extended by the Random::Formatter module which
22
22
  # defines the following methods:
23
23
  #
24
24
  # * alphanumeric
@@ -32,13 +32,17 @@ require 'random/formatter'
32
32
  # * urlsafe_base64
33
33
  # * uuid
34
34
  #
35
- # These methods are usable as class methods of Bundler::SecureRandom such as
36
- # +Bundler::SecureRandom.hex+.
35
+ # These methods are usable as class methods of Gem::SecureRandom such as
36
+ # +Gem::SecureRandom.hex+.
37
37
  #
38
38
  # If a secure random number generator is not available,
39
39
  # +NotImplementedError+ is raised.
40
40
 
41
- module Bundler::SecureRandom
41
+ # Skip reloading when an identical copy (e.g. the one shipped inside the Bundler
42
+ # gem) was already required from a different path, to avoid redefinition warnings.
43
+ return if defined?(Gem::SecureRandom::VERSION)
44
+
45
+ module Gem::SecureRandom
42
46
 
43
47
  # The version
44
48
  VERSION = "0.4.1"
@@ -99,4 +103,4 @@ module Bundler::SecureRandom
99
103
  end
100
104
  end
101
105
 
102
- Bundler::SecureRandom.extend(Random::Formatter)
106
+ Gem::SecureRandom.extend(Random::Formatter)