deb-s3 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -6
- data/lib/deb/s3.rb +2 -1
- data/lib/deb/s3/cli.rb +236 -31
- data/lib/deb/s3/manifest.rb +15 -10
- data/lib/deb/s3/package.rb +65 -56
- data/lib/deb/s3/release.rb +17 -5
- data/lib/deb/s3/templates/package.erb +15 -9
- data/lib/deb/s3/templates/release.erb +4 -0
- data/lib/deb/s3/utils.rb +14 -3
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c95a36618dfc6b8a2853b54c17101ae09140b3c
|
4
|
+
data.tar.gz: 5e14dda3916cd69e1e4eb3e5e26dd78b0f5cd94e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa1ce1124db8ca4a388e7a8141c88ccf6b262fe5d0f3f91a124e4311a255008b7f3b2c50c167154bbbeb31d614c380d22da02f0b8f7a9d8708ef968144795e38
|
7
|
+
data.tar.gz: c99fbb92d14f98a643b3f21d337aef9c6f773b98385eca3db3584480dd1369af2fff7c0fb93128f7ef624a488b9b50d37439176fd72697e4b8f14e53ed6a9f49
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ With `deb-s3`, there is no need for this. `deb-s3` features:
|
|
22
22
|
* Updates it with the new package, replacing the existing entry if already
|
23
23
|
there or adding a new one if not.
|
24
24
|
* Uploads the package itself, the Packages manifest, and the Packages.gz
|
25
|
-
manifest.
|
25
|
+
manifest. It will skip the uploading if the package is already there.
|
26
26
|
* Updates the Release file with the new hashes and file sizes.
|
27
27
|
|
28
28
|
## Getting Started
|
@@ -124,8 +124,3 @@ Options:
|
|
124
124
|
Verifies that the files in the package manifests exist
|
125
125
|
```
|
126
126
|
|
127
|
-
## TODO
|
128
|
-
|
129
|
-
This is still experimental. These are several things to be done:
|
130
|
-
|
131
|
-
* Don't re-upload a package if it already exists and has the same hashes.
|
data/lib/deb/s3.rb
CHANGED
data/lib/deb/s3/cli.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
require "aws"
|
2
3
|
require "thor"
|
3
4
|
|
@@ -20,6 +21,15 @@ class Deb::S3::CLI < Thor
|
|
20
21
|
:type => :string,
|
21
22
|
:desc => "The path prefix to use when storing on S3."
|
22
23
|
|
24
|
+
class_option :origin,
|
25
|
+
:type => :string,
|
26
|
+
:aliases => "-o",
|
27
|
+
:desc => "The origin to use in the repository Release file."
|
28
|
+
|
29
|
+
class_option :suite,
|
30
|
+
:type => :string,
|
31
|
+
:desc => "The suite to use in the repository Release file."
|
32
|
+
|
23
33
|
class_option :codename,
|
24
34
|
:default => "stable",
|
25
35
|
:type => :string,
|
@@ -77,6 +87,22 @@ class Deb::S3::CLI < Thor
|
|
77
87
|
:type => :string,
|
78
88
|
:desc => "Additional command line options to pass to GPG when signing"
|
79
89
|
|
90
|
+
class_option :encryption,
|
91
|
+
:default => false,
|
92
|
+
:type => :boolean,
|
93
|
+
:aliases => "-e",
|
94
|
+
:desc => "Use S3 server side encryption"
|
95
|
+
|
96
|
+
class_option :quiet,
|
97
|
+
:type => :boolean,
|
98
|
+
:aliases => "-q",
|
99
|
+
:desc => "Doesn't output information, just returns status appropriately."
|
100
|
+
|
101
|
+
class_option :cache_control,
|
102
|
+
:type => :string,
|
103
|
+
:aliases => "-C",
|
104
|
+
:desc => "Add cache-control headers to S3 objects"
|
105
|
+
|
80
106
|
desc "upload FILES",
|
81
107
|
"Uploads the given files to a S3 bucket as an APT repository."
|
82
108
|
|
@@ -93,12 +119,6 @@ class Deb::S3::CLI < Thor
|
|
93
119
|
"in the repository when uploading one."
|
94
120
|
|
95
121
|
def upload(*files)
|
96
|
-
component = options[:component]
|
97
|
-
if options[:section]
|
98
|
-
component = options[:section]
|
99
|
-
warn("===> WARNING: The --section/-s argument is deprecated, please use --component/-m.")
|
100
|
-
end
|
101
|
-
|
102
122
|
if files.nil? || files.empty?
|
103
123
|
error("You must specify at least one file to upload")
|
104
124
|
end
|
@@ -113,8 +133,13 @@ class Deb::S3::CLI < Thor
|
|
113
133
|
|
114
134
|
# retrieve the existing manifests
|
115
135
|
log("Retrieving existing manifests")
|
116
|
-
release = Deb::S3::Release.retrieve(options[:codename])
|
136
|
+
release = Deb::S3::Release.retrieve(options[:codename], options[:origin], options[:suite], options[:cache_control])
|
117
137
|
manifests = {}
|
138
|
+
release.architectures.each do |arch|
|
139
|
+
manifests[arch] = Deb::S3::Manifest.retrieve(options[:codename], component, arch, options[:cache_control])
|
140
|
+
end
|
141
|
+
|
142
|
+
packages_arch_all = []
|
118
143
|
|
119
144
|
# examine all the files
|
120
145
|
files.collect { |f| Dir.glob(f) }.flatten.each do |file|
|
@@ -126,13 +151,36 @@ class Deb::S3::CLI < Thor
|
|
126
151
|
|
127
152
|
# validate we have them
|
128
153
|
error("No architcture given and unable to determine one for #{file}. " +
|
129
|
-
"Please specify one with --arch [i386
|
154
|
+
"Please specify one with --arch [i386|amd64].") unless arch
|
155
|
+
|
156
|
+
# If the arch is all and the list of existing manifests is none, then
|
157
|
+
# throw an error. This is mainly the case when initializing a brand new
|
158
|
+
# repository. With "all", we won't know which architectures they're using.
|
159
|
+
if arch == "all" && manifests.count == 0
|
160
|
+
error("Package #{File.basename(file)} had architecture \"all\", " +
|
161
|
+
"however noexisting package lists exist. This can often happen " +
|
162
|
+
"if the first package you are add to a new repository is an " +
|
163
|
+
"\"all\" architecture file. Please use --arch [i386|amd64] or " +
|
164
|
+
"another platform type to upload the file.")
|
165
|
+
end
|
130
166
|
|
131
167
|
# retrieve the manifest for the arch if we don't have it already
|
132
|
-
manifests[arch] ||= Deb::S3::Manifest.retrieve(options[:codename], component, arch)
|
168
|
+
manifests[arch] ||= Deb::S3::Manifest.retrieve(options[:codename], component, arch, options[:cache_control])
|
133
169
|
|
134
|
-
# add in
|
170
|
+
# add package in manifests
|
135
171
|
manifests[arch].add(pkg, options[:preserve_versions])
|
172
|
+
|
173
|
+
# If arch is all, we must add this package in all arch available
|
174
|
+
if arch == 'all'
|
175
|
+
packages_arch_all << pkg
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
manifests.each do |arch, manifest|
|
180
|
+
next if arch == 'all'
|
181
|
+
packages_arch_all.each do |pkg|
|
182
|
+
manifest.add(pkg, options[:preserve_versions], false)
|
183
|
+
end
|
136
184
|
end
|
137
185
|
|
138
186
|
# upload the manifest
|
@@ -146,6 +194,158 @@ class Deb::S3::CLI < Thor
|
|
146
194
|
log("Update complete.")
|
147
195
|
end
|
148
196
|
|
197
|
+
desc "list", "Lists packages in given codename, component, and optionally architecture"
|
198
|
+
|
199
|
+
option :long,
|
200
|
+
:type => :boolean,
|
201
|
+
:aliases => '-l',
|
202
|
+
:desc => "Shows all package information in original format",
|
203
|
+
:default => false
|
204
|
+
|
205
|
+
option :arch,
|
206
|
+
:type => :string,
|
207
|
+
:aliases => "-a",
|
208
|
+
:desc => "The architecture of the package in the APT repository."
|
209
|
+
|
210
|
+
def list
|
211
|
+
configure_s3_client
|
212
|
+
|
213
|
+
release = Deb::S3::Release.retrieve(options[:codename])
|
214
|
+
archs = release.architectures
|
215
|
+
archs &= [options[:arch]] if options[:arch] && options[:arch] != "all"
|
216
|
+
widths = [0, 0]
|
217
|
+
rows = archs.map { |arch|
|
218
|
+
manifest = Deb::S3::Manifest.retrieve(options[:codename], component,
|
219
|
+
arch, options[:cache_control])
|
220
|
+
manifest.packages.map do |package|
|
221
|
+
if options[:long]
|
222
|
+
package.generate
|
223
|
+
else
|
224
|
+
[package.name, package.full_version, package.architecture].tap do |row|
|
225
|
+
row.each_with_index do |col, i|
|
226
|
+
widths[i] = [widths[i], col.size].max if widths[i]
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
}.flatten(1)
|
232
|
+
|
233
|
+
if options[:long]
|
234
|
+
$stdout.puts rows.join("\n")
|
235
|
+
else
|
236
|
+
rows.each do |row|
|
237
|
+
$stdout.puts "% -#{widths[0]}s % -#{widths[1]}s %s" % row
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
desc "show PACKAGE VERSION ARCH", "Shows information about a package."
|
243
|
+
|
244
|
+
def show(package_name, version, arch)
|
245
|
+
if version.nil?
|
246
|
+
error "You must specify the name of the package to show."
|
247
|
+
end
|
248
|
+
if version.nil?
|
249
|
+
error "You must specify the version of the package to show."
|
250
|
+
end
|
251
|
+
if arch.nil?
|
252
|
+
error "You must specify the architecture of the package to show."
|
253
|
+
end
|
254
|
+
|
255
|
+
configure_s3_client
|
256
|
+
|
257
|
+
# retrieve the existing manifests
|
258
|
+
manifest = Deb::S3::Manifest.retrieve(options[:codename], component, arch,
|
259
|
+
options[:cache_control])
|
260
|
+
package = manifest.packages.detect { |p|
|
261
|
+
p.name == package_name && p.full_version == version
|
262
|
+
}
|
263
|
+
if package.nil?
|
264
|
+
error "No such package found."
|
265
|
+
end
|
266
|
+
|
267
|
+
puts package.generate
|
268
|
+
end
|
269
|
+
|
270
|
+
desc "copy PACKAGE TO_CODENAME TO_COMPONENT ",
|
271
|
+
"Copy the package named PACKAGE to given codename and component. If --versions is not specified, copy all versions of PACKAGE. Otherwise, only the specified versions will be copied. Source codename and component is given by --codename and --component options."
|
272
|
+
|
273
|
+
option :cache_control,
|
274
|
+
:type => :string,
|
275
|
+
:aliases => "-C",
|
276
|
+
:desc => "Add cache-control headers to S3 objects"
|
277
|
+
|
278
|
+
option :arch,
|
279
|
+
:type => :string,
|
280
|
+
:aliases => "-a",
|
281
|
+
:desc => "The architecture of the package in the APT repository."
|
282
|
+
|
283
|
+
option :versions,
|
284
|
+
:default => nil,
|
285
|
+
:type => :array,
|
286
|
+
:desc => "The space-delimited versions of PACKAGE to delete. If not" +
|
287
|
+
"specified, ALL VERSIONS will be deleted. Fair warning." +
|
288
|
+
"E.g. --versions \"0.1 0.2 0.3\""
|
289
|
+
|
290
|
+
option :preserve_versions,
|
291
|
+
:default => false,
|
292
|
+
:type => :boolean,
|
293
|
+
:aliases => "-p",
|
294
|
+
:desc => "Whether to preserve other versions of a package " +
|
295
|
+
"in the repository when uploading one."
|
296
|
+
|
297
|
+
def copy(package_name, to_codename, to_component)
|
298
|
+
if package_name.nil?
|
299
|
+
error "You must specify a package name."
|
300
|
+
end
|
301
|
+
if to_codename.nil?
|
302
|
+
error "You must specify a codename to copy to."
|
303
|
+
end
|
304
|
+
if to_component.nil?
|
305
|
+
error "You must specify a component to copy to."
|
306
|
+
end
|
307
|
+
|
308
|
+
arch = options[:arch]
|
309
|
+
if arch.nil?
|
310
|
+
error "You must specify the architecture of the package to copy."
|
311
|
+
end
|
312
|
+
|
313
|
+
versions = options[:versions]
|
314
|
+
if versions.nil?
|
315
|
+
warn "===> WARNING: Copying all versions of #{package_name}"
|
316
|
+
else
|
317
|
+
log "Versions to copy: #{versions.join(', ')}"
|
318
|
+
end
|
319
|
+
|
320
|
+
configure_s3_client
|
321
|
+
|
322
|
+
# retrieve the existing manifests
|
323
|
+
log "Retrieving existing manifests"
|
324
|
+
from_manifest = Deb::S3::Manifest.retrieve(options[:codename],
|
325
|
+
component, arch,
|
326
|
+
options[:cache_control])
|
327
|
+
to_release = Deb::S3::Release.retrieve(to_codename)
|
328
|
+
to_manifest = Deb::S3::Manifest.retrieve(to_codename, to_component, arch,
|
329
|
+
options[:cache_control])
|
330
|
+
packages = from_manifest.packages.select { |p|
|
331
|
+
p.name == package_name &&
|
332
|
+
(versions.nil? || versions.include?(p.full_version))
|
333
|
+
}
|
334
|
+
if packages.size == 0
|
335
|
+
error "No packages found in repository."
|
336
|
+
end
|
337
|
+
|
338
|
+
packages.each do |package|
|
339
|
+
to_manifest.add package, options[:preserve_versions], false
|
340
|
+
end
|
341
|
+
|
342
|
+
to_manifest.write_to_s3 { |f| sublog("Transferring #{f}") }
|
343
|
+
to_release.update_manifest(to_manifest)
|
344
|
+
to_release.write_to_s3 { |f| sublog("Transferring #{f}") }
|
345
|
+
|
346
|
+
log "Copy complete."
|
347
|
+
end
|
348
|
+
|
149
349
|
desc "delete PACKAGE",
|
150
350
|
"Remove the package named PACKAGE. If --versions is not specified, delete" +
|
151
351
|
"all versions of PACKAGE. Otherwise, only the specified versions will be " +
|
@@ -164,12 +364,6 @@ class Deb::S3::CLI < Thor
|
|
164
364
|
"E.g. --versions \"0.1 0.2 0.3\""
|
165
365
|
|
166
366
|
def delete(package)
|
167
|
-
component = options[:component]
|
168
|
-
if options[:section]
|
169
|
-
component = options[:section]
|
170
|
-
warn("===> WARNING: The --section/-s argument is deprecated, please use --component/-m.")
|
171
|
-
end
|
172
|
-
|
173
367
|
if package.nil?
|
174
368
|
error("You must specify a package name.")
|
175
369
|
end
|
@@ -190,8 +384,8 @@ class Deb::S3::CLI < Thor
|
|
190
384
|
|
191
385
|
# retrieve the existing manifests
|
192
386
|
log("Retrieving existing manifests")
|
193
|
-
release = Deb::S3::Release.retrieve(options[:codename])
|
194
|
-
manifest = Deb::S3::Manifest.retrieve(options[:codename], component, options[:arch])
|
387
|
+
release = Deb::S3::Release.retrieve(options[:codename], options[:origin], options[:suite])
|
388
|
+
manifest = Deb::S3::Manifest.retrieve(options[:codename], component, options[:arch], options[:cache_control])
|
195
389
|
|
196
390
|
deleted = manifest.delete_package(package, versions)
|
197
391
|
if deleted.length == 0
|
@@ -224,20 +418,15 @@ class Deb::S3::CLI < Thor
|
|
224
418
|
:desc => "Whether to fix problems in manifests when verifying."
|
225
419
|
|
226
420
|
def verify
|
227
|
-
component = options[:component]
|
228
|
-
if options[:section]
|
229
|
-
component = options[:section]
|
230
|
-
warn("===> WARNING: The --section/-s argument is deprecated, please use --component/-m.")
|
231
|
-
end
|
232
|
-
|
233
421
|
configure_s3_client
|
234
422
|
|
235
423
|
log("Retrieving existing manifests")
|
236
|
-
release = Deb::S3::Release.retrieve(options[:codename])
|
424
|
+
release = Deb::S3::Release.retrieve(options[:codename], options[:origin], options[:suite])
|
237
425
|
|
238
|
-
|
426
|
+
release.architectures.each do |arch|
|
239
427
|
log("Checking for missing packages in: #{options[:codename]}/#{options[:component]} #{arch}")
|
240
|
-
manifest = Deb::S3::Manifest.retrieve(options[:codename], component,
|
428
|
+
manifest = Deb::S3::Manifest.retrieve(options[:codename], component,
|
429
|
+
arch, options[:cache_control])
|
241
430
|
missing_packages = []
|
242
431
|
|
243
432
|
manifest.packages.each do |p|
|
@@ -250,7 +439,7 @@ class Deb::S3::CLI < Thor
|
|
250
439
|
end
|
251
440
|
end
|
252
441
|
|
253
|
-
if options[:fix_manifests] && !missing_packages.empty?
|
442
|
+
if options[:sign] || (options[:fix_manifests] && !missing_packages.empty?)
|
254
443
|
log("Removing #{missing_packages.length} package(s) from the manifest...")
|
255
444
|
missing_packages.each { |p| manifest.packages.delete(p) }
|
256
445
|
manifest.write_to_s3 { |f| sublog("Transferring #{f}") }
|
@@ -264,16 +453,31 @@ class Deb::S3::CLI < Thor
|
|
264
453
|
|
265
454
|
private
|
266
455
|
|
456
|
+
def component
|
457
|
+
return @component if @component
|
458
|
+
@component = if (section = options[:section])
|
459
|
+
warn("===> WARNING: The --section/-s argument is " \
|
460
|
+
"deprecated, please use --component/-m.")
|
461
|
+
section
|
462
|
+
else
|
463
|
+
options[:component]
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
def puts(*args)
|
468
|
+
$stdout.puts(*args) unless options[:quiet]
|
469
|
+
end
|
470
|
+
|
267
471
|
def log(message)
|
268
|
-
puts ">> #{message}"
|
472
|
+
puts ">> #{message}" unless options[:quiet]
|
269
473
|
end
|
270
474
|
|
271
475
|
def sublog(message)
|
272
|
-
puts " -- #{message}"
|
476
|
+
puts " -- #{message}" unless options[:quiet]
|
273
477
|
end
|
274
478
|
|
275
479
|
def error(message)
|
276
|
-
puts "!! #{message}"
|
480
|
+
$stderr.puts "!! #{message}" unless options[:quiet]
|
277
481
|
exit 1
|
278
482
|
end
|
279
483
|
|
@@ -307,6 +511,7 @@ class Deb::S3::CLI < Thor
|
|
307
511
|
Deb::S3::Utils.signing_key = options[:sign]
|
308
512
|
Deb::S3::Utils.gpg_options = options[:gpg_options]
|
309
513
|
Deb::S3::Utils.prefix = options[:prefix]
|
514
|
+
Deb::S3::Utils.encryption = options[:encryption]
|
310
515
|
|
311
516
|
# make sure we have a valid visibility setting
|
312
517
|
Deb::S3::Utils.access_policy =
|
data/lib/deb/s3/manifest.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
require "tempfile"
|
2
3
|
require "zlib"
|
3
4
|
require 'deb/s3/utils'
|
@@ -8,21 +9,25 @@ class Deb::S3::Manifest
|
|
8
9
|
|
9
10
|
attr_accessor :codename
|
10
11
|
attr_accessor :component
|
12
|
+
attr_accessor :cache_control
|
11
13
|
attr_accessor :architecture
|
12
14
|
|
13
15
|
attr_accessor :files
|
14
16
|
|
15
17
|
attr_reader :packages
|
18
|
+
attr_reader :packages_to_be_upload
|
16
19
|
|
17
20
|
def initialize
|
18
21
|
@packages = []
|
22
|
+
@packages_to_be_upload = []
|
19
23
|
@component = nil
|
20
24
|
@architecture = nil
|
21
25
|
@files = {}
|
26
|
+
@cache_control = ""
|
22
27
|
end
|
23
28
|
|
24
29
|
class << self
|
25
|
-
def retrieve(codename, component, architecture)
|
30
|
+
def retrieve(codename, component, architecture, cache_control)
|
26
31
|
m = if s = Deb::S3::Utils.s3_read("dists/#{codename}/#{component}/binary-#{architecture}/Packages")
|
27
32
|
self.parse_packages(s)
|
28
33
|
else
|
@@ -32,6 +37,7 @@ class Deb::S3::Manifest
|
|
32
37
|
m.codename = codename
|
33
38
|
m.component = component
|
34
39
|
m.architecture = architecture
|
40
|
+
m.cache_control = cache_control
|
35
41
|
m
|
36
42
|
end
|
37
43
|
|
@@ -45,13 +51,14 @@ class Deb::S3::Manifest
|
|
45
51
|
end
|
46
52
|
end
|
47
53
|
|
48
|
-
def add(pkg, preserve_versions)
|
54
|
+
def add(pkg, preserve_versions, needs_uploading=true)
|
49
55
|
if preserve_versions
|
50
56
|
packages.delete_if { |p| p.name == pkg.name && p.full_version == pkg.full_version }
|
51
57
|
else
|
52
58
|
packages.delete_if { |p| p.name == pkg.name }
|
53
59
|
end
|
54
60
|
packages << pkg
|
61
|
+
packages_to_be_upload << pkg if needs_uploading
|
55
62
|
pkg
|
56
63
|
end
|
57
64
|
|
@@ -62,7 +69,7 @@ class Deb::S3::Manifest
|
|
62
69
|
if p.name != pkg
|
63
70
|
p
|
64
71
|
# Also include the packages not matching a specified version
|
65
|
-
elsif (!versions.nil? and p.name == pkg and !versions.include? p.version)
|
72
|
+
elsif (!versions.nil? and p.name == pkg and !versions.include? p.version and !versions.include? p.version + "-" + p.iteration)
|
66
73
|
p
|
67
74
|
end
|
68
75
|
}
|
@@ -79,11 +86,9 @@ class Deb::S3::Manifest
|
|
79
86
|
manifest = self.generate
|
80
87
|
|
81
88
|
# store any packages that need to be stored
|
82
|
-
@
|
83
|
-
|
84
|
-
|
85
|
-
s3_store(pkg.filename, pkg.url_filename, 'application/octet-stream; charset=binary')
|
86
|
-
end
|
89
|
+
@packages_to_be_upload.each do |pkg|
|
90
|
+
yield pkg.url_filename if block_given?
|
91
|
+
s3_store(pkg.filename, pkg.url_filename, 'application/octet-stream; charset=binary')
|
87
92
|
end
|
88
93
|
|
89
94
|
# generate the Packages file
|
@@ -92,7 +97,7 @@ class Deb::S3::Manifest
|
|
92
97
|
pkgs_temp.close
|
93
98
|
f = "dists/#{@codename}/#{@component}/binary-#{@architecture}/Packages"
|
94
99
|
yield f if block_given?
|
95
|
-
s3_store(pkgs_temp.path, f, '
|
100
|
+
s3_store(pkgs_temp.path, f, 'binary/octet-stream; charset=binary', self.cache_control)
|
96
101
|
@files["#{@component}/binary-#{@architecture}/Packages"] = hashfile(pkgs_temp.path)
|
97
102
|
pkgs_temp.unlink
|
98
103
|
|
@@ -102,7 +107,7 @@ class Deb::S3::Manifest
|
|
102
107
|
Zlib::GzipWriter.open(gztemp.path) { |gz| gz.write manifest }
|
103
108
|
f = "dists/#{@codename}/#{@component}/binary-#{@architecture}/Packages.gz"
|
104
109
|
yield f if block_given?
|
105
|
-
s3_store(gztemp.path, f, 'application/x-gzip; charset=binary')
|
110
|
+
s3_store(gztemp.path, f, 'application/x-gzip; charset=binary', self.cache_control)
|
106
111
|
@files["#{@component}/binary-#{@architecture}/Packages.gz"] = hashfile(gztemp.path)
|
107
112
|
gztemp.unlink
|
108
113
|
|
data/lib/deb/s3/package.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
require "digest/sha1"
|
2
3
|
require "digest/sha2"
|
3
4
|
require "digest/md5"
|
4
5
|
require "socket"
|
5
6
|
require "tmpdir"
|
7
|
+
require "uri"
|
8
|
+
|
6
9
|
require 'deb/s3/utils'
|
7
10
|
|
8
11
|
class Deb::S3::Package
|
@@ -21,11 +24,6 @@ class Deb::S3::Package
|
|
21
24
|
attr_accessor :description
|
22
25
|
|
23
26
|
attr_accessor :dependencies
|
24
|
-
attr_accessor :provides
|
25
|
-
attr_accessor :conflicts
|
26
|
-
attr_accessor :replaces
|
27
|
-
attr_accessor :excludes
|
28
|
-
|
29
27
|
|
30
28
|
# Any other attributes specific to this package.
|
31
29
|
# This is where you'd put rpm, deb, or other specific attributes.
|
@@ -116,12 +114,7 @@ class Deb::S3::Package
|
|
116
114
|
@filename = nil
|
117
115
|
@url_filename = nil
|
118
116
|
|
119
|
-
@provides = []
|
120
|
-
@conflicts = []
|
121
|
-
@replaces = []
|
122
117
|
@dependencies = []
|
123
|
-
|
124
|
-
@needs_uploading = false
|
125
118
|
end
|
126
119
|
|
127
120
|
def full_version
|
@@ -131,7 +124,6 @@ class Deb::S3::Package
|
|
131
124
|
|
132
125
|
def filename=(f)
|
133
126
|
@filename = f
|
134
|
-
@needs_uploading = true
|
135
127
|
@filename
|
136
128
|
end
|
137
129
|
|
@@ -143,10 +135,6 @@ class Deb::S3::Package
|
|
143
135
|
@url_filename || "pool/#{self.name[0]}/#{self.name[0..1]}/#{s3_escape(File.basename(self.filename))}"
|
144
136
|
end
|
145
137
|
|
146
|
-
def needs_uploading?
|
147
|
-
@needs_uploading
|
148
|
-
end
|
149
|
-
|
150
138
|
def generate
|
151
139
|
template("package.erb").result(binding)
|
152
140
|
end
|
@@ -232,55 +220,52 @@ class Deb::S3::Package
|
|
232
220
|
|
233
221
|
# from fpm
|
234
222
|
def extract_info(control)
|
235
|
-
|
236
|
-
value = control[/^#{field}: .*/]
|
237
|
-
if value.nil?
|
238
|
-
return nil
|
239
|
-
else
|
240
|
-
return value.split(": ",2).last
|
241
|
-
end
|
242
|
-
end
|
223
|
+
fields = parse_control(control)
|
243
224
|
|
244
225
|
# Parse 'epoch:version-iteration' in the version string
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
raise "Unsupported version string '#{parse.call("Version")}'"
|
226
|
+
full_version = fields.delete('Version')
|
227
|
+
if full_version !~ /^(?:([0-9]+):)?(.+?)(?:-(.*))?$/
|
228
|
+
raise "Unsupported version string '#{full_version}'"
|
249
229
|
end
|
250
|
-
self.epoch, self.version, self.iteration =
|
251
|
-
|
252
|
-
self.architecture =
|
253
|
-
self.category =
|
254
|
-
self.license =
|
255
|
-
self.maintainer =
|
256
|
-
self.name =
|
257
|
-
self.url =
|
258
|
-
self.vendor =
|
259
|
-
self.attributes[:deb_priority] =
|
260
|
-
self.attributes[:deb_origin] =
|
261
|
-
self.attributes[:deb_installed_size] =
|
230
|
+
self.epoch, self.version, self.iteration = $~.captures
|
231
|
+
|
232
|
+
self.architecture = fields.delete('Architecture')
|
233
|
+
self.category = fields.delete('Section')
|
234
|
+
self.license = fields.delete('License') || self.license
|
235
|
+
self.maintainer = fields.delete('Maintainer')
|
236
|
+
self.name = fields.delete('Package')
|
237
|
+
self.url = fields.delete('Homepage')
|
238
|
+
self.vendor = fields.delete('Vendor') || self.vendor
|
239
|
+
self.attributes[:deb_priority] = fields.delete('Priority')
|
240
|
+
self.attributes[:deb_origin] = fields.delete('Origin')
|
241
|
+
self.attributes[:deb_installed_size] = fields.delete('Installed-Size')
|
262
242
|
|
263
243
|
# Packages manifest fields
|
264
|
-
|
265
|
-
self.
|
266
|
-
self.
|
267
|
-
self.
|
268
|
-
self.
|
269
|
-
|
270
|
-
|
271
|
-
# The description is the first line as a normal Description field, but also continues
|
272
|
-
# on future lines indented by one space, until the end of the file. Blank
|
273
|
-
# lines are marked as ' .'
|
274
|
-
description = control[/^Description: .*[^\Z]/m]
|
275
|
-
description = description.gsub(/^[^(Description|\s)].*$/, "").split(": ", 2).last
|
276
|
-
self.description = description.gsub(/^ /, "").gsub(/^\.$/, "")
|
244
|
+
filename = fields.delete('Filename')
|
245
|
+
self.url_filename = filename && URI.unescape(filename)
|
246
|
+
self.sha1 = fields.delete('SHA1')
|
247
|
+
self.sha256 = fields.delete('SHA256')
|
248
|
+
self.md5 = fields.delete('MD5sum')
|
249
|
+
self.size = fields.delete('Size')
|
250
|
+
self.description = fields.delete('Description')
|
277
251
|
|
278
252
|
#self.config_files = config_files
|
279
253
|
|
280
|
-
self.dependencies += Array(parse_depends(
|
281
|
-
|
282
|
-
self.
|
283
|
-
self.
|
254
|
+
self.dependencies += Array(parse_depends(fields.delete('Depends')))
|
255
|
+
|
256
|
+
self.attributes[:deb_recommends] = fields.delete('Recommends')
|
257
|
+
self.attributes[:deb_suggests] = fields.delete('Suggests')
|
258
|
+
self.attributes[:deb_enhances] = fields.delete('Enhances')
|
259
|
+
self.attributes[:deb_pre_depends] = fields.delete('Pre-Depends')
|
260
|
+
|
261
|
+
self.attributes[:deb_breaks] = fields.delete('Breaks')
|
262
|
+
self.attributes[:deb_conflicts] = fields.delete('Conflicts')
|
263
|
+
self.attributes[:deb_provides] = fields.delete('Provides')
|
264
|
+
self.attributes[:deb_replaces] = fields.delete('Replaces')
|
265
|
+
|
266
|
+
self.attributes[:deb_field] = Hash[fields.map { |k, v|
|
267
|
+
[k.sub(/\AX[BCS]{0,3}-/, ''), v]
|
268
|
+
}]
|
284
269
|
end # def extract_info
|
285
270
|
|
286
271
|
def apply_file_info(file)
|
@@ -289,4 +274,28 @@ class Deb::S3::Package
|
|
289
274
|
self.sha256 = Digest::SHA2.file(file).hexdigest
|
290
275
|
self.md5 = Digest::MD5.file(file).hexdigest
|
291
276
|
end
|
277
|
+
|
278
|
+
def parse_control(control)
|
279
|
+
field = nil
|
280
|
+
value = ""
|
281
|
+
{}.tap do |fields|
|
282
|
+
control.each_line do |line|
|
283
|
+
if line =~ /^(\s+)(\S.*)$/
|
284
|
+
indent, rest = $1, $2
|
285
|
+
# Continuation
|
286
|
+
if indent.size == 1 && rest == "."
|
287
|
+
value << "\n\n"
|
288
|
+
rest = ""
|
289
|
+
elsif value.size > 0
|
290
|
+
value << "\n"
|
291
|
+
end
|
292
|
+
value << rest
|
293
|
+
elsif line =~ /^([-\w]+):(.*)$/
|
294
|
+
fields[field] = value if field
|
295
|
+
field, value = $1, $2.strip
|
296
|
+
end
|
297
|
+
end
|
298
|
+
fields[field] = value if field
|
299
|
+
end
|
300
|
+
end
|
292
301
|
end
|
data/lib/deb/s3/release.rb
CHANGED
@@ -1,32 +1,42 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
require "tempfile"
|
2
3
|
|
3
4
|
class Deb::S3::Release
|
4
5
|
include Deb::S3::Utils
|
5
6
|
|
6
7
|
attr_accessor :codename
|
8
|
+
attr_accessor :origin
|
9
|
+
attr_accessor :suite
|
7
10
|
attr_accessor :architectures
|
8
11
|
attr_accessor :components
|
12
|
+
attr_accessor :cache_control
|
9
13
|
|
10
14
|
attr_accessor :files
|
11
15
|
attr_accessor :policy
|
12
16
|
|
13
17
|
def initialize
|
18
|
+
@origin = nil
|
19
|
+
@suite = nil
|
14
20
|
@codename = nil
|
15
21
|
@architectures = []
|
16
22
|
@components = []
|
23
|
+
@cache_control = ""
|
17
24
|
@files = {}
|
18
25
|
@policy = :public_read
|
19
26
|
end
|
20
27
|
|
21
28
|
class << self
|
22
|
-
def retrieve(codename)
|
29
|
+
def retrieve(codename, origin=nil, suite=nil, cache_control=nil)
|
23
30
|
if s = Deb::S3::Utils.s3_read("dists/#{codename}/Release")
|
24
|
-
self.parse_release(s)
|
31
|
+
rel = self.parse_release(s)
|
25
32
|
else
|
26
33
|
rel = self.new
|
27
34
|
rel.codename = codename
|
28
|
-
rel
|
35
|
+
rel.origin = origin unless origin.nil?
|
36
|
+
rel.suite = suite unless suite.nil?
|
29
37
|
end
|
38
|
+
rel.cache_control = cache_control
|
39
|
+
rel
|
30
40
|
end
|
31
41
|
|
32
42
|
def parse_release(str)
|
@@ -52,6 +62,8 @@ class Deb::S3::Release
|
|
52
62
|
|
53
63
|
# grab basic fields
|
54
64
|
self.codename = parse.call("Codename")
|
65
|
+
self.origin = parse.call("Origin") || nil
|
66
|
+
self.suite = parse.call("Suite") || nil
|
55
67
|
self.architectures = (parse.call("Architectures") || "").split(/\s+/)
|
56
68
|
self.components = (parse.call("Components") || "").split(/\s+/)
|
57
69
|
|
@@ -86,7 +98,7 @@ class Deb::S3::Release
|
|
86
98
|
release_tmp.puts self.generate
|
87
99
|
release_tmp.close
|
88
100
|
yield self.filename if block_given?
|
89
|
-
s3_store(release_tmp.path, self.filename, '
|
101
|
+
s3_store(release_tmp.path, self.filename, 'binary/octet-stream; charset=binary', self.cache_control)
|
90
102
|
|
91
103
|
# sign the file, if necessary
|
92
104
|
if Deb::S3::Utils.signing_key
|
@@ -96,7 +108,7 @@ class Deb::S3::Release
|
|
96
108
|
remote_file = self.filename+".gpg"
|
97
109
|
yield remote_file if block_given?
|
98
110
|
raise "Unable to locate Release signature file" unless File.exists?(local_file)
|
99
|
-
s3_store(local_file, remote_file, 'application/pgp-signature; charset=us-ascii')
|
111
|
+
s3_store(local_file, remote_file, 'application/pgp-signature; charset=us-ascii', self.cache_control)
|
100
112
|
File.unlink(local_file)
|
101
113
|
else
|
102
114
|
raise "Signing the Release file failed."
|
@@ -8,25 +8,31 @@ Installed-Size: <%= attributes[:deb_installed_size] %>
|
|
8
8
|
<% if !dependencies.empty? and !attributes[:no_depends?] -%>
|
9
9
|
Depends: <%= dependencies.collect { |d| fix_dependency(d) }.flatten.join(", ") %>
|
10
10
|
<% end -%>
|
11
|
-
<% if
|
12
|
-
Conflicts: <%=
|
11
|
+
<% if attributes[:deb_conflicts] -%>
|
12
|
+
Conflicts: <%= attributes[:deb_conflicts] %>
|
13
|
+
<% end -%>
|
14
|
+
<% if attributes[:deb_breaks] -%>
|
15
|
+
Breaks: <%= attributes[:deb_breaks] %>
|
13
16
|
<% end -%>
|
14
17
|
<% if attributes[:deb_pre_depends] -%>
|
15
|
-
Pre-Depends: <%= attributes[:deb_pre_depends]
|
18
|
+
Pre-Depends: <%= attributes[:deb_pre_depends] %>
|
16
19
|
<% end -%>
|
17
|
-
<% if
|
20
|
+
<% if attributes[:deb_provides] -%>
|
18
21
|
<%# Turn each provides from 'foo = 123' to simply 'foo' because Debian :\ -%>
|
19
22
|
<%# http://www.debian.org/doc/debian-policy/ch-relationships.html -%>
|
20
|
-
Provides: <%=
|
23
|
+
Provides: <%= attributes[:deb_provides] %>
|
21
24
|
<% end -%>
|
22
|
-
<% if
|
23
|
-
Replaces: <%=
|
25
|
+
<% if attributes[:deb_replaces] -%>
|
26
|
+
Replaces: <%= attributes[:deb_replaces] %>
|
24
27
|
<% end -%>
|
25
28
|
<% if attributes[:deb_recommends] -%>
|
26
|
-
Recommends: <%= attributes[:deb_recommends]
|
29
|
+
Recommends: <%= attributes[:deb_recommends] %>
|
27
30
|
<% end -%>
|
28
31
|
<% if attributes[:deb_suggests] -%>
|
29
|
-
Suggests: <%= attributes[:deb_suggests]
|
32
|
+
Suggests: <%= attributes[:deb_suggests] %>
|
33
|
+
<% end -%>
|
34
|
+
<% if attributes[:deb_enhances] -%>
|
35
|
+
Enhances: <%= attributes[:deb_enhances] %>
|
30
36
|
<% end -%>
|
31
37
|
Section: <%= category %>
|
32
38
|
<% if attributes[:deb_origin] -%>
|
@@ -1,7 +1,11 @@
|
|
1
|
+
<% if origin -%>
|
2
|
+
Origin: <%= origin %>
|
3
|
+
<% end -%>
|
1
4
|
Codename: <%= codename %>
|
2
5
|
Date: <%= Time.now.utc.strftime("%a, %d %b %Y %T %Z") %>
|
3
6
|
Architectures: <%= architectures.join(" ") %>
|
4
7
|
Components: <%= components.join(" ") %>
|
8
|
+
Suite: <%= suite %>
|
5
9
|
MD5Sum:
|
6
10
|
<% files.sort.each do |f,p| -%>
|
7
11
|
<%= p[:md5] %> <%= p[:size].to_s.rjust(16) %> <%= f %>
|
data/lib/deb/s3/utils.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
require "base64"
|
2
3
|
require "digest/md5"
|
3
4
|
require "erb"
|
@@ -17,6 +18,8 @@ module Deb::S3::Utils
|
|
17
18
|
def gpg_options= v; @gpg_options = v end
|
18
19
|
def prefix; @prefix end
|
19
20
|
def prefix= v; @prefix = v end
|
21
|
+
def encryption; @encryption end
|
22
|
+
def encryption= v; @encryption = v end
|
20
23
|
|
21
24
|
class SafeSystemError < RuntimeError; end
|
22
25
|
|
@@ -46,7 +49,7 @@ module Deb::S3::Utils
|
|
46
49
|
|
47
50
|
# from fog, Fog::AWS.escape
|
48
51
|
def s3_escape(string)
|
49
|
-
string.gsub(/([^a-zA-Z0-9_
|
52
|
+
string.gsub(/([^a-zA-Z0-9_.\-~+]+)/) {
|
50
53
|
"%" + $1.unpack("H2" * $1.bytesize).join("%").upcase
|
51
54
|
}
|
52
55
|
end
|
@@ -60,7 +63,7 @@ module Deb::S3::Utils
|
|
60
63
|
Deb::S3::Utils.s3.buckets[Deb::S3::Utils.bucket].objects[s3_path(path)].read
|
61
64
|
end
|
62
65
|
|
63
|
-
def s3_store(path, filename=nil, content_type='application/octet-stream; charset=binary')
|
66
|
+
def s3_store(path, filename=nil, content_type='application/octet-stream; charset=binary', cache_control=nil)
|
64
67
|
filename = File.basename(path) unless filename
|
65
68
|
obj = Deb::S3::Utils.s3.buckets[Deb::S3::Utils.bucket].objects[s3_path(filename)]
|
66
69
|
|
@@ -71,8 +74,16 @@ module Deb::S3::Utils
|
|
71
74
|
return if (file_md5.to_s == obj.etag.gsub('"', '') or file_md5.to_s == obj.metadata['md5'])
|
72
75
|
end
|
73
76
|
|
77
|
+
options = {:acl => Deb::S3::Utils.access_policy, :content_type => content_type, :metadata => {'md5' => file_md5}}
|
78
|
+
if !cache_control.nil?
|
79
|
+
options[:cache_control] = cache_control
|
80
|
+
end
|
81
|
+
|
82
|
+
# specify if encryption is required
|
83
|
+
options[:server_side_encryption] = :aes256 if Deb::S3::Utils.encryption
|
84
|
+
|
74
85
|
# upload the file
|
75
|
-
obj.write(Pathname.new(path),
|
86
|
+
obj.write(Pathname.new(path), options)
|
76
87
|
end
|
77
88
|
|
78
89
|
def s3_remove(path)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deb-s3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ken Robertson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-02-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -73,16 +73,16 @@ executables:
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
-
- bin/deb-s3
|
77
|
-
- README.md
|
78
76
|
- lib/deb/s3/release.rb
|
77
|
+
- lib/deb/s3/templates/package.erb
|
78
|
+
- lib/deb/s3/templates/release.erb
|
79
79
|
- lib/deb/s3/package.rb
|
80
|
-
- lib/deb/s3/utils.rb
|
81
80
|
- lib/deb/s3/cli.rb
|
82
81
|
- lib/deb/s3/manifest.rb
|
83
|
-
- lib/deb/s3/
|
84
|
-
- lib/deb/s3/templates/package.erb
|
82
|
+
- lib/deb/s3/utils.rb
|
85
83
|
- lib/deb/s3.rb
|
84
|
+
- bin/deb-s3
|
85
|
+
- README.md
|
86
86
|
homepage: http://invalidlogic.com/
|
87
87
|
licenses: []
|
88
88
|
metadata: {}
|