Class: Gemvault::Vault

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

Defined Under Namespace

Classes: DuplicateGemError, Error, InvalidGemError, NotFoundError

Constant Summary collapse

SCHEMA_VERSION =
"1".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.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/gemvault/vault.rb', line 29

def initialize(path, create: false)
  @path = File.expand_path(path)

  if create
    raise Error, "Vault already exists: #{@path}" if File.exist?(@path)

    @db = SQLite3::Database.new(@path)
    @db.results_as_hash = true
    create_schema
  else
    raise NotFoundError, "Vault not found: #{@path}" unless File.exist?(@path)

    validate_sqlite!
    @db = SQLite3::Database.new(@path)
    @db.results_as_hash = true
  end
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



16
17
18
# File 'lib/gemvault/vault.rb', line 16

def path
  @path
end

Class Method Details

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

Raises:

  • (ArgumentError)


18
19
20
21
22
23
24
25
26
27
# File 'lib/gemvault/vault.rb', line 18

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:



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/gemvault/vault.rb', line 47

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

  begin
    pkg = Gem::Package.new(gem_path)
    spec = pkg.spec
  rescue StandardError => e
    raise InvalidGemError, "Invalid gem file #{gem_path}: #{e.message}"
  end

  name = spec.name
  version = spec.version.to_s
  platform = spec.platform.to_s

  existing = @db.execute(
    "SELECT 1 FROM gems WHERE name = ? AND version = ? AND platform = ?",
    [name, version, platform],
  )
  unless existing.empty?
    raise DuplicateGemError,
          "Gem already in vault: #{name}-#{version} (#{platform})"
  end

  data = File.binread(gem_path)
  @db.execute(
    "INSERT INTO gems (name, version, platform, data) VALUES (?, ?, ?, ?)",
    [name, version, platform, SQLite3::Blob.new(data)],
  )
end

#closeObject



118
119
120
# File 'lib/gemvault/vault.rb', line 118

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

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

Raises:



93
94
95
96
97
98
99
100
101
102
# File 'lib/gemvault/vault.rb', line 93

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



108
109
110
111
112
# File 'lib/gemvault/vault.rb', line 108

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(name, version = nil) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/gemvault/vault.rb', line 78

def remove(name, version = nil)
  if version
    @db.execute(
      "DELETE FROM gems WHERE name = ? AND version = ?",
      [name, version],
    )
  else
    @db.execute(
      "DELETE FROM gems WHERE name = ?",
      [name],
    )
  end
  @db.changes
end

#sizeObject



114
115
116
# File 'lib/gemvault/vault.rb', line 114

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

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



136
137
138
139
140
# File 'lib/gemvault/vault.rb', line 136

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



104
105
106
# File 'lib/gemvault/vault.rb', line 104

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

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



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/gemvault/vault.rb', line 122

def with_gem_file(name, version, platform: "ruby")
  data = gem_data(name, version, platform: platform)
  tmpfile = Tempfile.new(["vault_gem", ".gem"])
  begin
    tmpfile.binmode
    tmpfile.write(data)
    tmpfile.close
    yield tmpfile.path
  ensure
    tmpfile.close unless tmpfile.closed?
    tmpfile.unlink
  end
end