Module: Datadog::CI::Utils::FileStorage

Defined in:
lib/datadog/ci/utils/file_storage.rb

Overview

FileStorage module provides functionality for storing and retrieving arbitrary Ruby objects in a temp file to share them between processes.

Defined Under Namespace

Classes: MissingNamespaceError

Constant Summary collapse

TEMP_DIR =
File.join(Dir.tmpdir, "datadog-ci-storage")
ENV_NAMESPACE =
"DD_CIVISIBILITY_PARALLEL_TESTS_RUN_ID"

Class Method Summary collapse

Class Method Details

.ensure_temp_dir_exists ⇒ Object



77
78
79
# File 'lib/datadog/ci/utils/file_storage.rb', line 77

def self.ensure_temp_dir_exists
  FileUtils.mkdir_p(storage_dir)
end

.file_path_for(key) ⇒ Object



81
82
83
84
# File 'lib/datadog/ci/utils/file_storage.rb', line 81

def self.file_path_for(key)
  sanitized_key = key.to_s.gsub(/[^a-zA-Z0-9_-]/, "_")
  File.join(storage_dir, "dd-ci-#{sanitized_key}.dat")
end

.retrieve(key) ⇒ Object



39
40
41
42
43
44
45
46
47
# File 'lib/datadog/ci/utils/file_storage.rb', line 39

def self.retrieve(key)
  file_path = file_path_for(key)
  return nil unless File.exist?(file_path)

  Marshal.load(File.binread(file_path))
rescue => e
  Datadog.logger.error("Failed to retrieve data for key '#{key}': #{e.class}")
  nil
end

.storage_dir(namespace = ENV[ENV_NAMESPACE]) ⇒ Object



86
87
88
89
90
91
92
93
# File 'lib/datadog/ci/utils/file_storage.rb', line 86

def self.storage_dir(namespace = ENV[ENV_NAMESPACE])
  if namespace.nil? || namespace.empty?
    raise MissingNamespaceError, "File storage namespace is not set"
  end

  sanitized_namespace = namespace.gsub(/[^a-zA-Z0-9_-]/, "_")
  File.join(TEMP_DIR, sanitized_namespace)
end

.store(key, value) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/datadog/ci/utils/file_storage.rb', line 18

def self.store(key, value)
  ensure_temp_dir_exists
  file_path = file_path_for(key)
  temporary_path = File.join(storage_dir, "dd-ci-#{SecureRandom.uuid}.tmp")

  File.open(temporary_path, File::WRONLY | File::CREAT | File::EXCL, 0o600) do |file|
    file.binmode
    file.write(Marshal.dump(value))
    file.flush
    file.fsync
  end
  File.rename(temporary_path, file_path)

  true
rescue => e
  Datadog.logger.error("Failed to store data for key '#{key}': #{e.class}")
  false
ensure
  FileUtils.rm_f(temporary_path) if temporary_path
end

.with_new_namespace ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/datadog/ci/utils/file_storage.rb', line 61

def self.with_new_namespace
  previous_namespace = ENV[ENV_NAMESPACE]
  namespace = SecureRandom.uuid
  ENV[ENV_NAMESPACE] = namespace

  yield namespace
ensure
  cleanup(namespace) if namespace

  if previous_namespace
    ENV[ENV_NAMESPACE] = previous_namespace
  else
    ENV.delete(ENV_NAMESPACE)
  end
end