bundler 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bundler might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3111 -0
- data/LICENSE.md +23 -0
- data/README.md +63 -0
- data/bundler.gemspec +65 -0
- data/exe/bundle +31 -0
- data/exe/bundle_ruby +60 -0
- data/exe/bundler +4 -0
- data/lib/bundler.rb +567 -0
- data/lib/bundler/build_metadata.rb +53 -0
- data/lib/bundler/capistrano.rb +22 -0
- data/lib/bundler/cli.rb +792 -0
- data/lib/bundler/cli/add.rb +35 -0
- data/lib/bundler/cli/binstubs.rb +49 -0
- data/lib/bundler/cli/cache.rb +36 -0
- data/lib/bundler/cli/check.rb +38 -0
- data/lib/bundler/cli/clean.rb +25 -0
- data/lib/bundler/cli/common.rb +102 -0
- data/lib/bundler/cli/config.rb +119 -0
- data/lib/bundler/cli/console.rb +43 -0
- data/lib/bundler/cli/doctor.rb +140 -0
- data/lib/bundler/cli/exec.rb +105 -0
- data/lib/bundler/cli/gem.rb +252 -0
- data/lib/bundler/cli/info.rb +50 -0
- data/lib/bundler/cli/init.rb +47 -0
- data/lib/bundler/cli/inject.rb +60 -0
- data/lib/bundler/cli/install.rb +218 -0
- data/lib/bundler/cli/issue.rb +40 -0
- data/lib/bundler/cli/list.rb +58 -0
- data/lib/bundler/cli/lock.rb +63 -0
- data/lib/bundler/cli/open.rb +26 -0
- data/lib/bundler/cli/outdated.rb +266 -0
- data/lib/bundler/cli/package.rb +49 -0
- data/lib/bundler/cli/platform.rb +46 -0
- data/lib/bundler/cli/plugin.rb +24 -0
- data/lib/bundler/cli/pristine.rb +47 -0
- data/lib/bundler/cli/remove.rb +18 -0
- data/lib/bundler/cli/show.rb +75 -0
- data/lib/bundler/cli/update.rb +91 -0
- data/lib/bundler/cli/viz.rb +31 -0
- data/lib/bundler/compact_index_client.rb +109 -0
- data/lib/bundler/compact_index_client/cache.rb +118 -0
- data/lib/bundler/compact_index_client/updater.rb +116 -0
- data/lib/bundler/compatibility_guard.rb +13 -0
- data/lib/bundler/constants.rb +7 -0
- data/lib/bundler/current_ruby.rb +94 -0
- data/lib/bundler/definition.rb +995 -0
- data/lib/bundler/dep_proxy.rb +48 -0
- data/lib/bundler/dependency.rb +139 -0
- data/lib/bundler/deployment.rb +69 -0
- data/lib/bundler/deprecate.rb +44 -0
- data/lib/bundler/dsl.rb +615 -0
- data/lib/bundler/endpoint_specification.rb +141 -0
- data/lib/bundler/env.rb +149 -0
- data/lib/bundler/environment_preserver.rb +59 -0
- data/lib/bundler/errors.rb +158 -0
- data/lib/bundler/feature_flag.rb +75 -0
- data/lib/bundler/fetcher.rb +312 -0
- data/lib/bundler/fetcher/base.rb +52 -0
- data/lib/bundler/fetcher/compact_index.rb +126 -0
- data/lib/bundler/fetcher/dependency.rb +82 -0
- data/lib/bundler/fetcher/downloader.rb +84 -0
- data/lib/bundler/fetcher/index.rb +52 -0
- data/lib/bundler/friendly_errors.rb +131 -0
- data/lib/bundler/gem_helper.rb +217 -0
- data/lib/bundler/gem_helpers.rb +101 -0
- data/lib/bundler/gem_remote_fetcher.rb +43 -0
- data/lib/bundler/gem_tasks.rb +7 -0
- data/lib/bundler/gem_version_promoter.rb +190 -0
- data/lib/bundler/gemdeps.rb +29 -0
- data/lib/bundler/graph.rb +152 -0
- data/lib/bundler/index.rb +213 -0
- data/lib/bundler/injector.rb +253 -0
- data/lib/bundler/inline.rb +74 -0
- data/lib/bundler/installer.rb +318 -0
- data/lib/bundler/installer/gem_installer.rb +85 -0
- data/lib/bundler/installer/parallel_installer.rb +229 -0
- data/lib/bundler/installer/standalone.rb +53 -0
- data/lib/bundler/lazy_specification.rb +123 -0
- data/lib/bundler/lockfile_generator.rb +95 -0
- data/lib/bundler/lockfile_parser.rb +256 -0
- data/lib/bundler/match_platform.rb +24 -0
- data/lib/bundler/mirror.rb +223 -0
- data/lib/bundler/plugin.rb +294 -0
- data/lib/bundler/plugin/api.rb +81 -0
- data/lib/bundler/plugin/api/source.rb +306 -0
- data/lib/bundler/plugin/dsl.rb +53 -0
- data/lib/bundler/plugin/events.rb +61 -0
- data/lib/bundler/plugin/index.rb +165 -0
- data/lib/bundler/plugin/installer.rb +96 -0
- data/lib/bundler/plugin/installer/git.rb +38 -0
- data/lib/bundler/plugin/installer/rubygems.rb +27 -0
- data/lib/bundler/plugin/source_list.rb +27 -0
- data/lib/bundler/process_lock.rb +24 -0
- data/lib/bundler/psyched_yaml.rb +37 -0
- data/lib/bundler/remote_specification.rb +114 -0
- data/lib/bundler/resolver.rb +373 -0
- data/lib/bundler/resolver/spec_group.rb +106 -0
- data/lib/bundler/retry.rb +66 -0
- data/lib/bundler/ruby_dsl.rb +18 -0
- data/lib/bundler/ruby_version.rb +152 -0
- data/lib/bundler/rubygems_ext.rb +209 -0
- data/lib/bundler/rubygems_gem_installer.rb +99 -0
- data/lib/bundler/rubygems_integration.rb +915 -0
- data/lib/bundler/runtime.rb +322 -0
- data/lib/bundler/settings.rb +464 -0
- data/lib/bundler/settings/validator.rb +102 -0
- data/lib/bundler/setup.rb +28 -0
- data/lib/bundler/shared_helpers.rb +386 -0
- data/lib/bundler/similarity_detector.rb +63 -0
- data/lib/bundler/source.rb +94 -0
- data/lib/bundler/source/gemspec.rb +18 -0
- data/lib/bundler/source/git.rb +329 -0
- data/lib/bundler/source/git/git_proxy.rb +262 -0
- data/lib/bundler/source/metadata.rb +62 -0
- data/lib/bundler/source/path.rb +249 -0
- data/lib/bundler/source/path/installer.rb +74 -0
- data/lib/bundler/source/rubygems.rb +539 -0
- data/lib/bundler/source/rubygems/remote.rb +69 -0
- data/lib/bundler/source_list.rb +186 -0
- data/lib/bundler/spec_set.rb +208 -0
- data/lib/bundler/ssl_certs/.document +1 -0
- data/lib/bundler/ssl_certs/certificate_manager.rb +66 -0
- data/lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem +21 -0
- data/lib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem +23 -0
- data/lib/bundler/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem +25 -0
- data/lib/bundler/stub_specification.rb +108 -0
- data/lib/bundler/templates/.document +1 -0
- data/lib/bundler/templates/Executable +29 -0
- data/lib/bundler/templates/Executable.bundler +105 -0
- data/lib/bundler/templates/Executable.standalone +14 -0
- data/lib/bundler/templates/Gemfile +7 -0
- data/lib/bundler/templates/gems.rb +8 -0
- data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +74 -0
- data/lib/bundler/templates/newgem/Gemfile.tt +4 -0
- data/lib/bundler/templates/newgem/LICENSE.txt.tt +21 -0
- data/lib/bundler/templates/newgem/README.md.tt +47 -0
- data/lib/bundler/templates/newgem/Rakefile.tt +29 -0
- data/lib/bundler/templates/newgem/bin/console.tt +14 -0
- data/lib/bundler/templates/newgem/bin/setup.tt +8 -0
- data/lib/bundler/templates/newgem/exe/newgem.tt +3 -0
- data/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt +3 -0
- data/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +9 -0
- data/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt +6 -0
- data/lib/bundler/templates/newgem/gitignore.tt +20 -0
- data/lib/bundler/templates/newgem/lib/newgem.rb.tt +13 -0
- data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +7 -0
- data/lib/bundler/templates/newgem/newgem.gemspec.tt +50 -0
- data/lib/bundler/templates/newgem/rspec.tt +3 -0
- data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +9 -0
- data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +14 -0
- data/lib/bundler/templates/newgem/test/newgem_test.rb.tt +11 -0
- data/lib/bundler/templates/newgem/test/test_helper.rb.tt +8 -0
- data/lib/bundler/templates/newgem/travis.yml.tt +7 -0
- data/lib/bundler/ui.rb +9 -0
- data/lib/bundler/ui/rg_proxy.rb +19 -0
- data/lib/bundler/ui/shell.rb +146 -0
- data/lib/bundler/ui/silent.rb +69 -0
- data/lib/bundler/uri_credentials_filter.rb +37 -0
- data/lib/bundler/vendor/fileutils/lib/fileutils.rb +1741 -0
- data/lib/bundler/vendor/fileutils/lib/fileutils/version.rb +5 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo.rb +12 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb +26 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +57 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +81 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +223 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +36 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +66 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +62 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +63 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +61 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +126 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +46 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +36 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +136 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +143 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +6 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +101 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +67 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +837 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb +46 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +58 -0
- data/lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb +27 -0
- data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +1233 -0
- data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb +129 -0
- data/lib/bundler/vendor/thor/lib/thor.rb +509 -0
- data/lib/bundler/vendor/thor/lib/thor/actions.rb +331 -0
- data/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb +104 -0
- data/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb +60 -0
- data/lib/bundler/vendor/thor/lib/thor/actions/directory.rb +118 -0
- data/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +143 -0
- data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +373 -0
- data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +109 -0
- data/lib/bundler/vendor/thor/lib/thor/base.rb +678 -0
- data/lib/bundler/vendor/thor/lib/thor/command.rb +135 -0
- data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +97 -0
- data/lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
- data/lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb +129 -0
- data/lib/bundler/vendor/thor/lib/thor/error.rb +114 -0
- data/lib/bundler/vendor/thor/lib/thor/group.rb +281 -0
- data/lib/bundler/vendor/thor/lib/thor/invocation.rb +177 -0
- data/lib/bundler/vendor/thor/lib/thor/line_editor.rb +17 -0
- data/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb +37 -0
- data/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
- data/lib/bundler/vendor/thor/lib/thor/parser.rb +4 -0
- data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +70 -0
- data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +175 -0
- data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +146 -0
- data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +226 -0
- data/lib/bundler/vendor/thor/lib/thor/rake_compat.rb +71 -0
- data/lib/bundler/vendor/thor/lib/thor/runner.rb +324 -0
- data/lib/bundler/vendor/thor/lib/thor/shell.rb +81 -0
- data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +482 -0
- data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +149 -0
- data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +126 -0
- data/lib/bundler/vendor/thor/lib/thor/util.rb +268 -0
- data/lib/bundler/vendor/thor/lib/thor/version.rb +3 -0
- data/lib/bundler/vendored_fileutils.rb +9 -0
- data/lib/bundler/vendored_molinillo.rb +4 -0
- data/lib/bundler/vendored_persistent.rb +52 -0
- data/lib/bundler/vendored_thor.rb +8 -0
- data/lib/bundler/version.rb +28 -0
- data/lib/bundler/version_ranges.rb +76 -0
- data/lib/bundler/vlad.rb +17 -0
- data/lib/bundler/worker.rb +106 -0
- data/lib/bundler/yaml_serializer.rb +90 -0
- data/man/bundle-add.1 +58 -0
- data/man/bundle-add.1.txt +52 -0
- data/man/bundle-add.ronn +40 -0
- data/man/bundle-binstubs.1 +40 -0
- data/man/bundle-binstubs.1.txt +48 -0
- data/man/bundle-binstubs.ronn +43 -0
- data/man/bundle-check.1 +31 -0
- data/man/bundle-check.1.txt +33 -0
- data/man/bundle-check.ronn +26 -0
- data/man/bundle-clean.1 +24 -0
- data/man/bundle-clean.1.txt +26 -0
- data/man/bundle-clean.ronn +18 -0
- data/man/bundle-config.1 +497 -0
- data/man/bundle-config.1.txt +529 -0
- data/man/bundle-config.ronn +397 -0
- data/man/bundle-doctor.1 +44 -0
- data/man/bundle-doctor.1.txt +44 -0
- data/man/bundle-doctor.ronn +33 -0
- data/man/bundle-exec.1 +165 -0
- data/man/bundle-exec.1.txt +178 -0
- data/man/bundle-exec.ronn +152 -0
- data/man/bundle-gem.1 +80 -0
- data/man/bundle-gem.1.txt +91 -0
- data/man/bundle-gem.ronn +78 -0
- data/man/bundle-info.1 +20 -0
- data/man/bundle-info.1.txt +21 -0
- data/man/bundle-info.ronn +17 -0
- data/man/bundle-init.1 +25 -0
- data/man/bundle-init.1.txt +34 -0
- data/man/bundle-init.ronn +29 -0
- data/man/bundle-inject.1 +33 -0
- data/man/bundle-inject.1.txt +32 -0
- data/man/bundle-inject.ronn +22 -0
- data/man/bundle-install.1 +308 -0
- data/man/bundle-install.1.txt +396 -0
- data/man/bundle-install.ronn +378 -0
- data/man/bundle-list.1 +50 -0
- data/man/bundle-list.1.txt +43 -0
- data/man/bundle-list.ronn +33 -0
- data/man/bundle-lock.1 +84 -0
- data/man/bundle-lock.1.txt +93 -0
- data/man/bundle-lock.ronn +94 -0
- data/man/bundle-open.1 +32 -0
- data/man/bundle-open.1.txt +29 -0
- data/man/bundle-open.ronn +19 -0
- data/man/bundle-outdated.1 +155 -0
- data/man/bundle-outdated.1.txt +131 -0
- data/man/bundle-outdated.ronn +111 -0
- data/man/bundle-package.1 +55 -0
- data/man/bundle-package.1.txt +79 -0
- data/man/bundle-package.ronn +72 -0
- data/man/bundle-platform.1 +61 -0
- data/man/bundle-platform.1.txt +57 -0
- data/man/bundle-platform.ronn +42 -0
- data/man/bundle-pristine.1 +34 -0
- data/man/bundle-pristine.1.txt +44 -0
- data/man/bundle-pristine.ronn +34 -0
- data/man/bundle-remove.1 +31 -0
- data/man/bundle-remove.1.txt +34 -0
- data/man/bundle-remove.ronn +23 -0
- data/man/bundle-show.1 +23 -0
- data/man/bundle-show.1.txt +27 -0
- data/man/bundle-show.ronn +21 -0
- data/man/bundle-update.1 +394 -0
- data/man/bundle-update.1.txt +391 -0
- data/man/bundle-update.ronn +350 -0
- data/man/bundle-viz.1 +39 -0
- data/man/bundle-viz.1.txt +39 -0
- data/man/bundle-viz.ronn +30 -0
- data/man/bundle.1 +136 -0
- data/man/bundle.1.txt +116 -0
- data/man/bundle.ronn +111 -0
- data/man/gemfile.5 +689 -0
- data/man/gemfile.5.ronn +521 -0
- data/man/gemfile.5.txt +653 -0
- data/man/index.txt +25 -0
- metadata +463 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/vendored_fileutils"
|
4
|
+
require "stringio"
|
5
|
+
require "zlib"
|
6
|
+
|
7
|
+
module Bundler
|
8
|
+
class CompactIndexClient
|
9
|
+
class Updater
|
10
|
+
class MisMatchedChecksumError < Error
|
11
|
+
def initialize(path, server_checksum, local_checksum)
|
12
|
+
@path = path
|
13
|
+
@server_checksum = server_checksum
|
14
|
+
@local_checksum = local_checksum
|
15
|
+
end
|
16
|
+
|
17
|
+
def message
|
18
|
+
"The checksum of /#{@path} does not match the checksum provided by the server! Something is wrong " \
|
19
|
+
"(local checksum is #{@local_checksum.inspect}, was expecting #{@server_checksum.inspect})."
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(fetcher)
|
24
|
+
@fetcher = fetcher
|
25
|
+
require "tmpdir"
|
26
|
+
end
|
27
|
+
|
28
|
+
def update(local_path, remote_path, retrying = nil)
|
29
|
+
headers = {}
|
30
|
+
|
31
|
+
Dir.mktmpdir("bundler-compact-index-") do |local_temp_dir|
|
32
|
+
local_temp_path = Pathname.new(local_temp_dir).join(local_path.basename)
|
33
|
+
|
34
|
+
# first try to fetch any new bytes on the existing file
|
35
|
+
if retrying.nil? && local_path.file?
|
36
|
+
SharedHelpers.filesystem_access(local_temp_path) do
|
37
|
+
FileUtils.cp local_path, local_temp_path
|
38
|
+
end
|
39
|
+
headers["If-None-Match"] = etag_for(local_temp_path)
|
40
|
+
headers["Range"] =
|
41
|
+
if local_temp_path.size.nonzero?
|
42
|
+
# Subtract a byte to ensure the range won't be empty.
|
43
|
+
# Avoids 416 (Range Not Satisfiable) responses.
|
44
|
+
"bytes=#{local_temp_path.size - 1}-"
|
45
|
+
else
|
46
|
+
"bytes=#{local_temp_path.size}-"
|
47
|
+
end
|
48
|
+
else
|
49
|
+
# Fastly ignores Range when Accept-Encoding: gzip is set
|
50
|
+
headers["Accept-Encoding"] = "gzip"
|
51
|
+
end
|
52
|
+
|
53
|
+
response = @fetcher.call(remote_path, headers)
|
54
|
+
return nil if response.is_a?(Net::HTTPNotModified)
|
55
|
+
|
56
|
+
content = response.body
|
57
|
+
if response["Content-Encoding"] == "gzip"
|
58
|
+
content = Zlib::GzipReader.new(StringIO.new(content)).read
|
59
|
+
end
|
60
|
+
|
61
|
+
SharedHelpers.filesystem_access(local_temp_path) do
|
62
|
+
if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero?
|
63
|
+
local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) }
|
64
|
+
else
|
65
|
+
local_temp_path.open("w") {|f| f << content }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
response_etag = (response["ETag"] || "").gsub(%r{\AW/}, "")
|
70
|
+
if etag_for(local_temp_path) == response_etag
|
71
|
+
SharedHelpers.filesystem_access(local_path) do
|
72
|
+
FileUtils.mv(local_temp_path, local_path)
|
73
|
+
end
|
74
|
+
return nil
|
75
|
+
end
|
76
|
+
|
77
|
+
if retrying
|
78
|
+
raise MisMatchedChecksumError.new(remote_path, response_etag, etag_for(local_temp_path))
|
79
|
+
end
|
80
|
+
|
81
|
+
update(local_path, remote_path, :retrying)
|
82
|
+
end
|
83
|
+
rescue Errno::EACCES
|
84
|
+
raise Bundler::PermissionError,
|
85
|
+
"Bundler does not have write access to create a temp directory " \
|
86
|
+
"within #{Dir.tmpdir}. Bundler must have write access to your " \
|
87
|
+
"systems temp directory to function properly. "
|
88
|
+
rescue Zlib::GzipFile::Error
|
89
|
+
raise Bundler::HTTPError
|
90
|
+
end
|
91
|
+
|
92
|
+
def etag_for(path)
|
93
|
+
sum = checksum_for_file(path)
|
94
|
+
sum ? %("#{sum}") : nil
|
95
|
+
end
|
96
|
+
|
97
|
+
def slice_body(body, range)
|
98
|
+
if body.respond_to?(:byteslice)
|
99
|
+
body.byteslice(range)
|
100
|
+
else # pre-1.9.3
|
101
|
+
body.unpack("@#{range.first}a#{range.end + 1}").first
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def checksum_for_file(path)
|
106
|
+
return nil unless path.file?
|
107
|
+
# This must use IO.read instead of Digest.file().hexdigest
|
108
|
+
# because we need to preserve \n line endings on windows when calculating
|
109
|
+
# the checksum
|
110
|
+
SharedHelpers.filesystem_access(path, :read) do
|
111
|
+
SharedHelpers.digest(:MD5).hexdigest(IO.read(path))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require "bundler/version"
|
4
|
+
|
5
|
+
if Bundler::VERSION.split(".").first.to_i >= 2
|
6
|
+
if Gem::Version.new(Object::RUBY_VERSION.dup) < Gem::Version.new("2.3")
|
7
|
+
abort "Bundler 2 requires Ruby 2.3 or later. Either install bundler 1 or update to a supported Ruby version."
|
8
|
+
end
|
9
|
+
|
10
|
+
if Gem::Version.new(Gem::VERSION.dup) < Gem::Version.new("2.5")
|
11
|
+
abort "Bundler 2 requires RubyGems 2.5 or later. Either install bundler 1 or update to a supported RubyGems version."
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
# Returns current version of Ruby
|
5
|
+
#
|
6
|
+
# @return [CurrentRuby] Current version of Ruby
|
7
|
+
def self.current_ruby
|
8
|
+
@current_ruby ||= CurrentRuby.new
|
9
|
+
end
|
10
|
+
|
11
|
+
class CurrentRuby
|
12
|
+
KNOWN_MINOR_VERSIONS = %w[
|
13
|
+
1.8
|
14
|
+
1.9
|
15
|
+
2.0
|
16
|
+
2.1
|
17
|
+
2.2
|
18
|
+
2.3
|
19
|
+
2.4
|
20
|
+
2.5
|
21
|
+
2.6
|
22
|
+
2.7
|
23
|
+
].freeze
|
24
|
+
|
25
|
+
KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze
|
26
|
+
|
27
|
+
KNOWN_PLATFORMS = %w[
|
28
|
+
jruby
|
29
|
+
maglev
|
30
|
+
mingw
|
31
|
+
mri
|
32
|
+
mswin
|
33
|
+
mswin64
|
34
|
+
rbx
|
35
|
+
ruby
|
36
|
+
truffleruby
|
37
|
+
x64_mingw
|
38
|
+
].freeze
|
39
|
+
|
40
|
+
def ruby?
|
41
|
+
!mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" ||
|
42
|
+
RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby")
|
43
|
+
end
|
44
|
+
|
45
|
+
def mri?
|
46
|
+
!mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby")
|
47
|
+
end
|
48
|
+
|
49
|
+
def rbx?
|
50
|
+
ruby? && defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx"
|
51
|
+
end
|
52
|
+
|
53
|
+
def jruby?
|
54
|
+
defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
|
55
|
+
end
|
56
|
+
|
57
|
+
def maglev?
|
58
|
+
defined?(RUBY_ENGINE) && RUBY_ENGINE == "maglev"
|
59
|
+
end
|
60
|
+
|
61
|
+
def truffleruby?
|
62
|
+
defined?(RUBY_ENGINE) && RUBY_ENGINE == "truffleruby"
|
63
|
+
end
|
64
|
+
|
65
|
+
def mswin?
|
66
|
+
Bundler::WINDOWS
|
67
|
+
end
|
68
|
+
|
69
|
+
def mswin64?
|
70
|
+
Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64"
|
71
|
+
end
|
72
|
+
|
73
|
+
def mingw?
|
74
|
+
Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64"
|
75
|
+
end
|
76
|
+
|
77
|
+
def x64_mingw?
|
78
|
+
Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu == "x64"
|
79
|
+
end
|
80
|
+
|
81
|
+
(KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version|
|
82
|
+
trimmed_version = version.tr(".", "")
|
83
|
+
define_method(:"on_#{trimmed_version}?") do
|
84
|
+
RUBY_VERSION.start_with?("#{version}.")
|
85
|
+
end
|
86
|
+
|
87
|
+
KNOWN_PLATFORMS.each do |platform|
|
88
|
+
define_method(:"#{platform}_#{trimmed_version}?") do
|
89
|
+
send(:"#{platform}?") && send(:"on_#{trimmed_version}?")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,995 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/lockfile_parser"
|
4
|
+
require "set"
|
5
|
+
|
6
|
+
module Bundler
|
7
|
+
class Definition
|
8
|
+
include GemHelpers
|
9
|
+
|
10
|
+
attr_reader(
|
11
|
+
:dependencies,
|
12
|
+
:locked_deps,
|
13
|
+
:locked_gems,
|
14
|
+
:platforms,
|
15
|
+
:requires,
|
16
|
+
:ruby_version,
|
17
|
+
:lockfile,
|
18
|
+
:gemfiles
|
19
|
+
)
|
20
|
+
|
21
|
+
# Given a gemfile and lockfile creates a Bundler definition
|
22
|
+
#
|
23
|
+
# @param gemfile [Pathname] Path to Gemfile
|
24
|
+
# @param lockfile [Pathname,nil] Path to Gemfile.lock
|
25
|
+
# @param unlock [Hash, Boolean, nil] Gems that have been requested
|
26
|
+
# to be updated or true if all gems should be updated
|
27
|
+
# @return [Bundler::Definition]
|
28
|
+
def self.build(gemfile, lockfile, unlock)
|
29
|
+
unlock ||= {}
|
30
|
+
gemfile = Pathname.new(gemfile).expand_path
|
31
|
+
|
32
|
+
raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file?
|
33
|
+
|
34
|
+
Dsl.evaluate(gemfile, lockfile, unlock)
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# How does the new system work?
|
39
|
+
#
|
40
|
+
# * Load information from Gemfile and Lockfile
|
41
|
+
# * Invalidate stale locked specs
|
42
|
+
# * All specs from stale source are stale
|
43
|
+
# * All specs that are reachable only through a stale
|
44
|
+
# dependency are stale.
|
45
|
+
# * If all fresh dependencies are satisfied by the locked
|
46
|
+
# specs, then we can try to resolve locally.
|
47
|
+
#
|
48
|
+
# @param lockfile [Pathname] Path to Gemfile.lock
|
49
|
+
# @param dependencies [Array(Bundler::Dependency)] array of dependencies from Gemfile
|
50
|
+
# @param sources [Bundler::SourceList]
|
51
|
+
# @param unlock [Hash, Boolean, nil] Gems that have been requested
|
52
|
+
# to be updated or true if all gems should be updated
|
53
|
+
# @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version
|
54
|
+
# @param optional_groups [Array(String)] A list of optional groups
|
55
|
+
def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [])
|
56
|
+
if [true, false].include?(unlock)
|
57
|
+
@unlocking_bundler = false
|
58
|
+
@unlocking = unlock
|
59
|
+
else
|
60
|
+
unlock = unlock.dup
|
61
|
+
@unlocking_bundler = unlock.delete(:bundler)
|
62
|
+
unlock.delete_if {|_k, v| Array(v).empty? }
|
63
|
+
@unlocking = !unlock.empty?
|
64
|
+
end
|
65
|
+
|
66
|
+
@dependencies = dependencies
|
67
|
+
@sources = sources
|
68
|
+
@unlock = unlock
|
69
|
+
@optional_groups = optional_groups
|
70
|
+
@remote = false
|
71
|
+
@specs = nil
|
72
|
+
@ruby_version = ruby_version
|
73
|
+
@gemfiles = gemfiles
|
74
|
+
|
75
|
+
@lockfile = lockfile
|
76
|
+
@lockfile_contents = String.new
|
77
|
+
@locked_bundler_version = nil
|
78
|
+
@locked_ruby_version = nil
|
79
|
+
@locked_specs_incomplete_for_platform = false
|
80
|
+
|
81
|
+
if lockfile && File.exist?(lockfile)
|
82
|
+
@lockfile_contents = Bundler.read_file(lockfile)
|
83
|
+
@locked_gems = LockfileParser.new(@lockfile_contents)
|
84
|
+
@locked_platforms = @locked_gems.platforms
|
85
|
+
@platforms = @locked_platforms.dup
|
86
|
+
@locked_bundler_version = @locked_gems.bundler_version
|
87
|
+
@locked_ruby_version = @locked_gems.ruby_version
|
88
|
+
|
89
|
+
if unlock != true
|
90
|
+
@locked_deps = @locked_gems.dependencies
|
91
|
+
@locked_specs = SpecSet.new(@locked_gems.specs)
|
92
|
+
@locked_sources = @locked_gems.sources
|
93
|
+
else
|
94
|
+
@unlock = {}
|
95
|
+
@locked_deps = {}
|
96
|
+
@locked_specs = SpecSet.new([])
|
97
|
+
@locked_sources = []
|
98
|
+
end
|
99
|
+
else
|
100
|
+
@unlock = {}
|
101
|
+
@platforms = []
|
102
|
+
@locked_gems = nil
|
103
|
+
@locked_deps = {}
|
104
|
+
@locked_specs = SpecSet.new([])
|
105
|
+
@locked_sources = []
|
106
|
+
@locked_platforms = []
|
107
|
+
end
|
108
|
+
|
109
|
+
@unlock[:gems] ||= []
|
110
|
+
@unlock[:sources] ||= []
|
111
|
+
@unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
|
112
|
+
@ruby_version.diff(locked_ruby_version_object)
|
113
|
+
end
|
114
|
+
@unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
|
115
|
+
|
116
|
+
add_current_platform unless Bundler.frozen_bundle?
|
117
|
+
|
118
|
+
converge_path_sources_to_gemspec_sources
|
119
|
+
@path_changes = converge_paths
|
120
|
+
@source_changes = converge_sources
|
121
|
+
|
122
|
+
unless @unlock[:lock_shared_dependencies]
|
123
|
+
eager_unlock = expand_dependencies(@unlock[:gems], true)
|
124
|
+
@unlock[:gems] = @locked_specs.for(eager_unlock, [], false, false, false).map(&:name)
|
125
|
+
end
|
126
|
+
|
127
|
+
@dependency_changes = converge_dependencies
|
128
|
+
@local_changes = converge_locals
|
129
|
+
|
130
|
+
@requires = compute_requires
|
131
|
+
end
|
132
|
+
|
133
|
+
def gem_version_promoter
|
134
|
+
@gem_version_promoter ||= begin
|
135
|
+
locked_specs =
|
136
|
+
if unlocking? && @locked_specs.empty? && !@lockfile_contents.empty?
|
137
|
+
# Definition uses an empty set of locked_specs to indicate all gems
|
138
|
+
# are unlocked, but GemVersionPromoter needs the locked_specs
|
139
|
+
# for conservative comparison.
|
140
|
+
Bundler::SpecSet.new(@locked_gems.specs)
|
141
|
+
else
|
142
|
+
@locked_specs
|
143
|
+
end
|
144
|
+
GemVersionPromoter.new(locked_specs, @unlock[:gems])
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def resolve_with_cache!
|
149
|
+
raise "Specs already loaded" if @specs
|
150
|
+
sources.cached!
|
151
|
+
specs
|
152
|
+
end
|
153
|
+
|
154
|
+
def resolve_remotely!
|
155
|
+
raise "Specs already loaded" if @specs
|
156
|
+
@remote = true
|
157
|
+
sources.remote!
|
158
|
+
specs
|
159
|
+
end
|
160
|
+
|
161
|
+
# For given dependency list returns a SpecSet with Gemspec of all the required
|
162
|
+
# dependencies.
|
163
|
+
# 1. The method first resolves the dependencies specified in Gemfile
|
164
|
+
# 2. After that it tries and fetches gemspec of resolved dependencies
|
165
|
+
#
|
166
|
+
# @return [Bundler::SpecSet]
|
167
|
+
def specs
|
168
|
+
@specs ||= begin
|
169
|
+
begin
|
170
|
+
specs = resolve.materialize(Bundler.settings[:cache_all_platforms] ? dependencies : requested_dependencies)
|
171
|
+
rescue GemNotFound => e # Handle yanked gem
|
172
|
+
gem_name, gem_version = extract_gem_info(e)
|
173
|
+
locked_gem = @locked_specs[gem_name].last
|
174
|
+
raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote
|
175
|
+
raise GemNotFound, "Your bundle is locked to #{locked_gem}, but that version could not " \
|
176
|
+
"be found in any of the sources listed in your Gemfile. If you haven't changed sources, " \
|
177
|
+
"that means the author of #{locked_gem} has removed it. You'll need to update your bundle " \
|
178
|
+
"to a version other than #{locked_gem} that hasn't been removed in order to install."
|
179
|
+
end
|
180
|
+
unless specs["bundler"].any?
|
181
|
+
bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last
|
182
|
+
specs["bundler"] = bundler
|
183
|
+
end
|
184
|
+
|
185
|
+
specs
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def new_specs
|
190
|
+
specs - @locked_specs
|
191
|
+
end
|
192
|
+
|
193
|
+
def removed_specs
|
194
|
+
@locked_specs - specs
|
195
|
+
end
|
196
|
+
|
197
|
+
def new_platform?
|
198
|
+
@new_platform
|
199
|
+
end
|
200
|
+
|
201
|
+
def missing_specs
|
202
|
+
missing = []
|
203
|
+
resolve.materialize(requested_dependencies, missing)
|
204
|
+
missing
|
205
|
+
end
|
206
|
+
|
207
|
+
def missing_specs?
|
208
|
+
missing = missing_specs
|
209
|
+
return false if missing.empty?
|
210
|
+
Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}"
|
211
|
+
true
|
212
|
+
rescue BundlerError => e
|
213
|
+
@index = nil
|
214
|
+
@resolve = nil
|
215
|
+
@specs = nil
|
216
|
+
@gem_version_promoter = nil
|
217
|
+
|
218
|
+
Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})"
|
219
|
+
true
|
220
|
+
end
|
221
|
+
|
222
|
+
def requested_specs
|
223
|
+
@requested_specs ||= begin
|
224
|
+
groups = requested_groups
|
225
|
+
groups.map!(&:to_sym)
|
226
|
+
specs_for(groups)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def current_dependencies
|
231
|
+
dependencies.select(&:should_include?)
|
232
|
+
end
|
233
|
+
|
234
|
+
def specs_for(groups)
|
235
|
+
deps = dependencies.select {|d| (d.groups & groups).any? }
|
236
|
+
deps.delete_if {|d| !d.should_include? }
|
237
|
+
specs.for(expand_dependencies(deps))
|
238
|
+
end
|
239
|
+
|
240
|
+
# Resolve all the dependencies specified in Gemfile. It ensures that
|
241
|
+
# dependencies that have been already resolved via locked file and are fresh
|
242
|
+
# are reused when resolving dependencies
|
243
|
+
#
|
244
|
+
# @return [SpecSet] resolved dependencies
|
245
|
+
def resolve
|
246
|
+
@resolve ||= begin
|
247
|
+
last_resolve = converge_locked_specs
|
248
|
+
resolve =
|
249
|
+
if Bundler.frozen_bundle?
|
250
|
+
Bundler.ui.debug "Frozen, using resolution from the lockfile"
|
251
|
+
last_resolve
|
252
|
+
elsif !unlocking? && nothing_changed?
|
253
|
+
Bundler.ui.debug("Found no changes, using resolution from the lockfile")
|
254
|
+
last_resolve
|
255
|
+
else
|
256
|
+
# Run a resolve against the locally available gems
|
257
|
+
Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
|
258
|
+
last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms)
|
259
|
+
end
|
260
|
+
|
261
|
+
# filter out gems that _can_ be installed on multiple platforms, but don't need
|
262
|
+
# to be
|
263
|
+
resolve.for(expand_dependencies(dependencies, true), [], false, false, false)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def index
|
268
|
+
@index ||= Index.build do |idx|
|
269
|
+
dependency_names = @dependencies.map(&:name)
|
270
|
+
|
271
|
+
sources.all_sources.each do |source|
|
272
|
+
source.dependency_names = dependency_names - pinned_spec_names(source)
|
273
|
+
idx.add_source source.specs
|
274
|
+
dependency_names.concat(source.unmet_deps).uniq!
|
275
|
+
end
|
276
|
+
|
277
|
+
double_check_for_index(idx, dependency_names)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both
|
282
|
+
# sources A and B. At this point, the API request will have found all the versions of Bar in source A,
|
283
|
+
# but will not have found any versions of Bar from source B, which is a problem if the requested version
|
284
|
+
# of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for
|
285
|
+
# each spec we found, we add all possible versions from all sources to the index.
|
286
|
+
def double_check_for_index(idx, dependency_names)
|
287
|
+
pinned_names = pinned_spec_names
|
288
|
+
loop do
|
289
|
+
idxcount = idx.size
|
290
|
+
|
291
|
+
names = :names # do this so we only have to traverse to get dependency_names from the index once
|
292
|
+
unmet_dependency_names = lambda do
|
293
|
+
return names unless names == :names
|
294
|
+
new_names = sources.all_sources.map(&:dependency_names_to_double_check)
|
295
|
+
return names = nil if new_names.compact!
|
296
|
+
names = new_names.flatten(1).concat(dependency_names)
|
297
|
+
names.uniq!
|
298
|
+
names -= pinned_names
|
299
|
+
names
|
300
|
+
end
|
301
|
+
|
302
|
+
sources.all_sources.each do |source|
|
303
|
+
source.double_check_for(unmet_dependency_names)
|
304
|
+
end
|
305
|
+
|
306
|
+
break if idxcount == idx.size
|
307
|
+
end
|
308
|
+
end
|
309
|
+
private :double_check_for_index
|
310
|
+
|
311
|
+
def has_rubygems_remotes?
|
312
|
+
sources.rubygems_sources.any? {|s| s.remotes.any? }
|
313
|
+
end
|
314
|
+
|
315
|
+
def has_local_dependencies?
|
316
|
+
!sources.path_sources.empty? || !sources.git_sources.empty?
|
317
|
+
end
|
318
|
+
|
319
|
+
def spec_git_paths
|
320
|
+
sources.git_sources.map {|s| s.path.to_s }
|
321
|
+
end
|
322
|
+
|
323
|
+
def groups
|
324
|
+
dependencies.map(&:groups).flatten.uniq
|
325
|
+
end
|
326
|
+
|
327
|
+
def lock(file, preserve_unknown_sections = false)
|
328
|
+
contents = to_lock
|
329
|
+
|
330
|
+
# Convert to \r\n if the existing lock has them
|
331
|
+
# i.e., Windows with `git config core.autocrlf=true`
|
332
|
+
contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match("\r\n")
|
333
|
+
|
334
|
+
if @locked_bundler_version && Bundler.feature_flag.lockfile_upgrade_warning?
|
335
|
+
locked_major = @locked_bundler_version.segments.first
|
336
|
+
current_major = Gem::Version.create(Bundler::VERSION).segments.first
|
337
|
+
|
338
|
+
if updating_major = locked_major < current_major
|
339
|
+
Bundler.ui.warn "Warning: the lockfile is being updated to Bundler #{current_major}, " \
|
340
|
+
"after which you will be unable to return to Bundler #{@locked_bundler_version.segments.first}."
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
|
345
|
+
|
346
|
+
return if file && File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
|
347
|
+
|
348
|
+
if Bundler.frozen_bundle?
|
349
|
+
Bundler.ui.error "Cannot write a changed lockfile while frozen."
|
350
|
+
return
|
351
|
+
end
|
352
|
+
|
353
|
+
SharedHelpers.filesystem_access(file) do |p|
|
354
|
+
File.open(p, "wb") {|f| f.puts(contents) }
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
def locked_bundler_version
|
359
|
+
if @locked_bundler_version && @locked_bundler_version < Gem::Version.new(Bundler::VERSION)
|
360
|
+
new_version = Bundler::VERSION
|
361
|
+
end
|
362
|
+
|
363
|
+
new_version || @locked_bundler_version || Bundler::VERSION
|
364
|
+
end
|
365
|
+
|
366
|
+
def locked_ruby_version
|
367
|
+
return unless ruby_version
|
368
|
+
if @unlock[:ruby] || !@locked_ruby_version
|
369
|
+
Bundler::RubyVersion.system
|
370
|
+
else
|
371
|
+
@locked_ruby_version
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def locked_ruby_version_object
|
376
|
+
return unless @locked_ruby_version
|
377
|
+
@locked_ruby_version_object ||= begin
|
378
|
+
unless version = RubyVersion.from_string(@locked_ruby_version)
|
379
|
+
raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \
|
380
|
+
"#{@lockfile} could not be parsed. " \
|
381
|
+
"Try running bundle update --ruby to resolve this."
|
382
|
+
end
|
383
|
+
version
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
def to_lock
|
388
|
+
require "bundler/lockfile_generator"
|
389
|
+
LockfileGenerator.generate(self)
|
390
|
+
end
|
391
|
+
|
392
|
+
def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
|
393
|
+
msg = String.new
|
394
|
+
msg << "You are trying to install in deployment mode after changing\n" \
|
395
|
+
"your Gemfile. Run `bundle install` elsewhere and add the\n" \
|
396
|
+
"updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control."
|
397
|
+
|
398
|
+
unless explicit_flag
|
399
|
+
suggested_command = if Bundler.settings.locations("frozen")[:global]
|
400
|
+
"bundle config --delete frozen"
|
401
|
+
elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any?
|
402
|
+
"bundle config --delete deployment"
|
403
|
+
else
|
404
|
+
"bundle install --no-deployment"
|
405
|
+
end
|
406
|
+
msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \
|
407
|
+
"freeze \nby running `#{suggested_command}`."
|
408
|
+
end
|
409
|
+
|
410
|
+
added = []
|
411
|
+
deleted = []
|
412
|
+
changed = []
|
413
|
+
|
414
|
+
new_platforms = @platforms - @locked_platforms
|
415
|
+
deleted_platforms = @locked_platforms - @platforms
|
416
|
+
added.concat new_platforms.map {|p| "* platform: #{p}" }
|
417
|
+
deleted.concat deleted_platforms.map {|p| "* platform: #{p}" }
|
418
|
+
|
419
|
+
gemfile_sources = sources.lock_sources
|
420
|
+
|
421
|
+
new_sources = gemfile_sources - @locked_sources
|
422
|
+
deleted_sources = @locked_sources - gemfile_sources
|
423
|
+
|
424
|
+
new_deps = @dependencies - @locked_deps.values
|
425
|
+
deleted_deps = @locked_deps.values - @dependencies
|
426
|
+
|
427
|
+
# Check if it is possible that the source is only changed thing
|
428
|
+
if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?)
|
429
|
+
new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
|
430
|
+
deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
|
431
|
+
end
|
432
|
+
|
433
|
+
if @locked_sources != gemfile_sources
|
434
|
+
if new_sources.any?
|
435
|
+
added.concat new_sources.map {|source| "* source: #{source}" }
|
436
|
+
end
|
437
|
+
|
438
|
+
if deleted_sources.any?
|
439
|
+
deleted.concat deleted_sources.map {|source| "* source: #{source}" }
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
|
444
|
+
if deleted_deps.any?
|
445
|
+
deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" }
|
446
|
+
end
|
447
|
+
|
448
|
+
both_sources = Hash.new {|h, k| h[k] = [] }
|
449
|
+
@dependencies.each {|d| both_sources[d.name][0] = d }
|
450
|
+
@locked_deps.each {|name, d| both_sources[name][1] = d.source }
|
451
|
+
|
452
|
+
both_sources.each do |name, (dep, lock_source)|
|
453
|
+
next unless (dep.nil? && !lock_source.nil?) || (!dep.nil? && !lock_source.nil? && !lock_source.can_lock?(dep))
|
454
|
+
gemfile_source_name = (dep && dep.source) || "no specified source"
|
455
|
+
lockfile_source_name = lock_source || "no specified source"
|
456
|
+
changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`"
|
457
|
+
end
|
458
|
+
|
459
|
+
reason = change_reason
|
460
|
+
msg << "\n\n#{reason.split(", ").map(&:capitalize).join("\n")}" unless reason.strip.empty?
|
461
|
+
msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
|
462
|
+
msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
|
463
|
+
msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any?
|
464
|
+
msg << "\n"
|
465
|
+
|
466
|
+
raise ProductionError, msg if added.any? || deleted.any? || changed.any? || !nothing_changed?
|
467
|
+
end
|
468
|
+
|
469
|
+
def validate_runtime!
|
470
|
+
validate_ruby!
|
471
|
+
validate_platforms!
|
472
|
+
end
|
473
|
+
|
474
|
+
def validate_ruby!
|
475
|
+
return unless ruby_version
|
476
|
+
|
477
|
+
if diff = ruby_version.diff(Bundler::RubyVersion.system)
|
478
|
+
problem, expected, actual = diff
|
479
|
+
|
480
|
+
msg = case problem
|
481
|
+
when :engine
|
482
|
+
"Your Ruby engine is #{actual}, but your Gemfile specified #{expected}"
|
483
|
+
when :version
|
484
|
+
"Your Ruby version is #{actual}, but your Gemfile specified #{expected}"
|
485
|
+
when :engine_version
|
486
|
+
"Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}"
|
487
|
+
when :patchlevel
|
488
|
+
if !expected.is_a?(String)
|
489
|
+
"The Ruby patchlevel in your Gemfile must be a string"
|
490
|
+
else
|
491
|
+
"Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}"
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
raise RubyVersionMismatch, msg
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
def validate_platforms!
|
500
|
+
return if @platforms.any? do |bundle_platform|
|
501
|
+
Bundler.rubygems.platforms.any? do |local_platform|
|
502
|
+
MatchPlatform.platforms_match?(bundle_platform, local_platform)
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
|
507
|
+
"but your local platforms are #{Bundler.rubygems.platforms.map(&:to_s)}, and " \
|
508
|
+
"there's no compatible match between those two lists."
|
509
|
+
end
|
510
|
+
|
511
|
+
def add_platform(platform)
|
512
|
+
@new_platform ||= !@platforms.include?(platform)
|
513
|
+
@platforms |= [platform]
|
514
|
+
end
|
515
|
+
|
516
|
+
def remove_platform(platform)
|
517
|
+
return if @platforms.delete(Gem::Platform.new(platform))
|
518
|
+
raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
|
519
|
+
end
|
520
|
+
|
521
|
+
def add_current_platform
|
522
|
+
current_platform = Bundler.local_platform
|
523
|
+
add_platform(current_platform) if Bundler.feature_flag.specific_platform?
|
524
|
+
add_platform(generic(current_platform))
|
525
|
+
end
|
526
|
+
|
527
|
+
def find_resolved_spec(current_spec)
|
528
|
+
specs.find_by_name_and_platform(current_spec.name, current_spec.platform)
|
529
|
+
end
|
530
|
+
|
531
|
+
def find_indexed_specs(current_spec)
|
532
|
+
index[current_spec.name].select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version)
|
533
|
+
end
|
534
|
+
|
535
|
+
attr_reader :sources
|
536
|
+
private :sources
|
537
|
+
|
538
|
+
def nothing_changed?
|
539
|
+
!@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform
|
540
|
+
end
|
541
|
+
|
542
|
+
def unlocking?
|
543
|
+
@unlocking
|
544
|
+
end
|
545
|
+
|
546
|
+
private
|
547
|
+
|
548
|
+
def change_reason
|
549
|
+
if unlocking?
|
550
|
+
unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v|
|
551
|
+
if v == true
|
552
|
+
k.to_s
|
553
|
+
else
|
554
|
+
v = Array(v)
|
555
|
+
"#{k}: (#{v.join(", ")})"
|
556
|
+
end
|
557
|
+
end.join(", ")
|
558
|
+
return "bundler is unlocking #{unlock_reason}"
|
559
|
+
end
|
560
|
+
[
|
561
|
+
[@source_changes, "the list of sources changed"],
|
562
|
+
[@dependency_changes, "the dependencies in your gemfile changed"],
|
563
|
+
[@new_platform, "you added a new platform to your gemfile"],
|
564
|
+
[@path_changes, "the gemspecs for path gems changed"],
|
565
|
+
[@local_changes, "the gemspecs for git local gems changed"],
|
566
|
+
[@locked_specs_incomplete_for_platform, "the lockfile does not have all gems needed for the current platform"],
|
567
|
+
].select(&:first).map(&:last).join(", ")
|
568
|
+
end
|
569
|
+
|
570
|
+
def pretty_dep(dep, source = false)
|
571
|
+
SharedHelpers.pretty_dependency(dep, source)
|
572
|
+
end
|
573
|
+
|
574
|
+
# Check if the specs of the given source changed
|
575
|
+
# according to the locked source.
|
576
|
+
def specs_changed?(source)
|
577
|
+
locked = @locked_sources.find {|s| s == source }
|
578
|
+
|
579
|
+
!locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source)
|
580
|
+
end
|
581
|
+
|
582
|
+
def dependencies_for_source_changed?(source, locked_source = source)
|
583
|
+
deps_for_source = @dependencies.select {|s| s.source == source }
|
584
|
+
locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source }
|
585
|
+
|
586
|
+
Set.new(deps_for_source) != Set.new(locked_deps_for_source)
|
587
|
+
end
|
588
|
+
|
589
|
+
def specs_for_source_changed?(source)
|
590
|
+
locked_index = Index.new
|
591
|
+
locked_index.use(@locked_specs.select {|s| source.can_lock?(s) })
|
592
|
+
|
593
|
+
# order here matters, since Index#== is checking source.specs.include?(locked_index)
|
594
|
+
locked_index != source.specs
|
595
|
+
rescue PathError, GitError => e
|
596
|
+
Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})"
|
597
|
+
false
|
598
|
+
end
|
599
|
+
|
600
|
+
# Get all locals and override their matching sources.
|
601
|
+
# Return true if any of the locals changed (for example,
|
602
|
+
# they point to a new revision) or depend on new specs.
|
603
|
+
def converge_locals
|
604
|
+
locals = []
|
605
|
+
|
606
|
+
Bundler.settings.local_overrides.map do |k, v|
|
607
|
+
spec = @dependencies.find {|s| s.name == k }
|
608
|
+
source = spec && spec.source
|
609
|
+
if source && source.respond_to?(:local_override!)
|
610
|
+
source.unlock! if @unlock[:gems].include?(spec.name)
|
611
|
+
locals << [source, source.local_override!(v)]
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
sources_with_changes = locals.select do |source, changed|
|
616
|
+
changed || specs_changed?(source)
|
617
|
+
end.map(&:first)
|
618
|
+
!sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty?
|
619
|
+
end
|
620
|
+
|
621
|
+
def converge_paths
|
622
|
+
sources.path_sources.any? do |source|
|
623
|
+
specs_changed?(source)
|
624
|
+
end
|
625
|
+
end
|
626
|
+
|
627
|
+
def converge_path_source_to_gemspec_source(source)
|
628
|
+
return source unless source.instance_of?(Source::Path)
|
629
|
+
gemspec_source = sources.path_sources.find {|s| s.is_a?(Source::Gemspec) && s.as_path_source == source }
|
630
|
+
gemspec_source || source
|
631
|
+
end
|
632
|
+
|
633
|
+
def converge_path_sources_to_gemspec_sources
|
634
|
+
@locked_sources.map! do |source|
|
635
|
+
converge_path_source_to_gemspec_source(source)
|
636
|
+
end
|
637
|
+
@locked_specs.each do |spec|
|
638
|
+
spec.source &&= converge_path_source_to_gemspec_source(spec.source)
|
639
|
+
end
|
640
|
+
@locked_deps.each do |_, dep|
|
641
|
+
dep.source &&= converge_path_source_to_gemspec_source(dep.source)
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
def converge_rubygems_sources
|
646
|
+
return false if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
|
647
|
+
|
648
|
+
changes = false
|
649
|
+
|
650
|
+
# Get the RubyGems sources from the Gemfile.lock
|
651
|
+
locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
|
652
|
+
# Get the RubyGems remotes from the Gemfile
|
653
|
+
actual_remotes = sources.rubygems_remotes
|
654
|
+
|
655
|
+
# If there is a RubyGems source in both
|
656
|
+
if !locked_gem_sources.empty? && !actual_remotes.empty?
|
657
|
+
locked_gem_sources.each do |locked_gem|
|
658
|
+
# Merge the remotes from the Gemfile into the Gemfile.lock
|
659
|
+
changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes])
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
changes
|
664
|
+
end
|
665
|
+
|
666
|
+
def converge_sources
|
667
|
+
changes = false
|
668
|
+
|
669
|
+
changes |= converge_rubygems_sources
|
670
|
+
|
671
|
+
# Replace the sources from the Gemfile with the sources from the Gemfile.lock,
|
672
|
+
# if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent
|
673
|
+
# source in the Gemfile.lock, use the one from the Gemfile.
|
674
|
+
changes |= sources.replace_sources!(@locked_sources)
|
675
|
+
|
676
|
+
sources.all_sources.each do |source|
|
677
|
+
# If the source is unlockable and the current command allows an unlock of
|
678
|
+
# the source (for example, you are doing a `bundle update <foo>` of a git-pinned
|
679
|
+
# gem), unlock it. For git sources, this means to unlock the revision, which
|
680
|
+
# will cause the `ref` used to be the most recent for the branch (or master) if
|
681
|
+
# an explicit `ref` is not used.
|
682
|
+
if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
|
683
|
+
source.unlock!
|
684
|
+
changes = true
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
changes
|
689
|
+
end
|
690
|
+
|
691
|
+
def converge_dependencies
|
692
|
+
frozen = Bundler.frozen_bundle?
|
693
|
+
(@dependencies + @locked_deps.values).each do |dep|
|
694
|
+
locked_source = @locked_deps[dep.name]
|
695
|
+
# This is to make sure that if bundler is installing in deployment mode and
|
696
|
+
# after locked_source and sources don't match, we still use locked_source.
|
697
|
+
if frozen && !locked_source.nil? &&
|
698
|
+
locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist?
|
699
|
+
dep.source = locked_source.source
|
700
|
+
elsif dep.source
|
701
|
+
dep.source = sources.get(dep.source)
|
702
|
+
end
|
703
|
+
if dep.source.is_a?(Source::Gemspec)
|
704
|
+
dep.platforms.concat(@platforms.map {|p| Dependency::REVERSE_PLATFORM_MAP[p] }.flatten(1)).uniq!
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
changes = false
|
709
|
+
# We want to know if all match, but don't want to check all entries
|
710
|
+
# This means we need to return false if any dependency doesn't match
|
711
|
+
# the lock or doesn't exist in the lock.
|
712
|
+
@dependencies.each do |dependency|
|
713
|
+
unless locked_dep = @locked_deps[dependency.name]
|
714
|
+
changes = true
|
715
|
+
next
|
716
|
+
end
|
717
|
+
|
718
|
+
# Gem::Dependency#== matches Gem::Dependency#type. As the lockfile
|
719
|
+
# doesn't carry a notion of the dependency type, if you use
|
720
|
+
# add_development_dependency in a gemspec that's loaded with the gemspec
|
721
|
+
# directive, the lockfile dependencies and resolved dependencies end up
|
722
|
+
# with a mismatch on #type. Work around that by setting the type on the
|
723
|
+
# dep from the lockfile.
|
724
|
+
locked_dep.instance_variable_set(:@type, dependency.type)
|
725
|
+
|
726
|
+
# We already know the name matches from the hash lookup
|
727
|
+
# so we only need to check the requirement now
|
728
|
+
changes ||= dependency.requirement != locked_dep.requirement
|
729
|
+
end
|
730
|
+
|
731
|
+
changes
|
732
|
+
end
|
733
|
+
|
734
|
+
# Remove elements from the locked specs that are expired. This will most
|
735
|
+
# commonly happen if the Gemfile has changed since the lockfile was last
|
736
|
+
# generated
|
737
|
+
def converge_locked_specs
|
738
|
+
deps = []
|
739
|
+
|
740
|
+
# Build a list of dependencies that are the same in the Gemfile
|
741
|
+
# and Gemfile.lock. If the Gemfile modified a dependency, but
|
742
|
+
# the gem in the Gemfile.lock still satisfies it, this is fine
|
743
|
+
# too.
|
744
|
+
@dependencies.each do |dep|
|
745
|
+
locked_dep = @locked_deps[dep.name]
|
746
|
+
|
747
|
+
# If the locked_dep doesn't match the dependency we're looking for then we ignore the locked_dep
|
748
|
+
locked_dep = nil unless locked_dep == dep
|
749
|
+
|
750
|
+
if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep)
|
751
|
+
deps << dep
|
752
|
+
elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source)
|
753
|
+
@locked_specs.each do |s|
|
754
|
+
@unlock[:gems] << s.name if s.source == dep.source
|
755
|
+
end
|
756
|
+
|
757
|
+
dep.source.unlock! if dep.source.respond_to?(:unlock!)
|
758
|
+
dep.source.specs.each {|s| @unlock[:gems] << s.name }
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
unlock_source_unlocks_spec = Bundler.feature_flag.unlock_source_unlocks_spec?
|
763
|
+
|
764
|
+
converged = []
|
765
|
+
@locked_specs.each do |s|
|
766
|
+
# Replace the locked dependency's source with the equivalent source from the Gemfile
|
767
|
+
dep = @dependencies.find {|d| s.satisfies?(d) }
|
768
|
+
s.source = (dep && dep.source) || sources.get(s.source)
|
769
|
+
|
770
|
+
# Don't add a spec to the list if its source is expired. For example,
|
771
|
+
# if you change a Git gem to RubyGems.
|
772
|
+
next if s.source.nil?
|
773
|
+
next if @unlock[:sources].include?(s.source.name)
|
774
|
+
|
775
|
+
# XXX This is a backwards-compatibility fix to preserve the ability to
|
776
|
+
# unlock a single gem by passing its name via `--source`. See issue #3759
|
777
|
+
# TODO: delete in Bundler 2
|
778
|
+
next if unlock_source_unlocks_spec && @unlock[:sources].include?(s.name)
|
779
|
+
|
780
|
+
# If the spec is from a path source and it doesn't exist anymore
|
781
|
+
# then we unlock it.
|
782
|
+
|
783
|
+
# Path sources have special logic
|
784
|
+
if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
|
785
|
+
other_sources_specs = begin
|
786
|
+
s.source.specs
|
787
|
+
rescue PathError, GitError
|
788
|
+
# if we won't need the source (according to the lockfile),
|
789
|
+
# don't error if the path/git source isn't available
|
790
|
+
next if @locked_specs.
|
791
|
+
for(requested_dependencies, [], false, true, false).
|
792
|
+
none? {|locked_spec| locked_spec.source == s.source }
|
793
|
+
|
794
|
+
raise
|
795
|
+
end
|
796
|
+
|
797
|
+
other = other_sources_specs[s].first
|
798
|
+
|
799
|
+
# If the spec is no longer in the path source, unlock it. This
|
800
|
+
# commonly happens if the version changed in the gemspec
|
801
|
+
next unless other
|
802
|
+
|
803
|
+
deps2 = other.dependencies.select {|d| d.type != :development }
|
804
|
+
runtime_dependencies = s.dependencies.select {|d| d.type != :development }
|
805
|
+
# If the dependencies of the path source have changed, unlock it
|
806
|
+
next unless runtime_dependencies.sort == deps2.sort
|
807
|
+
end
|
808
|
+
|
809
|
+
converged << s
|
810
|
+
end
|
811
|
+
|
812
|
+
resolve = SpecSet.new(converged)
|
813
|
+
expanded_deps = expand_dependencies(deps, true)
|
814
|
+
@locked_specs_incomplete_for_platform = !resolve.for(expanded_deps, @unlock[:gems], true, true)
|
815
|
+
resolve = resolve.for(expanded_deps, @unlock[:gems], false, false, false)
|
816
|
+
diff = nil
|
817
|
+
|
818
|
+
# Now, we unlock any sources that do not have anymore gems pinned to it
|
819
|
+
sources.all_sources.each do |source|
|
820
|
+
next unless source.respond_to?(:unlock!)
|
821
|
+
|
822
|
+
unless resolve.any? {|s| s.source == source }
|
823
|
+
diff ||= @locked_specs.to_a - resolve.to_a
|
824
|
+
source.unlock! if diff.any? {|s| s.source == source }
|
825
|
+
end
|
826
|
+
end
|
827
|
+
|
828
|
+
resolve
|
829
|
+
end
|
830
|
+
|
831
|
+
def in_locked_deps?(dep, locked_dep)
|
832
|
+
# Because the lockfile can't link a dep to a specific remote, we need to
|
833
|
+
# treat sources as equivalent anytime the locked dep has all the remotes
|
834
|
+
# that the Gemfile dep does.
|
835
|
+
locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source)
|
836
|
+
end
|
837
|
+
|
838
|
+
def satisfies_locked_spec?(dep)
|
839
|
+
@locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
|
840
|
+
end
|
841
|
+
|
842
|
+
# This list of dependencies is only used in #resolve, so it's OK to add
|
843
|
+
# the metadata dependencies here
|
844
|
+
def expanded_dependencies
|
845
|
+
@expanded_dependencies ||= begin
|
846
|
+
expand_dependencies(dependencies + metadata_dependencies, @remote)
|
847
|
+
end
|
848
|
+
end
|
849
|
+
|
850
|
+
def metadata_dependencies
|
851
|
+
@metadata_dependencies ||= begin
|
852
|
+
ruby_versions = concat_ruby_version_requirements(@ruby_version)
|
853
|
+
if ruby_versions.empty? || !@ruby_version.exact?
|
854
|
+
concat_ruby_version_requirements(RubyVersion.system)
|
855
|
+
concat_ruby_version_requirements(locked_ruby_version_object) unless @unlock[:ruby]
|
856
|
+
end
|
857
|
+
[
|
858
|
+
Dependency.new("ruby\0", ruby_versions),
|
859
|
+
Dependency.new("rubygems\0", Gem::VERSION),
|
860
|
+
]
|
861
|
+
end
|
862
|
+
end
|
863
|
+
|
864
|
+
def concat_ruby_version_requirements(ruby_version, ruby_versions = [])
|
865
|
+
return ruby_versions unless ruby_version
|
866
|
+
if ruby_version.patchlevel
|
867
|
+
ruby_versions << ruby_version.to_gem_version_with_patchlevel
|
868
|
+
else
|
869
|
+
ruby_versions.concat(ruby_version.versions.map do |version|
|
870
|
+
requirement = Gem::Requirement.new(version)
|
871
|
+
if requirement.exact?
|
872
|
+
"~> #{version}.0"
|
873
|
+
else
|
874
|
+
requirement
|
875
|
+
end
|
876
|
+
end)
|
877
|
+
end
|
878
|
+
end
|
879
|
+
|
880
|
+
def expand_dependencies(dependencies, remote = false)
|
881
|
+
sorted_platforms = Resolver.sort_platforms(@platforms)
|
882
|
+
deps = []
|
883
|
+
dependencies.each do |dep|
|
884
|
+
dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
|
885
|
+
next if !remote && !dep.current_platform?
|
886
|
+
platforms = dep.gem_platforms(sorted_platforms)
|
887
|
+
if platforms.empty? && !Bundler.settings[:disable_platform_warnings]
|
888
|
+
mapped_platforms = dep.platforms.map {|p| Dependency::PLATFORM_MAP[p] }
|
889
|
+
Bundler.ui.warn \
|
890
|
+
"The dependency #{dep} will be unused by any of the platforms Bundler is installing for. " \
|
891
|
+
"Bundler is installing for #{@platforms.join ", "} but the dependency " \
|
892
|
+
"is only for #{mapped_platforms.join ", "}. " \
|
893
|
+
"To add those platforms to the bundle, " \
|
894
|
+
"run `bundle lock --add-platform #{mapped_platforms.join " "}`."
|
895
|
+
end
|
896
|
+
platforms.each do |p|
|
897
|
+
deps << DepProxy.new(dep, p) if remote || p == generic_local_platform
|
898
|
+
end
|
899
|
+
end
|
900
|
+
deps
|
901
|
+
end
|
902
|
+
|
903
|
+
def requested_dependencies
|
904
|
+
groups = requested_groups
|
905
|
+
groups.map!(&:to_sym)
|
906
|
+
dependencies.reject {|d| !d.should_include? || (d.groups & groups).empty? }
|
907
|
+
end
|
908
|
+
|
909
|
+
def source_requirements
|
910
|
+
# Load all specs from remote sources
|
911
|
+
index
|
912
|
+
|
913
|
+
# Record the specs available in each gem's source, so that those
|
914
|
+
# specs will be available later when the resolver knows where to
|
915
|
+
# look for that gemspec (or its dependencies)
|
916
|
+
default = sources.default_source
|
917
|
+
source_requirements = { :default => default }
|
918
|
+
default = nil unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
|
919
|
+
dependencies.each do |dep|
|
920
|
+
next unless source = dep.source || default
|
921
|
+
source_requirements[dep.name] = source
|
922
|
+
end
|
923
|
+
metadata_dependencies.each do |dep|
|
924
|
+
source_requirements[dep.name] = sources.metadata_source
|
925
|
+
end
|
926
|
+
source_requirements["bundler"] = sources.metadata_source # needs to come last to override
|
927
|
+
source_requirements
|
928
|
+
end
|
929
|
+
|
930
|
+
def pinned_spec_names(skip = nil)
|
931
|
+
pinned_names = []
|
932
|
+
default = Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? && sources.default_source
|
933
|
+
@dependencies.each do |dep|
|
934
|
+
next unless dep_source = dep.source || default
|
935
|
+
next if dep_source == skip
|
936
|
+
pinned_names << dep.name
|
937
|
+
end
|
938
|
+
pinned_names
|
939
|
+
end
|
940
|
+
|
941
|
+
def requested_groups
|
942
|
+
groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with]
|
943
|
+
end
|
944
|
+
|
945
|
+
def lockfiles_equal?(current, proposed, preserve_unknown_sections)
|
946
|
+
if preserve_unknown_sections
|
947
|
+
sections_to_ignore = LockfileParser.sections_to_ignore(@locked_bundler_version)
|
948
|
+
sections_to_ignore += LockfileParser.unknown_sections_in_lockfile(current)
|
949
|
+
sections_to_ignore += LockfileParser::ENVIRONMENT_VERSION_SECTIONS
|
950
|
+
pattern = /#{Regexp.union(sections_to_ignore)}\n(\s{2,}.*\n)+/
|
951
|
+
whitespace_cleanup = /\n{2,}/
|
952
|
+
current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip
|
953
|
+
proposed = proposed.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip
|
954
|
+
end
|
955
|
+
current == proposed
|
956
|
+
end
|
957
|
+
|
958
|
+
def extract_gem_info(error)
|
959
|
+
# This method will extract the error message like "Could not find foo-1.2.3 in any of the sources"
|
960
|
+
# to an array. The first element will be the gem name (e.g. foo), the second will be the version number.
|
961
|
+
error.message.scan(/Could not find (\w+)-(\d+(?:\.\d+)+)/).flatten
|
962
|
+
end
|
963
|
+
|
964
|
+
def compute_requires
|
965
|
+
dependencies.reduce({}) do |requires, dep|
|
966
|
+
next requires unless dep.should_include?
|
967
|
+
requires[dep.name] = Array(dep.autorequire || dep.name).map do |file|
|
968
|
+
# Allow `require: true` as an alias for `require: <name>`
|
969
|
+
file == true ? dep.name : file
|
970
|
+
end
|
971
|
+
requires
|
972
|
+
end
|
973
|
+
end
|
974
|
+
|
975
|
+
def additional_base_requirements_for_resolve
|
976
|
+
return [] unless @locked_gems && Bundler.feature_flag.only_update_to_newer_versions?
|
977
|
+
dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) }
|
978
|
+
@locked_gems.specs.reduce({}) do |requirements, locked_spec|
|
979
|
+
name = locked_spec.name
|
980
|
+
dependency = dependencies_by_name[name]
|
981
|
+
next requirements if @locked_gems.dependencies[name] != dependency
|
982
|
+
next requirements if dependency && dependency.source.is_a?(Source::Path)
|
983
|
+
dep = Gem::Dependency.new(name, ">= #{locked_spec.version}")
|
984
|
+
requirements[name] = DepProxy.new(dep, locked_spec.platform)
|
985
|
+
requirements
|
986
|
+
end.values
|
987
|
+
end
|
988
|
+
|
989
|
+
def equivalent_rubygems_remotes?(source)
|
990
|
+
return false unless source.is_a?(Source::Rubygems)
|
991
|
+
|
992
|
+
Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes)
|
993
|
+
end
|
994
|
+
end
|
995
|
+
end
|