Class: Gemvault::Vault

Inherits:
Object
  • Object
show all
Extended by:
Forwardable, VaultSession
Defined in:
lib/gemvault/vault.rb

Overview

The public vault interface. Delegates storage to a backend chosen by file format: a Dbvault (SQLite) for existing SQLite files, a Tarvault (tarball) otherwise. New vaults are Tarvaults. Only the selected backend is loaded, so the tar path never requires sqlite3.

Defined Under Namespace

Classes: DuplicateGemError, Error, InvalidGemError, NotFoundError, ReadOnlyError, UnsupportedVersionError

Constant Summary collapse

SQLITE_MAGIC =
"SQLite format 3#{0.chr}".freeze
TAR_MAGIC =
"ustar".freeze
TAR_MAGIC_OFFSET =
257
CURRENT_FORMAT =
2
MIN_READABLE_FORMAT =
1

Class Method Summary collapse

Instance Method Summary collapse

Methods included from VaultSession

open

Constructor Details

#initialize(path, create: false) ⇒ Vault

Returns a new instance of Vault.



91
92
93
94
# File 'lib/gemvault/vault.rb', line 91

def initialize(path, create: false)
  absolute_path = Pathname(path).expand_path
  @backend = self.class.backend_for(absolute_path, create:)
end

Class Method Details

.assert_readable!(version:, path:) ⇒ Object



38
39
40
41
42
43
# File 'lib/gemvault/vault.rb', line 38

def self.assert_readable!(version:, path:)
  return if version.between?(MIN_READABLE_FORMAT, CURRENT_FORMAT)

  raise UnsupportedVersionError,
        "Vault #{path} is format #{version}; this gemvault reads up to #{CURRENT_FORMAT}. Upgrade gemvault."
end

.backend_for(path, create:) ⇒ Object

Raises:



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/gemvault/vault.rb', line 45

def self.backend_for(path, create:)
  return build_tarvault(path, create: true) if create
  raise NotFoundError, "Vault not found: #{path}" unless path.exist?

  case container_kind(path)
  when :sqlite then build_dbvault(path)
  when :tar then build_tarvault(path, create: false)
  else
    raise Error, "Unrecognized vault format: #{path} (not a Dbvault or Tarvault; it may require a newer gemvault)"
  end
end

.build_dbvault(path) ⇒ Object



75
76
77
78
79
80
81
82
83
84
# File 'lib/gemvault/vault.rb', line 75

def self.build_dbvault(path)
  begin
    require_relative "dbvault"
    Dbvault.new(path)
  rescue LoadError => e
    raise Error,
          "#{path} is a legacy SQLite vault; it needs the sqlite3 gem (#{e.message}). " \
          "Install sqlite3, or upgrade the vault with a gemvault that includes it."
  end
end

.build_tarvault(path, create:) ⇒ Object



86
87
88
89
# File 'lib/gemvault/vault.rb', line 86

def self.build_tarvault(path, create:)
  require_relative "tarvault"
  Tarvault.new(path, create:)
end

.container_kind(path) ⇒ Object



57
58
59
60
61
62
# File 'lib/gemvault/vault.rb', line 57

def self.container_kind(path)
  return :sqlite if sqlite?(path)
  return :tar if tar?(path)

  :unknown
end

.create(path) ⇒ Object

Creates an empty vault file at path, leaving it closed.



34
35
36
# File 'lib/gemvault/vault.rb', line 34

def self.create(path)
  new(path, create: true).close
end

.sqlite?(path) ⇒ Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/gemvault/vault.rb', line 64

def self.sqlite?(path)
  path.exist? && path.binread(SQLITE_MAGIC.bytesize) == SQLITE_MAGIC
end

.tar?(path) ⇒ Boolean

Returns:

  • (Boolean)


68
69
70
71
72
73
# File 'lib/gemvault/vault.rb', line 68

def self.tar?(path)
  return false unless path.exist?

  header = path.binread(TAR_MAGIC_OFFSET + TAR_MAGIC.bytesize)
  header.to_s[TAR_MAGIC_OFFSET, TAR_MAGIC.bytesize] == TAR_MAGIC
end