Class: Paquette::GemServer::DirectoryGemRepository
Overview
Repository implementation that reads gems from a directory
Defined Under Namespace
Classes: GemAlreadyExists, GemNotFound, GemYanked, InvalidGem
Instance Method Summary
collapse
Constructor Details
Returns a new instance of DirectoryGemRepository.
17
18
19
20
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 17
def initialize(gems_dir)
@gems_dir = gems_dir
FileUtils.mkdir_p(@gems_dir)
end
|
Instance Method Details
#add_gem(binary_data) ⇒ Object
Persists a .gem file from its raw binary contents. Returns the parsed spec on success. Raises InvalidGem when the payload can’t be opened as a gem, or GemAlreadyExists if the name+version is already on disk.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 25
def add_gem(binary_data)
raise InvalidGem, "Empty gem payload" if binary_data.nil? || binary_data.empty?
tmp = Tempfile.new(["paquette_push", ".gem"])
tmp.binmode
tmp.write(binary_data)
tmp.close
spec = begin
Gem::Package.new(tmp.path).spec
rescue Gem::Package::Error, StandardError => e
raise InvalidGem, "Could not read gem: #{e.message}"
end
name = spec.name
version = spec.version.to_s
raise GemYanked, "#{name}-#{version} was yanked and cannot be republished" if tomb_exists?(name, version)
raise GemAlreadyExists, "#{name}-#{version} already exists" if gem_exists?(name, version)
dest_dir = File.join(@gems_dir, name)
FileUtils.mkdir_p(dest_dir)
FileUtils.mv(tmp.path, gem_file_path(name, version))
spec
ensure
tmp&.close unless tmp&.closed?
File.unlink(tmp.path) if tmp && File.exist?(tmp.path)
end
|
#compact_info(gem_name) ⇒ Object
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 131
def compact_info(gem_name)
versions = versions_for_gem(gem_name)
return [] if versions.empty?
require "digest"
versions.map do |version|
spec = gem_spec(gem_name, version)
next unless spec
gem_file = gem_file_path(gem_name, version)
checksum = Digest::SHA256.file(gem_file).hexdigest
ruby_version = spec.required_ruby_version&.to_s || ">= 0"
"#{version} |checksum:#{checksum},ruby:#{ruby_version}"
end.compact
end
|
#gem_dependencies(gem_name, version) ⇒ Object
117
118
119
120
121
122
123
124
125
126
127
128
129
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 117
def gem_dependencies(gem_name, version)
spec = gem_spec(gem_name, version)
return [] unless spec
runtime_deps = spec.dependencies.select { |dep| dep.type == :runtime }
runtime_deps.map do |dep|
{
name: dep.name,
requirements: dep.requirement.to_s
}
end
end
|
#gem_exists?(gem_name, version) ⇒ Boolean
105
106
107
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 105
def gem_exists?(gem_name, version)
File.exist?(gem_file_path(gem_name, version))
end
|
#gem_file_path(gem_name, version) ⇒ Object
101
102
103
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 101
def gem_file_path(gem_name, version)
File.join(@gems_dir, gem_name, "#{gem_name}-#{version}.gem")
end
|
#gem_names ⇒ Object
73
74
75
76
77
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 73
def gem_names
Dir.glob(File.join(@gems_dir, "*")).select { |path| File.directory?(path) }.map do |package_path|
File.basename(package_path)
end.sort
end
|
#gem_spec(gem_name, version) ⇒ Object
109
110
111
112
113
114
115
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 109
def gem_spec(gem_name, version)
gem_file = gem_file_path(gem_name, version)
return nil unless File.exist?(gem_file)
pkg = Gem::Package.new(gem_file)
pkg.spec
end
|
#gem_versions ⇒ Object
79
80
81
82
83
84
85
86
87
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 79
def gem_versions
versions = []
gem_names.each do |gem_name|
versions_for_gem(gem_name).each do |version|
versions << [gem_name, version]
end
end
versions.sort
end
|
#tomb_exists?(gem_name, version) ⇒ Boolean
69
70
71
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 69
def tomb_exists?(gem_name, version)
File.exist?(tomb_file_path(gem_name, version))
end
|
#tomb_file_path(gem_name, version) ⇒ Object
65
66
67
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 65
def tomb_file_path(gem_name, version)
gem_file_path(gem_name, version) + ".tomb"
end
|
#versions_for_gem(gem_name) ⇒ Object
89
90
91
92
93
94
95
96
97
98
99
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 89
def versions_for_gem(gem_name)
gem_dir = File.join(@gems_dir, gem_name)
return [] unless Dir.exist?(gem_dir)
Dir.glob(File.join(gem_dir, "*.gem")).map do |gem_path|
filename = File.basename(gem_path, ".gem")
if (match = filename.match(/^#{Regexp.escape(gem_name)}-(\d+\.\d+\.\d+.*)$/))
match[1]
end
end.compact.sort
end
|
#yank_gem(gem_name, version) ⇒ Object
Yanks a gem by renaming its .gem file to .gem.tomb. The tomb prevents the same name+version from being re-pushed later. Raises GemNotFound when the gem was never present or already yanked.
57
58
59
60
61
62
63
|
# File 'lib/paquette/gem_server/directory_gem_repository.rb', line 57
def yank_gem(gem_name, version)
gem_path = gem_file_path(gem_name, version)
raise GemNotFound, "#{gem_name}-#{version} not found" unless File.exist?(gem_path)
FileUtils.mv(gem_path, tomb_file_path(gem_name, version))
nil
end
|