Module: MilkTea::PackageAtomicWrite

Defined in:
lib/milk_tea/packages/atomic_write.rb

Class Method Summary collapse

Class Method Details

.open(path, binmode: false) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/milk_tea/packages/atomic_write.rb', line 16

def open(path, binmode: false)
  expanded_path = File.expand_path(path)
  directory = File.dirname(expanded_path)

  FileUtils.mkdir_p(directory)

  Tempfile.create(["milk-tea-package", File.extname(expanded_path)], directory) do |file|
    file.binmode if binmode
    yield file

    unless file.closed?
      file.flush
      file.fsync
      file.close
    end

    replace(file.path, expanded_path)
  end

  expanded_path
end

.replace(source_path, destination_path) ⇒ Object



38
39
40
41
42
# File 'lib/milk_tea/packages/atomic_write.rb', line 38

def replace(source_path, destination_path)
  File.rename(source_path, destination_path)
rescue Errno::EACCES, Errno::EEXIST, Errno::EPERM
  replace_via_backup(source_path, destination_path)
end

.replace_via_backup(source_path, destination_path) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/milk_tea/packages/atomic_write.rb', line 44

def replace_via_backup(source_path, destination_path)
  backup_path = "#{destination_path}.bak.#{$$}.#{Thread.current.object_id}"

  File.rename(destination_path, backup_path) if File.exist?(destination_path)

  begin
    File.rename(source_path, destination_path)
  rescue SystemCallError
    if File.exist?(backup_path) && !File.exist?(destination_path)
      File.rename(backup_path, destination_path)
    end
    raise
  end

  File.delete(backup_path) if File.exist?(backup_path)
rescue Errno::ENOENT
  nil
end

.write(path, content, binmode: false) ⇒ Object



10
11
12
13
14
# File 'lib/milk_tea/packages/atomic_write.rb', line 10

def write(path, content, binmode: false)
  open(path, binmode:) do |file|
    file.write(content)
  end
end