deb-s3 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: {}