Skip to content

Commit

Permalink
Allow noop bundle install to work on read-only or protected folders
Browse files Browse the repository at this point in the history
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
345ec45, so this commit partially
reverts that change.
  • Loading branch information
deivid-rodriguez committed Feb 20, 2025
1 parent 4d5e7f3 commit 794b0ec
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 5 deletions.
18 changes: 18 additions & 0 deletions bundler/lib/bundler/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,24 @@ def message
status_code(31)
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
attr_reader :underlying_error

Expand Down
2 changes: 1 addition & 1 deletion bundler/lib/bundler/plugin/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def initialize

begin
load_index(global_index_file, true)
rescue GenericSystemCallError
rescue PermissionError
# no need to fail when on a read-only FS, for example
nil
rescue ArgumentError => e
Expand Down
4 changes: 4 additions & 0 deletions bundler/lib/bundler/shared_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ def filesystem_access(path, action = :write, &block)
raise NoSpaceOnDeviceError.new(path, action)
rescue Errno::ENOTSUP
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
raise
rescue SystemCallError => e
Expand Down
25 changes: 21 additions & 4 deletions bundler/spec/install/process_lock_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,36 @@
expect(the_bundle).to include_gems "myrack 1.0"
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
before { allow(File).to receive(:open).and_raise(Errno::EPERM) }

it "raises a friendly error" do
expect { Bundler::ProcessLock.lock(default_bundle_path) }.to raise_error(Bundler::GenericSystemCallError)
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::EROFS" do
before { allow(File).to receive(:open).and_raise(Errno::EROFS) }

it "raises a friendly error" do
expect { Bundler::ProcessLock.lock(default_bundle_path) }.to raise_error(Bundler::GenericSystemCallError)
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
end
Expand Down

0 comments on commit 794b0ec

Please sign in to comment.