You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
48 lines
1.0 KiB
48 lines
1.0 KiB
2 years ago
|
# frozen_string_literal: true
|
||
|
|
||
|
require 'atomos/version'
|
||
|
|
||
|
module Atomos
|
||
|
module_function
|
||
|
|
||
|
# rubocop:disable Metrics/MethodLength
|
||
|
def atomic_write(dest, contents = nil, tmpdir: nil, &block)
|
||
|
unless contents.nil? ^ block.nil?
|
||
|
raise ArgumentError, 'must provide either contents or a block'
|
||
|
end
|
||
|
|
||
|
tmpdir = Atomos.default_tmpdir_for_file(dest, tmpdir)
|
||
|
|
||
|
require 'tempfile'
|
||
|
Tempfile.open(".atomos.#{File.basename(dest)}", tmpdir) do |tmpfile|
|
||
|
if contents
|
||
|
tmpfile << contents
|
||
|
else
|
||
|
retval = yield tmpfile
|
||
|
end
|
||
|
|
||
|
tmpfile.close
|
||
|
|
||
|
File.rename(tmpfile.path, dest)
|
||
|
|
||
|
retval
|
||
|
end
|
||
|
end
|
||
|
# rubocop:enable Metrics/MethodLength
|
||
|
|
||
|
def self.default_tmpdir_for_file(dest, tmpdir)
|
||
|
tmpdir ||= begin
|
||
|
require 'tmpdir'
|
||
|
Dir.tmpdir
|
||
|
end
|
||
|
|
||
|
# Ensure the destination is on the same device as tmpdir
|
||
|
if File.stat(tmpdir).dev != File.stat(File.dirname(dest)).dev
|
||
|
# If not, use the directory of the destination as the tmpdir.
|
||
|
tmpdir = File.dirname(dest)
|
||
|
end
|
||
|
|
||
|
tmpdir
|
||
|
end
|
||
|
end
|