bundler 1.13.7 → 1.14.0.pre.1
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 +4 -4
- data/.gitignore +2 -0
- data/.rubocop_todo.yml +100 -18
- data/.travis.yml +32 -18
- data/CHANGELOG.md +64 -2
- data/DEVELOPMENT.md +5 -3
- data/ISSUES.md +17 -0
- data/README.md +7 -0
- data/Rakefile +34 -23
- data/bin/rubocop +1 -1
- data/bundler.gemspec +2 -2
- data/exe/bundle +4 -6
- data/lib/bundler.rb +57 -5
- data/lib/bundler/cli.rb +51 -38
- data/lib/bundler/cli/binstubs.rb +1 -1
- data/lib/bundler/cli/cache.rb +1 -1
- data/lib/bundler/cli/check.rb +1 -1
- data/lib/bundler/cli/clean.rb +1 -1
- data/lib/bundler/cli/common.rb +30 -0
- data/lib/bundler/cli/doctor.rb +17 -19
- data/lib/bundler/cli/exec.rb +6 -0
- data/lib/bundler/cli/gem.rb +18 -4
- data/lib/bundler/cli/install.rb +9 -25
- data/lib/bundler/cli/lock.rb +8 -7
- data/lib/bundler/cli/outdated.rb +163 -56
- data/lib/bundler/cli/platform.rb +1 -1
- data/lib/bundler/cli/show.rb +1 -1
- data/lib/bundler/cli/update.rb +10 -23
- data/lib/bundler/compact_index_client.rb +108 -0
- data/lib/bundler/compact_index_client/cache.rb +119 -0
- data/lib/bundler/compact_index_client/updater.rb +88 -0
- data/lib/bundler/current_ruby.rb +4 -3
- data/lib/bundler/definition.rb +107 -17
- data/lib/bundler/dependency.rb +6 -0
- data/lib/bundler/dsl.rb +3 -2
- data/lib/bundler/env.rb +27 -18
- data/lib/bundler/errors.rb +22 -0
- data/lib/bundler/feature_flag.rb +32 -0
- data/lib/bundler/fetcher.rb +2 -2
- data/lib/bundler/fetcher/compact_index.rb +17 -5
- data/lib/bundler/fetcher/dependency.rb +1 -1
- data/lib/bundler/fetcher/downloader.rb +11 -0
- data/lib/bundler/friendly_errors.rb +28 -7
- data/lib/bundler/gem_helper.rb +1 -1
- data/lib/bundler/gem_helpers.rb +69 -1
- data/lib/bundler/gemdeps.rb +28 -0
- data/lib/bundler/index.rb +9 -4
- data/lib/bundler/inline.rb +3 -3
- data/lib/bundler/installer.rb +3 -2
- data/lib/bundler/installer/gem_installer.rb +2 -2
- data/lib/bundler/installer/parallel_installer.rb +40 -9
- data/lib/bundler/lazy_specification.rb +16 -1
- data/lib/bundler/lockfile_parser.rb +1 -2
- data/lib/bundler/match_platform.rb +12 -3
- data/lib/bundler/plugin.rb +4 -2
- data/lib/bundler/plugin/api.rb +2 -1
- data/lib/bundler/plugin/api/source.rb +1 -1
- data/lib/bundler/postit_trampoline.rb +12 -7
- data/lib/bundler/remote_specification.rb +5 -0
- data/lib/bundler/resolver.rb +59 -49
- data/lib/bundler/retry.rb +4 -1
- data/lib/bundler/ruby_version.rb +5 -0
- data/lib/bundler/rubygems_ext.rb +5 -0
- data/lib/bundler/rubygems_gem_installer.rb +60 -0
- data/lib/bundler/rubygems_integration.rb +28 -2
- data/lib/bundler/runtime.rb +2 -1
- data/lib/bundler/settings.rb +29 -5
- data/lib/bundler/setup.rb +1 -1
- data/lib/bundler/shared_helpers.rb +26 -15
- data/lib/bundler/source.rb +5 -0
- data/lib/bundler/source/git.rb +1 -1
- data/lib/bundler/source/git/git_proxy.rb +5 -0
- data/lib/bundler/source/path.rb +6 -1
- data/lib/bundler/source/rubygems.rb +11 -1
- data/lib/bundler/spec_set.rb +32 -13
- data/lib/bundler/templates/newgem/README.md.tt +1 -1
- data/lib/bundler/templates/newgem/bin/console.tt +1 -1
- data/lib/bundler/templates/newgem/gitignore.tt +5 -0
- data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +1 -1
- data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +10 -1
- data/lib/bundler/ui/shell.rb +4 -0
- data/lib/bundler/ui/silent.rb +9 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +7 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +1 -1
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +2 -2
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +2 -2
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +62 -0
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +1 -1
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +12 -1
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +2 -2
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +2 -2
- data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +1 -1
- data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +22 -13
- data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/faster.rb +1 -0
- data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/persistent.rb +24 -23
- data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/persistent/ssl_reuse.rb +2 -1
- data/lib/bundler/vendored_persistent.rb +9 -4
- data/lib/bundler/version.rb +1 -1
- data/lib/bundler/worker.rb +27 -5
- data/lib/bundler/yaml_serializer.rb +1 -1
- data/man/bundle-config.ronn +29 -2
- data/man/bundle-install.ronn +1 -1
- data/man/bundle-lock.ronn +47 -0
- data/man/bundle-outdated.ronn +107 -0
- data/man/bundle-update.ronn +152 -3
- data/man/bundle.ronn +27 -9
- data/man/gemfile.5.ronn +8 -0
- metadata +37 -31
- data/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb +0 -79
- data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/cache.rb +0 -112
- data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb +0 -80
- data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/version.rb +0 -4
data/lib/bundler/cli/platform.rb
CHANGED
@@ -29,7 +29,7 @@ module Bundler
|
|
29
29
|
output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}"
|
30
30
|
|
31
31
|
begin
|
32
|
-
Bundler.definition.
|
32
|
+
Bundler.definition.validate_runtime!
|
33
33
|
output << "Your current platform satisfies the Ruby version requirement."
|
34
34
|
rescue RubyVersionMismatch => e
|
35
35
|
output << e.message
|
data/lib/bundler/cli/show.rb
CHANGED
data/lib/bundler/cli/update.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "bundler/cli/common"
|
3
|
+
|
2
4
|
module Bundler
|
3
5
|
class CLI::Update
|
4
6
|
attr_reader :options, :gems
|
@@ -10,7 +12,7 @@ module Bundler
|
|
10
12
|
def run
|
11
13
|
Bundler.ui.level = "error" if options[:quiet]
|
12
14
|
|
13
|
-
Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.
|
15
|
+
Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
|
14
16
|
|
15
17
|
sources = Array(options[:source])
|
16
18
|
groups = Array(options[:group]).map(&:to_sym)
|
@@ -27,7 +29,6 @@ module Bundler
|
|
27
29
|
names = Bundler.locked_gems.specs.map(&:name)
|
28
30
|
gems.each do |g|
|
29
31
|
next if names.include?(g)
|
30
|
-
require "bundler/cli/common"
|
31
32
|
raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(g, names)
|
32
33
|
end
|
33
34
|
|
@@ -36,15 +37,11 @@ module Bundler
|
|
36
37
|
gems.concat(specs.map(&:name))
|
37
38
|
end
|
38
39
|
|
39
|
-
Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby]
|
40
|
+
Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby],
|
41
|
+
:lock_shared_dependencies => options[:conservative])
|
40
42
|
end
|
41
43
|
|
42
|
-
|
43
|
-
raise ProductionError, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1
|
44
|
-
Bundler.definition.gem_version_promoter.tap do |gvp|
|
45
|
-
gvp.level = patch_level.first || :major
|
46
|
-
gvp.strict = options[:strict]
|
47
|
-
end
|
44
|
+
Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options)
|
48
45
|
|
49
46
|
Bundler::Fetcher.disable_endpoint = options["full-index"]
|
50
47
|
|
@@ -54,11 +51,8 @@ module Bundler
|
|
54
51
|
|
55
52
|
Bundler.settings[:jobs] = opts["jobs"] if opts["jobs"]
|
56
53
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
Bundler.definition.validate_ruby!
|
61
|
-
Installer.install Bundler.root, Bundler.definition, opts
|
54
|
+
Bundler.definition.validate_runtime!
|
55
|
+
installer = Installer.install Bundler.root, Bundler.definition, opts
|
62
56
|
Bundler.load.cache if Bundler.app_cache.exist?
|
63
57
|
|
64
58
|
if Bundler.settings[:clean] && Bundler.settings[:path]
|
@@ -67,15 +61,8 @@ module Bundler
|
|
67
61
|
end
|
68
62
|
|
69
63
|
Bundler.ui.confirm "Bundle updated!"
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
def without_groups_messages
|
76
|
-
return unless Bundler.settings.without.any?
|
77
|
-
require "bundler/cli/common"
|
78
|
-
Bundler.ui.confirm Bundler::CLI::Common.without_groups_message
|
64
|
+
Bundler::CLI::Common.output_without_groups_message
|
65
|
+
Bundler::CLI::Common.output_post_install_messages installer.post_install_messages
|
79
66
|
end
|
80
67
|
end
|
81
68
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "pathname"
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
module Bundler
|
6
|
+
class CompactIndexClient
|
7
|
+
DEBUG_MUTEX = Mutex.new
|
8
|
+
def self.debug
|
9
|
+
return unless ENV["DEBUG_COMPACT_INDEX"]
|
10
|
+
DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") }
|
11
|
+
end
|
12
|
+
|
13
|
+
class Error < StandardError; end
|
14
|
+
|
15
|
+
require "bundler/compact_index_client/cache"
|
16
|
+
require "bundler/compact_index_client/updater"
|
17
|
+
|
18
|
+
attr_reader :directory
|
19
|
+
|
20
|
+
# @return [Lambda] A lambda that takes an array of inputs and a block, and
|
21
|
+
# maps the inputs with the block in parallel.
|
22
|
+
#
|
23
|
+
attr_accessor :in_parallel
|
24
|
+
|
25
|
+
def initialize(directory, fetcher)
|
26
|
+
@directory = Pathname.new(directory)
|
27
|
+
@updater = Updater.new(fetcher)
|
28
|
+
@cache = Cache.new(@directory)
|
29
|
+
@endpoints = Set.new
|
30
|
+
@info_checksums_by_name = {}
|
31
|
+
@parsed_checksums = false
|
32
|
+
@mutex = Mutex.new
|
33
|
+
@in_parallel = lambda do |inputs, &blk|
|
34
|
+
inputs.map(&blk)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def names
|
39
|
+
Bundler::CompactIndexClient.debug { "/names" }
|
40
|
+
update(@cache.names_path, "names")
|
41
|
+
@cache.names
|
42
|
+
end
|
43
|
+
|
44
|
+
def versions
|
45
|
+
Bundler::CompactIndexClient.debug { "/versions" }
|
46
|
+
update(@cache.versions_path, "versions")
|
47
|
+
versions, @info_checksums_by_name = @cache.versions
|
48
|
+
versions
|
49
|
+
end
|
50
|
+
|
51
|
+
def dependencies(names)
|
52
|
+
Bundler::CompactIndexClient.debug { "dependencies(#{names})" }
|
53
|
+
in_parallel.call(names) do |name|
|
54
|
+
update_info(name)
|
55
|
+
@cache.dependencies(name).map {|d| d.unshift(name) }
|
56
|
+
end.flatten(1)
|
57
|
+
end
|
58
|
+
|
59
|
+
def spec(name, version, platform = nil)
|
60
|
+
Bundler::CompactIndexClient.debug { "spec(name = #{name}, version = #{version}, platform = #{platform})" }
|
61
|
+
update_info(name)
|
62
|
+
@cache.specific_dependency(name, version, platform)
|
63
|
+
end
|
64
|
+
|
65
|
+
def update_and_parse_checksums!
|
66
|
+
Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" }
|
67
|
+
return @info_checksums_by_name if @parsed_checksums
|
68
|
+
update(@cache.versions_path, "versions")
|
69
|
+
@info_checksums_by_name = @cache.checksums
|
70
|
+
@parsed_checksums = true
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def update(local_path, remote_path)
|
76
|
+
Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" }
|
77
|
+
unless synchronize { @endpoints.add?(remote_path) }
|
78
|
+
Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" }
|
79
|
+
return
|
80
|
+
end
|
81
|
+
@updater.update(local_path, url(remote_path))
|
82
|
+
end
|
83
|
+
|
84
|
+
def update_info(name)
|
85
|
+
Bundler::CompactIndexClient.debug { "update_info(#{name})" }
|
86
|
+
path = @cache.info_path(name)
|
87
|
+
checksum = @updater.checksum_for_file(path)
|
88
|
+
unless existing = @info_checksums_by_name[name]
|
89
|
+
Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" }
|
90
|
+
return
|
91
|
+
end
|
92
|
+
if checksum == existing
|
93
|
+
Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" }
|
94
|
+
return
|
95
|
+
end
|
96
|
+
Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" }
|
97
|
+
update(path, "info/#{name}")
|
98
|
+
end
|
99
|
+
|
100
|
+
def url(path)
|
101
|
+
path
|
102
|
+
end
|
103
|
+
|
104
|
+
def synchronize
|
105
|
+
@mutex.synchronize { yield }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "digest/md5"
|
3
|
+
|
4
|
+
module Bundler
|
5
|
+
class CompactIndexClient
|
6
|
+
class Cache
|
7
|
+
attr_reader :directory
|
8
|
+
|
9
|
+
def initialize(directory)
|
10
|
+
@directory = Pathname.new(directory).expand_path
|
11
|
+
info_roots.each do |dir|
|
12
|
+
SharedHelpers.filesystem_access(dir) do
|
13
|
+
FileUtils.mkdir_p(dir)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def names
|
19
|
+
lines(names_path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def names_path
|
23
|
+
directory.join("names")
|
24
|
+
end
|
25
|
+
|
26
|
+
def versions
|
27
|
+
versions_by_name = Hash.new {|hash, key| hash[key] = [] }
|
28
|
+
info_checksums_by_name = {}
|
29
|
+
|
30
|
+
lines(versions_path).each do |line|
|
31
|
+
name, versions_string, info_checksum = line.split(" ", 3)
|
32
|
+
info_checksums_by_name[name] = info_checksum || ""
|
33
|
+
versions_string.split(",").each do |version|
|
34
|
+
if version.start_with?("-")
|
35
|
+
version = version[1..-1].split("-", 2).unshift(name)
|
36
|
+
versions_by_name[name].delete(version)
|
37
|
+
else
|
38
|
+
version = version.split("-", 2).unshift(name)
|
39
|
+
versions_by_name[name] << version
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
[versions_by_name, info_checksums_by_name]
|
45
|
+
end
|
46
|
+
|
47
|
+
def versions_path
|
48
|
+
directory.join("versions")
|
49
|
+
end
|
50
|
+
|
51
|
+
def checksums
|
52
|
+
checksums = {}
|
53
|
+
|
54
|
+
lines(versions_path).each do |line|
|
55
|
+
name, _, checksum = line.split(" ", 3)
|
56
|
+
checksums[name] = checksum
|
57
|
+
end
|
58
|
+
|
59
|
+
checksums
|
60
|
+
end
|
61
|
+
|
62
|
+
def dependencies(name)
|
63
|
+
lines(info_path(name)).map do |line|
|
64
|
+
parse_gem(line)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def info_path(name)
|
69
|
+
name = name.to_s
|
70
|
+
if name =~ /[^a-z0-9_-]/
|
71
|
+
name += "-#{Digest::MD5.hexdigest(name).downcase}"
|
72
|
+
info_roots.last.join(name)
|
73
|
+
else
|
74
|
+
info_roots.first.join(name)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def specific_dependency(name, version, platform)
|
79
|
+
pattern = [version, platform].compact.join("-")
|
80
|
+
return nil if pattern.empty?
|
81
|
+
|
82
|
+
gem_lines = info_path(name).read
|
83
|
+
gem_line = gem_lines[/^#{Regexp.escape(pattern)}\b.*/, 0]
|
84
|
+
gem_line ? parse_gem(gem_line) : nil
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def lines(path)
|
90
|
+
return [] unless path.file?
|
91
|
+
lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n")
|
92
|
+
header = lines.index("---")
|
93
|
+
header ? lines[header + 1..-1] : lines
|
94
|
+
end
|
95
|
+
|
96
|
+
def parse_gem(string)
|
97
|
+
version_and_platform, rest = string.split(" ", 2)
|
98
|
+
version, platform = version_and_platform.split("-", 2)
|
99
|
+
dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
|
100
|
+
dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
|
101
|
+
requirements = requirements ? requirements.map {|r| parse_dependency(r) } : []
|
102
|
+
[version, platform, dependencies, requirements]
|
103
|
+
end
|
104
|
+
|
105
|
+
def parse_dependency(string)
|
106
|
+
dependency = string.split(":")
|
107
|
+
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
|
108
|
+
dependency
|
109
|
+
end
|
110
|
+
|
111
|
+
def info_roots
|
112
|
+
[
|
113
|
+
directory.join("info"),
|
114
|
+
directory.join("info-special-characters"),
|
115
|
+
]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "fileutils"
|
3
|
+
require "stringio"
|
4
|
+
require "tmpdir"
|
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
|
+
end
|
26
|
+
|
27
|
+
def update(local_path, remote_path, retrying = nil)
|
28
|
+
headers = {}
|
29
|
+
|
30
|
+
Dir.mktmpdir("bundler-compact-index-") do |local_temp_dir|
|
31
|
+
local_temp_path = Pathname.new(local_temp_dir).join(local_path.basename)
|
32
|
+
|
33
|
+
# first try to fetch any new bytes on the existing file
|
34
|
+
if retrying.nil? && local_path.file?
|
35
|
+
FileUtils.cp local_path, local_temp_path
|
36
|
+
headers["If-None-Match"] = etag_for(local_temp_path)
|
37
|
+
headers["Range"] = "bytes=#{local_temp_path.size}-"
|
38
|
+
else
|
39
|
+
# Fastly ignores Range when Accept-Encoding: gzip is set
|
40
|
+
headers["Accept-Encoding"] = "gzip"
|
41
|
+
end
|
42
|
+
|
43
|
+
response = @fetcher.call(remote_path, headers)
|
44
|
+
return nil if response.is_a?(Net::HTTPNotModified)
|
45
|
+
|
46
|
+
content = response.body
|
47
|
+
if response["Content-Encoding"] == "gzip"
|
48
|
+
content = Zlib::GzipReader.new(StringIO.new(content)).read
|
49
|
+
end
|
50
|
+
|
51
|
+
mode = response.is_a?(Net::HTTPPartialContent) ? "a" : "w"
|
52
|
+
SharedHelpers.filesystem_access(local_temp_path) do
|
53
|
+
local_temp_path.open(mode) {|f| f << content }
|
54
|
+
end
|
55
|
+
|
56
|
+
response_etag = response["ETag"].gsub(%r{\AW/}, "")
|
57
|
+
if etag_for(local_temp_path) == response_etag
|
58
|
+
SharedHelpers.filesystem_access(local_path) do
|
59
|
+
FileUtils.mv(local_temp_path, local_path)
|
60
|
+
end
|
61
|
+
return nil
|
62
|
+
end
|
63
|
+
|
64
|
+
if retrying
|
65
|
+
raise MisMatchedChecksumError.new(remote_path, response_etag, etag_for(local_temp_path))
|
66
|
+
end
|
67
|
+
|
68
|
+
update(local_path, remote_path, :retrying)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def etag_for(path)
|
73
|
+
sum = checksum_for_file(path)
|
74
|
+
sum ? %("#{sum}") : nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def checksum_for_file(path)
|
78
|
+
return nil unless path.file?
|
79
|
+
# This must use IO.read instead of Digest.file().hexdigest
|
80
|
+
# because we need to preserve \n line endings on windows when calculating
|
81
|
+
# the checksum
|
82
|
+
SharedHelpers.filesystem_access(path, :read) do
|
83
|
+
Digest::MD5.hexdigest(IO.read(path))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/bundler/current_ruby.rb
CHANGED
@@ -16,6 +16,7 @@ module Bundler
|
|
16
16
|
2.2
|
17
17
|
2.3
|
18
18
|
2.4
|
19
|
+
2.5
|
19
20
|
).freeze
|
20
21
|
|
21
22
|
KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze
|
@@ -57,15 +58,15 @@ module Bundler
|
|
57
58
|
end
|
58
59
|
|
59
60
|
def mswin64?
|
60
|
-
Bundler::WINDOWS &&
|
61
|
+
Bundler::WINDOWS && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64"
|
61
62
|
end
|
62
63
|
|
63
64
|
def mingw?
|
64
|
-
Bundler::WINDOWS &&
|
65
|
+
Bundler::WINDOWS && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64"
|
65
66
|
end
|
66
67
|
|
67
68
|
def x64_mingw?
|
68
|
-
Bundler::WINDOWS &&
|
69
|
+
Bundler::WINDOWS && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu == "x64"
|
69
70
|
end
|
70
71
|
|
71
72
|
(KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version|
|
data/lib/bundler/definition.rb
CHANGED
@@ -62,6 +62,7 @@ module Bundler
|
|
62
62
|
@specs = nil
|
63
63
|
@ruby_version = ruby_version
|
64
64
|
|
65
|
+
@lockfile = lockfile
|
65
66
|
@lockfile_contents = String.new
|
66
67
|
@locked_bundler_version = nil
|
67
68
|
@locked_ruby_version = nil
|
@@ -69,7 +70,8 @@ module Bundler
|
|
69
70
|
if lockfile && File.exist?(lockfile)
|
70
71
|
@lockfile_contents = Bundler.read_file(lockfile)
|
71
72
|
@locked_gems = LockfileParser.new(@lockfile_contents)
|
72
|
-
@
|
73
|
+
@locked_platforms = @locked_gems.platforms
|
74
|
+
@platforms = @locked_platforms.dup
|
73
75
|
@locked_bundler_version = @locked_gems.bundler_version
|
74
76
|
@locked_ruby_version = @locked_gems.ruby_version
|
75
77
|
|
@@ -90,25 +92,24 @@ module Bundler
|
|
90
92
|
@locked_deps = []
|
91
93
|
@locked_specs = SpecSet.new([])
|
92
94
|
@locked_sources = []
|
95
|
+
@locked_platforms = []
|
93
96
|
end
|
94
97
|
|
95
98
|
@unlock[:gems] ||= []
|
96
99
|
@unlock[:sources] ||= []
|
97
|
-
@unlock[:ruby] ||= if @ruby_version &&
|
98
|
-
unless locked_ruby_version_object = RubyVersion.from_string(@locked_ruby_version)
|
99
|
-
raise LockfileError, "Failed to create a `RubyVersion` object from " \
|
100
|
-
"`#{@locked_ruby_version}` found in #{lockfile} -- try running `bundle update --ruby`."
|
101
|
-
end
|
100
|
+
@unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
|
102
101
|
@ruby_version.diff(locked_ruby_version_object)
|
103
102
|
end
|
104
103
|
@unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
|
105
104
|
|
106
|
-
|
107
|
-
add_platform(current_platform)
|
105
|
+
add_current_platform unless Bundler.settings[:frozen]
|
108
106
|
|
109
107
|
@path_changes = converge_paths
|
110
|
-
|
111
|
-
@unlock[:
|
108
|
+
|
109
|
+
unless @unlock[:lock_shared_dependencies]
|
110
|
+
eager_unlock = expand_dependencies(@unlock[:gems])
|
111
|
+
@unlock[:gems] = @locked_specs.for(eager_unlock).map(&:name)
|
112
|
+
end
|
112
113
|
|
113
114
|
@gem_version_promoter = create_gem_version_promoter
|
114
115
|
|
@@ -175,7 +176,7 @@ module Bundler
|
|
175
176
|
rescue GemNotFound => e # Handle yanked gem
|
176
177
|
gem_name, gem_version = extract_gem_info(e)
|
177
178
|
locked_gem = @locked_specs[gem_name].last
|
178
|
-
raise if locked_gem.nil? || locked_gem.version.to_s != gem_version
|
179
|
+
raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote
|
179
180
|
raise GemNotFound, "Your bundle is locked to #{locked_gem}, but that version could not " \
|
180
181
|
"be found in any of the sources listed in your Gemfile. If you haven't changed sources, " \
|
181
182
|
"that means the author of #{locked_gem} has removed it. You'll need to update your bundle " \
|
@@ -247,7 +248,7 @@ module Bundler
|
|
247
248
|
else
|
248
249
|
# Run a resolve against the locally available gems
|
249
250
|
Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
|
250
|
-
last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve,
|
251
|
+
last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve)
|
251
252
|
end
|
252
253
|
end
|
253
254
|
end
|
@@ -262,6 +263,8 @@ module Bundler
|
|
262
263
|
dependency_names -= pinned_spec_names(source.specs)
|
263
264
|
dependency_names.concat(source.unmet_deps).uniq!
|
264
265
|
end
|
266
|
+
idx << Gem::Specification.new("ruby\0", RubyVersion.system.to_gem_version_with_patchlevel)
|
267
|
+
idx << Gem::Specification.new("rubygems\0", Gem::VERSION)
|
265
268
|
end
|
266
269
|
end
|
267
270
|
|
@@ -338,6 +341,18 @@ module Bundler
|
|
338
341
|
end
|
339
342
|
end
|
340
343
|
|
344
|
+
def locked_ruby_version_object
|
345
|
+
return unless @locked_ruby_version
|
346
|
+
@locked_ruby_version_object ||= begin
|
347
|
+
unless version = RubyVersion.from_string(@locked_ruby_version)
|
348
|
+
raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \
|
349
|
+
"#{@lockfile} could not be parsed. " \
|
350
|
+
"Try running bundle update --ruby to resolve this."
|
351
|
+
end
|
352
|
+
version
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
341
356
|
def to_lock
|
342
357
|
out = String.new
|
343
358
|
|
@@ -401,6 +416,11 @@ module Bundler
|
|
401
416
|
deleted = []
|
402
417
|
changed = []
|
403
418
|
|
419
|
+
new_platforms = @platforms - @locked_platforms
|
420
|
+
deleted_platforms = @locked_platforms - @platforms
|
421
|
+
added.concat new_platforms.map {|p| "* platform: #{p}" }
|
422
|
+
deleted.concat deleted_platforms.map {|p| "* platform: #{p}" }
|
423
|
+
|
404
424
|
gemfile_sources = sources.lock_sources
|
405
425
|
|
406
426
|
new_sources = gemfile_sources - @locked_sources
|
@@ -449,6 +469,11 @@ module Bundler
|
|
449
469
|
raise ProductionError, msg if added.any? || deleted.any? || changed.any?
|
450
470
|
end
|
451
471
|
|
472
|
+
def validate_runtime!
|
473
|
+
validate_ruby!
|
474
|
+
validate_platforms!
|
475
|
+
end
|
476
|
+
|
452
477
|
def validate_ruby!
|
453
478
|
return unless ruby_version
|
454
479
|
|
@@ -474,6 +499,18 @@ module Bundler
|
|
474
499
|
end
|
475
500
|
end
|
476
501
|
|
502
|
+
def validate_platforms!
|
503
|
+
return if @platforms.any? do |bundle_platform|
|
504
|
+
Bundler.rubygems.platforms.any? do |local_platform|
|
505
|
+
MatchPlatform.platforms_match?(bundle_platform, local_platform)
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
|
510
|
+
"but your local platforms are #{Bundler.rubygems.platforms.map(&:to_s)}, and " \
|
511
|
+
"there's no compatible match between those two lists."
|
512
|
+
end
|
513
|
+
|
477
514
|
def add_platform(platform)
|
478
515
|
@new_platform ||= !@platforms.include?(platform)
|
479
516
|
@platforms |= [platform]
|
@@ -484,6 +521,20 @@ module Bundler
|
|
484
521
|
raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
|
485
522
|
end
|
486
523
|
|
524
|
+
def add_current_platform
|
525
|
+
current_platform = Bundler.local_platform
|
526
|
+
add_platform(current_platform) if Bundler.settings[:specific_platform]
|
527
|
+
add_platform(generic(current_platform))
|
528
|
+
end
|
529
|
+
|
530
|
+
def find_resolved_spec(current_spec)
|
531
|
+
specs.find_by_name_and_platform(current_spec.name, current_spec.platform)
|
532
|
+
end
|
533
|
+
|
534
|
+
def find_indexed_specs(current_spec)
|
535
|
+
index[current_spec.name].select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version)
|
536
|
+
end
|
537
|
+
|
487
538
|
attr_reader :sources
|
488
539
|
private :sources
|
489
540
|
|
@@ -726,16 +777,54 @@ module Bundler
|
|
726
777
|
@locked_specs.any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
|
727
778
|
end
|
728
779
|
|
780
|
+
# This list of dependencies is only used in #resolve, so it's OK to add
|
781
|
+
# the metadata dependencies here
|
729
782
|
def expanded_dependencies
|
730
|
-
@expanded_dependencies ||=
|
783
|
+
@expanded_dependencies ||= begin
|
784
|
+
ruby_versions = concat_ruby_version_requirements(@ruby_version)
|
785
|
+
if ruby_versions.empty? || !@ruby_version.exact?
|
786
|
+
concat_ruby_version_requirements(RubyVersion.system)
|
787
|
+
concat_ruby_version_requirements(locked_ruby_version_object) unless @unlock[:ruby]
|
788
|
+
end
|
789
|
+
|
790
|
+
metadata_dependencies = [
|
791
|
+
Dependency.new("ruby\0", ruby_versions),
|
792
|
+
Dependency.new("rubygems\0", Gem::VERSION),
|
793
|
+
]
|
794
|
+
expand_dependencies(dependencies + metadata_dependencies, @remote)
|
795
|
+
end
|
796
|
+
end
|
797
|
+
|
798
|
+
def concat_ruby_version_requirements(ruby_version, ruby_versions = [])
|
799
|
+
return ruby_versions unless ruby_version
|
800
|
+
if ruby_version.patchlevel
|
801
|
+
ruby_versions << ruby_version.to_gem_version_with_patchlevel
|
802
|
+
else
|
803
|
+
ruby_versions.concat(ruby_version.versions.map do |version|
|
804
|
+
requirement = Gem::Requirement.new(version)
|
805
|
+
if requirement.exact?
|
806
|
+
"~> #{version}.0"
|
807
|
+
else
|
808
|
+
requirement
|
809
|
+
end
|
810
|
+
end)
|
811
|
+
end
|
731
812
|
end
|
732
813
|
|
733
814
|
def expand_dependencies(dependencies, remote = false)
|
734
815
|
deps = []
|
735
816
|
dependencies.each do |dep|
|
736
817
|
dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
|
737
|
-
next
|
738
|
-
dep.gem_platforms(@platforms)
|
818
|
+
next if !remote && !dep.current_platform?
|
819
|
+
platforms = dep.gem_platforms(@platforms)
|
820
|
+
if platforms.empty?
|
821
|
+
Bundler.ui.warn \
|
822
|
+
"The dependency #{dep} will be unused by any of the platforms Bundler is installing for. " \
|
823
|
+
"Bundler is installing for #{@platforms.join ", "} but the dependency " \
|
824
|
+
"is only for #{dep.platforms.map {|p| Dependency::PLATFORM_MAP[p] }.join ", "}. " \
|
825
|
+
"To add those platforms to the bundle, run `bundle lock --add-platform #{dep.platforms.join ", "}`."
|
826
|
+
end
|
827
|
+
platforms.each do |p|
|
739
828
|
deps << DepProxy.new(dep, p) if remote || p == generic_local_platform
|
740
829
|
end
|
741
830
|
end
|
@@ -812,9 +901,10 @@ module Bundler
|
|
812
901
|
end
|
813
902
|
|
814
903
|
def additional_base_requirements_for_resolve
|
815
|
-
return [] unless @locked_gems && Bundler.
|
904
|
+
return [] unless @locked_gems && Bundler.feature_flag.only_update_to_newer_versions?
|
816
905
|
@locked_gems.specs.reduce({}) do |requirements, locked_spec|
|
817
|
-
|
906
|
+
dep = Gem::Dependency.new(locked_spec.name, ">= #{locked_spec.version}")
|
907
|
+
requirements[locked_spec.name] = DepProxy.new(dep, locked_spec.platform)
|
818
908
|
requirements
|
819
909
|
end.values
|
820
910
|
end
|