Class: Gemvault::Vault

Inherits:
Object
  • Object
show all
Defined in:
lib/gemvault/vault.rb

Overview

SQLite-backed archive of .gem blobs; supports add/remove/list/extract.

Defined Under Namespace

Classes: DuplicateGemError, Error, InvalidGemError, NotFoundError

Constant Summary collapse

SCHEMA_VERSION =
"1".freeze
SQLITE_MAGIC =
"SQLite format 3#{0.chr}".freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, create: false) ⇒ Vault

Returns a new instance of Vault.



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

def initialize(path, create: false)
  @path = File.expand_path(path)
  create ? create_vault! : open_vault!
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



19
20
21
# File 'lib/gemvault/vault.rb', line 19

def path
  @path
end

Class Method Details

.open(path, **opts, &block) ⇒ Object

Raises:

  • (ArgumentError)


21
22
23
24
25
26
27
28
29
30
# File 'lib/gemvault/vault.rb', line 21

def self.open(path, **opts, &block)
  raise ArgumentError, "#{name}.open requires a block" unless block

  vault = new(path, **opts)
  begin
    yield vault
  ensure
    vault.close
  end
end

Instance Method Details

#add(gem_path) ⇒ Object

Raises:



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

def add(gem_path)
  gem_path = File.expand_path(gem_path)
  raise NotFoundError, "Gem file not found: #{gem_path}" unless File.file?(gem_path)

  spec = load_gem_spec(gem_path)
  raise_if_duplicate(spec)
  insert_gem(gem_path, spec)
end

#closeObject



84
85
86
# File 'lib/gemvault/vault.rb', line 84

def close
  @db.close if @db && !@db.closed?
end

#gem_data(name, version, platform: "ruby") ⇒ Object

Raises:



59
60
61
62
63
64
65
66
67
68
# File 'lib/gemvault/vault.rb', line 59

def gem_data(name, version, platform: "ruby")
  row = @db.execute(
    "SELECT data FROM gems WHERE name = ? AND version = ? AND platform = ?",
    [name, version, platform],
  ).first

  raise NotFoundError, "Gem not found: #{name}-#{version} (#{platform})" unless row

  row["data"]
end

#gem_entriesObject



74
75
76
77
78
# File 'lib/gemvault/vault.rb', line 74

def gem_entries
  @db.execute(
    "SELECT name, version, platform, created_at FROM gems ORDER BY name, version",
  ).map { |row| GemEntry.new(**row.transform_keys(&:to_sym)) }
end

#remove(reference) ⇒ Object



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

def remove(reference)
  case reference
  in GemReference::AnyVersion[name:]
    @db.execute("DELETE FROM gems WHERE name = ?", [name])
  in GemReference::SpecificVersion[name:, version:]
    @db.execute(
      "DELETE FROM gems WHERE name = ? AND version = ?",
      [name, version.to_s],
    )
  end
  @db.changes
end

#sizeObject



80
81
82
# File 'lib/gemvault/vault.rb', line 80

def size
  @db.execute("SELECT COUNT(*) AS count FROM gems").first["count"]
end

#spec_from_blob(name, version, platform = "ruby") ⇒ Object



99
100
101
102
103
# File 'lib/gemvault/vault.rb', line 99

def spec_from_blob(name, version, platform = "ruby")
  with_gem_file(name, version, platform: platform) do |path|
    Gem::Package.new(path).spec
  end
end

#specsObject



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

def specs
  gem_entries.map { |entry| spec_from_blob(entry.name, entry.version, entry.platform) }
end

#with_gem_file(name, version, platform: "ruby") ⇒ Object



88
89
90
91
92
93
94
95
96
97
# File 'lib/gemvault/vault.rb', line 88

def with_gem_file(name, version, platform: "ruby")
  data = gem_data(name, version, platform: platform)
  tmpfile = write_tempfile(data)
  begin
    yield tmpfile.path
  ensure
    tmpfile.close unless tmpfile.closed?
    tmpfile.unlink
  end
end