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.
- checksums.yaml +4 -4
- data/{lib/bundler/vendor/connection_pool/LICENSE → MIT.txt} +8 -6
- data/bundler.gemspec +23 -6
- data/lib/bundler/build_metadata.rb +2 -2
- data/lib/bundler/checksum.rb +40 -25
- data/lib/bundler/ci_detector.rb +1 -1
- data/lib/bundler/cli/add.rb +3 -4
- data/lib/bundler/cli/cache.rb +4 -0
- data/lib/bundler/cli/clean.rb +5 -0
- data/lib/bundler/cli/common.rb +37 -1
- data/lib/bundler/cli/config.rb +4 -2
- data/lib/bundler/cli/gem.rb +0 -17
- data/lib/bundler/cli/install.rb +4 -5
- data/lib/bundler/cli/lock.rb +1 -2
- data/lib/bundler/cli/outdated.rb +8 -3
- data/lib/bundler/cli/pristine.rb +2 -1
- data/lib/bundler/cli/update.rb +21 -12
- data/lib/bundler/cli.rb +14 -11
- data/lib/bundler/definition.rb +61 -24
- data/lib/bundler/dependency.rb +4 -0
- data/lib/bundler/dsl.rb +77 -11
- data/lib/bundler/endpoint_specification.rb +51 -14
- data/lib/bundler/env.rb +7 -24
- data/lib/bundler/errors.rb +34 -5
- data/lib/bundler/fetcher/compact_index.rb +14 -5
- data/lib/bundler/fetcher/connection_pools.rb +150 -0
- data/lib/bundler/fetcher/downloader.rb +31 -16
- data/lib/bundler/fetcher.rb +8 -47
- data/lib/bundler/injector.rb +3 -3
- data/lib/bundler/inline.rb +44 -4
- data/lib/bundler/installer/parallel_installer.rb +25 -30
- data/lib/bundler/installer.rb +20 -6
- data/lib/bundler/lazy_specification.rb +44 -17
- data/lib/bundler/lockfile_generator.rb +24 -2
- data/lib/bundler/lockfile_parser.rb +43 -5
- data/lib/bundler/man/bundle-add.1 +7 -4
- data/lib/bundler/man/bundle-add.1.ronn +8 -4
- data/lib/bundler/man/bundle-binstubs.1 +1 -1
- data/lib/bundler/man/bundle-cache.1 +2 -2
- data/lib/bundler/man/bundle-cache.1.ronn +2 -2
- data/lib/bundler/man/bundle-check.1 +1 -1
- data/lib/bundler/man/bundle-clean.1 +1 -1
- data/lib/bundler/man/bundle-config.1 +38 -6
- data/lib/bundler/man/bundle-config.1.ronn +143 -10
- data/lib/bundler/man/bundle-console.1 +1 -1
- data/lib/bundler/man/bundle-doctor.1 +1 -1
- data/lib/bundler/man/bundle-env.1 +1 -1
- data/lib/bundler/man/bundle-exec.1 +1 -1
- data/lib/bundler/man/bundle-fund.1 +1 -1
- data/lib/bundler/man/bundle-gem.1 +1 -1
- data/lib/bundler/man/bundle-help.1 +1 -1
- data/lib/bundler/man/bundle-info.1 +1 -1
- data/lib/bundler/man/bundle-init.1 +1 -1
- data/lib/bundler/man/bundle-install.1 +2 -2
- data/lib/bundler/man/bundle-install.1.ronn +4 -4
- data/lib/bundler/man/bundle-issue.1 +1 -1
- data/lib/bundler/man/bundle-licenses.1 +1 -1
- data/lib/bundler/man/bundle-list.1 +1 -1
- data/lib/bundler/man/bundle-lock.1 +3 -3
- data/lib/bundler/man/bundle-lock.1.ronn +5 -5
- data/lib/bundler/man/bundle-open.1 +1 -1
- data/lib/bundler/man/bundle-outdated.1 +1 -1
- data/lib/bundler/man/bundle-platform.1 +1 -1
- data/lib/bundler/man/bundle-plugin.1 +1 -1
- data/lib/bundler/man/bundle-pristine.1 +1 -1
- data/lib/bundler/man/bundle-remove.1 +1 -1
- data/lib/bundler/man/bundle-show.1 +1 -1
- data/lib/bundler/man/bundle-update.1 +3 -3
- data/lib/bundler/man/bundle-update.1.ronn +3 -5
- data/lib/bundler/man/bundle-version.1 +1 -1
- data/lib/bundler/man/bundle.1 +1 -1
- data/lib/bundler/man/gemfile.5 +45 -1
- data/lib/bundler/man/gemfile.5.ronn +53 -0
- data/lib/bundler/match_metadata.rb +20 -0
- data/lib/bundler/match_platform.rb +25 -2
- data/lib/bundler/match_remote_metadata.rb +21 -6
- data/lib/bundler/materialization.rb +2 -1
- data/lib/bundler/override.rb +69 -0
- data/lib/bundler/plugin/dsl.rb +3 -5
- data/lib/bundler/plugin/events.rb +55 -13
- data/lib/bundler/plugin/index.rb +87 -11
- data/lib/bundler/plugin/installer/path.rb +1 -1
- data/lib/bundler/plugin/installer.rb +13 -5
- data/lib/bundler/plugin.rb +58 -30
- data/lib/bundler/remote_specification.rb +6 -3
- data/lib/bundler/resolver/base.rb +2 -1
- data/lib/bundler/resolver/incompatibility.rb +1 -1
- data/lib/bundler/resolver.rb +73 -23
- data/lib/bundler/ruby_version.rb +0 -2
- data/lib/bundler/rubygems_ext.rb +71 -1
- data/lib/bundler/rubygems_gem_installer.rb +41 -2
- data/lib/bundler/rubygems_integration.rb +7 -2
- data/lib/bundler/runtime.rb +69 -2
- data/lib/bundler/self_manager.rb +9 -15
- data/lib/bundler/settings.rb +373 -30
- data/lib/bundler/shared_helpers.rb +2 -1
- data/lib/bundler/source/git/git_proxy.rb +2 -10
- data/lib/bundler/source/git.rb +15 -6
- data/lib/bundler/source/path/installer.rb +1 -1
- data/lib/bundler/source/rubygems/remote.rb +10 -5
- data/lib/bundler/source/rubygems.rb +48 -12
- data/lib/bundler/spec_set.rb +16 -4
- data/lib/bundler/stub_specification.rb +2 -1
- data/lib/bundler/templates/newgem/Gemfile.tt +4 -4
- data/lib/bundler/templates/newgem/newgem.gemspec.tt +3 -3
- data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +1 -1
- data/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt +1 -1
- data/lib/bundler/ui/shell.rb +0 -4
- data/lib/bundler/ui/silent.rb +0 -4
- data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +35 -2
- data/lib/bundler/vendor/thor/lib/thor/base.rb +2 -1
- data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +14 -6
- data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +2 -0
- data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
- data/lib/bundler/vendor/thor/lib/thor.rb +34 -1
- data/lib/bundler/vendored_pub_grub.rb +5 -2
- data/lib/bundler/vendored_securerandom.rb +11 -8
- data/lib/bundler/vendored_uri.rb +14 -14
- data/lib/bundler/version.rb +1 -1
- data/lib/bundler/worker.rb +3 -2
- data/lib/bundler.rb +1 -1
- data/lib/rubygems/compact_index_client/cache.rb +122 -0
- data/lib/rubygems/compact_index_client/cache_file.rb +147 -0
- data/lib/rubygems/compact_index_client/http_fetcher.rb +88 -0
- data/lib/rubygems/compact_index_client/parser.rb +90 -0
- data/lib/rubygems/compact_index_client/updater.rb +113 -0
- data/lib/rubygems/compact_index_client.rb +111 -0
- data/lib/rubygems/cooldown_settings.rb +57 -0
- data/lib/rubygems/credential_store/native/linux.rb +97 -0
- data/lib/rubygems/credential_store/native/macos.rb +88 -0
- data/lib/rubygems/credential_store/native/windows.rb +130 -0
- data/lib/rubygems/credential_store.rb +332 -0
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/assignment.rb +1 -1
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +7 -7
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/failure_writer.rb +1 -1
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/incompatibility.rb +4 -4
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/package.rb +1 -1
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/partial_solution.rb +1 -1
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/rubygems.rb +3 -3
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/solve_failure.rb +1 -1
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/static_package_source.rb +3 -3
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/strategy.rb +2 -2
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/term.rb +1 -1
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version.rb +1 -1
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_constraint.rb +3 -3
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_range.rb +1 -1
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_solver.rb +2 -2
- data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_union.rb +1 -1
- data/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb +57 -0
- data/lib/{bundler → rubygems}/vendor/securerandom/lib/securerandom.rb +10 -6
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/common.rb +119 -119
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/file.rb +13 -13
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ftp.rb +24 -24
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/generic.rb +132 -132
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/http.rb +18 -18
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/https.rb +4 -4
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ldap.rb +14 -14
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ldaps.rb +4 -4
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/mailto.rb +21 -21
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/rfc2396_parser.rb +39 -39
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/rfc3986_parser.rb +14 -14
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/version.rb +1 -1
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ws.rb +12 -12
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri/wss.rb +4 -4
- data/lib/{bundler → rubygems}/vendor/uri/lib/uri.rb +35 -31
- data/lib/rubygems/yaml_serializer.rb +880 -0
- metadata +77 -68
- data/CHANGELOG.md +0 -5784
- data/LICENSE.md +0 -22
- data/README.md +0 -58
- data/lib/bundler/compact_index_client/cache.rb +0 -107
- data/lib/bundler/compact_index_client/cache_file.rb +0 -148
- data/lib/bundler/compact_index_client/parser.rb +0 -87
- data/lib/bundler/compact_index_client/updater.rb +0 -105
- data/lib/bundler/compact_index_client.rb +0 -92
- data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +0 -227
- data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +0 -3
- data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +0 -56
- data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +0 -230
- data/lib/bundler/vendor/net-http-persistent/README.rdoc +0 -82
- data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +0 -41
- data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +0 -65
- data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +0 -80
- data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +0 -1153
- data/lib/bundler/vendor/pub_grub/lib/pub_grub.rb +0 -31
- data/lib/bundler/vendored_persistent.rb +0 -11
- data/lib/bundler/yaml_serializer.rb +0 -98
- /data/lib/{bundler → rubygems}/vendor/pub_grub/LICENSE.txt +0 -0
- /data/lib/{bundler → rubygems}/vendor/securerandom/COPYING +0 -0
- /data/lib/{bundler → rubygems}/vendor/uri/COPYING +0 -0
data/lib/bundler/runtime.rb
CHANGED
|
@@ -4,6 +4,8 @@ module Bundler
|
|
|
4
4
|
class Runtime
|
|
5
5
|
include SharedHelpers
|
|
6
6
|
|
|
7
|
+
PRUNE_CATEGORIES = [:cache, :git].freeze
|
|
8
|
+
|
|
7
9
|
def initialize(root, definition)
|
|
8
10
|
@root = root
|
|
9
11
|
@definition = definition
|
|
@@ -146,7 +148,7 @@ module Bundler
|
|
|
146
148
|
FileUtils.touch(File.expand_path("../.bundlecache", git_dir))
|
|
147
149
|
end
|
|
148
150
|
|
|
149
|
-
prune_cache(cache_path) unless Bundler.settings[:
|
|
151
|
+
prune_cache(cache_path) unless Bundler.settings[:keep_outdated_cache]
|
|
150
152
|
end
|
|
151
153
|
|
|
152
154
|
def prune_cache(cache_path)
|
|
@@ -164,7 +166,9 @@ module Bundler
|
|
|
164
166
|
git_cache_dirs = SharedHelpers.glob_files_in_dir("cache/bundler/git/*", Gem.dir)
|
|
165
167
|
gem_dirs = SharedHelpers.glob_files_in_dir("gems/*", Gem.dir)
|
|
166
168
|
gem_files = SharedHelpers.glob_files_in_dir("cache/*.gem", Gem.dir)
|
|
167
|
-
gemspec_files =
|
|
169
|
+
gemspec_files = Gem::SpecificationRecord.dirs_from([Gem.dir]).flat_map do |dir|
|
|
170
|
+
SharedHelpers.glob_files_in_dir("*.gemspec", dir)
|
|
171
|
+
end
|
|
168
172
|
extension_dirs = SharedHelpers.glob_files_in_dir("extensions/*/*/*", Gem.dir) + SharedHelpers.glob_files_in_dir("bundler/gems/extensions/*/*/*", Gem.dir)
|
|
169
173
|
spec_gem_paths = []
|
|
170
174
|
# need to keep git sources around
|
|
@@ -229,8 +233,71 @@ module Bundler
|
|
|
229
233
|
output
|
|
230
234
|
end
|
|
231
235
|
|
|
236
|
+
# Removes the artifacts Bundler keeps for its own bookkeeping and can rebuild
|
|
237
|
+
# from the lockfile. Gem contents are never touched.
|
|
238
|
+
def prune(categories)
|
|
239
|
+
categories = expand_prune_categories(categories)
|
|
240
|
+
return if categories.empty?
|
|
241
|
+
|
|
242
|
+
# Without a bundle path the cache is shared with RubyGems, so it holds gem
|
|
243
|
+
# files Bundler never put there.
|
|
244
|
+
if Bundler.use_system_gems?
|
|
245
|
+
Bundler.ui.warn "The `prune` setting was ignored because this bundle installs into the system gem " \
|
|
246
|
+
"directory, which Bundler shares with RubyGems. Run " \
|
|
247
|
+
"`bundle config set --local path vendor/bundle` to prune.", wrap: true
|
|
248
|
+
return
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Git metadata first, because resolving a checkout's install path can need
|
|
252
|
+
# the mirror that pruning the cache removes.
|
|
253
|
+
prune_git_metadata if categories.include?(:git)
|
|
254
|
+
prune_download_cache if categories.include?(:cache)
|
|
255
|
+
end
|
|
256
|
+
|
|
232
257
|
private
|
|
233
258
|
|
|
259
|
+
# Anything that is not a category name is read as a boolean with Bundler's
|
|
260
|
+
# usual vocabulary, so `BUNDLE_PRUNE=1` selects every category and keeps
|
|
261
|
+
# doing so as categories are added. That way a tool can set the flag without
|
|
262
|
+
# tracking this list.
|
|
263
|
+
def expand_prune_categories(categories)
|
|
264
|
+
Array(categories).flat_map do |category|
|
|
265
|
+
name = category.to_s
|
|
266
|
+
next name.to_sym if PRUNE_CATEGORIES.include?(name.to_sym)
|
|
267
|
+
|
|
268
|
+
Settings.to_bool(name) ? PRUNE_CATEGORIES : []
|
|
269
|
+
end.uniq
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def prune_download_cache
|
|
273
|
+
cache_path = File.join(Bundler.bundle_path, "cache")
|
|
274
|
+
return unless File.exist?(cache_path)
|
|
275
|
+
|
|
276
|
+
Bundler.ui.info "Removing the download cache at #{cache_path}"
|
|
277
|
+
SharedHelpers.filesystem_access(cache_path) do |p|
|
|
278
|
+
FileUtils.rm_rf(p)
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def prune_git_metadata
|
|
283
|
+
owned = "#{Bundler.install_path}#{File::SEPARATOR}"
|
|
284
|
+
git_dirs = @definition.sources.git_sources.reject(&:local?).filter_map do |source|
|
|
285
|
+
install_path = source.install_path.to_s
|
|
286
|
+
next unless install_path.start_with?(owned)
|
|
287
|
+
|
|
288
|
+
git_dir = File.join(install_path, ".git")
|
|
289
|
+
git_dir if File.exist?(git_dir)
|
|
290
|
+
end
|
|
291
|
+
return if git_dirs.empty?
|
|
292
|
+
|
|
293
|
+
Bundler.ui.info "Removing git metadata from checked out git gems"
|
|
294
|
+
git_dirs.each do |git_dir|
|
|
295
|
+
SharedHelpers.filesystem_access(git_dir) do |p|
|
|
296
|
+
FileUtils.rm_rf(p)
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
234
301
|
def prune_gem_cache(resolve, cache_path)
|
|
235
302
|
cached = SharedHelpers.glob_files_in_dir("*.gem", cache_path.to_s)
|
|
236
303
|
|
data/lib/bundler/self_manager.rb
CHANGED
|
@@ -30,8 +30,8 @@ module Bundler
|
|
|
30
30
|
install_and_restart_with(restart_version)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def update_bundler_and_restart_with_it_if_needed(target
|
|
34
|
-
spec = resolve_update_version_from(target
|
|
33
|
+
def update_bundler_and_restart_with_it_if_needed(target)
|
|
34
|
+
spec = resolve_update_version_from(target)
|
|
35
35
|
return unless spec
|
|
36
36
|
|
|
37
37
|
version = spec.version
|
|
@@ -108,9 +108,9 @@ module Bundler
|
|
|
108
108
|
lockfile_version
|
|
109
109
|
end
|
|
110
110
|
|
|
111
|
-
def resolve_update_version_from(target
|
|
111
|
+
def resolve_update_version_from(target)
|
|
112
112
|
requirement = Gem::Requirement.new(target)
|
|
113
|
-
update_candidate = find_latest_matching_spec(requirement
|
|
113
|
+
update_candidate = find_latest_matching_spec(requirement)
|
|
114
114
|
|
|
115
115
|
if update_candidate.nil?
|
|
116
116
|
raise InvalidOption, "The `bundle update --bundler` target version (#{target}) does not exist"
|
|
@@ -137,24 +137,18 @@ module Bundler
|
|
|
137
137
|
end
|
|
138
138
|
end
|
|
139
139
|
|
|
140
|
-
def find_latest_matching_spec(requirement
|
|
140
|
+
def find_latest_matching_spec(requirement)
|
|
141
141
|
Bundler.configure
|
|
142
|
-
|
|
143
|
-
# --system`, so only `--pre` or a prerelease requirement opts into one.
|
|
144
|
-
allow_prerelease = pre || requirement.prerelease?
|
|
145
|
-
|
|
146
|
-
local_result = find_latest_matching_spec_from_collection(local_specs, requirement, allow_prerelease)
|
|
142
|
+
local_result = find_latest_matching_spec_from_collection(local_specs, requirement)
|
|
147
143
|
return local_result if local_result && requirement.specific?
|
|
148
144
|
|
|
149
|
-
remote_result = find_latest_matching_spec_from_collection(remote_specs, requirement
|
|
145
|
+
remote_result = find_latest_matching_spec_from_collection(remote_specs, requirement)
|
|
150
146
|
return remote_result if local_result.nil?
|
|
151
147
|
|
|
152
|
-
[local_result, remote_result].
|
|
148
|
+
[local_result, remote_result].max
|
|
153
149
|
end
|
|
154
150
|
|
|
155
|
-
def find_latest_matching_spec_from_collection(specs, requirement
|
|
156
|
-
specs = specs.reject {|spec| spec.version.prerelease? } unless allow_prerelease
|
|
157
|
-
|
|
151
|
+
def find_latest_matching_spec_from_collection(specs, requirement)
|
|
158
152
|
specs.sort.reverse_each.find {|spec| requirement.satisfied_by?(spec.version) }
|
|
159
153
|
end
|
|
160
154
|
|
data/lib/bundler/settings.rb
CHANGED
|
@@ -29,8 +29,11 @@ module Bundler
|
|
|
29
29
|
ignore_messages
|
|
30
30
|
init_gems_rb
|
|
31
31
|
inline
|
|
32
|
+
keep_outdated_cache
|
|
32
33
|
lockfile_checksums
|
|
34
|
+
no_build_extension
|
|
33
35
|
no_install
|
|
36
|
+
no_install_plugin
|
|
34
37
|
no_prune
|
|
35
38
|
path.system
|
|
36
39
|
plugins
|
|
@@ -52,6 +55,7 @@ module Bundler
|
|
|
52
55
|
|
|
53
56
|
ARRAY_KEYS = %w[
|
|
54
57
|
only
|
|
58
|
+
prune
|
|
55
59
|
with
|
|
56
60
|
without
|
|
57
61
|
].freeze
|
|
@@ -60,6 +64,7 @@ module Bundler
|
|
|
60
64
|
bin
|
|
61
65
|
cache_path
|
|
62
66
|
console
|
|
67
|
+
credential_store
|
|
63
68
|
default_cli_command
|
|
64
69
|
gem.ci
|
|
65
70
|
gem.github_username
|
|
@@ -91,6 +96,14 @@ module Bundler
|
|
|
91
96
|
"BUNDLE_UPDATE_REQUIRES_ALL_FLAG" => false,
|
|
92
97
|
}.freeze
|
|
93
98
|
|
|
99
|
+
##
|
|
100
|
+
# Settings renamed in Bundler 4, mapping the current name to the one it
|
|
101
|
+
# replaced. The old name is still read, and goes away in Bundler 5.
|
|
102
|
+
|
|
103
|
+
RENAMED_KEYS = {
|
|
104
|
+
"keep_outdated_cache" => "no_prune",
|
|
105
|
+
}.freeze
|
|
106
|
+
|
|
94
107
|
def initialize(root = nil)
|
|
95
108
|
@root = root
|
|
96
109
|
@local_config = load_config(local_config_file)
|
|
@@ -107,16 +120,7 @@ module Bundler
|
|
|
107
120
|
end
|
|
108
121
|
|
|
109
122
|
def [](name)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
value = nil
|
|
113
|
-
configs.each do |_, config|
|
|
114
|
-
value = config[key]
|
|
115
|
-
next if value.nil?
|
|
116
|
-
break
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
converted_value(value, name)
|
|
123
|
+
converted_value(configured_value(name), name)
|
|
120
124
|
end
|
|
121
125
|
|
|
122
126
|
def set_command_option(key, value)
|
|
@@ -165,6 +169,29 @@ module Bundler
|
|
|
165
169
|
keys
|
|
166
170
|
end
|
|
167
171
|
|
|
172
|
+
##
|
|
173
|
+
# #all plus the keys whose credential lives in the credential store. Kept
|
|
174
|
+
# apart from #all because that one is on the hot path (it is read per gem
|
|
175
|
+
# source and per download, and its keys are advertised in the User-Agent),
|
|
176
|
+
# while this one is for the commands that display settings.
|
|
177
|
+
|
|
178
|
+
def all_including_stored_credentials
|
|
179
|
+
keys = stored_credential_keys.map do |key|
|
|
180
|
+
key = key.delete_prefix("BUNDLE_")
|
|
181
|
+
key.gsub!("___", "-")
|
|
182
|
+
key.gsub!("__", ".")
|
|
183
|
+
key.downcase!
|
|
184
|
+
key
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# The listing comes from the globally selected store, but a host can name
|
|
188
|
+
# its own, so keep only the keys the per-host lookup agrees are set.
|
|
189
|
+
keys.select! {|key| credential_stored?(key) }
|
|
190
|
+
keys << "cooldown" if gemrc_cooldown_days
|
|
191
|
+
|
|
192
|
+
all.union(keys).sort
|
|
193
|
+
end
|
|
194
|
+
|
|
168
195
|
def local_overrides
|
|
169
196
|
repos = {}
|
|
170
197
|
all.each do |k|
|
|
@@ -183,6 +210,9 @@ module Bundler
|
|
|
183
210
|
end
|
|
184
211
|
|
|
185
212
|
def credentials_for(uri)
|
|
213
|
+
stored = credentials_from_store(uri)
|
|
214
|
+
return credentials_from_env(uri) || stored if stored
|
|
215
|
+
|
|
186
216
|
self[uri.to_s] || self[uri.host]
|
|
187
217
|
end
|
|
188
218
|
|
|
@@ -219,14 +249,62 @@ module Bundler
|
|
|
219
249
|
locations << "Set via #{key}: #{printable_value(value, exposed_key).inspect}"
|
|
220
250
|
end
|
|
221
251
|
|
|
252
|
+
if credential_stored?(exposed_key)
|
|
253
|
+
# The heading calls this a priority order, but a stored credential sits
|
|
254
|
+
# outside it and is used ahead of every config file.
|
|
255
|
+
locations << "Set in the credential store, which is used ahead of the config files"
|
|
256
|
+
end
|
|
257
|
+
|
|
222
258
|
if value = @global_config[key]
|
|
223
259
|
locations << "Set for the current user (#{global_config_file}): #{printable_value(value, exposed_key).inspect}"
|
|
224
260
|
end
|
|
225
261
|
|
|
262
|
+
# The gemrc cooldown sits outside the priority order too. It is not one
|
|
263
|
+
# of the layers, it raises whatever they resolve to. See #cooldown_for.
|
|
264
|
+
if key == key_for(:cooldown) && (days = gemrc_cooldown_days)
|
|
265
|
+
line = "Set in the RubyGems configuration as `:cooldown:`: #{days}"
|
|
266
|
+
line += ". The longer of that and the top value applies" unless locations.empty?
|
|
267
|
+
locations << line
|
|
268
|
+
end
|
|
269
|
+
|
|
226
270
|
return ["You have not configured a value for `#{exposed_key}`"] if locations.empty?
|
|
227
271
|
locations
|
|
228
272
|
end
|
|
229
273
|
|
|
274
|
+
##
|
|
275
|
+
# True when +name+ has a configured value Settings#[] cannot see. A
|
|
276
|
+
# credential in the store is one, and so is the RubyGems `:cooldown:`
|
|
277
|
+
# setting that #cooldown_for raises the config layers to.
|
|
278
|
+
|
|
279
|
+
def stored_outside_config_files?(name)
|
|
280
|
+
credential_stored?(name) || (key_for(name) == key_for(:cooldown) && !gemrc_cooldown_days.nil?)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
##
|
|
284
|
+
# True when +name+'s credential lives in the credential store. The secret
|
|
285
|
+
# itself is never returned: callers only need to know the setting exists,
|
|
286
|
+
# since Settings#[] cannot see past the config files.
|
|
287
|
+
|
|
288
|
+
def credential_stored?(name)
|
|
289
|
+
raw_key = self.class.key_to_s(name)
|
|
290
|
+
return false unless credential_store_key?(raw_key)
|
|
291
|
+
return false unless store = active_credential_store(credential_host(raw_key))
|
|
292
|
+
|
|
293
|
+
!store.get(credential_account(raw_key)).nil?
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
##
|
|
297
|
+
# The keys credentials are stored under, in the same encoding the config
|
|
298
|
+
# hashes use, so #all can fold them in. Empty when no store is enabled or
|
|
299
|
+
# when the backend cannot enumerate its entries, which is why
|
|
300
|
+
# bundle-config(1) warns that a third-party backend may not list.
|
|
301
|
+
|
|
302
|
+
def stored_credential_keys
|
|
303
|
+
return [] unless store = active_credential_store
|
|
304
|
+
|
|
305
|
+
Array(store.list)
|
|
306
|
+
end
|
|
307
|
+
|
|
230
308
|
def processor_count
|
|
231
309
|
require "etc"
|
|
232
310
|
Etc.nprocessors
|
|
@@ -309,6 +387,50 @@ module Bundler
|
|
|
309
387
|
self[:jobs] || processor_count
|
|
310
388
|
end
|
|
311
389
|
|
|
390
|
+
##
|
|
391
|
+
# The cooldown that applies to a source whose Gemfile declaration asks for
|
|
392
|
+
# +source_cooldown+ days.
|
|
393
|
+
#
|
|
394
|
+
# `--cooldown` is set as a command line option, and it wins outright so
|
|
395
|
+
# that `--cooldown 0` bypasses the cooldown however the two tools are
|
|
396
|
+
# configured. Otherwise this setting, or the per-source value when this
|
|
397
|
+
# setting is unset, is raised to RubyGems' own `:cooldown:` setting, so a
|
|
398
|
+
# cooldown configured for only one of the two tools covers both.
|
|
399
|
+
|
|
400
|
+
def cooldown_for(source_cooldown = nil)
|
|
401
|
+
command_line = @temporary[key_for(:cooldown)]
|
|
402
|
+
return converted_value(command_line, :cooldown) unless command_line.nil?
|
|
403
|
+
|
|
404
|
+
# Read raw rather than through #[], whose `to_i` would turn a value that
|
|
405
|
+
# is not a number into a 0 that suppresses `source_cooldown`.
|
|
406
|
+
configured = cooldown_settings.days(configured_value(:cooldown))
|
|
407
|
+
|
|
408
|
+
cooldown_settings.combine(configured || source_cooldown, rubygems_cooldown)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
##
|
|
412
|
+
# RubyGems' `:cooldown:` gemrc setting, read from the loaded gemrc rather
|
|
413
|
+
# than from `Gem.configuration.cooldown`, which only exists on RubyGems
|
|
414
|
+
# versions that know the setting. A value assigned to that accessor from
|
|
415
|
+
# Ruby after startup is therefore not seen here.
|
|
416
|
+
#
|
|
417
|
+
# Reading it builds Gem::ConfigFile, which costs a command that never
|
|
418
|
+
# resolves against a remote around 30ms it has no use for, so the setting
|
|
419
|
+
# is validated here, at the point of use, rather than when the command
|
|
420
|
+
# starts.
|
|
421
|
+
|
|
422
|
+
def rubygems_cooldown
|
|
423
|
+
return @rubygems_cooldown if defined?(@rubygems_cooldown)
|
|
424
|
+
|
|
425
|
+
@rubygems_cooldown = gemrc_cooldown
|
|
426
|
+
|
|
427
|
+
if cooldown_settings.invalid?(@rubygems_cooldown)
|
|
428
|
+
Bundler.ui.warn cooldown_settings.invalid_message(@rubygems_cooldown, "the gemrc file")
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
@rubygems_cooldown
|
|
432
|
+
end
|
|
433
|
+
|
|
312
434
|
def validate!
|
|
313
435
|
all.each do |raw_key|
|
|
314
436
|
[@local_config, @env_config, @global_config].each do |settings|
|
|
@@ -324,6 +446,27 @@ module Bundler
|
|
|
324
446
|
|
|
325
447
|
private
|
|
326
448
|
|
|
449
|
+
def cooldown_settings
|
|
450
|
+
require "rubygems/cooldown_settings"
|
|
451
|
+
Gem::CooldownSettings
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# Scanned rather than looked up, because ConfigFile#[] stringifies the key
|
|
455
|
+
# on RubyGems 3.4 and a `:cooldown:` gemrc entry is stored under a Symbol.
|
|
456
|
+
|
|
457
|
+
def gemrc_cooldown
|
|
458
|
+
Gem.configuration.each {|key, value| return value if key.to_s == "cooldown" }
|
|
459
|
+
nil
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
# The gemrc cooldown as a usable number of days, or nil. A value that is
|
|
463
|
+
# not one takes no part in the resolution, so nothing reports it as
|
|
464
|
+
# configured either.
|
|
465
|
+
|
|
466
|
+
def gemrc_cooldown_days
|
|
467
|
+
cooldown_settings.days(rubygems_cooldown)
|
|
468
|
+
end
|
|
469
|
+
|
|
327
470
|
def configs
|
|
328
471
|
@configs ||= {
|
|
329
472
|
temporary: @temporary,
|
|
@@ -338,12 +481,37 @@ module Bundler
|
|
|
338
481
|
converted_value(config[key_for(name)], name)
|
|
339
482
|
end
|
|
340
483
|
|
|
341
|
-
|
|
342
|
-
|
|
484
|
+
##
|
|
485
|
+
# A renamed setting is resolved one level at a time rather than by looking
|
|
486
|
+
# for the current name everywhere first, so that the old name keeps the
|
|
487
|
+
# documented priority order: an old name set locally still beats a current
|
|
488
|
+
# name set globally.
|
|
489
|
+
|
|
490
|
+
def configured_value(name)
|
|
491
|
+
key = key_for(name)
|
|
492
|
+
old_name = RENAMED_KEYS[self.class.key_to_s(name)]
|
|
493
|
+
old_key = key_for(old_name) if old_name
|
|
494
|
+
|
|
495
|
+
configs.each do |_, config|
|
|
496
|
+
value = config[key]
|
|
497
|
+
return value unless value.nil?
|
|
498
|
+
|
|
499
|
+
next if old_key.nil?
|
|
500
|
+
|
|
501
|
+
value = config[old_key]
|
|
502
|
+
next if value.nil?
|
|
503
|
+
|
|
504
|
+
SharedHelpers.feature_deprecated! "The `#{old_name}` setting has been renamed to `#{name}` and will be " \
|
|
505
|
+
"removed in Bundler 5. Use `#{name}` instead."
|
|
506
|
+
|
|
507
|
+
return value
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
nil
|
|
343
511
|
end
|
|
344
512
|
|
|
345
|
-
def
|
|
346
|
-
split_specific_setting_for(name)[
|
|
513
|
+
def parent_setting_for(name)
|
|
514
|
+
split_specific_setting_for(name)[0]
|
|
347
515
|
end
|
|
348
516
|
|
|
349
517
|
def split_specific_setting_for(name)
|
|
@@ -357,18 +525,11 @@ module Bundler
|
|
|
357
525
|
|
|
358
526
|
def is_string(name)
|
|
359
527
|
name = self.class.key_to_s(name)
|
|
360
|
-
STRING_KEYS.include?(name) || name.start_with?("local.") || name.start_with?("mirror.") || name.start_with?("build.")
|
|
528
|
+
STRING_KEYS.include?(name) || name.start_with?("local.") || name.start_with?("mirror.") || name.start_with?("build.") || name.start_with?("credential_store.")
|
|
361
529
|
end
|
|
362
530
|
|
|
363
531
|
def to_bool(value)
|
|
364
|
-
|
|
365
|
-
when String
|
|
366
|
-
value.match?(/\A(false|f|no|n|0|)\z/i) ? false : true
|
|
367
|
-
when nil, false
|
|
368
|
-
false
|
|
369
|
-
else
|
|
370
|
-
true
|
|
371
|
-
end
|
|
532
|
+
self.class.to_bool(value)
|
|
372
533
|
end
|
|
373
534
|
|
|
374
535
|
def is_num(key)
|
|
@@ -387,6 +548,145 @@ module Bundler
|
|
|
387
548
|
value.include?(":")
|
|
388
549
|
end
|
|
389
550
|
|
|
551
|
+
# Kept separate from RubyGems so gem signout does not remove Bundler's
|
|
552
|
+
# host credentials.
|
|
553
|
+
CREDENTIAL_STORE_SERVICE = "bundler"
|
|
554
|
+
|
|
555
|
+
##
|
|
556
|
+
# The Gem::CredentialStore for the spec #credential_store_spec returns,
|
|
557
|
+
# or nil when the setting is off or this RubyGems has no credential store.
|
|
558
|
+
# Guarded by a cheap lookup so reading and writing settings costs nothing
|
|
559
|
+
# extra when the setting is disabled.
|
|
560
|
+
|
|
561
|
+
def active_credential_store(host = nil)
|
|
562
|
+
spec = credential_store_spec(host)
|
|
563
|
+
return nil unless spec
|
|
564
|
+
|
|
565
|
+
store_class = credential_store_class
|
|
566
|
+
return nil unless store_class
|
|
567
|
+
|
|
568
|
+
store_class.for(spec, service: CREDENTIAL_STORE_SERVICE)
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
# A `credential_store.<host>` setting overrides the global one for that
|
|
572
|
+
# host only. There is no chain between backends.
|
|
573
|
+
def credential_store_spec(host = nil)
|
|
574
|
+
value = self["credential_store.#{host}"] if host
|
|
575
|
+
value = self[:credential_store] if value.nil?
|
|
576
|
+
|
|
577
|
+
# An environment variable can carry bytes String#downcase would reject.
|
|
578
|
+
normalized = value.to_s.b.downcase
|
|
579
|
+
|
|
580
|
+
# Tri-state, unlike a BOOL_KEYS setting, so #to_bool is only consulted
|
|
581
|
+
# for the false half.
|
|
582
|
+
return nil unless to_bool(normalized)
|
|
583
|
+
|
|
584
|
+
case normalized
|
|
585
|
+
when "true", "1", "yes", "on", "t", "y" then true
|
|
586
|
+
else value.to_s
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def credential_store_class
|
|
591
|
+
return @credential_store_class if defined?(@credential_store_class)
|
|
592
|
+
|
|
593
|
+
@credential_store_class =
|
|
594
|
+
begin
|
|
595
|
+
require "rubygems/credential_store"
|
|
596
|
+
Gem::CredentialStore if Gem::CredentialStore.respond_to?(:for)
|
|
597
|
+
rescue LoadError
|
|
598
|
+
nil
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
if @credential_store_class.nil?
|
|
602
|
+
Bundler.ui.warn "The `credential_store` setting is set but this RubyGems does not provide a credential store. Falling back to the Bundler config file."
|
|
603
|
+
elsif @credential_store_class.respond_to?(:warn_handler=)
|
|
604
|
+
# Bundler replaces Gem.ui with a Gem::SilentUI subclass, which drops
|
|
605
|
+
# alert_warning, so every store warning would be lost.
|
|
606
|
+
@credential_store_class.warn_handler = ->(message) { Bundler.ui.warn(message) }
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
@credential_store_class
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
CREDENTIAL_URL_KEY = %r{\Ahttps?://}i
|
|
613
|
+
CREDENTIAL_HOST_KEY = /\A[a-z0-9-]+(\.[a-z0-9-]+)+(:\d+)?\z/i
|
|
614
|
+
|
|
615
|
+
##
|
|
616
|
+
# True for keys that name a host and can therefore hold a credential,
|
|
617
|
+
# like the ones set via `bundle config set gems.example.com user:pass`.
|
|
618
|
+
# Deliberately a positive test: a key this version does not recognize
|
|
619
|
+
# stays in the config file, where Settings#[] can read it back. Matching
|
|
620
|
+
# everything not on the known-settings lists would send values such as
|
|
621
|
+
# `ssl_client_cert` to the credential store, and they would then read
|
|
622
|
+
# back as nil because only #credentials_for consults the store.
|
|
623
|
+
|
|
624
|
+
def credential_store_key?(raw_key)
|
|
625
|
+
return false if is_bool(raw_key) || is_num(raw_key) || is_array(raw_key) || is_string(raw_key) || is_credential(raw_key)
|
|
626
|
+
|
|
627
|
+
CREDENTIAL_URL_KEY.match?(raw_key) || CREDENTIAL_HOST_KEY.match?(raw_key)
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
def remove_from_store(store, key)
|
|
631
|
+
unless store.available?
|
|
632
|
+
Bundler.ui.warn "The credential store is enabled but unavailable, so any credential it holds was left in place."
|
|
633
|
+
return true
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
store.delete(key)
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
# A write clears the plaintext only from the config file it targets, so a
|
|
640
|
+
# copy in the other scope comes back into use once the setting is off.
|
|
641
|
+
def warn_plaintext_in_other_scope(raw_key, key, hash)
|
|
642
|
+
other, other_file =
|
|
643
|
+
if hash.equal?(@local_config)
|
|
644
|
+
[@global_config, global_config_file]
|
|
645
|
+
else
|
|
646
|
+
[@local_config, @local_root.join("config")]
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
return unless other.key?(key)
|
|
650
|
+
|
|
651
|
+
# Deliberately not `bundle config unset`, which would clear the store as
|
|
652
|
+
# well and throw away the credential this write moved into it.
|
|
653
|
+
safe_key = self.class.remove_userinfo(raw_key)
|
|
654
|
+
Bundler.ui.warn "The credential for #{safe_key} moved into the credential store, but a plain text copy" \
|
|
655
|
+
" remains in #{other_file}. Delete the #{key_for(safe_key)} entry from that file to finish the move."
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
def warn_unremoved_credential(raw_key)
|
|
659
|
+
Bundler.ui.warn "Could not remove the credential for #{self.class.remove_userinfo(raw_key)} from the credential store." \
|
|
660
|
+
" It is still there. Remove it with your platform's credential manager."
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
# See Gem::ConfigFile.credential_store_account for why userinfo is dropped.
|
|
664
|
+
def credential_account(raw_key)
|
|
665
|
+
key_for(self.class.remove_userinfo(raw_key))
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
def credential_host(raw_key)
|
|
669
|
+
return raw_key unless CREDENTIAL_URL_KEY.match?(raw_key)
|
|
670
|
+
|
|
671
|
+
require_relative "vendored_uri"
|
|
672
|
+
Gem::URI(raw_key).host || raw_key
|
|
673
|
+
rescue Gem::URI::Error
|
|
674
|
+
raw_key
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
# The store stands in for the config file, so it must not override the
|
|
678
|
+
# environment, which already overrides that file. Consulted only when the
|
|
679
|
+
# store answered, so the layer order without a store is unchanged.
|
|
680
|
+
def credentials_from_env(uri)
|
|
681
|
+
@env_config[key_for(uri.to_s)] || @env_config[key_for(uri.host)]
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
def credentials_from_store(uri)
|
|
685
|
+
return nil unless store = active_credential_store(uri.host)
|
|
686
|
+
|
|
687
|
+
store.get(credential_account(uri.to_s)) || store.get(credential_account(uri.host))
|
|
688
|
+
end
|
|
689
|
+
|
|
390
690
|
def to_array(value)
|
|
391
691
|
return [] unless value
|
|
392
692
|
value.tr(" ", ":").split(":").map(&:to_sym)
|
|
@@ -400,9 +700,29 @@ module Bundler
|
|
|
400
700
|
|
|
401
701
|
def set_key(raw_key, value, hash, file)
|
|
402
702
|
raw_key = self.class.key_to_s(raw_key)
|
|
403
|
-
value = array_to_s(value) if is_array(raw_key)
|
|
404
|
-
|
|
405
703
|
key = key_for(raw_key)
|
|
704
|
+
account = credential_account(raw_key)
|
|
705
|
+
|
|
706
|
+
# #temporary passes a nil file, and storing its value would outlive the
|
|
707
|
+
# block while its restore pass deleted the real entry.
|
|
708
|
+
if file && credential_store_key?(raw_key) && (store = active_credential_store(credential_host(raw_key)))
|
|
709
|
+
if value.nil?
|
|
710
|
+
warn_unremoved_credential(raw_key) unless remove_from_store(store, account)
|
|
711
|
+
elsif value.is_a?(String) && is_userinfo(value)
|
|
712
|
+
if store.set(account, value)
|
|
713
|
+
value = nil
|
|
714
|
+
warn_plaintext_in_other_scope(raw_key, key, hash)
|
|
715
|
+
else
|
|
716
|
+
warn_unremoved_credential(raw_key) if store.available? && !store.delete(account)
|
|
717
|
+
Bundler.ui.warn "Could not write the credential for #{self.class.remove_userinfo(raw_key)} to the credential store," \
|
|
718
|
+
" so it was written to #{file} in plain text."
|
|
719
|
+
end
|
|
720
|
+
else
|
|
721
|
+
warn_unremoved_credential(raw_key) unless remove_from_store(store, account)
|
|
722
|
+
end
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
value = array_to_s(value) if is_array(raw_key)
|
|
406
726
|
|
|
407
727
|
return if hash[key] == value
|
|
408
728
|
|
|
@@ -482,7 +802,7 @@ module Bundler
|
|
|
482
802
|
SharedHelpers.filesystem_access(config_file, :read) do |file|
|
|
483
803
|
valid_file = file.exist? && !file.size.zero?
|
|
484
804
|
return {} unless valid_file
|
|
485
|
-
serializer_class.load(file.read).inject({}) do |config, (k, v)|
|
|
805
|
+
(serializer_class.load(file.read) || {}).inject({}) do |config, (k, v)|
|
|
486
806
|
k = k.dup
|
|
487
807
|
k << "/" if /https?:/i.match?(k) && !k.end_with?("/", "__#{FALLBACK_TIMEOUT_URI_OPTION.upcase}")
|
|
488
808
|
k.gsub!(".", "__")
|
|
@@ -506,12 +826,10 @@ module Bundler
|
|
|
506
826
|
end
|
|
507
827
|
|
|
508
828
|
def serializer_class
|
|
829
|
+
# The Bundler gem ships its own copy of Gem::YAMLSerializer, so this
|
|
830
|
+
# resolves even on RubyGems versions that predate it.
|
|
509
831
|
require "rubygems/yaml_serializer"
|
|
510
832
|
Gem::YAMLSerializer
|
|
511
|
-
rescue LoadError
|
|
512
|
-
# TODO: Remove this when RubyGems 3.4 is EOL
|
|
513
|
-
require_relative "yaml_serializer"
|
|
514
|
-
YAMLSerializer
|
|
515
833
|
end
|
|
516
834
|
|
|
517
835
|
FALLBACK_TIMEOUT_URI_OPTION = "fallback_timeout"
|
|
@@ -525,6 +843,17 @@ module Bundler
|
|
|
525
843
|
\z
|
|
526
844
|
/ix
|
|
527
845
|
|
|
846
|
+
def self.to_bool(value)
|
|
847
|
+
case value
|
|
848
|
+
when String
|
|
849
|
+
value.match?(/\A(false|f|no|n|0|)\z/i) ? false : true
|
|
850
|
+
when nil, false
|
|
851
|
+
false
|
|
852
|
+
else
|
|
853
|
+
true
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
|
|
528
857
|
def self.key_for(key)
|
|
529
858
|
key = key_to_s(key)
|
|
530
859
|
key = normalize_uri(key) if key.start_with?("http", "mirror.http")
|
|
@@ -535,6 +864,20 @@ module Bundler
|
|
|
535
864
|
key.gsub(/\A([ #]*)/, '\1BUNDLE_')
|
|
536
865
|
end
|
|
537
866
|
|
|
867
|
+
def self.remove_userinfo(key)
|
|
868
|
+
return key unless CREDENTIAL_URL_KEY.match?(key)
|
|
869
|
+
|
|
870
|
+
require_relative "vendored_uri"
|
|
871
|
+
uri = Gem::URI(key)
|
|
872
|
+
return key unless uri.userinfo
|
|
873
|
+
|
|
874
|
+
uri = uri.dup
|
|
875
|
+
uri.user = uri.password = nil
|
|
876
|
+
uri.to_s
|
|
877
|
+
rescue Gem::URI::Error
|
|
878
|
+
key
|
|
879
|
+
end
|
|
880
|
+
|
|
538
881
|
# TODO: duplicates Rubygems#normalize_uri
|
|
539
882
|
# TODO: is this the correct place to validate mirror URIs?
|
|
540
883
|
def self.normalize_uri(uri)
|
|
@@ -105,7 +105,8 @@ module Bundler
|
|
|
105
105
|
def filesystem_access(path, action = :write, &block)
|
|
106
106
|
yield(path.dup)
|
|
107
107
|
rescue Errno::EACCES => e
|
|
108
|
-
|
|
108
|
+
path_basename = File.basename(path.to_s)
|
|
109
|
+
raise unless e.message.include?(path_basename) || action == :create
|
|
109
110
|
|
|
110
111
|
raise PermissionError.new(path, action)
|
|
111
112
|
rescue Errno::EAGAIN
|