[rubygems/rubygems] Allow noop bundle install to work on read-only or protected folders

As long as there's nothing new to install and gems are already there.

If not, give a meaningful error about what happened.

This was how things already worked until
https://github.com/rubygems/rubygems/commit/345ec45f5a87, so this commit partially
reverts that change.

https://github.com/rubygems/rubygems/commit/794b0ecb39
This commit is contained in:
David Rodríguez 2022-09-09 11:18:18 +02:00 committed by Hiroshi SHIBATA
parent ca46a15991
commit ee2c7bcae5
4 changed files with 44 additions and 5 deletions

View File

@ -193,6 +193,24 @@ module Bundler
status_code(31) status_code(31)
end end
class ReadOnlyFileSystemError < PermissionError
def message
"There was an error while trying to #{action} `#{@path}`. " \
"File system is read-only."
end
status_code(42)
end
class OperationNotPermittedError < PermissionError
def message
"There was an error while trying to #{action} `#{@path}`. " \
"Underlying OS system call raised an EPERM error."
end
status_code(43)
end
class GenericSystemCallError < BundlerError class GenericSystemCallError < BundlerError
attr_reader :underlying_error attr_reader :underlying_error

View File

@ -31,7 +31,7 @@ module Bundler
begin begin
load_index(global_index_file, true) load_index(global_index_file, true)
rescue GenericSystemCallError rescue PermissionError
# no need to fail when on a read-only FS, for example # no need to fail when on a read-only FS, for example
nil nil
rescue ArgumentError => e rescue ArgumentError => e

View File

@ -115,6 +115,10 @@ module Bundler
raise NoSpaceOnDeviceError.new(path, action) raise NoSpaceOnDeviceError.new(path, action)
rescue Errno::ENOTSUP rescue Errno::ENOTSUP
raise OperationNotSupportedError.new(path, action) raise OperationNotSupportedError.new(path, action)
rescue Errno::EPERM
raise OperationNotPermittedError.new(path, action)
rescue Errno::EROFS
raise ReadOnlyFileSystemError.new(path, action)
rescue Errno::EEXIST, Errno::ENOENT rescue Errno::EEXIST, Errno::ENOENT
raise raise
rescue SystemCallError => e rescue SystemCallError => e

View File

@ -21,19 +21,36 @@ RSpec.describe "process lock spec" do
expect(the_bundle).to include_gems "myrack 1.0" expect(the_bundle).to include_gems "myrack 1.0"
end end
context "when creating a lock raises Errno::ENOTSUP" do
before { allow(File).to receive(:open).and_raise(Errno::ENOTSUP) }
it "skips creating the lock file and yields" do
processed = false
Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
expect(processed).to eq true
end
end
context "when creating a lock raises Errno::EPERM" do context "when creating a lock raises Errno::EPERM" do
before { allow(File).to receive(:open).and_raise(Errno::EPERM) } before { allow(File).to receive(:open).and_raise(Errno::EPERM) }
it "raises a friendly error" do it "skips creating the lock file and yields" do
expect { Bundler::ProcessLock.lock(default_bundle_path) }.to raise_error(Bundler::GenericSystemCallError) processed = false
Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
expect(processed).to eq true
end end
end end
context "when creating a lock raises Errno::EROFS" do context "when creating a lock raises Errno::EROFS" do
before { allow(File).to receive(:open).and_raise(Errno::EROFS) } before { allow(File).to receive(:open).and_raise(Errno::EROFS) }
it "raises a friendly error" do it "skips creating the lock file and yields" do
expect { Bundler::ProcessLock.lock(default_bundle_path) }.to raise_error(Bundler::GenericSystemCallError) processed = false
Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
expect(processed).to eq true
end end
end end
end end