frm 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/LICENSE +30 -0
- data/Rakefile +19 -0
- data/bin/fpm +91 -0
- data/lib/frm/deb.rb +327 -0
- data/lib/frm/s3.rb +89 -0
- data/lib/frm/version.rb +1 -1
- data/test/deb_test.rb +457 -0
- data/test/deb_test2.rb +31 -0
- data/test/s3.rb +56 -0
- metadata +15 -7
- data/frm/.gitignore +0 -4
data/.gitignore
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Copyright (c) 2012, Martin K. Rhoads and FRM Project Contributors.
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are
|
6
|
+
met:
|
7
|
+
|
8
|
+
* Redistributions of source code must retain the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
10
|
+
|
11
|
+
* Redistributions in binary form must reproduce the above copyright
|
12
|
+
notice, this list of conditions and the following disclaimer in the
|
13
|
+
documentation and/or other materials provided with the distribution.
|
14
|
+
|
15
|
+
* Neither the name of the FRM Project, Martin K. Rhoads, nor the names
|
16
|
+
of its contributors may be used to endorse or promote products
|
17
|
+
derived from this software without specific prior written
|
18
|
+
permission.
|
19
|
+
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
21
|
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
23
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
24
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
25
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
26
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
27
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
28
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
29
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
30
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/Rakefile
CHANGED
@@ -1,2 +1,21 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
fpm_base = File.dirname __FILE__
|
5
|
+
|
6
|
+
namespace :bump do
|
7
|
+
|
8
|
+
desc "bump the patch version number"
|
9
|
+
task :patch do
|
10
|
+
version_file_path = File.join fpm_base, 'lib', 'frm', 'version.rb'
|
11
|
+
current_version_file = File.read version_file_path
|
12
|
+
current_version_file =~ /VERSION[^\d]+(\d+)\.(\d+)\.(\d+)(\.([^'"]*))?/
|
13
|
+
major,minor,patch = $1, $2, $3
|
14
|
+
new_version = [$1,$2,$3.to_i+1].join('.')
|
15
|
+
new_version_file = current_version_file.sub /VERSION\s*=.*/, %Q{VERSION = "#{new_version}"}
|
16
|
+
File.open(version_file_path, 'w') {|f| f.write(new_version_file) }
|
17
|
+
puts "bumping version to #{new_version}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
data/bin/fpm
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This is the CLI interface into Effin Repo Manager
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
# This hash will hold all of the options
|
7
|
+
# parsed from the command-line by
|
8
|
+
# OptionParser.
|
9
|
+
options = {}
|
10
|
+
|
11
|
+
packages = []
|
12
|
+
|
13
|
+
def print_and_exit(message)
|
14
|
+
puts
|
15
|
+
puts message
|
16
|
+
puts
|
17
|
+
puts `#{__FILE__} -h`
|
18
|
+
exit 1
|
19
|
+
end
|
20
|
+
|
21
|
+
optparse = OptionParser.new do|opts|
|
22
|
+
opts.banner = "Usage: frm.rb [options] package1 [package2]B ..."
|
23
|
+
|
24
|
+
options[:access_key] = nil
|
25
|
+
opts.on( '-a', '--access-key ACCESS_KEY', 'S3 public access key' ) do |key|
|
26
|
+
options[:access_key] = key
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
options[:secret_key] = nil
|
31
|
+
opts.on( '-s', '--secret-key SECRET_KEY', 'S3 private access key' ) do |key|
|
32
|
+
options[:secret_key] = key
|
33
|
+
end
|
34
|
+
|
35
|
+
options[:bucket] = nil
|
36
|
+
opts.on( '-b', '--bucket BUCKET', 'S3 bucket' ) do |bucket|
|
37
|
+
options[:bucket] = bucket
|
38
|
+
end
|
39
|
+
|
40
|
+
options[:prefix] = nil
|
41
|
+
opts.on( '-p', '--prefix PREFIX', 'S3 prefix of repostory' ) do |prefix|
|
42
|
+
options[:prefix] = prefix
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# This displays the help screen, all programs are
|
47
|
+
# assumed to have this option.
|
48
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
49
|
+
puts opts
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
optparse.parse!
|
55
|
+
|
56
|
+
|
57
|
+
ARGV.each do |package|
|
58
|
+
packages << package
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# verify that the required inputs are set
|
63
|
+
%w{access_key secret_key bucket prefix }.each do |input|
|
64
|
+
print_and_exit "you must specify the #{input} parameter!!!" if options.values_at(input.to_sym) == [nil]
|
65
|
+
end
|
66
|
+
|
67
|
+
# verify that we have at least one package to install
|
68
|
+
print_and_exit "you need to specify at least one package to publish!!!" if packages.empty?
|
69
|
+
|
70
|
+
packages.each do |package|
|
71
|
+
print_and_exit "package '#{package}' does not exits!!!" unless File.exists?(package)
|
72
|
+
print_and_exit "package '#{package}' does not appear to be a valid deb" unless system("dpkg --field #{package} > /dev/null 2>&1 ")
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# if we have gotten this far it means that all required parameters have been set, so let's begin
|
77
|
+
|
78
|
+
|
79
|
+
# chdir to the top level of the code
|
80
|
+
Dir.chdir(File.dirname(File.dirname(__FILE__)))
|
81
|
+
|
82
|
+
# require the necessary FRM libs
|
83
|
+
require File.join Dir.pwd, 'lib', 'deb'
|
84
|
+
|
85
|
+
puts "creating release..."
|
86
|
+
package_release = FRM::PackageRelease.new(packages)
|
87
|
+
|
88
|
+
puts "pushing release..."
|
89
|
+
release_pusher = FRM::ReleasePusher.new(package_release,options[:access_key],options[:secret_key],options[:bucket],options[:prefix])
|
90
|
+
|
91
|
+
puts "looks like everything ran ok!"
|
data/lib/frm/deb.rb
ADDED
@@ -0,0 +1,327 @@
|
|
1
|
+
DEFAULT_HOST = 's3-us-west-1.amazonaws.com' # stupid hack to point to
|
2
|
+
# the right region
|
3
|
+
|
4
|
+
module FRM
|
5
|
+
|
6
|
+
|
7
|
+
class Base
|
8
|
+
my_dir = File.dirname __FILE__
|
9
|
+
require File.join my_dir, 's3'
|
10
|
+
require 'zlib'
|
11
|
+
require 'tempfile'
|
12
|
+
require 'digest/md5'
|
13
|
+
require 'digest/sha1'
|
14
|
+
require 'digest/sha2'
|
15
|
+
|
16
|
+
def compute_md5(string)
|
17
|
+
Digest::MD5.hexdigest(string)
|
18
|
+
end
|
19
|
+
|
20
|
+
def compute_sha1(string)
|
21
|
+
Digest::SHA1.hexdigest(string)
|
22
|
+
end
|
23
|
+
|
24
|
+
def compute_sha2(string)
|
25
|
+
Digest::SHA2.hexdigest(string)
|
26
|
+
end
|
27
|
+
|
28
|
+
# TODO:
|
29
|
+
# there has to be a better way to use gpg withen ruby. found many
|
30
|
+
# broken solutions :\
|
31
|
+
def gpg_clearsign(message)
|
32
|
+
`echo "#{message}" | gpg --clearsign`
|
33
|
+
end
|
34
|
+
|
35
|
+
# TODO: same as above
|
36
|
+
def gpg_detached(message)
|
37
|
+
`echo "#{message}" | gpg -abs`
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def generate_gzip_pipe(contents)
|
42
|
+
read_buffer, write_buffer = IO.pipe
|
43
|
+
gzip_writer = Zlib::GzipWriter.new write_buffer
|
44
|
+
gzip_writer.mtime = 1 # ensure that the header is determinstic
|
45
|
+
gzip_writer.write contents
|
46
|
+
gzip_writer.close
|
47
|
+
read_buffer
|
48
|
+
end
|
49
|
+
|
50
|
+
def gunzip_pipe(gziped_pipe)
|
51
|
+
gzip_reader = Zlib::GzipReader.new gziped_pipe
|
52
|
+
unzipped_string = gzip_reader.read
|
53
|
+
gzip_reader.close
|
54
|
+
return unzipped_string
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_package_stub(read_buffer)
|
58
|
+
package = {}
|
59
|
+
stub = ""
|
60
|
+
while line = read_buffer.gets
|
61
|
+
return nil if line.strip.empty?
|
62
|
+
raise "bad input" unless (match = line.match /^\w+\-?\w+?: /)
|
63
|
+
stub << line
|
64
|
+
key = match[0].delete ': ' # if match
|
65
|
+
value = match.post_match.strip
|
66
|
+
package[key] = value
|
67
|
+
if key == 'Description'
|
68
|
+
while (line = read_buffer.gets).strip != ""
|
69
|
+
package['Description'] << line
|
70
|
+
stub << line
|
71
|
+
end
|
72
|
+
package['Description'].rstrip!
|
73
|
+
return package, stub
|
74
|
+
end
|
75
|
+
end
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def merge_package_file(in_pipe,out_pipe,package_list)
|
80
|
+
sorted_list = package_list.sort { |a,b| a['Package'] <=> b['Package'] }
|
81
|
+
while (next_stub = parse_package_stub in_pipe)
|
82
|
+
STDERR.puts "next_stub[0] = #{next_stub[0]}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
class Package < Base
|
89
|
+
attr_accessor :repo_filename
|
90
|
+
attr_reader :path, :content, :md5, :sha1, :sha2 , :size
|
91
|
+
def initialize(path)
|
92
|
+
@path = path
|
93
|
+
raise "Can not find file '#{path}'" unless File.exists?(path)
|
94
|
+
begin
|
95
|
+
@content = File.read(path)
|
96
|
+
rescue Object => o
|
97
|
+
STDERR.puts "Could not open file '#{path}'. Exiting..."
|
98
|
+
STDERR.puts o.inspect
|
99
|
+
STDERR.puts o.backtrace
|
100
|
+
raise "Could not open file '#{path}'. Exiting..."
|
101
|
+
end
|
102
|
+
@size = File.size(@path)
|
103
|
+
@md5 = compute_md5(@content)
|
104
|
+
@sha1 = compute_sha1(@content)
|
105
|
+
@sha2 = compute_sha2(@content)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class PackageRelease < Base
|
110
|
+
attr_reader :packages, :standards_version, :priority, :package_file, :gzipped_package_file, :release_file, :short_release_file, :component
|
111
|
+
def initialize(packages={},component='main/binary-amd64')
|
112
|
+
@component = component
|
113
|
+
@standards_version = standards_version
|
114
|
+
@priority = priority
|
115
|
+
@packages = []
|
116
|
+
packages.each { |package| @packages << Package.new(package) }
|
117
|
+
@package_file = generate_package_file
|
118
|
+
@gzipped_package_file = generate_gzip_pipe(@package_file).read
|
119
|
+
@short_release_file = generate_short_release_file
|
120
|
+
@release_file = generate_release_file
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def generate_release_file()
|
126
|
+
partial_release_file = "Origin: apt.cloudscaling.com
|
127
|
+
Label: apt repository natty
|
128
|
+
Codename: natty
|
129
|
+
Date: Thu, 22 Dec 2011 00:29:55 UTC
|
130
|
+
Architectures: amd64
|
131
|
+
Components: main universe multiverse
|
132
|
+
Description: Cloudscaling APT repository
|
133
|
+
MD5Sum:
|
134
|
+
#{compute_md5(@package_file)} #{@package_file.size} #{@component}/Packages
|
135
|
+
#{compute_md5(@gzipped_package_file)} #{@gzipped_package_file.size} #{@component}/Packages.gz
|
136
|
+
#{compute_md5(@short_release_file)} #{@short_release_file.size} #{@component}/Release
|
137
|
+
SHA1:
|
138
|
+
#{compute_sha1(@package_file)} #{@package_file.size} #{@component}/Packages
|
139
|
+
#{compute_sha1(@gzipped_package_file)} #{@gzipped_package_file.size} #{@component}/Packages.gz
|
140
|
+
#{compute_sha1(@short_release_file)} #{@short_release_file.size} #{@component}/Release
|
141
|
+
SHA256:
|
142
|
+
#{compute_sha2(@package_file)} #{@package_file.size} #{@component}/Packages
|
143
|
+
#{compute_sha2(@gzipped_package_file)} #{@gzipped_package_file.size} #{@component}/Packages.gz
|
144
|
+
#{compute_sha2(@short_release_file)} #{@short_release_file.size} #{@component}/Release
|
145
|
+
"
|
146
|
+
return partial_release_file
|
147
|
+
end
|
148
|
+
|
149
|
+
def generate_short_release_file
|
150
|
+
"Component: main
|
151
|
+
Origin: apt.cloudscaling.com
|
152
|
+
Label: apt repository natty
|
153
|
+
Architecture: amd64
|
154
|
+
Description: Cloudscaling APT repository
|
155
|
+
"
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
def filename(package)
|
160
|
+
filename = File.basename package.path
|
161
|
+
shortname = `dpkg --field #{package.path} Package`.chomp
|
162
|
+
first_letter = shortname[0]
|
163
|
+
package.repo_filename = "pool/main/#{first_letter}/#{shortname}/#{filename}"
|
164
|
+
end
|
165
|
+
|
166
|
+
def generate_package_file()
|
167
|
+
package_file = ''
|
168
|
+
@packages.each { |package| package_file << generate_package_stub(package) }
|
169
|
+
return package_file
|
170
|
+
end
|
171
|
+
|
172
|
+
def generate_package_stub(package)
|
173
|
+
package_stub = ''
|
174
|
+
package_stub << `dpkg --field #{package.path}`
|
175
|
+
package_stub << "Filename: #{filename(package)}\n"
|
176
|
+
package_stub << "Size: #{package.size}\n"
|
177
|
+
package_stub << "MD5sum: #{package.md5}\n"
|
178
|
+
package_stub << "SHA1: #{package.sha1}\n"
|
179
|
+
package_stub << "SHA256: #{package.sha2}\n"
|
180
|
+
package_stub << "\n"
|
181
|
+
return package_stub
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class ReleasePusher < Base
|
186
|
+
def initialize(package_release,access_key,secret_key,bucket,prefix,server='s3-us-west-1.amazonaws.com')
|
187
|
+
@bucket = bucket
|
188
|
+
@prefix = prefix
|
189
|
+
@s3 = FRM::S3.new(access_key,secret_key,server)
|
190
|
+
push_packages(package_release.packages)
|
191
|
+
push_release_files(package_release)
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
|
197
|
+
def push_release_files(package_release)
|
198
|
+
# TODO: un-hardcode this
|
199
|
+
release_path = @prefix + "/dists/natty/Release"
|
200
|
+
@s3.put(release_path,package_release.release_file,@bucket)
|
201
|
+
|
202
|
+
in_release_path = @prefix + "/dists/natty/InRelease"
|
203
|
+
@s3.put(in_release_path,gpg_clearsign(package_release.release_file),@bucket)
|
204
|
+
|
205
|
+
gpg_release_path = @prefix + "/dists/natty/Release.gpg"
|
206
|
+
@s3.put(gpg_release_path,gpg_detached(package_release.release_file),@bucket)
|
207
|
+
|
208
|
+
release_file_path = @prefix + "/dists/natty/" + package_release.component
|
209
|
+
@s3.put(release_file_path + '/Release',package_release.short_release_file,@bucket)
|
210
|
+
@s3.put(release_file_path + '/Packages',package_release.package_file,@bucket)
|
211
|
+
@s3.put(release_file_path + '/Packages.gz',package_release.gzipped_package_file,@bucket)
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
def push_packages(packages)
|
216
|
+
packages.each { |package| push_package(package) }
|
217
|
+
end
|
218
|
+
|
219
|
+
def push_package(package)
|
220
|
+
remote_path = @prefix + '/' + package.repo_filename
|
221
|
+
@s3.put(remote_path,package.content,@bucket)
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
|
229
|
+
class Deb < Base
|
230
|
+
|
231
|
+
def initialize()
|
232
|
+
end
|
233
|
+
|
234
|
+
def generate_package_file(in_packages=[])
|
235
|
+
packages = in_packages.dup
|
236
|
+
package_file = ''
|
237
|
+
packages.each { |package| package_file << generate_package_stub(package) }
|
238
|
+
return package_file
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
def generate_package_stub(in_package={})
|
243
|
+
package = in_package.dup
|
244
|
+
package_stub = ''
|
245
|
+
description = package.delete('Description') || "no description given"
|
246
|
+
path_to_deb = package.delete 'path_to_deb'
|
247
|
+
section = package.delete 'section'
|
248
|
+
package["Filename"] = "pool/#{section}/#{package['Package'][0]}/#{package['Package']}/#{package['Package']}_#{package['Version']}_#{package['Architecture']}.deb"
|
249
|
+
package["Size"] = File.new(path_to_deb).size
|
250
|
+
package["MD5sum"] = self.compute_md5 File.read path_to_deb
|
251
|
+
package["SHA1"] = compute_sha1 File.read path_to_deb
|
252
|
+
package["SHA256"] = compute_sha2 File.read path_to_deb
|
253
|
+
package["Description"] = description
|
254
|
+
package.each { |key,value| package_stub << generate_package_line(key,value) }
|
255
|
+
package_stub << "\n"
|
256
|
+
return package_stub
|
257
|
+
end
|
258
|
+
|
259
|
+
|
260
|
+
def generate_package_release
|
261
|
+
return "Component: main
|
262
|
+
Origin: apt.cloudscaling.com
|
263
|
+
Label: apt repository natty
|
264
|
+
Architecture: amd64
|
265
|
+
Description: Cloudscaling APT repository
|
266
|
+
"
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
def generate_release
|
271
|
+
return "Origin: apt.cloudscaling.com
|
272
|
+
Label: apt repository natty
|
273
|
+
Codename: natty
|
274
|
+
Date: Thu, 22 Dec 2011 00:29:55 UTC
|
275
|
+
Architectures: amd64
|
276
|
+
Components: main universe multiverse
|
277
|
+
Description: Cloudscaling APT repository
|
278
|
+
MD5Sum:
|
279
|
+
a4b943ff89790ccdc186875dad67827b 5813 main/binary-amd64/Packages
|
280
|
+
004fd3f868ebbe7501fb2e1c0c54e2a7 2148 main/binary-amd64/Packages.gz
|
281
|
+
79dd2fee35fba7255dcd40e1f6529591 134 main/binary-amd64/Release
|
282
|
+
d41d8cd98f00b204e9800998ecf8427e 0 universe/binary-amd64/Packages
|
283
|
+
7029066c27ac6f5ef18d660d5741979a 20 universe/binary-amd64/Packages.gz
|
284
|
+
018c8e37146b908a6bde46012a83d4ba 138 universe/binary-amd64/Release
|
285
|
+
d41d8cd98f00b204e9800998ecf8427e 0 multiverse/binary-amd64/Packages
|
286
|
+
7029066c27ac6f5ef18d660d5741979a 20 multiverse/binary-amd64/Packages.gz
|
287
|
+
4680f88c741bad22529909db5be4f608 140 multiverse/binary-amd64/Release
|
288
|
+
SHA1:
|
289
|
+
6e03924030eab56cb9735a52ec710537e682bcfc 5813 main/binary-amd64/Packages
|
290
|
+
5f2989bae96e148cb5f18accc4357305926ab1e1 2148 main/binary-amd64/Packages.gz
|
291
|
+
6d932af9af761f418e5374f73dcd09badb4fe57e 134 main/binary-amd64/Release
|
292
|
+
da39a3ee5e6b4b0d3255bfef95601890afd80709 0 universe/binary-amd64/Packages
|
293
|
+
46c6643f07aa7f6bfe7118de926b86defc5087c4 20 universe/binary-amd64/Packages.gz
|
294
|
+
4d428e7ad434df47cffc40cabf8e238ee76ea434 138 universe/binary-amd64/Release
|
295
|
+
da39a3ee5e6b4b0d3255bfef95601890afd80709 0 multiverse/binary-amd64/Packages
|
296
|
+
46c6643f07aa7f6bfe7118de926b86defc5087c4 20 multiverse/binary-amd64/Packages.gz
|
297
|
+
c8a7d2eb24ece57d460106506fcff99cb2ada015 140 multiverse/binary-amd64/Release
|
298
|
+
SHA256:
|
299
|
+
dd8283f06beb4a5fc06ac62d3ae098e5ba2717daef2a15b5f3e9233eb64e0227 5813 main/binary-amd64/Packages
|
300
|
+
b197c5a3c1fe6a6d286e9f066a0cade289e3a2fc485c90407179951634788aa8 2148 main/binary-amd64/Packages.gz
|
301
|
+
690b44df6fe65f40f260b73394e87804df78c9ccf13999889259faeed3eec40d 134 main/binary-amd64/Release
|
302
|
+
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 universe/binary-amd64/Packages
|
303
|
+
59869db34853933b239f1e2219cf7d431da006aa919635478511fabbfc8849d2 20 universe/binary-amd64/Packages.gz
|
304
|
+
32f35b1fc2bdc5a11b53abeadaaa77771b15acb5305777484bf4390d697ae5bd 138 universe/binary-amd64/Release
|
305
|
+
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 multiverse/binary-amd64/Packages
|
306
|
+
59869db34853933b239f1e2219cf7d431da006aa919635478511fabbfc8849d2 20 multiverse/binary-amd64/Packages.gz
|
307
|
+
f29816e3a4f90a8b4c688fdb2ac3056d5fb7349857c9ea8da2fbccf8e931baca 140 multiverse/binary-amd64/Release"
|
308
|
+
end
|
309
|
+
|
310
|
+
|
311
|
+
def generate_package_line(key='',value='')
|
312
|
+
valid_options = %w{Package Version Architecture Maintainer Standards-Version Homepage Priority Depends Filename Size SHA256 SHA1 MD5sum Description}
|
313
|
+
raise "Bogus option passed: #{key}" unless valid_options.include?(key)
|
314
|
+
|
315
|
+
case key
|
316
|
+
when 'Depends'
|
317
|
+
return "Depends: #{value.join(', ')}\n"
|
318
|
+
when 'Maintainer'
|
319
|
+
return "Maintainer: <#{value}>\n"
|
320
|
+
else
|
321
|
+
return "#{key}: #{value}\n"
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
end
|
326
|
+
|
327
|
+
end
|
data/lib/frm/s3.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
my_dir = File.dirname __FILE__
|
2
|
+
STDERR.puts "#{File.join my_dir, 's3'}"
|
3
|
+
require File.join my_dir, 'base'
|
4
|
+
|
5
|
+
|
6
|
+
module FRM
|
7
|
+
class S3 < Base
|
8
|
+
attr_reader :max_retries
|
9
|
+
@connection
|
10
|
+
def initialize(access_key_id,secret_access_key,server='s3.amazonaws.com')
|
11
|
+
require 'aws/s3'
|
12
|
+
@max_retries = 10
|
13
|
+
@connection = AWS::S3::Base.establish_connection!(:access_key_id => access_key_id,
|
14
|
+
:secret_access_key => secret_access_key,
|
15
|
+
:server => server )
|
16
|
+
end
|
17
|
+
|
18
|
+
def key?(key,bucket)
|
19
|
+
AWS::S3::S3Object.exists?(key,bucket)
|
20
|
+
end
|
21
|
+
|
22
|
+
def put(key,value,bucket)
|
23
|
+
@max_retries.times do |i|
|
24
|
+
begin
|
25
|
+
AWS::S3::S3Object.store(key,value,bucket,:server => 's3-us-west-1.amazonaws.com',:access => :public_read)
|
26
|
+
return true
|
27
|
+
rescue Object => o
|
28
|
+
print_retry(__method__,o)
|
29
|
+
end
|
30
|
+
raise "could not put object!!!" if i == (@max_retries - 1)
|
31
|
+
end
|
32
|
+
raise "could not put object!!!"
|
33
|
+
end
|
34
|
+
|
35
|
+
def get(key,bucket)
|
36
|
+
@max_retries.times do |i|
|
37
|
+
begin
|
38
|
+
value = AWS::S3::S3Object.value(key,bucket)
|
39
|
+
return value
|
40
|
+
rescue Object => o
|
41
|
+
print_retry(__method__,o)
|
42
|
+
end
|
43
|
+
raise "could not get object!!!" if i == (@max_retries - 1)
|
44
|
+
end
|
45
|
+
raise "could not get object!!!"
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_stream(key,bucket)
|
49
|
+
@max_retries.times do |i|
|
50
|
+
begin
|
51
|
+
stream = AWS::S3::S3Object.stream(key,bucket)
|
52
|
+
return stream
|
53
|
+
rescue Object => o
|
54
|
+
print_retry(__method__,o)
|
55
|
+
end
|
56
|
+
raise "could not get object!!!" if i == (@max_retries - 1)
|
57
|
+
end
|
58
|
+
raise "could not get object!!!"
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete(key,bucket)
|
62
|
+
begin
|
63
|
+
AWS::S3::S3Object.delete(key,bucket)
|
64
|
+
true
|
65
|
+
rescue Object => o
|
66
|
+
print_retry(__method__,o)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def move(old_key,new_key,vucket)
|
71
|
+
begin
|
72
|
+
AWS::S3::S3Object.rename(old_key,new_key,bucket)
|
73
|
+
return
|
74
|
+
rescue Object => o
|
75
|
+
print_retry(__method__,o)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
def print_retry(action,error)
|
82
|
+
STDERR.puts "coudld not #{action} object because of:"
|
83
|
+
STDERR.puts error.inspect
|
84
|
+
STDERR.puts ", retrying..."
|
85
|
+
sleep 2
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
data/lib/frm/version.rb
CHANGED
data/test/deb_test.rb
ADDED
@@ -0,0 +1,457 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
my_dir = File.dirname __FILE__
|
6
|
+
require File.join my_dir, 'deb'
|
7
|
+
|
8
|
+
class TestReleasePusher < MiniTest::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
@tempfile1 = File.open('/tmp/foo_1.2.68_amd64.deb','w+') { |f| f.write 'foo' }
|
11
|
+
@tempfile2 = File.open('/tmp/bar_1.2.3.4_amd64.deb','w+') { |f| f.write 'bar' }
|
12
|
+
@tempfile3 = File.open('/tmp/martin_1.2.3.4_amd64.deb','w+') { |f| f.write 'martin' }
|
13
|
+
|
14
|
+
hashes = [{
|
15
|
+
"Package" => "foo",
|
16
|
+
"Version" => "1.2.68",
|
17
|
+
"Architecture" => "amd64",
|
18
|
+
"Maintainer" => "support@cloudscaling.com",
|
19
|
+
"Homepage" => "http://www.cloudscaling.com",
|
20
|
+
"Priority" => "extra",
|
21
|
+
"Depends" => %w{one two three},
|
22
|
+
"section" => "main",
|
23
|
+
"path_to_deb" => '/tmp/foo_1.2.68_amd64.deb',
|
24
|
+
"Description" => 'some
|
25
|
+
multiline
|
26
|
+
description'
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"Package" => "bar",
|
30
|
+
"Version" => "1.2.3.4",
|
31
|
+
"Architecture" => "amd64",
|
32
|
+
"Maintainer" => "support@cloudscaling.com",
|
33
|
+
"Homepage" => "http://www.cloudscaling.com",
|
34
|
+
"Priority" => "extra",
|
35
|
+
"Depends" => %w{one two three},
|
36
|
+
"section" => "main",
|
37
|
+
"path_to_deb" => '/tmp/bar_1.2.3.4_amd64.deb'
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"Package" => "martin",
|
41
|
+
"Version" => "1.2.3.4",
|
42
|
+
"Architecture" => "amd64",
|
43
|
+
"Maintainer" => "support@cloudscaling.com",
|
44
|
+
"Homepage" => "http://www.cloudscaling.com",
|
45
|
+
"Priority" => "extra",
|
46
|
+
"section" => "main",
|
47
|
+
"path_to_deb" => '/tmp/martin_1.2.3.4_amd64.deb'
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"Package" => "cs-chef",
|
51
|
+
"Version" => "1.2.3.4",
|
52
|
+
"Architecture" => "amd64",
|
53
|
+
"Maintainer" => "support@cloudscaling.com",
|
54
|
+
"Homepage" => "http://www.cloudscaling.com",
|
55
|
+
"Priority" => "extra",
|
56
|
+
"section" => "main",
|
57
|
+
"path_to_deb" => '/tmp/debs/cs-chef-0.9.1-1782-all.deb'
|
58
|
+
}
|
59
|
+
]
|
60
|
+
|
61
|
+
@package_release = FRM::PackageRelease.new(hashes)
|
62
|
+
@release_pusher = FRM::ReleasePusher.new(@package_release,'abcd','1234',\
|
63
|
+
'some-bucket','testing/tmp/martin/foo')
|
64
|
+
end
|
65
|
+
|
66
|
+
def test
|
67
|
+
puts "@release_pusher.inspect = #{@release_pusher.inspect}"
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
class TestPackageRelease < MiniTest::Unit::TestCase
|
73
|
+
def setup
|
74
|
+
@tempfile1 = File.open('/tmp/foo_1.2.68_amd64.deb','w+') { |f| f.write 'foo' }
|
75
|
+
@tempfile2 = File.open('/tmp/bar_1.2.3.4_amd64.deb','w+') { |f| f.write 'bar' }
|
76
|
+
|
77
|
+
hashes = [{
|
78
|
+
"Package" => "foo",
|
79
|
+
"Version" => "1.2.68",
|
80
|
+
"Architecture" => "amd64",
|
81
|
+
"Maintainer" => "support@cloudscaling.com",
|
82
|
+
"Homepage" => "http://www.cloudscaling.com",
|
83
|
+
"Priority" => "extra",
|
84
|
+
"Depends" => %w{one two three},
|
85
|
+
"section" => "main",
|
86
|
+
"path_to_deb" => '/tmp/foo_1.2.68_amd64.deb',
|
87
|
+
"Description" => 'some
|
88
|
+
multiline
|
89
|
+
description'
|
90
|
+
},
|
91
|
+
{
|
92
|
+
"Package" => "bar",
|
93
|
+
"Version" => "1.2.3.4",
|
94
|
+
"Architecture" => "amd64",
|
95
|
+
"Maintainer" => "support@cloudscaling.com",
|
96
|
+
"Homepage" => "http://www.cloudscaling.com",
|
97
|
+
"Priority" => "extra",
|
98
|
+
"Depends" => %w{one two three},
|
99
|
+
"section" => "main",
|
100
|
+
"path_to_deb" => '/tmp/bar_1.2.3.4_amd64.deb'
|
101
|
+
}
|
102
|
+
]
|
103
|
+
|
104
|
+
@package_release = FRM::PackageRelease.new(hashes)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test()
|
108
|
+
correct_output = "Package: foo
|
109
|
+
Version: 1.2.68
|
110
|
+
Architecture: amd64
|
111
|
+
Maintainer: <support@cloudscaling.com>
|
112
|
+
Standards-Version: 3.9.1
|
113
|
+
Homepage: http://www.cloudscaling.com
|
114
|
+
Priority: extra
|
115
|
+
Depends: one, two, three
|
116
|
+
Filename: pool/main/f/foo/foo_1.2.68_amd64.deb
|
117
|
+
Size: 3
|
118
|
+
MD5sum: acbd18db4cc2f85cedef654fccc4a4d8
|
119
|
+
SHA1: 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
120
|
+
SHA256: 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
|
121
|
+
Description: some
|
122
|
+
multiline
|
123
|
+
description
|
124
|
+
|
125
|
+
Package: bar
|
126
|
+
Version: 1.2.3.4
|
127
|
+
Architecture: amd64
|
128
|
+
Maintainer: <support@cloudscaling.com>
|
129
|
+
Standards-Version: 3.9.1
|
130
|
+
Homepage: http://www.cloudscaling.com
|
131
|
+
Priority: extra
|
132
|
+
Depends: one, two, three
|
133
|
+
Filename: pool/main/b/bar/bar_1.2.3.4_amd64.deb
|
134
|
+
Size: 3
|
135
|
+
MD5sum: 37b51d194a7513e45b56f6524f2d51f2
|
136
|
+
SHA1: 62cdb7020ff920e5aa642c3d4066950dd1f01f4d
|
137
|
+
SHA256: fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9
|
138
|
+
Description: no description given
|
139
|
+
|
140
|
+
"
|
141
|
+
assert @package_release.package_file == correct_output
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_generate_short_release_file
|
145
|
+
correct_short_release_file = "Component: main
|
146
|
+
Origin: apt.cloudscaling.com
|
147
|
+
Label: apt repository natty
|
148
|
+
Architecture: amd64
|
149
|
+
Description: Cloudscaling APT repository
|
150
|
+
"
|
151
|
+
assert @package_release.short_release_file == correct_short_release_file
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_generate_release
|
155
|
+
# skip 'need to finish generate_release function'
|
156
|
+
correct_release_file = "Origin: apt.cloudscaling.com
|
157
|
+
Label: apt repository natty
|
158
|
+
Codename: natty
|
159
|
+
Date: Thu, 22 Dec 2011 00:29:55 UTC
|
160
|
+
Architectures: amd64
|
161
|
+
Components: main universe multiverse
|
162
|
+
Description: Cloudscaling APT repository
|
163
|
+
MD5Sum:
|
164
|
+
32aed966f2f629d6229d14cd37da740e 896 main/binary-amd64/Packages
|
165
|
+
a2ea734a1d863873d0acd98845bd0573 438 main/binary-amd64/Packages.gz
|
166
|
+
79dd2fee35fba7255dcd40e1f6529591 134 main/binary-amd64/Release
|
167
|
+
SHA1:
|
168
|
+
b2f872140a4e651609c1ce7538dba871a4ad49de 896 main/binary-amd64/Packages
|
169
|
+
86b1fc7c8905cf35a9ff2544bb277c332e93b7d1 438 main/binary-amd64/Packages.gz
|
170
|
+
6d932af9af761f418e5374f73dcd09badb4fe57e 134 main/binary-amd64/Release
|
171
|
+
SHA256:
|
172
|
+
14139ad7300259e51e2c0d75891966d10f9382adbda61c7348990ccf125e4d4f 896 main/binary-amd64/Packages
|
173
|
+
67014ee7cc96108af726aae5636d26225c2cd833301765e44cf6cb6ea7719698 438 main/binary-amd64/Packages.gz
|
174
|
+
690b44df6fe65f40f260b73394e87804df78c9ccf13999889259faeed3eec40d 134 main/binary-amd64/Release
|
175
|
+
"
|
176
|
+
assert @package_release.release_file == correct_release_file
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
class TestPackage < MiniTest::Unit::TestCase
|
183
|
+
def setup
|
184
|
+
@tempfile1 = File.open('/tmp/foo','w+') { |f| f.write 'foo' }
|
185
|
+
@tempfile2 = File.open('/tmp/bar','w+') { |f| f.write 'bar' }
|
186
|
+
|
187
|
+
@hash = {
|
188
|
+
"Package" => "foo",
|
189
|
+
"Version" => "1.2.68",
|
190
|
+
"Architecture" => "amd64",
|
191
|
+
"Maintainer" => "support@cloudscaling.com",
|
192
|
+
"Homepage" => "http://www.cloudscaling.com",
|
193
|
+
"Priority" => "extra",
|
194
|
+
"Depends" => %w{one two three},
|
195
|
+
"section" => "main",
|
196
|
+
"path_to_deb" => '/tmp/foo',
|
197
|
+
"Description" => 'some
|
198
|
+
multiline
|
199
|
+
description'
|
200
|
+
}
|
201
|
+
|
202
|
+
@package1 = FRM::Package.new(@hash)
|
203
|
+
end
|
204
|
+
|
205
|
+
def test()
|
206
|
+
assert @package1.name == 'foo'
|
207
|
+
assert @package1.content == 'foo'
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_bad_file()
|
211
|
+
bad_hash = {
|
212
|
+
"Package" => "foo",
|
213
|
+
"Version" => "1.2.68",
|
214
|
+
"Architecture" => "amd64",
|
215
|
+
"Maintainer" => "support@cloudscaling.com",
|
216
|
+
"Homepage" => "http://www.cloudscaling.com",
|
217
|
+
"Priority" => "extra",
|
218
|
+
"Depends" => %w{one two three},
|
219
|
+
"section" => "main",
|
220
|
+
"path_to_deb" => '/some/bad/path',
|
221
|
+
"Description" => 'some
|
222
|
+
multiline
|
223
|
+
description'
|
224
|
+
}
|
225
|
+
assert_raises(RuntimeError) { FRM::Package.new(bad_hash) }
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_good_file()
|
229
|
+
assert @package1.content == 'foo'
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_hashes()
|
233
|
+
assert @package1.md5 == 'acbd18db4cc2f85cedef654fccc4a4d8'
|
234
|
+
assert @package1.sha1 == '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
|
235
|
+
assert @package1.sha2 == '2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
class TestDeb < MiniTest::Unit::TestCase
|
244
|
+
|
245
|
+
def setup
|
246
|
+
@deb = FRM::Deb.new()
|
247
|
+
@tempfile1 = File.open('/tmp/foo_1.2.68_amd64.deb','w+') { |f| f.write 'foo' }
|
248
|
+
@tempfile2 = File.open('/tmp/bar_1.2.3.4_amd64.deb','w+') { |f| f.write 'bar' }
|
249
|
+
|
250
|
+
@hash = [
|
251
|
+
{
|
252
|
+
"Package" => "foo",
|
253
|
+
"Version" => "1.2.68",
|
254
|
+
"Architecture" => "amd64",
|
255
|
+
"Maintainer" => "support@cloudscaling.com",
|
256
|
+
"Homepage" => "http://www.cloudscaling.com",
|
257
|
+
"Priority" => "extra",
|
258
|
+
"Depends" => %w{one two three},
|
259
|
+
"section" => "main",
|
260
|
+
"path_to_deb" => '/tmp/foo_1.2.68_amd64.deb',
|
261
|
+
"Description" => 'some
|
262
|
+
multiline
|
263
|
+
description'
|
264
|
+
},
|
265
|
+
{
|
266
|
+
"Package" => "bar",
|
267
|
+
"Version" => "1.2.3.4",
|
268
|
+
"Architecture" => "amd64",
|
269
|
+
"Maintainer" => "support@cloudscaling.com",
|
270
|
+
"Homepage" => "http://www.cloudscaling.com",
|
271
|
+
"Priority" => "extra",
|
272
|
+
"Depends" => %w{one two three},
|
273
|
+
"section" => "main",
|
274
|
+
"path_to_deb" => '/tmp/bar_1.2.3.4_amd64.deb'
|
275
|
+
}
|
276
|
+
]
|
277
|
+
end
|
278
|
+
|
279
|
+
def teardown
|
280
|
+
File.delete '/tmp/foo_1.2.68_amd64.deb' if File.exists? '/tmp/foo_1.2.68_amd64.deb'
|
281
|
+
File.delete '/tmp/bar_1.2.3.4_amd64.deb' if File.exists? '/tmp/bar_1.2.3.4_amd64.deb'
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
def test_generate_package_stub
|
286
|
+
correct_output = "Package: foo
|
287
|
+
Version: 1.2.68
|
288
|
+
Architecture: amd64
|
289
|
+
Maintainer: <support@cloudscaling.com>
|
290
|
+
Homepage: http://www.cloudscaling.com
|
291
|
+
Priority: extra
|
292
|
+
Depends: one, two, three
|
293
|
+
Filename: pool/main/f/foo/foo_1.2.68_amd64.deb
|
294
|
+
Size: 3
|
295
|
+
MD5sum: acbd18db4cc2f85cedef654fccc4a4d8
|
296
|
+
SHA1: 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
297
|
+
SHA256: 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
|
298
|
+
Description: some
|
299
|
+
multiline
|
300
|
+
description
|
301
|
+
|
302
|
+
"
|
303
|
+
|
304
|
+
duplicate_hash = @hash[0].dup
|
305
|
+
assert @deb.generate_package_stub(duplicate_hash) == correct_output
|
306
|
+
assert @hash[0] == duplicate_hash
|
307
|
+
end
|
308
|
+
|
309
|
+
|
310
|
+
def test_generate_package_file
|
311
|
+
correct_output = "Package: foo
|
312
|
+
Version: 1.2.68
|
313
|
+
Architecture: amd64
|
314
|
+
Maintainer: <support@cloudscaling.com>
|
315
|
+
Homepage: http://www.cloudscaling.com
|
316
|
+
Priority: extra
|
317
|
+
Depends: one, two, three
|
318
|
+
Filename: pool/main/f/foo/foo_1.2.68_amd64.deb
|
319
|
+
Size: 3
|
320
|
+
MD5sum: acbd18db4cc2f85cedef654fccc4a4d8
|
321
|
+
SHA1: 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
322
|
+
SHA256: 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
|
323
|
+
Description: some
|
324
|
+
multiline
|
325
|
+
description
|
326
|
+
|
327
|
+
Package: bar
|
328
|
+
Version: 1.2.3.4
|
329
|
+
Architecture: amd64
|
330
|
+
Maintainer: <support@cloudscaling.com>
|
331
|
+
Homepage: http://www.cloudscaling.com
|
332
|
+
Priority: extra
|
333
|
+
Depends: one, two, three
|
334
|
+
Filename: pool/main/b/bar/bar_1.2.3.4_amd64.deb
|
335
|
+
Size: 3
|
336
|
+
MD5sum: 37b51d194a7513e45b56f6524f2d51f2
|
337
|
+
SHA1: 62cdb7020ff920e5aa642c3d4066950dd1f01f4d
|
338
|
+
SHA256: fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9
|
339
|
+
Description: no description given
|
340
|
+
|
341
|
+
"
|
342
|
+
assert @deb.generate_package_file(@hash) == correct_output
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_gzip
|
346
|
+
input = generate_random_string
|
347
|
+
gziped_pipe = @deb.generate_gzip_pipe(input)
|
348
|
+
output = @deb.gunzip_pipe gziped_pipe
|
349
|
+
assert input == output
|
350
|
+
end
|
351
|
+
|
352
|
+
|
353
|
+
def test_md5
|
354
|
+
input = 'foo'
|
355
|
+
assert @deb.compute_md5(input) == 'acbd18db4cc2f85cedef654fccc4a4d8'
|
356
|
+
end
|
357
|
+
|
358
|
+
def test_sha1
|
359
|
+
input = 'foo'
|
360
|
+
assert @deb.compute_sha1(input) == '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_sha256
|
364
|
+
input = 'foo'
|
365
|
+
assert @deb.compute_sha2(input) == '2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'
|
366
|
+
end
|
367
|
+
|
368
|
+
def test_generate_package_release
|
369
|
+
package_release_file = "Component: main
|
370
|
+
Origin: apt.cloudscaling.com
|
371
|
+
Label: apt repository natty
|
372
|
+
Architecture: amd64
|
373
|
+
Description: Cloudscaling APT repository
|
374
|
+
"
|
375
|
+
assert @deb.generate_package_release == package_release_file
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_generate_release
|
379
|
+
skip 'need to finish generate_release function'
|
380
|
+
release_file = "Origin: apt.cloudscaling.com
|
381
|
+
Label: apt repository natty
|
382
|
+
Codename: natty
|
383
|
+
Date: Thu, 22 Dec 2011 00:29:55 UTC
|
384
|
+
Architectures: amd64
|
385
|
+
;Components: main universe multiverse
|
386
|
+
Description: Cloudscaling APT repository
|
387
|
+
MD5Sum:
|
388
|
+
a4b943ff89790ccdc186875dad67827b 5813 main/binary-amd64/Packages
|
389
|
+
004fd3f868ebbe7501fb2e1c0c54e2a7 2148 main/binary-amd64/Packages.gz
|
390
|
+
79dd2fee35fba7255dcd40e1f6529591 134 main/binary-amd64/Release
|
391
|
+
SHA1:
|
392
|
+
6e03924030eab56cb9735a52ec710537e682bcfc 5813 main/binary-amd64/Packages
|
393
|
+
5f2989bae96e148cb5f18accc4357305926ab1e1 2148 main/binary-amd64/Packages.gz
|
394
|
+
6d932af9af761f418e5374f73dcd09badb4fe57e 134 main/binary-amd64/Release
|
395
|
+
SHA256:
|
396
|
+
dd8283f06beb4a5fc06ac62d3ae098e5ba2717daef2a15b5f3e9233eb64e0227 5813 main/binary-amd64/Packages
|
397
|
+
b197c5a3c1fe6a6d286e9f066a0cade289e3a2fc485c90407179951634788aa8 2148 main/binary-amd64/Packages.gz
|
398
|
+
690b44df6fe65f40f260b73394e87804df78c9ccf13999889259faeed3eec40d 134 main/binary-amd64/Release
|
399
|
+
"
|
400
|
+
assert @deb.generate_release == release_file
|
401
|
+
end
|
402
|
+
|
403
|
+
def generate_random_string
|
404
|
+
rand(36**rand(50)).to_s(36)
|
405
|
+
end
|
406
|
+
|
407
|
+
def test_parse_package_stub
|
408
|
+
input_stub = "Package: foo
|
409
|
+
Version: 1.2.68
|
410
|
+
Architecture: amd64
|
411
|
+
Maintainer: <support@cloudscaling.com>
|
412
|
+
Homepage: http://www.cloudscaling.com
|
413
|
+
Priority: extra
|
414
|
+
Depends: one, two, three
|
415
|
+
Filename: pool/main/f/foo/foo_1.2.68_amd64.deb
|
416
|
+
Size: 3
|
417
|
+
MD5sum: acbd18db4cc2f85cedef654fccc4a4d8
|
418
|
+
SHA1: 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
419
|
+
SHA256: 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
|
420
|
+
Description: some
|
421
|
+
multiline
|
422
|
+
description
|
423
|
+
|
424
|
+
Package: bar
|
425
|
+
Version: 1.2.3.4
|
426
|
+
Architecture: amd64
|
427
|
+
Maintainer: <support@cloudscaling.com>
|
428
|
+
Homepage: http://www.cloudscaling.com
|
429
|
+
Priority: extra
|
430
|
+
Depends: one, two, three
|
431
|
+
Filename: pool/main/b/bar/bar_1.2.3.4_amd64.deb
|
432
|
+
Size: 3
|
433
|
+
MD5sum: 37b51d194a7513e45b56f6524f2d51f2
|
434
|
+
SHA1: 62cdb7020ff920e5aa642c3d4066950dd1f01f4d
|
435
|
+
SHA256: fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9
|
436
|
+
Description: no description given
|
437
|
+
|
438
|
+
"
|
439
|
+
correct_hash = {"Package"=>"foo", "Version"=>"1.2.68", "Architecture"=>"amd64", "Maintainer"=>"<support@cloudscaling.com>", "Homepage"=>"http://www.cloudscaling.com", "Priority"=>"extra", "Depends"=>"one, two, three", "Filename"=>"pool/main/f/foo/foo_1.2.68_amd64.deb", "Size"=>"3", "MD5sum"=>"acbd18db4cc2f85cedef654fccc4a4d8", "SHA1"=>"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33", "SHA256"=>"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", "Description"=>"some multiline\n description"}
|
440
|
+
read_buffer, write_buffer = IO.pipe
|
441
|
+
write_buffer.write input_stub
|
442
|
+
write_buffer.close
|
443
|
+
assert @deb.parse_package_stub(read_buffer.dup)[0] == correct_hash
|
444
|
+
assert_raises(RuntimeError) { @deb.parse_package_stub File.open('/tmp/foo') }
|
445
|
+
end
|
446
|
+
|
447
|
+
|
448
|
+
def test_merge_package_file
|
449
|
+
package_file = File.open 'Packages.txt'
|
450
|
+
read_buffer, write_buffer = IO.pipe
|
451
|
+
|
452
|
+
@deb.merge_package_file(package_file,write_buffer,@hash)
|
453
|
+
|
454
|
+
end
|
455
|
+
|
456
|
+
|
457
|
+
end
|
data/test/deb_test2.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
my_dir = File.dirname __FILE__
|
6
|
+
require File.join my_dir, 'deb'
|
7
|
+
|
8
|
+
class TestReleasePusher < MiniTest::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
@tempfile1 = File.open('/tmp/foo_1.2.68_amd64.deb','w+') { |f| f.write 'foo' }
|
11
|
+
@tempfile2 = File.open('/tmp/bar_1.2.3.4_amd64.deb','w+') { |f| f.write 'bar' }
|
12
|
+
@tempfile3 = File.open('/tmp/martin_1.2.3.4_amd64.deb','w+') { |f| f.write 'martin' }
|
13
|
+
|
14
|
+
hashes = %w{
|
15
|
+
/home/martin/sheep/modules/substratum/debs/pod-services-0.5.0-967-amd64.deb
|
16
|
+
/home/martin/sheep/modules/substratum/debs/cs-chef-0.9.1-1782-all.deb
|
17
|
+
/home/martin/sheep/modules/substratum/debs/ruby1.9.2-1-amd64.deb
|
18
|
+
}
|
19
|
+
|
20
|
+
|
21
|
+
@package_release = FRM::PackageRelease.new(hashes)
|
22
|
+
@release_pusher = FRM::ReleasePusher.new(@package_release,'1234','abcd',\
|
23
|
+
'some-bucket','testing/tmp/frm')
|
24
|
+
end
|
25
|
+
|
26
|
+
def test
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
data/test/s3.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
my_dir = File.dirname __FILE__
|
5
|
+
require File.join my_dir, 's3'
|
6
|
+
|
7
|
+
|
8
|
+
# this is a stupid hack to get the @@bucket region set properly
|
9
|
+
DEFAULT_HOST = 's3-us-west-1.amazonaws.com'
|
10
|
+
|
11
|
+
class TestFRM < MiniTest::Unit::TestCase
|
12
|
+
|
13
|
+
# these credentials only have access inside of cloudscaling-us-west-develop/testing/
|
14
|
+
@@access_key_id = 'abcd'
|
15
|
+
@@secret_key_id = '1234'
|
16
|
+
@@bucket = 'some-bucket'
|
17
|
+
@@prefix = 'testing/tmp/' + Time.now.strftime("%Y/%m/%d/%H:%M:%S ")
|
18
|
+
@@server = 's3-us-west-1.amazonaws.com'
|
19
|
+
@@timestamp = rand(9999).to_s
|
20
|
+
|
21
|
+
|
22
|
+
@@key = @@prefix + "testing-" + @@timestamp.to_s
|
23
|
+
@@value = "rand: " + @@timestamp
|
24
|
+
|
25
|
+
# we need minitest to run in order
|
26
|
+
def self.test_order
|
27
|
+
:alpha
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup
|
31
|
+
@frm = FRM::S3.new(@@access_key_id,@@secret_key_id,@@server)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_aput
|
35
|
+
assert @frm.put @@key,@@value,@@bucket
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_bkey?
|
39
|
+
assert @frm.key? @@key,@@bucket
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_cget
|
43
|
+
assert_equal @@value, @frm.get(@@key,@@bucket)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_ddelete
|
47
|
+
assert @frm.delete @@key, @@bucket
|
48
|
+
end
|
49
|
+
|
50
|
+
# this is broken :(
|
51
|
+
def test_ekey?
|
52
|
+
skip 'need to debug key?'
|
53
|
+
refute @frm.key?(@@key,@@bucket)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Martin Rhoads
|
@@ -21,8 +21,8 @@ dependencies: []
|
|
21
21
|
description: FRM makes it easy to build package repositories on S3
|
22
22
|
email:
|
23
23
|
- ermal14@gmail.com
|
24
|
-
executables:
|
25
|
-
|
24
|
+
executables:
|
25
|
+
- fpm
|
26
26
|
extensions: []
|
27
27
|
|
28
28
|
extra_rdoc_files: []
|
@@ -30,11 +30,17 @@ extra_rdoc_files: []
|
|
30
30
|
files:
|
31
31
|
- .gitignore
|
32
32
|
- Gemfile
|
33
|
+
- LICENSE
|
33
34
|
- Rakefile
|
35
|
+
- bin/fpm
|
34
36
|
- frm.gemspec
|
35
|
-
- frm/.gitignore
|
36
37
|
- lib/frm.rb
|
38
|
+
- lib/frm/deb.rb
|
39
|
+
- lib/frm/s3.rb
|
37
40
|
- lib/frm/version.rb
|
41
|
+
- test/deb_test.rb
|
42
|
+
- test/deb_test2.rb
|
43
|
+
- test/s3.rb
|
38
44
|
has_rdoc: true
|
39
45
|
homepage: https://github.com/ermal14/frm
|
40
46
|
licenses: []
|
@@ -67,5 +73,7 @@ rubygems_version: 1.3.7
|
|
67
73
|
signing_key:
|
68
74
|
specification_version: 3
|
69
75
|
summary: Effin Repo Manager
|
70
|
-
test_files:
|
71
|
-
|
76
|
+
test_files:
|
77
|
+
- test/deb_test.rb
|
78
|
+
- test/deb_test2.rb
|
79
|
+
- test/s3.rb
|
data/frm/.gitignore
DELETED