bundler 4.0.22 → 4.1.0.beta2
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 +41 -1
- data/lib/bundler/cli/config.rb +4 -2
- data/lib/bundler/cli/doctor/ssl.rb +4 -8
- data/lib/bundler/cli/gem.rb +0 -17
- data/lib/bundler/cli/info.rb +1 -1
- data/lib/bundler/cli/install.rb +4 -5
- data/lib/bundler/cli/lock.rb +15 -5
- data/lib/bundler/cli/open.rb +7 -1
- data/lib/bundler/cli/outdated.rb +16 -13
- data/lib/bundler/cli/pristine.rb +2 -1
- data/lib/bundler/cli/show.rb +5 -1
- data/lib/bundler/cli/update.rb +20 -11
- data/lib/bundler/cli.rb +15 -9
- data/lib/bundler/constants.rb +1 -1
- data/lib/bundler/definition.rb +102 -15
- data/lib/bundler/dependency.rb +4 -0
- data/lib/bundler/dsl.rb +137 -13
- 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 +35 -16
- data/lib/bundler/fetcher.rb +8 -47
- data/lib/bundler/gem_helper.rb +1 -1
- data/lib/bundler/injector.rb +3 -3
- data/lib/bundler/inline.rb +44 -4
- data/lib/bundler/installer/parallel_installer.rb +27 -31
- data/lib/bundler/installer.rb +21 -7
- data/lib/bundler/lazy_specification.rb +45 -18
- data/lib/bundler/lockfile_generator.rb +24 -2
- data/lib/bundler/lockfile_parser.rb +44 -6
- 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 +5 -2
- data/lib/bundler/man/bundle-info.1.ronn +4 -0
- 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 +2 -2
- data/lib/bundler/man/bundle-lock.1.ronn +3 -2
- data/lib/bundler/man/bundle-open.1 +5 -2
- data/lib/bundler/man/bundle-open.1.ronn +4 -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 +5 -2
- data/lib/bundler/man/bundle-show.1.ronn +4 -0
- data/lib/bundler/man/bundle-update.1 +2 -2
- data/lib/bundler/man/bundle-update.1.ronn +2 -2
- data/lib/bundler/man/bundle-version.1 +1 -1
- data/lib/bundler/man/bundle.1 +1 -1
- data/lib/bundler/man/gemfile.5 +77 -1
- data/lib/bundler/man/gemfile.5.ronn +104 -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 +5 -2
- data/lib/bundler/override.rb +97 -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 +97 -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/settings.rb +383 -56
- data/lib/bundler/shared_helpers.rb +2 -1
- data/lib/bundler/source/git/git_proxy.rb +31 -2
- data/lib/bundler/source/git.rb +49 -13
- 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/source/rubygems_aggregate.rb +1 -1
- data/lib/bundler/source_map.rb +7 -3
- data/lib/bundler/spec_set.rb +23 -7
- 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 +90 -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 +391 -381
- data/CHANGELOG.md +0 -5801
- 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/source/git.rb
CHANGED
|
@@ -7,12 +7,13 @@ module Bundler
|
|
|
7
7
|
class Git < Path
|
|
8
8
|
autoload :GitProxy, File.expand_path("git/git_proxy", __dir__)
|
|
9
9
|
|
|
10
|
-
attr_reader :uri, :ref, :branch, :options, :glob, :submodules
|
|
10
|
+
attr_reader :uri, :ref, :branch, :options, :glob, :submodules, :sparse_checkout
|
|
11
11
|
|
|
12
12
|
def initialize(options)
|
|
13
13
|
@options = options
|
|
14
14
|
@checksum_store = Checksum::Store.new
|
|
15
|
-
@
|
|
15
|
+
@sparse_checkout = normalize_sparse_checkout(options)
|
|
16
|
+
@glob = options["glob"] || sparse_checkout_glob || DEFAULT_GLOB
|
|
16
17
|
|
|
17
18
|
@allow_cached = false
|
|
18
19
|
@allow_remote = false
|
|
@@ -30,6 +31,7 @@ module Bundler
|
|
|
30
31
|
|
|
31
32
|
@copied = false
|
|
32
33
|
@local = false
|
|
34
|
+
@cached_app_cache_path = nil
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def remote!
|
|
@@ -57,12 +59,13 @@ module Bundler
|
|
|
57
59
|
%w[ref branch tag submodules].each do |opt|
|
|
58
60
|
out << " #{opt}: #{options[opt]}\n" if options[opt]
|
|
59
61
|
end
|
|
62
|
+
@sparse_checkout&.each {|dir| out << " sparse_checkout: #{dir}\n" }
|
|
60
63
|
out << " glob: #{@glob}\n" unless default_glob?
|
|
61
64
|
out << " specs:\n"
|
|
62
65
|
end
|
|
63
66
|
|
|
64
67
|
def to_gemfile
|
|
65
|
-
specifiers = %w[ref branch tag submodules glob].map do |opt|
|
|
68
|
+
specifiers = %w[ref branch tag submodules glob sparse_checkout].map do |opt|
|
|
66
69
|
"#{opt}: #{options[opt]}" if options[opt]
|
|
67
70
|
end
|
|
68
71
|
|
|
@@ -70,14 +73,15 @@ module Bundler
|
|
|
70
73
|
end
|
|
71
74
|
|
|
72
75
|
def hash
|
|
73
|
-
[self.class, uri, ref, branch, name, glob, submodules].hash
|
|
76
|
+
[self.class, uri, ref, branch, name, glob, submodules, sparse_checkout].hash
|
|
74
77
|
end
|
|
75
78
|
|
|
76
79
|
def eql?(other)
|
|
77
80
|
other.is_a?(Git) && uri == other.uri && ref == other.ref &&
|
|
78
81
|
branch == other.branch && name == other.name &&
|
|
79
82
|
glob == other.glob &&
|
|
80
|
-
submodules == other.submodules
|
|
83
|
+
submodules == other.submodules &&
|
|
84
|
+
sparse_checkout == other.sparse_checkout
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
alias_method :==, :eql?
|
|
@@ -86,7 +90,8 @@ module Bundler
|
|
|
86
90
|
other.is_a?(Git) && uri == other.uri &&
|
|
87
91
|
name == other.name &&
|
|
88
92
|
glob == other.glob &&
|
|
89
|
-
submodules == other.submodules
|
|
93
|
+
submodules == other.submodules &&
|
|
94
|
+
sparse_checkout == other.sparse_checkout
|
|
90
95
|
end
|
|
91
96
|
|
|
92
97
|
def to_s
|
|
@@ -191,8 +196,13 @@ module Bundler
|
|
|
191
196
|
set_cache_path!(app_cache_path) if use_app_cache?
|
|
192
197
|
|
|
193
198
|
if requires_checkout? && !@copied
|
|
194
|
-
|
|
195
|
-
|
|
199
|
+
Plugin.hook(Plugin::Events::GIT_BEFORE_FETCH, self)
|
|
200
|
+
begin
|
|
201
|
+
fetch unless use_app_cache?
|
|
202
|
+
checkout
|
|
203
|
+
ensure
|
|
204
|
+
Plugin.hook(Plugin::Events::GIT_AFTER_FETCH, self)
|
|
205
|
+
end
|
|
196
206
|
end
|
|
197
207
|
|
|
198
208
|
local_specs
|
|
@@ -272,6 +282,11 @@ module Bundler
|
|
|
272
282
|
|
|
273
283
|
app_cache_path = app_cache_path(custom_path)
|
|
274
284
|
|
|
285
|
+
# When several gems share a single git source, this is called once per
|
|
286
|
+
# gem. Copying the repository is expensive for large repos, so skip it
|
|
287
|
+
# if we already populated this cache during the same command.
|
|
288
|
+
return if @cached_app_cache_path == app_cache_path
|
|
289
|
+
|
|
275
290
|
migrate = try_migrate ? bare_repo?(app_cache_path) : false
|
|
276
291
|
|
|
277
292
|
set_cache_path!(nil) if migrate
|
|
@@ -283,6 +298,8 @@ module Bundler
|
|
|
283
298
|
git_proxy.checkout if migrate || requires_checkout?
|
|
284
299
|
git_proxy.copy_to(app_cache_path, @submodules)
|
|
285
300
|
serialize_gemspecs_in(app_cache_path)
|
|
301
|
+
|
|
302
|
+
@cached_app_cache_path = app_cache_path
|
|
286
303
|
end
|
|
287
304
|
|
|
288
305
|
def checkout
|
|
@@ -376,7 +393,30 @@ module Bundler
|
|
|
376
393
|
end
|
|
377
394
|
|
|
378
395
|
def shortref_for_path(ref)
|
|
379
|
-
ref[0..11]
|
|
396
|
+
shortref = ref[0..11]
|
|
397
|
+
return shortref unless @sparse_checkout
|
|
398
|
+
|
|
399
|
+
# Checkouts of the same revision with different cones hold different files
|
|
400
|
+
"#{shortref}-#{Bundler::Digest.sha1(@sparse_checkout.join("\n"))[0..7]}"
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def normalize_sparse_checkout(options)
|
|
404
|
+
return unless options["sparse_checkout"]
|
|
405
|
+
|
|
406
|
+
dirs = Array(options["sparse_checkout"])
|
|
407
|
+
unless dirs.any? && dirs.all? {|dir| dir.is_a?(String) && !dir.empty? }
|
|
408
|
+
raise GemfileError, "The :sparse_checkout option must be a directory or an array of directories, " \
|
|
409
|
+
"but #{options["sparse_checkout"].inspect} was given"
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
options["sparse_checkout"] = dirs
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def sparse_checkout_glob
|
|
416
|
+
return unless @sparse_checkout
|
|
417
|
+
|
|
418
|
+
dirs = @sparse_checkout.size == 1 ? @sparse_checkout.first : "{#{@sparse_checkout.join(",")}}"
|
|
419
|
+
"#{dirs}/#{DEFAULT_GLOB}"
|
|
380
420
|
end
|
|
381
421
|
|
|
382
422
|
def glob_for_display
|
|
@@ -405,10 +445,6 @@ module Bundler
|
|
|
405
445
|
options["revision"]
|
|
406
446
|
end
|
|
407
447
|
|
|
408
|
-
def cached?
|
|
409
|
-
cache_path.exist?
|
|
410
|
-
end
|
|
411
|
-
|
|
412
448
|
def git_proxy
|
|
413
449
|
@git_proxy ||= GitProxy.new(cache_path, uri, options, locked_revision, self)
|
|
414
450
|
end
|
|
@@ -18,12 +18,17 @@ module Bundler
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
# Returns the cooldown days that apply to this remote, resolving the
|
|
21
|
-
# precedence CLI > config > Gemfile per-source
|
|
22
|
-
# cooldown applies.
|
|
21
|
+
# precedence CLI > config > Gemfile per-source and then raising the
|
|
22
|
+
# result to RubyGems' own setting. Returns nil if no cooldown applies.
|
|
23
|
+
#
|
|
24
|
+
# The resolver asks once per candidate spec, so the settings lookup is
|
|
25
|
+
# memoized. That snapshots the value: a Remote created before a
|
|
26
|
+
# settings change keeps the old one. Nothing in Bundler changes the
|
|
27
|
+
# cooldown setting after the sources are built (the CLI flag is applied
|
|
28
|
+
# before the Definition exists), so build a new Remote if you need to.
|
|
23
29
|
def effective_cooldown
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@cooldown
|
|
30
|
+
return @effective_cooldown if defined?(@effective_cooldown)
|
|
31
|
+
@effective_cooldown = Bundler.settings.cooldown_for(@cooldown)
|
|
27
32
|
end
|
|
28
33
|
|
|
29
34
|
MAX_CACHE_SLUG_HOST_SIZE = 255 - 1 - 32 # 255 minus dot minus MD5 length
|
|
@@ -25,6 +25,7 @@ module Bundler
|
|
|
25
25
|
@checksum_store = Checksum::Store.new
|
|
26
26
|
@gem_installers = {}
|
|
27
27
|
@gem_installers_mutex = Mutex.new
|
|
28
|
+
@remote_spec_for_mutex = Mutex.new
|
|
28
29
|
@remote_specs_mutex = Mutex.new
|
|
29
30
|
|
|
30
31
|
cooldown = options["cooldown"]
|
|
@@ -196,6 +197,8 @@ module Bundler
|
|
|
196
197
|
"the security policy didn't allow it, with the message: #{e.message}"
|
|
197
198
|
end
|
|
198
199
|
|
|
200
|
+
s.content_address = spec.content_address if spec.content_address
|
|
201
|
+
|
|
199
202
|
spec.__swap__(s)
|
|
200
203
|
end
|
|
201
204
|
|
|
@@ -230,8 +233,12 @@ module Bundler
|
|
|
230
233
|
spec.post_install_message
|
|
231
234
|
end
|
|
232
235
|
|
|
236
|
+
def uncached?(spec)
|
|
237
|
+
caches.none? {|cache| File.exist?(package_path(cache, spec)) }
|
|
238
|
+
end
|
|
239
|
+
|
|
233
240
|
def cache(spec, custom_path = nil)
|
|
234
|
-
cached_path =
|
|
241
|
+
cached_path = fetch_gem_if_possible(spec)
|
|
235
242
|
raise GemNotFound, "Missing gem file '#{spec.file_name}'." unless cached_path
|
|
236
243
|
return if File.dirname(cached_path) == Bundler.app_cache.to_s
|
|
237
244
|
Bundler.ui.info " * #{File.basename(cached_path)}"
|
|
@@ -437,12 +444,14 @@ module Bundler
|
|
|
437
444
|
# Looks up a single spec in the remote sources, fetching only its own
|
|
438
445
|
# name when the full remote index is not already materialized.
|
|
439
446
|
def remote_spec_for(spec)
|
|
440
|
-
|
|
447
|
+
@remote_spec_for_mutex.synchronize do
|
|
448
|
+
return remote_specs.search(spec).first if @remote_specs || api_fetchers.empty?
|
|
441
449
|
|
|
442
|
-
|
|
443
|
-
|
|
450
|
+
index = Index.build do |idx|
|
|
451
|
+
fetch_names(api_fetchers, [spec.name], idx)
|
|
452
|
+
end
|
|
453
|
+
index.search(spec).first
|
|
444
454
|
end
|
|
445
|
-
index.search(spec).first
|
|
446
455
|
end
|
|
447
456
|
|
|
448
457
|
def fetch_names(fetchers, dependency_names, index)
|
|
@@ -462,10 +471,24 @@ module Bundler
|
|
|
462
471
|
if spec.remote
|
|
463
472
|
fetch_gem(spec, previous_spec)
|
|
464
473
|
else
|
|
465
|
-
cached_gem(spec)
|
|
474
|
+
cached_gem(spec) || refetch_gem(spec, previous_spec)
|
|
466
475
|
end
|
|
467
476
|
end
|
|
468
477
|
|
|
478
|
+
# An installed gem materializes without a remote, so a reinstall forced by
|
|
479
|
+
# `--redownload` has to look the gem up in the remote index again before it
|
|
480
|
+
# can download the archive that the cache no longer holds.
|
|
481
|
+
def refetch_gem(spec, previous_spec = nil)
|
|
482
|
+
return unless @allow_remote
|
|
483
|
+
|
|
484
|
+
remote_spec = remote_spec_for(spec)
|
|
485
|
+
return unless remote_spec && remote_spec.full_name == spec.full_name
|
|
486
|
+
|
|
487
|
+
path = fetch_gem(remote_spec, previous_spec)
|
|
488
|
+
spec.remote = remote_spec.remote
|
|
489
|
+
path
|
|
490
|
+
end
|
|
491
|
+
|
|
469
492
|
def fetch_gem(spec, previous_spec = nil)
|
|
470
493
|
spec.fetch_platform
|
|
471
494
|
|
|
@@ -545,8 +568,13 @@ module Bundler
|
|
|
545
568
|
Bundler.ui.confirm("Fetching #{version_message(spec, previous_spec)}")
|
|
546
569
|
gem_remote_fetcher = remote_fetchers.fetch(spec.remote).gem_remote_fetcher
|
|
547
570
|
|
|
548
|
-
|
|
549
|
-
|
|
571
|
+
Plugin.hook(Plugin::Events::GEM_BEFORE_FETCH, spec)
|
|
572
|
+
begin
|
|
573
|
+
Gem.time("Downloaded #{spec.name} in", 0, true) do
|
|
574
|
+
Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher)
|
|
575
|
+
end
|
|
576
|
+
ensure
|
|
577
|
+
Plugin.hook(Plugin::Events::GEM_AFTER_FETCH, spec)
|
|
550
578
|
end
|
|
551
579
|
end
|
|
552
580
|
|
|
@@ -566,7 +594,12 @@ module Bundler
|
|
|
566
594
|
return unless remote = spec.remote
|
|
567
595
|
return unless cache_slug = remote.cache_slug
|
|
568
596
|
|
|
569
|
-
|
|
597
|
+
if Gem.respond_to?(:global_gem_cache_path)
|
|
598
|
+
Pathname.new(Gem.global_gem_cache_path).join(cache_slug)
|
|
599
|
+
else
|
|
600
|
+
# Fall back to old location for older RubyGems versions
|
|
601
|
+
Bundler.user_cache.join("gems", cache_slug)
|
|
602
|
+
end
|
|
570
603
|
end
|
|
571
604
|
|
|
572
605
|
def extension_cache_slug(spec)
|
|
@@ -574,11 +607,11 @@ module Bundler
|
|
|
574
607
|
remote.cache_slug
|
|
575
608
|
end
|
|
576
609
|
|
|
577
|
-
# We are using a mutex to
|
|
610
|
+
# We are using a mutex to read and write from/to the hash.
|
|
578
611
|
# The reason this double synchronization was added is for performance
|
|
579
612
|
# and to lock the mutex for the shortest possible amount of time. Otherwise,
|
|
580
613
|
# all threads are fighting over this mutex and when it gets acquired it gets locked
|
|
581
|
-
# until a
|
|
614
|
+
# until a thread finishes downloading a gem, leaving the other threads waiting
|
|
582
615
|
# doing nothing.
|
|
583
616
|
def rubygems_gem_installer(spec, options)
|
|
584
617
|
@gem_installers_mutex.synchronize { @gem_installers[spec.name] } || begin
|
|
@@ -589,6 +622,7 @@ module Bundler
|
|
|
589
622
|
|
|
590
623
|
installer = Bundler::RubyGemsGemInstaller.at(
|
|
591
624
|
path,
|
|
625
|
+
content_address: (spec.content_address if Gem::ContentAddress.content_addressed?(spec, validate_ruby_abi: false)),
|
|
592
626
|
security_policy: Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]],
|
|
593
627
|
install_dir: rubygems_dir.to_s,
|
|
594
628
|
bin_dir: Bundler.system_bindir.to_s,
|
|
@@ -596,7 +630,9 @@ module Bundler
|
|
|
596
630
|
wrappers: true,
|
|
597
631
|
env_shebang: true,
|
|
598
632
|
build_args: options[:build_args],
|
|
599
|
-
bundler_extension_cache_path: extension_cache_path(spec)
|
|
633
|
+
bundler_extension_cache_path: extension_cache_path(spec),
|
|
634
|
+
build_extension: Bundler.settings[:no_build_extension] ? false : nil,
|
|
635
|
+
install_plugin: Bundler.settings[:no_install_plugin] ? false : nil
|
|
600
636
|
)
|
|
601
637
|
@gem_installers_mutex.synchronize { @gem_installers[spec.name] ||= installer }
|
|
602
638
|
end
|
|
@@ -29,7 +29,7 @@ module Bundler
|
|
|
29
29
|
|
|
30
30
|
def build_index
|
|
31
31
|
Index.build do |idx|
|
|
32
|
-
dependency_names = source_map.pinned_spec_names
|
|
32
|
+
dependency_names = source_map.pinned_spec_names | source_map.replacement_names
|
|
33
33
|
|
|
34
34
|
sources.all_sources.each do |source|
|
|
35
35
|
next if @excluded_sources.include?(source)
|
data/lib/bundler/source_map.rb
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
module Bundler
|
|
4
4
|
class SourceMap
|
|
5
|
-
attr_reader :sources, :dependencies, :locked_specs
|
|
5
|
+
attr_reader :sources, :dependencies, :locked_specs, :replacement_names
|
|
6
6
|
|
|
7
|
-
def initialize(sources, dependencies, locked_specs)
|
|
7
|
+
def initialize(sources, dependencies, locked_specs, replacement_names = [])
|
|
8
8
|
@sources = sources
|
|
9
9
|
@dependencies = dependencies
|
|
10
10
|
@locked_specs = locked_specs
|
|
11
|
+
# No gemspec names a gem that a `from:`/`to:` override substitutes, so
|
|
12
|
+
# the dependency API never fetches it unless asked.
|
|
13
|
+
@replacement_names = replacement_names
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
def pinned_spec_names(skip = nil)
|
|
@@ -22,6 +25,7 @@ module Bundler
|
|
|
22
25
|
end
|
|
23
26
|
|
|
24
27
|
unmet_deps = explicit_sources.map do |source|
|
|
28
|
+
source.add_dependency_names(replacement_names)
|
|
25
29
|
(source.spec_names - pinned_spec_names).each do |indirect_dependency_name|
|
|
26
30
|
previous_source = requirements[indirect_dependency_name]
|
|
27
31
|
if previous_source.nil?
|
|
@@ -39,7 +43,7 @@ module Bundler
|
|
|
39
43
|
source.unmet_deps
|
|
40
44
|
end
|
|
41
45
|
|
|
42
|
-
sources.default_source.add_dependency_names(unmet_deps.flatten - requirements.keys)
|
|
46
|
+
sources.default_source.add_dependency_names(unmet_deps.flatten + replacement_names - requirements.keys)
|
|
43
47
|
|
|
44
48
|
requirements
|
|
45
49
|
end
|
data/lib/bundler/spec_set.rb
CHANGED
|
@@ -84,11 +84,14 @@ module Bundler
|
|
|
84
84
|
platforms.delete(Bundler.local_platform) if less_specific_platform
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
def validate_deps(s)
|
|
88
|
-
s.runtime_dependencies.each do |dep|
|
|
87
|
+
def validate_deps(s, overrides = s.is_a?(LazySpecification) ? Array(s.overrides) : [])
|
|
88
|
+
Override.rewrite_dependencies(overrides, s.name, s.runtime_dependencies).each do |dep|
|
|
89
89
|
next if dep.name == "bundler"
|
|
90
90
|
|
|
91
91
|
return :missing unless names.include?(dep.name)
|
|
92
|
+
|
|
93
|
+
override = Override.find_for(overrides, dep.name, :version)
|
|
94
|
+
dep = Gem::Dependency.new(dep.name, override.apply_to(dep.requirement)) if override
|
|
92
95
|
return :invalid if none? {|spec| dep.matches_spec?(spec) }
|
|
93
96
|
end
|
|
94
97
|
|
|
@@ -178,7 +181,7 @@ module Bundler
|
|
|
178
181
|
end
|
|
179
182
|
|
|
180
183
|
def find_by_name_and_platform(name, platform)
|
|
181
|
-
|
|
184
|
+
lookup[name]&.detect {|spec| spec.installable_on_platform?(platform) }
|
|
182
185
|
end
|
|
183
186
|
|
|
184
187
|
def specs_with_additional_variants_from(other)
|
|
@@ -274,13 +277,25 @@ module Bundler
|
|
|
274
277
|
|
|
275
278
|
valid_platform = lookup.all? do |_, specs|
|
|
276
279
|
spec = specs.first
|
|
280
|
+
# The matching candidates returned by source.specs.search are remote
|
|
281
|
+
# specs that do not carry the override list themselves. Borrow it from
|
|
282
|
+
# the LazySpec we are validating so platform-variant validation honors
|
|
283
|
+
# the same overrides the install/resolve path already applies.
|
|
284
|
+
overrides = spec.is_a?(LazySpecification) ? Array(spec.overrides) : []
|
|
277
285
|
matching_specs = spec.source.specs.search([spec.name, spec.version])
|
|
278
286
|
platform_spec = MatchPlatform.select_best_platform_match(matching_specs, platform).find do |s|
|
|
279
|
-
|
|
287
|
+
s.matches_current_metadata_with_overrides?(overrides) && validate_deps(s, overrides) == :valid
|
|
280
288
|
end
|
|
281
289
|
|
|
282
290
|
if platform_spec
|
|
283
|
-
|
|
291
|
+
unless specs.include?(platform_spec)
|
|
292
|
+
new_lazy = LazySpecification.from_spec(platform_spec)
|
|
293
|
+
# Carry the overrides forward so a follow-up complete_platform
|
|
294
|
+
# call that picks this synthesized variant as its exemplar still
|
|
295
|
+
# honors the user's override list.
|
|
296
|
+
new_lazy.overrides = overrides if overrides.any?
|
|
297
|
+
new_specs << new_lazy
|
|
298
|
+
end
|
|
284
299
|
true
|
|
285
300
|
else
|
|
286
301
|
false
|
|
@@ -314,7 +329,7 @@ module Bundler
|
|
|
314
329
|
end
|
|
315
330
|
|
|
316
331
|
def sorted
|
|
317
|
-
@sorted ||= ([
|
|
332
|
+
@sorted ||= ([lookup["rake"]&.first] + tsort).compact.uniq
|
|
318
333
|
rescue Gem::TSort::Cyclic => error
|
|
319
334
|
cgems = extract_circular_gems(error)
|
|
320
335
|
raise CyclicDependencyError, "Your bundle requires gems that depend" \
|
|
@@ -342,7 +357,8 @@ module Bundler
|
|
|
342
357
|
end
|
|
343
358
|
|
|
344
359
|
def tsort_each_child(s)
|
|
345
|
-
s.
|
|
360
|
+
dependencies = s.is_a?(LazySpecification) ? Override.rewrite_dependencies(s.overrides, s.name, s.dependencies) : s.dependencies
|
|
361
|
+
dependencies.sort_by(&:name).each do |d|
|
|
346
362
|
next if d.type == :development
|
|
347
363
|
|
|
348
364
|
specs_for_name = lookup[d.name]
|
|
@@ -4,7 +4,8 @@ module Bundler
|
|
|
4
4
|
class StubSpecification < RemoteSpecification
|
|
5
5
|
def self.from_stub(stub)
|
|
6
6
|
return stub if stub.is_a?(Bundler::StubSpecification)
|
|
7
|
-
|
|
7
|
+
content_address = stub.content_address
|
|
8
|
+
spec = new(stub.name, stub.version, stub.platform, nil, content_address: content_address)
|
|
8
9
|
spec.stub = stub
|
|
9
10
|
spec
|
|
10
11
|
end
|
|
@@ -6,19 +6,19 @@ source "https://rubygems.org"
|
|
|
6
6
|
gemspec
|
|
7
7
|
|
|
8
8
|
gem "irb"
|
|
9
|
-
gem "rake", "
|
|
9
|
+
gem "rake", ">= 13.0"
|
|
10
10
|
<%- if config[:ext] -%>
|
|
11
11
|
|
|
12
12
|
gem "rake-compiler"
|
|
13
13
|
<%- end -%>
|
|
14
14
|
<%- if config[:test] -%>
|
|
15
15
|
|
|
16
|
-
gem "<%= config[:test] %>"
|
|
16
|
+
gem "<%= config[:test] %>"
|
|
17
17
|
<%- end -%>
|
|
18
18
|
<%- if config[:linter] == "rubocop" -%>
|
|
19
19
|
|
|
20
|
-
gem "rubocop"
|
|
20
|
+
gem "rubocop"
|
|
21
21
|
<%- elsif config[:linter] == "standard" -%>
|
|
22
22
|
|
|
23
|
-
gem "standard"
|
|
23
|
+
gem "standard"
|
|
24
24
|
<%- end -%>
|
|
@@ -45,12 +45,12 @@ Gem::Specification.new do |spec|
|
|
|
45
45
|
<%- end -%>
|
|
46
46
|
|
|
47
47
|
# Uncomment to register a new dependency of your gem
|
|
48
|
-
# spec.add_dependency "example-gem", "
|
|
48
|
+
# spec.add_dependency "example-gem", ">= 1.0"
|
|
49
49
|
<%- if config[:ext] == 'rust' -%>
|
|
50
|
-
spec.add_dependency "rb_sys", "
|
|
50
|
+
spec.add_dependency "rb_sys", ">= 0.9.128"
|
|
51
51
|
<%- end -%>
|
|
52
52
|
<%- if config[:ext] == 'go' -%>
|
|
53
|
-
spec.add_dependency "go_gem", "
|
|
53
|
+
spec.add_dependency "go_gem", ">= 0.2"
|
|
54
54
|
<%- end -%>
|
|
55
55
|
|
|
56
56
|
# For more information and examples about making a new gem, check out our
|
|
@@ -9,7 +9,7 @@ RSpec.describe <%= config[:constant_name] %> do
|
|
|
9
9
|
it "can call into Rust" do
|
|
10
10
|
result = <%= config[:constant_name] %>.hello("world")
|
|
11
11
|
|
|
12
|
-
expect(result).to
|
|
12
|
+
expect(result).to eq("Hello world, from Rust!")
|
|
13
13
|
end
|
|
14
14
|
<%- else -%>
|
|
15
15
|
it "does something useful" do
|
|
@@ -9,7 +9,7 @@ class <%= config[:minitest_constant_name] %> < Minitest::Test
|
|
|
9
9
|
|
|
10
10
|
<%- if config[:ext] == 'rust' -%>
|
|
11
11
|
def test_hello_world
|
|
12
|
-
assert_equal "Hello
|
|
12
|
+
assert_equal "Hello world, from Rust!", <%= config[:constant_name] %>.hello("world")
|
|
13
13
|
end
|
|
14
14
|
<%- else -%>
|
|
15
15
|
def test_it_does_something_useful
|
data/lib/bundler/ui/shell.rb
CHANGED
data/lib/bundler/ui/silent.rb
CHANGED
|
@@ -2,6 +2,38 @@ require_relative "empty_directory"
|
|
|
2
2
|
|
|
3
3
|
class Bundler::Thor
|
|
4
4
|
module Actions
|
|
5
|
+
WARNINGS = {unchanged_no_flag: "File unchanged! Either the supplied flag value not found or the content has already been inserted!"}
|
|
6
|
+
|
|
7
|
+
# Injects the given content into a file, raising an error if the contents of
|
|
8
|
+
# the file are not changed. Different from gsub_file, this method is reversible.
|
|
9
|
+
#
|
|
10
|
+
# ==== Parameters
|
|
11
|
+
# destination<String>:: Relative path to the destination root
|
|
12
|
+
# data<String>:: Data to add to the file. Can be given as a block.
|
|
13
|
+
# config<Hash>:: give :verbose => false to not log the status and the flag
|
|
14
|
+
# for injection (:after or :before) or :force => true for
|
|
15
|
+
# insert two or more times the same content.
|
|
16
|
+
#
|
|
17
|
+
# ==== Examples
|
|
18
|
+
#
|
|
19
|
+
# insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
|
|
20
|
+
#
|
|
21
|
+
# insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
|
|
22
|
+
# gems = ask "Which gems would you like to add?"
|
|
23
|
+
# gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
def insert_into_file!(destination, *args, &block)
|
|
27
|
+
data = block_given? ? block : args.shift
|
|
28
|
+
|
|
29
|
+
config = args.shift || {}
|
|
30
|
+
config[:after] = /\z/ unless config.key?(:before) || config.key?(:after)
|
|
31
|
+
config = config.merge({error_on_no_change: true})
|
|
32
|
+
|
|
33
|
+
action InjectIntoFile.new(self, destination, data, config)
|
|
34
|
+
end
|
|
35
|
+
alias_method :inject_into_file!, :insert_into_file!
|
|
36
|
+
|
|
5
37
|
# Injects the given content into a file. Different from gsub_file, this
|
|
6
38
|
# method is reversible.
|
|
7
39
|
#
|
|
@@ -21,8 +53,6 @@ class Bundler::Thor
|
|
|
21
53
|
# gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
|
|
22
54
|
# end
|
|
23
55
|
#
|
|
24
|
-
WARNINGS = {unchanged_no_flag: "File unchanged! Either the supplied flag value not found or the content has already been inserted!"}
|
|
25
|
-
|
|
26
56
|
def insert_into_file(destination, *args, &block)
|
|
27
57
|
data = block_given? ? block : args.shift
|
|
28
58
|
|
|
@@ -47,6 +77,7 @@ class Bundler::Thor
|
|
|
47
77
|
|
|
48
78
|
@replacement = data.is_a?(Proc) ? data.call : data
|
|
49
79
|
@flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
|
|
80
|
+
@error_on_no_change = @config.fetch(:error_on_no_change, false)
|
|
50
81
|
end
|
|
51
82
|
|
|
52
83
|
def invoke!
|
|
@@ -59,6 +90,8 @@ class Bundler::Thor
|
|
|
59
90
|
if exists?
|
|
60
91
|
if replace!(/#{flag}/, content, config[:force])
|
|
61
92
|
say_status(:invoke)
|
|
93
|
+
elsif @error_on_no_change
|
|
94
|
+
raise Bundler::Thor::Error, "The content of #{destination} did not change"
|
|
62
95
|
elsif replacement_present?
|
|
63
96
|
say_status(:unchanged, color: :blue)
|
|
64
97
|
else
|
|
@@ -13,8 +13,9 @@ class Bundler::Thor
|
|
|
13
13
|
autoload :RakeCompat, File.expand_path("rake_compat", __dir__)
|
|
14
14
|
autoload :Group, File.expand_path("group", __dir__)
|
|
15
15
|
|
|
16
|
-
# Shortcuts for help.
|
|
16
|
+
# Shortcuts for help and tree commands.
|
|
17
17
|
HELP_MAPPINGS = %w(-h -? --help -D)
|
|
18
|
+
TREE_MAPPINGS = %w(-t --tree)
|
|
18
19
|
|
|
19
20
|
# Bundler::Thor methods that should not be overwritten by the user.
|
|
20
21
|
THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
|
|
@@ -311,13 +311,11 @@ class Bundler::Thor
|
|
|
311
311
|
end
|
|
312
312
|
|
|
313
313
|
def show_diff(destination, content) #:nodoc:
|
|
314
|
-
diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u"
|
|
315
|
-
|
|
316
314
|
require "tempfile"
|
|
317
315
|
Tempfile.open(File.basename(destination), File.dirname(destination), binmode: true) do |temp|
|
|
318
316
|
temp.write content
|
|
319
317
|
temp.rewind
|
|
320
|
-
system
|
|
318
|
+
system(*diff_tool, destination, temp.path)
|
|
321
319
|
end
|
|
322
320
|
end
|
|
323
321
|
|
|
@@ -369,15 +367,25 @@ class Bundler::Thor
|
|
|
369
367
|
|
|
370
368
|
def merge(destination, content) #:nodoc:
|
|
371
369
|
require "tempfile"
|
|
372
|
-
Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
|
|
370
|
+
Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination), binmode: true) do |temp|
|
|
373
371
|
temp.write content
|
|
374
372
|
temp.rewind
|
|
375
|
-
system(merge_tool, temp.path, destination)
|
|
373
|
+
system(*merge_tool, temp.path, destination)
|
|
376
374
|
end
|
|
377
375
|
end
|
|
378
376
|
|
|
379
377
|
def merge_tool #:nodoc:
|
|
380
|
-
@merge_tool ||=
|
|
378
|
+
@merge_tool ||= begin
|
|
379
|
+
require "shellwords"
|
|
380
|
+
Shellwords.split(ENV["THOR_MERGE"] || "git difftool --no-index")
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def diff_tool #:nodoc:
|
|
385
|
+
@diff_cmd ||= begin
|
|
386
|
+
require "shellwords"
|
|
387
|
+
Shellwords.split(ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u")
|
|
388
|
+
end
|
|
381
389
|
end
|
|
382
390
|
end
|
|
383
391
|
end
|