reaper-man 0.1.4 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/CONTRIBUTING.md +2 -2
- data/README.md +4 -5
- data/lib/reaper-man/generator.rb +1 -1
- data/lib/reaper-man/generator/rubygems.rb +5 -1
- data/lib/reaper-man/generator/yum.rb +239 -0
- data/lib/reaper-man/package_list.rb +3 -0
- data/lib/reaper-man/package_list/gem.rb +2 -2
- data/lib/reaper-man/package_list/rpm.rb +234 -0
- data/lib/reaper-man/signer/rpm.rb +42 -0
- data/lib/reaper-man/version.rb +1 -1
- data/reaper-man.gemspec +2 -1
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 632a3a30795b366dec8638fdd49b437ee9672f33
|
4
|
+
data.tar.gz: 38261b77a034dd4024da01794451266a7e6698cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 726a868ca539dd913f79393df783df70f0967e281280994751ccd9bc080cca7f909121a17c251d62cfca01452ad023852227f26a0e46186fc4f34b1af68977ed
|
7
|
+
data.tar.gz: b73b0dc046dbb1fa02b129e5fc7fbe7294984c7149a5dd088169b5f4c96d95bc69f5d18e5a93d601e58613c10e7ffec2c32696b37e52ad2ab3e465d3da63b328
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# v0.1.6
|
2
|
+
* [fix] update gem spec loading and requirement building for package list
|
3
|
+
* [fix] deflate contents of quick specs on gem repositories
|
4
|
+
|
1
5
|
# v0.1.4
|
2
6
|
* [fix] fix package and repository signing for deb/apt
|
3
7
|
* [enhancement] allow passing mix of files/directories for signing
|
data/CONTRIBUTING.md
CHANGED
@@ -12,7 +12,7 @@ The develop branch is the current edge of development.
|
|
12
12
|
|
13
13
|
## Pull requests
|
14
14
|
|
15
|
-
* https://github.com/
|
15
|
+
* https://github.com/spox/reaper-man
|
16
16
|
|
17
17
|
Please base all pull requests of the `develop` branch. Merges to
|
18
18
|
`master` only occur through the `develop` branch. Pull requests
|
@@ -22,4 +22,4 @@ based on `master` will likely be cherry picked.
|
|
22
22
|
|
23
23
|
Need to report an issue? Use the github issues:
|
24
24
|
|
25
|
-
* https://github.com/
|
25
|
+
* https://github.com/spox/reaper-man/issues
|
data/README.md
CHANGED
@@ -19,9 +19,6 @@ assets (and the delivery of said assets) is left to the reader.
|
|
19
19
|
|
20
20
|
* deb/apt
|
21
21
|
* gem/rubygems
|
22
|
-
|
23
|
-
#### In Progress
|
24
|
-
|
25
22
|
* rpm/yum
|
26
23
|
|
27
24
|
### Usage
|
@@ -58,8 +55,10 @@ Commands that must be available within the path:
|
|
58
55
|
|
59
56
|
* `gpg`
|
60
57
|
* `debsigs`
|
58
|
+
* `dpkg-deb`
|
59
|
+
* `rpm`
|
60
|
+
* `rpmsign`
|
61
61
|
* `expect`
|
62
62
|
|
63
63
|
## Infos
|
64
|
-
* Repository: https://github.com/
|
65
|
-
* IRC: Freenode @ #heavywater
|
64
|
+
* Repository: https://github.com/spox/reaper-man
|
data/lib/reaper-man/generator.rb
CHANGED
@@ -56,6 +56,8 @@ module ReaperMan
|
|
56
56
|
info.each do |var, value|
|
57
57
|
if(spec.respond_to?("#{var}="))
|
58
58
|
begin
|
59
|
+
# Ensure we convert Smash instances
|
60
|
+
value = value.to_hash if value.is_a?(Hash)
|
59
61
|
spec.send("#{var}=", value)
|
60
62
|
rescue Gem::InvalidSpecificationException => e
|
61
63
|
# TODO: Do we have a logger in this project?
|
@@ -67,8 +69,10 @@ module ReaperMan
|
|
67
69
|
info[:dependencies].each do |dep|
|
68
70
|
spec.add_dependency(*dep)
|
69
71
|
end
|
72
|
+
deflator = Zlib::Deflate.new
|
70
73
|
create_file('quick', marshal_path, "#{name}-#{version}.gemspec.rz") do |file|
|
71
|
-
file.write(Marshal.dump(spec))
|
74
|
+
file.write(deflator.deflate(Marshal.dump(spec), Zlib::SYNC_FLUSH))
|
75
|
+
file.write(deflator.finish)
|
72
76
|
end
|
73
77
|
end
|
74
78
|
end
|
@@ -1,10 +1,249 @@
|
|
1
1
|
require 'reaper-man'
|
2
|
+
require 'xmlsimple'
|
2
3
|
require 'time'
|
3
4
|
|
4
5
|
module ReaperMan
|
5
6
|
class Generator
|
6
7
|
# Generator methods for yum
|
7
8
|
module Yum
|
9
|
+
|
10
|
+
# Version flag mappings
|
11
|
+
VERSION_FLAGS = {
|
12
|
+
'2' => 'LT',
|
13
|
+
'4' => 'GT',
|
14
|
+
'8' => 'EQ',
|
15
|
+
'10' => 'LE',
|
16
|
+
'12' => 'GE'
|
17
|
+
}
|
18
|
+
|
19
|
+
# Location of xmlns (though all are now defunct)
|
20
|
+
XMLNS_MAP = {
|
21
|
+
:repo => 'http://linux.duke.edu/metadata/repo',
|
22
|
+
:common => 'http://linux.duke.edu/metadata/common',
|
23
|
+
:rpm => 'http://linux.duke.edu/metadata/rpm',
|
24
|
+
:filelists => 'http://linux.duke.edu/metadata/filelists',
|
25
|
+
:other => 'http://linux.duke.edu/metadata/other'
|
26
|
+
}
|
27
|
+
|
28
|
+
# Generate the repository
|
29
|
+
def generate!
|
30
|
+
generate_dists(package_config[:yum])
|
31
|
+
end
|
32
|
+
|
33
|
+
# Generate the repository dists
|
34
|
+
#
|
35
|
+
# @param pkg_hash [Hash] repository description
|
36
|
+
# @return [TrueClass]
|
37
|
+
def generate_dists(pkg_hash)
|
38
|
+
pkg_hash.each do |origin_name, dists|
|
39
|
+
dists.each do |dist_name, dist_args|
|
40
|
+
dist_args[:components].each do |component_name, arches|
|
41
|
+
packages = arches.values.flatten.compact.map(&:values).flatten.compact.map(&:values).flatten.compact
|
42
|
+
p_file = primary_file(origin_name, dist_name, component_name, packages)
|
43
|
+
f_file = filelist_file(origin_name, dist_name, component_name, packages)
|
44
|
+
sign_file_if_setup do
|
45
|
+
repomd_file(origin_name, dist_name, component_name,
|
46
|
+
:primary => p_file,
|
47
|
+
:filelists => f_file
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
# Sign file if configured for signing
|
57
|
+
#
|
58
|
+
# @yield block returning file path
|
59
|
+
# @return [String] file path
|
60
|
+
def sign_file_if_setup(opts=nil)
|
61
|
+
path = yield
|
62
|
+
if(signer && options[:sign])
|
63
|
+
signer.file(path, nil, opts)
|
64
|
+
end
|
65
|
+
path
|
66
|
+
end
|
67
|
+
|
68
|
+
# Create a primary file
|
69
|
+
#
|
70
|
+
# @param origin_name [String]
|
71
|
+
# @param dist_name [String]
|
72
|
+
# @param component_name [String]
|
73
|
+
# @param packages [Hash]
|
74
|
+
# @return [Array<String>] path to file, path to compressed file
|
75
|
+
def primary_file(origin_name, dist_name, component_name, packages)
|
76
|
+
content = {
|
77
|
+
:metadata => {
|
78
|
+
:@xmlns => XMLNS_MAP[:common],
|
79
|
+
'@xmlns:rpm' => XMLNS_MAP[:rpm],
|
80
|
+
:@packages => packages.size,
|
81
|
+
:package => packages.map{ |package|
|
82
|
+
{
|
83
|
+
:@type => 'rpm',
|
84
|
+
:name => package['NAME'],
|
85
|
+
:arch => package['ARCH'],
|
86
|
+
:version => {
|
87
|
+
:@epoch => package['EPOCHNUM'],
|
88
|
+
:@ver => package['VERSION'],
|
89
|
+
:@rel => package['RELEASE'].split('.').first
|
90
|
+
},
|
91
|
+
:checksum => [
|
92
|
+
{
|
93
|
+
:@type => 'sha',
|
94
|
+
:@pkgid => 'YES'
|
95
|
+
},
|
96
|
+
package[:generated_sha]
|
97
|
+
],
|
98
|
+
:summary => package['SUMMARY'],
|
99
|
+
:description => [package['DESCRIPTION']].flatten.compact.join(' '),
|
100
|
+
:packager => package['PACKAGER'],
|
101
|
+
:url => package['URL'],
|
102
|
+
:time => {
|
103
|
+
:@file => Time.now.to_i,
|
104
|
+
:@build => package['BUILDTIME']
|
105
|
+
},
|
106
|
+
:size => {
|
107
|
+
:@archive => package['ARCHIVESIZE'],
|
108
|
+
:@package => package[:generated_size],
|
109
|
+
:@installed => package['LONGSIZE']
|
110
|
+
},
|
111
|
+
:location => package[:generated_path],
|
112
|
+
:format => {
|
113
|
+
'rpm:license' => package['LICENSE'],
|
114
|
+
'rpm:vendor' => package['VENDOR'],
|
115
|
+
'rpm:group' => package['GROUP'],
|
116
|
+
'rpm:buildhost' => package['BUILDHOST'],
|
117
|
+
'rpm:header-range' => {
|
118
|
+
:@start => package[:generated_header][:start],
|
119
|
+
:@end => package[:generated_header][:end]
|
120
|
+
},
|
121
|
+
'rpm:provides' => {
|
122
|
+
'rpm:entry' => Array.new.tap{ |entries|
|
123
|
+
pro_ver = package['PROVIDEVERSION'].dup
|
124
|
+
package['PROVIDENAME'].each_with_index do |p_name, p_idx|
|
125
|
+
item = {:@name => p_name}
|
126
|
+
if(p_flag = VERSION_FLAGS[package['PROVIDEFLAGS'][p_idx]])
|
127
|
+
p_ver, p_rel = pro_ver.shift.split('-', 2)
|
128
|
+
item.merge!(:@flags => p_flag, :@ver => p_ver, :@rel => p_rel, :@epoch => package['EPOCHNUM'])
|
129
|
+
end
|
130
|
+
entries.push(item)
|
131
|
+
end
|
132
|
+
}
|
133
|
+
},
|
134
|
+
'rpm:requires' => {
|
135
|
+
'rpm:entry' => Array.new.tap{ |entries|
|
136
|
+
req_ver = package['REQUIREVERSION'].dup
|
137
|
+
package['REQUIRENAME'].each_with_index do |r_name, r_idx|
|
138
|
+
item = {:@name => r_name}
|
139
|
+
if(r_flag = VERSION_FLAGS[package['REQUIREFLAGS'][r_idx]])
|
140
|
+
r_ver, r_rel = req_ver.shift.split('-', 2)
|
141
|
+
item.merge!(:@flags => r_flag, :@ver => r_ver, :@rel => r_rel, :@epoch => package['EPOCHNUM'])
|
142
|
+
end
|
143
|
+
entries.push(item)
|
144
|
+
end
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
args = [origin_name, dist_name, component_name, 'repodata', 'primary.xml']
|
153
|
+
[
|
154
|
+
create_file(*args) do |file|
|
155
|
+
file.puts generate_xml(content)
|
156
|
+
end,
|
157
|
+
compress_file(*args)
|
158
|
+
]
|
159
|
+
end
|
160
|
+
|
161
|
+
# Create a filelist file
|
162
|
+
#
|
163
|
+
# @param origin_name [String]
|
164
|
+
# @param dist_name [String]
|
165
|
+
# @param component_name [String]
|
166
|
+
# @param packages [Hash]
|
167
|
+
# @return [Array<String>] path to file, path to compressed file
|
168
|
+
def filelist_file(origin_name, dist_name, component_name, packages)
|
169
|
+
content = {
|
170
|
+
'filelists' => {
|
171
|
+
:@xmlns => XMLNS_MAP[:filelists],
|
172
|
+
:@packages => packages.size,
|
173
|
+
:package => packages.map{ |package|
|
174
|
+
{
|
175
|
+
:@pkgid => package[:generated_sha],
|
176
|
+
:@name => package['NAME'],
|
177
|
+
:@arch => package['ARCH'],
|
178
|
+
:version => {
|
179
|
+
:@epoch => package['EPOCHNUM'],
|
180
|
+
:@ver => package['VERSION'],
|
181
|
+
:@rel => package['RELEASE'].split('.').first
|
182
|
+
},
|
183
|
+
:file => (package['FILENAMES'] + package['DIRNAMES']).map{ |dir|
|
184
|
+
{:@type => 'dir', :_content_ => dir}
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
args = [origin_name, dist_name, component_name, 'repodata', 'filelists.xml']
|
191
|
+
[
|
192
|
+
create_file(*args) do |file|
|
193
|
+
file.puts generate_xml(content)
|
194
|
+
end,
|
195
|
+
compress_file(*args)
|
196
|
+
]
|
197
|
+
end
|
198
|
+
|
199
|
+
# Create a repomd file
|
200
|
+
#
|
201
|
+
# @param origin_name [String]
|
202
|
+
# @param dist_name [String]
|
203
|
+
# @param component_name [String]
|
204
|
+
# @param packages [Hash]
|
205
|
+
# @return [String] path to file
|
206
|
+
def repomd_file(origin_name, dist_name, component_name, files)
|
207
|
+
content = {
|
208
|
+
:repomd => {
|
209
|
+
:@xmlns => XMLNS_MAP[:repo],
|
210
|
+
:data => Hash.new.tap{ |data|
|
211
|
+
files.each do |f_name, f_paths|
|
212
|
+
data[f_name] = {
|
213
|
+
:location => File.join('repodata', File.basename(f_paths.first)),
|
214
|
+
'open-checksum' => {
|
215
|
+
:@type => 'sha',
|
216
|
+
:_content_ => checksum(File.open(f_paths.first), :sha1)
|
217
|
+
},
|
218
|
+
:checksum => {
|
219
|
+
:@type => 'sha',
|
220
|
+
:_content_ => checksum(File.open(f_paths.last), :sha1)
|
221
|
+
},
|
222
|
+
:timestamp => File.mtime(f_paths.first).to_i
|
223
|
+
}
|
224
|
+
end
|
225
|
+
}
|
226
|
+
}
|
227
|
+
}
|
228
|
+
args = [origin_name, dist_name, component_name, 'repodata', 'repomd.xml']
|
229
|
+
create_file(*args) do |file|
|
230
|
+
file.puts generate_xml(content)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# Generate XML document
|
235
|
+
#
|
236
|
+
# @param hash [Hash]
|
237
|
+
# @return [String]
|
238
|
+
def generate_xml(hash)
|
239
|
+
XmlSimple.xml_out(hash,
|
240
|
+
'AttrPrefix' => true,
|
241
|
+
'KeepRoot' => true,
|
242
|
+
'ContentKey' => :_content_,
|
243
|
+
'XmlDeclaration' => '<?xml version="1.0" encoding="UTF-8" ?>'
|
244
|
+
)
|
245
|
+
end
|
246
|
+
|
8
247
|
end
|
9
248
|
end
|
10
249
|
end
|
@@ -38,14 +38,14 @@ module ReaperMan
|
|
38
38
|
# @param package [String] path to package
|
39
39
|
# @return [Hash]
|
40
40
|
def extract_fields(package)
|
41
|
-
spec = ::Gem::Package.
|
41
|
+
spec = ::Gem::Package.new(package).spec
|
42
42
|
fields = Smash[
|
43
43
|
spec.to_yaml_properties.map do |var_name|
|
44
44
|
[var_name.to_s.tr('@', ''), spec.instance_variable_get(var_name)]
|
45
45
|
end
|
46
46
|
]
|
47
47
|
fields['dependencies'] = fields['dependencies'].map do |dep|
|
48
|
-
[dep.name, dep.requirement.to_s]
|
48
|
+
[dep.name, dep.requirement.to_s.split(',').map(&:strip)]
|
49
49
|
end
|
50
50
|
fields
|
51
51
|
end
|
@@ -3,8 +3,242 @@ require 'reaper-man'
|
|
3
3
|
module ReaperMan
|
4
4
|
class PackageList
|
5
5
|
class Processor
|
6
|
+
# Package list process for RPM packages
|
6
7
|
class Rpm < Processor
|
7
8
|
|
9
|
+
# @return [String]
|
10
|
+
attr_reader :origin
|
11
|
+
# @return [String]
|
12
|
+
attr_reader :dist
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :component
|
15
|
+
# @return [Array<String>] architectures
|
16
|
+
attr_reader :all_map
|
17
|
+
# @return [String] prefix for package file location
|
18
|
+
attr_reader :package_root
|
19
|
+
# @return [String] namespace for packages
|
20
|
+
attr_reader :package_bucket
|
21
|
+
|
22
|
+
# default package root prefix
|
23
|
+
DEFAULT_ROOT = 'pool'
|
24
|
+
# default namespace for packages
|
25
|
+
DEFAULT_BUCKET = 'public'
|
26
|
+
# default architectures to define
|
27
|
+
DEFAULT_ALL_MAP = ['amd64', 'i386']
|
28
|
+
|
29
|
+
# Create new instance
|
30
|
+
#
|
31
|
+
# @param args [Hash]
|
32
|
+
# @option args [String] :origin
|
33
|
+
# @option args [String] :codename
|
34
|
+
# @option args [String] :component
|
35
|
+
# @option args [String] :package_root
|
36
|
+
# @option args [String] :package_bucket
|
37
|
+
# @option args [Array<String>] :all_map
|
38
|
+
def initialize(args={})
|
39
|
+
@origin = args[:origin].to_s
|
40
|
+
@dist = args[:codename].to_s
|
41
|
+
@component = args[:component].to_s
|
42
|
+
@package_root = args.fetch(:package_root, DEFAULT_ROOT)
|
43
|
+
@package_bucket = args.fetch(:package_bucket, DEFAULT_BUCKET)
|
44
|
+
if(dist.empty? || component.empty?)
|
45
|
+
raise 'Both `codename` and `component` must contain valid values'
|
46
|
+
end
|
47
|
+
@all_map = args.fetch(:all_map, DEFAULT_ALL_MAP)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Add a package to the list
|
51
|
+
#
|
52
|
+
# @param conf [Hash]
|
53
|
+
# @param package [String] path to package
|
54
|
+
def add(hash, package)
|
55
|
+
info = extract_fields(package)
|
56
|
+
info.merge!(generate_checksums(package))
|
57
|
+
filenames = inject_package(hash, info, package)
|
58
|
+
filenames
|
59
|
+
end
|
60
|
+
|
61
|
+
# Remove package from the list
|
62
|
+
#
|
63
|
+
# @param conf [Hash] configuration hash
|
64
|
+
# @param package_name [String] name
|
65
|
+
# @param version [String]
|
66
|
+
def remove(hash, package_name, version, args={})
|
67
|
+
hash = hash.to_smash
|
68
|
+
arch = [args.fetch(:arch, all_map)].flatten.compact
|
69
|
+
deleted = false
|
70
|
+
arch.each do |arch_name|
|
71
|
+
arch_name = "binary-#{arch_name}"
|
72
|
+
if(hash.get(:yum, origin, dist, :components, component, arch_name, package_name))
|
73
|
+
if(version)
|
74
|
+
deleted = hash[:yum][origin][dist][:components][component][arch_name][package_name].delete(version)
|
75
|
+
else
|
76
|
+
deleted = hash[:yum][origin][dist][:components][component][arch_name].delete(package_name)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
!!deleted
|
81
|
+
end
|
82
|
+
|
83
|
+
# Extract package metadata
|
84
|
+
#
|
85
|
+
# @param package [String] path to package
|
86
|
+
# @return [Hash]
|
87
|
+
def extract_fields(package)
|
88
|
+
fields = shellout('rpm --querytags').stdout.split("\n").map do |line|
|
89
|
+
line.strip!
|
90
|
+
unless(line.empty? || line.start_with?('HEADER'))
|
91
|
+
line
|
92
|
+
end
|
93
|
+
end.compact
|
94
|
+
|
95
|
+
fmt = fields.map do |k|
|
96
|
+
["\\[#{k}\\]", "[%{#{k}}\n]"]
|
97
|
+
end.flatten.join("\n")
|
98
|
+
|
99
|
+
cmd = "rpm -q -p #{package} --queryformat 'output:\n#{fmt}'"
|
100
|
+
result = shellout(cmd).stdout.sub(/.*output:/, '')
|
101
|
+
|
102
|
+
data = Smash.new
|
103
|
+
key = nil
|
104
|
+
result.split("\n").each do |item|
|
105
|
+
item.strip!
|
106
|
+
next if item.empty?
|
107
|
+
if(item.start_with?('[') && item.end_with?(']'))
|
108
|
+
key = item.tr('[]', '')
|
109
|
+
else
|
110
|
+
if(data[key])
|
111
|
+
if(!data[key].is_a?(Array))
|
112
|
+
data[key] = [data[key]]
|
113
|
+
end
|
114
|
+
data[key] << item
|
115
|
+
else
|
116
|
+
data[key] = item
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
data[:generated_sha] = checksum(File.open(package, 'r'), :sha1)
|
121
|
+
data[:generated_size] = File.size(package)
|
122
|
+
data[:generated_header] = extract_header_information(package)
|
123
|
+
data
|
124
|
+
end
|
125
|
+
|
126
|
+
# Insert package information into package list
|
127
|
+
#
|
128
|
+
# @param hash [Hash] package list contents
|
129
|
+
# @param info [Hash] package information
|
130
|
+
# @param package [String] path to package file
|
131
|
+
# @return [Array<String>] package paths within package list contents
|
132
|
+
def inject_package(hash, info, package)
|
133
|
+
arch = info['ARCH']
|
134
|
+
arch = arch == 'all' ? all_map : [arch]
|
135
|
+
arch.map do |arch|
|
136
|
+
package_file_name = File.join(
|
137
|
+
package_root, package_bucket, origin,
|
138
|
+
dist, component, File.basename(package)
|
139
|
+
)
|
140
|
+
hash.deep_merge!(
|
141
|
+
'yum' => {
|
142
|
+
origin => {
|
143
|
+
dist => {
|
144
|
+
'components' => {
|
145
|
+
component => {
|
146
|
+
arch => {
|
147
|
+
info['NAME'] => {
|
148
|
+
info['NEVR'] => info.merge(:generated_path => package_file_name)
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
)
|
157
|
+
File.join('yum', origin, package_file_name)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Generate required checksums for given package
|
162
|
+
#
|
163
|
+
# @param package [String] path to package file
|
164
|
+
# @return [Hash] checksums
|
165
|
+
def generate_checksums(package)
|
166
|
+
File.open(package, 'r') do |pkg|
|
167
|
+
{
|
168
|
+
'MD5sum' => checksum(pkg.rewind && pkg, :md5),
|
169
|
+
'SHA1' => checksum(pkg.rewind && pkg, :sha1),
|
170
|
+
'SHA256' => checksum(pkg.rewind && pkg, :sha256)
|
171
|
+
}
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Extract the start and end points of the header within the
|
176
|
+
# package
|
177
|
+
#
|
178
|
+
# @param package [String] path to package
|
179
|
+
# @return [Smash<start,end>]
|
180
|
+
# @note ported from: http://yum.baseurl.org/gitweb?p=yum.git;a=blob;f=yum/packages.py;h=eebeb9dfd264b887b054187276cea12ced3a0bc2;hb=HEAD#l2212
|
181
|
+
def extract_header_information(package)
|
182
|
+
io = File.open(package, 'rb')
|
183
|
+
|
184
|
+
# read past lead and 8 bytes of signature header
|
185
|
+
io.seek(104)
|
186
|
+
binindex = io.read(4)
|
187
|
+
sigindex, _ = binindex.unpack('I>')
|
188
|
+
|
189
|
+
bindata = io.read(4)
|
190
|
+
sigdata, _ = bindata.unpack('I>')
|
191
|
+
|
192
|
+
# seeked in to 112 bytes
|
193
|
+
|
194
|
+
# each index is 4 32bit segments == 16 bytes
|
195
|
+
|
196
|
+
sigindexsize = sigindex * 16
|
197
|
+
sigsize = sigdata + sigindexsize
|
198
|
+
|
199
|
+
# Round to next 8 byte boundary
|
200
|
+
|
201
|
+
disttoboundary = (sigsize % 8)
|
202
|
+
unless(disttoboundary == 0)
|
203
|
+
disttoboundary = 8 - disttoboundary
|
204
|
+
end
|
205
|
+
|
206
|
+
# 112 bytes - 96 == lead
|
207
|
+
# 8 == magic and reserved
|
208
|
+
# 8 == signature header data
|
209
|
+
|
210
|
+
hdrstart = 112 + sigsize + disttoboundary
|
211
|
+
|
212
|
+
# seek to start of header
|
213
|
+
io.seek(hdrstart)
|
214
|
+
# seek past magic
|
215
|
+
io.seek(8, IO::SEEK_CUR)
|
216
|
+
|
217
|
+
binindex = io.read(4)
|
218
|
+
|
219
|
+
hdrindex, _ = binindex.unpack('I>')
|
220
|
+
bindata = io.read(4)
|
221
|
+
hdrdata, _ = bindata.unpack('I>')
|
222
|
+
|
223
|
+
# each index is 4 32bit segments - so each is 16 bytes
|
224
|
+
|
225
|
+
hdrindexsize = hdrindex * 16
|
226
|
+
|
227
|
+
# add 16 to the hdrsize to account for 16 bytes of misc data
|
228
|
+
# between the end of the sig and the header
|
229
|
+
|
230
|
+
hdrsize = hdrdata + hdrindexsize + 16
|
231
|
+
|
232
|
+
# header end is hdrstart + hdrsize
|
233
|
+
|
234
|
+
hdrend = hdrstart + hdrsize
|
235
|
+
|
236
|
+
Smash.new(
|
237
|
+
:start => hdrstart,
|
238
|
+
:end => hdrend
|
239
|
+
)
|
240
|
+
end
|
241
|
+
|
8
242
|
end
|
9
243
|
end
|
10
244
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'reaper-man'
|
2
|
+
|
3
|
+
module ReaperMan
|
4
|
+
class Signer
|
5
|
+
# Signing methods for rpm files
|
6
|
+
module Rpm
|
7
|
+
|
8
|
+
# Sign given files
|
9
|
+
#
|
10
|
+
# @param pkgs [String] list of file paths
|
11
|
+
# @return [TrueClass]
|
12
|
+
def package(*pkgs)
|
13
|
+
pkgs = valid_packages(*pkgs)
|
14
|
+
pkgs.each_slice(sign_chunk_size) do |pkgs|
|
15
|
+
cmd = %(rpmsign --resign --key-id="#{key_id}" #{pkgs.join(' ')})
|
16
|
+
if(key_password)
|
17
|
+
shellout(
|
18
|
+
"#{Signer::HELPER_COMMAND} #{cmd}",
|
19
|
+
:environment => {
|
20
|
+
'REAPER_KEY_PASSWORD' => key_password
|
21
|
+
}
|
22
|
+
)
|
23
|
+
else
|
24
|
+
shellout(cmd)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
# Filter only valid paths for signing (.rpm extensions)
|
31
|
+
#
|
32
|
+
# @param pkgs [String] list of file paths
|
33
|
+
# @return [Array<String>]
|
34
|
+
def valid_packages(*pkgs)
|
35
|
+
pkgs.find_all do |pkg|
|
36
|
+
File.extname(pkg) == '.rpm'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/reaper-man/version.rb
CHANGED
data/reaper-man.gemspec
CHANGED
@@ -6,11 +6,12 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.summary = 'Reap packages'
|
7
7
|
s.author = 'Chris Roberts'
|
8
8
|
s.email = 'code@chrisroberts.org'
|
9
|
-
s.homepage = 'https://github.com/
|
9
|
+
s.homepage = 'https://github.com/spox/reaper-man'
|
10
10
|
s.description = 'Grow code, reap packages'
|
11
11
|
s.require_path = 'lib'
|
12
12
|
s.add_runtime_dependency 'bogo-cli'
|
13
13
|
s.add_runtime_dependency 'childprocess'
|
14
|
+
s.add_runtime_dependency 'xml-simple'
|
14
15
|
s.add_development_dependency 'minitest'
|
15
16
|
s.executables << 'reaper-man'
|
16
17
|
s.files = Dir['lib/**/*'] + %w(reaper-man.gemspec README.md CHANGELOG.md CONTRIBUTING.md LICENSE)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reaper-man
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Roberts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bogo-cli
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: xml-simple
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: minitest
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,13 +97,14 @@ files:
|
|
83
97
|
- lib/reaper-man/package_list/rpm.rb
|
84
98
|
- lib/reaper-man/signer.rb
|
85
99
|
- lib/reaper-man/signer/deb.rb
|
100
|
+
- lib/reaper-man/signer/rpm.rb
|
86
101
|
- lib/reaper-man/signer/rubygems.rb
|
87
102
|
- lib/reaper-man/util-scripts/auto-helper
|
88
103
|
- lib/reaper-man/utils.rb
|
89
104
|
- lib/reaper-man/utils/process.rb
|
90
105
|
- lib/reaper-man/version.rb
|
91
106
|
- reaper-man.gemspec
|
92
|
-
homepage: https://github.com/
|
107
|
+
homepage: https://github.com/spox/reaper-man
|
93
108
|
licenses: []
|
94
109
|
metadata: {}
|
95
110
|
post_install_message:
|
@@ -108,9 +123,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
123
|
version: '0'
|
109
124
|
requirements: []
|
110
125
|
rubyforge_project:
|
111
|
-
rubygems_version: 2.
|
126
|
+
rubygems_version: 2.4.8
|
112
127
|
signing_key:
|
113
128
|
specification_version: 4
|
114
129
|
summary: Reap packages
|
115
130
|
test_files: []
|
116
|
-
has_rdoc:
|