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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bfc086aa33f2a9323c9857a09195870476722f30
4
- data.tar.gz: cd183d45cd2c91600ea1ba93f441fd9c0ab2702f
3
+ metadata.gz: 6c95a36618dfc6b8a2853b54c17101ae09140b3c
4
+ data.tar.gz: 5e14dda3916cd69e1e4eb3e5e26dd78b0f5cd94e
5
5
  SHA512:
6
- metadata.gz: a5932bfec7b7de8859520e8dfbcf7cb2ce3cb9b2019aa1bde7a98f4b229d1f45240a30aaed12346e1d96ff9925e3db77c833eb72bab091c7d3d12cc2a2213eec
7
- data.tar.gz: 3135fb0e0a7f31a2fe5329210514fc3faae5451a6e1f3b55aef4164a320bbb0f5784231e6dbbbcc3a845a538816c94feb33509a9a88a9e0daf7ea755154b1138
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.
@@ -1,5 +1,6 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  module Deb
2
3
  module S3
3
- VERSION = "0.6.2"
4
+ VERSION = "0.7.0"
4
5
  end
5
6
  end
@@ -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,amd64].") unless arch
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 the package
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
- %w[amd64 armel i386 all].each do |arch|
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, arch)
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 =
@@ -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
- @packages.each do |pkg|
83
- if pkg.needs_uploading?
84
- yield pkg.url_filename if block_given?
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, 'text/plain; charset=us-ascii')
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
 
@@ -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
- parse = lambda do |field|
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
- version_re = /^(?:([0-9]+):)?(.+?)(?:-(.*))?$/
246
- m = version_re.match(parse.call("Version"))
247
- if !m
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 = m.captures
251
-
252
- self.architecture = parse.call("Architecture")
253
- self.category = parse.call("Section")
254
- self.license = parse.call("License") || self.license
255
- self.maintainer = parse.call("Maintainer")
256
- self.name = parse.call("Package")
257
- self.url = parse.call("Homepage")
258
- self.vendor = parse.call("Vendor") || self.vendor
259
- self.attributes[:deb_priority] = parse.call("Priority")
260
- self.attributes[:deb_origin] = parse.call("Origin")
261
- self.attributes[:deb_installed_size] = parse.call("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
- self.url_filename = parse.call("Filename")
265
- self.sha1 = parse.call("SHA1")
266
- self.sha256 = parse.call("SHA256")
267
- self.md5 = parse.call("MD5sum")
268
- self.size = parse.call("Size")
269
-
270
- # The description field is a special flower, parse it that way.
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(parse.call("Depends")))
281
- self.conflicts += Array(parse_depends(parse.call("Conflicts")))
282
- self.provides += Array(parse_depends(parse.call("Provides")))
283
- self.replaces += Array(parse_depends(parse.call("Replaces")))
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
@@ -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, 'text/plain; charset=us-ascii')
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 !conflicts.empty? -%>
12
- Conflicts: <%= conflicts.join(", ") %>
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].collect { |d| fix_dependency(d) }.flatten.join(", ") %>
18
+ Pre-Depends: <%= attributes[:deb_pre_depends] %>
16
19
  <% end -%>
17
- <% if !provides.empty? -%>
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: <%= provides.map {|p| p.split(" ").first}.join ", " %>
23
+ Provides: <%= attributes[:deb_provides] %>
21
24
  <% end -%>
22
- <% if !replaces.empty? -%>
23
- Replaces: <%= replaces.join(", ") %>
25
+ <% if attributes[:deb_replaces] -%>
26
+ Replaces: <%= attributes[:deb_replaces] %>
24
27
  <% end -%>
25
28
  <% if attributes[:deb_recommends] -%>
26
- Recommends: <%= attributes[:deb_recommends].collect { |d| fix_dependency(d) }.flatten.join(", ") %>
29
+ Recommends: <%= attributes[:deb_recommends] %>
27
30
  <% end -%>
28
31
  <% if attributes[:deb_suggests] -%>
29
- Suggests: <%= attributes[:deb_suggests].collect { |d| fix_dependency(d) }.flatten.join(", ") %>
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 %>
@@ -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), :acl => Deb::S3::Utils.access_policy, :content_type => content_type, :metadata => {'md5' => file_md5})
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.6.2
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: 2014-07-03 00:00:00.000000000 Z
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/templates/release.erb
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: {}