Module: SugarUtils::File

Defined in:
lib/sugar_utils/file.rb

Defined Under Namespace

Classes: Error

Class Method Summary collapse

Class Method Details

.flock(file, locking_constant, options = {}) ⇒ void

This method returns an undefined value.

flock with a timeout to ensure that it does not flock forever.

Parameters:

  • file (File)
  • locking_constant (File::LOCK_EX, File::LOCK_SH)
  • options (Hash) (defaults to: {})

Options Hash (options):

  • :timeout (Integer) — default: 10

See Also:



21
22
23
24
# File 'lib/sugar_utils/file.rb', line 21

def self.flock(file, locking_constant, options = {})
  timeout = options[:timeout] || 10
  Timeout.timeout(timeout) { file.flock(locking_constant) }
end

.read_json(filename, options = {}) ⇒ Object

Parameters:

  • filename (String)
  • options (Hash) (defaults to: {})

Options Hash (options):

  • :timeout (Integer) — default: 10
  • :raise_on_missing (Boolean) — default: true

Returns:

  • (Object)

Raises:



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/sugar_utils/file.rb', line 34

def self.read_json(filename, options = {})
  assert(options.is_a?(Hash), 'options MUST be a Hash')

  options[:raise_on_missing] = true if options[:raise_on_missing].nil?

  ::File.open(filename, ::File::RDONLY) do |file|
    flock(file, ::File::LOCK_SH, options)
    MultiJson.load(file.read)
  end
rescue SystemCallError, IOError
  raise(Error, "Cannot read #{filename}") if options[:raise_on_missing]
  {}
rescue MultiJson::ParseError
  raise(Error, "Cannot parse #{filename}")
rescue Timeout::Error
  raise(Error, "Cannot read #{filename} because it is locked")
end

.write_json(filename, data, options = {}) ⇒ void

This method returns an undefined value.

Parameters:

  • filename (String)
  • data (#to_json)
  • options (Hash) (defaults to: {})

Options Hash (options):

  • :timeout (Integer) — default: 10
  • :flush (Boolean) — default: false
  • :perm (Integer) — default: 0666

Raises:



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/sugar_utils/file.rb', line 62

def self.write_json(filename, data, options = {})
  perm  = options[:perm] || 0666
  flush = options[:flush] || false

  FileUtils.mkdir_p(::File.dirname(filename))
  ::File.open(filename, ::File::RDWR | ::File::CREAT, perm) do |file|
    flock(file, ::File::LOCK_EX, options)

    file.truncate(0) # Ensure file is empty before proceeding.
    file.puts(MultiJson.dump(data, pretty: true))

    # Flush and fsync to be 100% sure we write this data out now because we
    # are often reading it immediately and if the OS is buffering, it is
    # possible we might read it before it is been physically written to disk.
    # We are not worried about speed here, so this should be OKAY.
    if flush
      file.flush
      file.fsync
    end

    # Ensure that the permissions are correct if the file already existed.
    file.chmod(perm)
  end
rescue Timeout::Error
  raise(Error, "Unable to write #{filename} because it is locked")
rescue SystemCallError, IOError => boom
  raise(Error, "Unable to write #{filename} with #{boom}")
end