deb-s3-patched 0.11.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f1db4e190c7eeaa5507b185efb701080a3b8d5764d4177d9f5923df44486cf24
4
+ data.tar.gz: a764e51d767d238e4805e277840e60529acd133dc5daa42112fb7281670695df
5
+ SHA512:
6
+ metadata.gz: 3e193dfd10cee3e3bb3043588d074b65f02516c832df2efb9b514b8915ce420141fec2fe4460834b5af20b479618eee437805beff82bab89dc790d3097c9d7b2
7
+ data.tar.gz: 3e40c8611ebf88dcdddd11fa3a4d317d7cbc881af9edabf3df5e10d99d71a6323d2413af6348e3b01a3fd1d33379907e1eb34dcd48025d3a9ca22bbf65e8a2e9
@@ -0,0 +1,186 @@
1
+ # deb-s3
2
+
3
+ [![Build Status](https://travis-ci.org/krobertson/deb-s3.svg?branch=master)](https://travis-ci.org/krobertson/deb-s3)
4
+
5
+ **This repository is no longer maintained.** I am no longer actively maintaining
6
+ deb-s3. I haven't been using it to maintain any repositories since
7
+ ~2016. Someone had expressed interest in taking over development, but they
8
+ appear to be inactive with it as well.
9
+
10
+ `deb-s3` is a simple utility to make creating and managing APT repositories on
11
+ S3.
12
+
13
+ Most existing guides on using S3 to host an APT repository have you
14
+ using something like [reprepro](http://mirrorer.alioth.debian.org/) to generate
15
+ the repository file structure, and then [s3cmd](http://s3tools.org/s3cmd) to
16
+ sync the files to S3.
17
+
18
+ The annoying thing about this process is it requires you to maintain a local
19
+ copy of the file tree for regenerating and syncing the next time. Personally,
20
+ my process is to use one-off virtual machines with
21
+ [Vagrant](http://vagrantup.com), script out the build process, and then would
22
+ prefer to just upload the final `.deb` from my Mac.
23
+
24
+ With `deb-s3`, there is no need for this. `deb-s3` features:
25
+
26
+ * Downloads the existing package manifest and parses it.
27
+ * Updates it with the new package, replacing the existing entry if already
28
+ there or adding a new one if not.
29
+ * Uploads the package itself, the Packages manifest, and the Packages.gz
30
+ manifest. It will skip the uploading if the package is already there.
31
+ * Updates the Release file with the new hashes and file sizes.
32
+
33
+ ## Getting Started
34
+
35
+ You can simply install it from rubygems:
36
+
37
+ ```console
38
+ $ gem install deb-s3
39
+ ```
40
+
41
+ Or to run the code directly, just check out the repo and run Bundler to ensure
42
+ all dependencies are installed:
43
+
44
+ ```console
45
+ $ git clone https://github.com/krobertson/deb-s3.git
46
+ $ cd deb-s3
47
+ $ bundle install
48
+ ```
49
+
50
+ Now to upload a package, simply use:
51
+
52
+ ```console
53
+ $ deb-s3 upload --bucket my-bucket my-deb-package-1.0.0_amd64.deb
54
+ >> Examining package file my-deb-package-1.0.0_amd64.deb
55
+ >> Retrieving existing package manifest
56
+ >> Uploading package and new manifests to S3
57
+ -- Transferring pool/m/my/my-deb-package-1.0.0_amd64.deb
58
+ -- Transferring dists/stable/main/binary-amd64/Packages
59
+ -- Transferring dists/stable/main/binary-amd64/Packages.gz
60
+ -- Transferring dists/stable/Release
61
+ >> Update complete.
62
+ ```
63
+
64
+ ```
65
+ Usage:
66
+ deb-s3 upload FILES
67
+
68
+ Options:
69
+ -a, [--arch=ARCH] # The architecture of the package in the APT repository.
70
+ -p, [--preserve-versions], [--no-preserve-versions] # Whether to preserve other versions of a package in the repository when uploading one.
71
+ -l, [--lock], [--no-lock] # Whether to check for an existing lock on the repository to prevent simultaneous updates
72
+ [--fail-if-exists], [--no-fail-if-exists] # Whether to overwrite any existing package that has the same filename in the pool or the same name and version in the manifest but different contents.
73
+ [--skip-package-upload], [--no-skip-package-upload] # Whether to skip all package uploads.This is useful when hosting .deb files outside of the bucket.
74
+ -b, [--bucket=BUCKET] # The name of the S3 bucket to upload to.
75
+ [--prefix=PREFIX] # The path prefix to use when storing on S3.
76
+ -o, [--origin=ORIGIN] # The origin to use in the repository Release file.
77
+ [--suite=SUITE] # The suite to use in the repository Release file.
78
+ -c, [--codename=CODENAME] # The codename of the APT repository.
79
+ # Default: stable
80
+ -m, [--component=COMPONENT] # The component of the APT repository.
81
+ # Default: main
82
+ [--access-key-id=ACCESS_KEY_ID] # The access key for connecting to S3.
83
+ [--secret-access-key=SECRET_ACCESS_KEY] # The secret key for connecting to S3.
84
+ [--s3-region=S3_REGION] # The region for connecting to S3.
85
+ # Default: us-east-1
86
+ [--force-path-style], [--no-force-path-style] # Use S3 path style instead of subdomains.
87
+ [--proxy-uri=PROXY_URI] # The URI of the proxy to send service requests through.
88
+ -v, [--visibility=VISIBILITY] # The access policy for the uploaded files. Can be public, private, or authenticated.
89
+ # Default: public
90
+ [--sign=SIGN] # GPG Sign the Release file when uploading a package, or when verifying it after removing a package. Use --sign with your GPG key ID to use a specific key (--sign=6643C242C18FE05B).
91
+ [--gpg-options=GPG_OPTIONS] # Additional command line options to pass to GPG when signing.
92
+ -e, [--encryption], [--no-encryption] # Use S3 server side encryption.
93
+ -q, [--quiet], [--no-quiet] # Doesn't output information, just returns status appropriately.
94
+ -C, [--cache-control=CACHE_CONTROL] # Add cache-control headers to S3 objects.
95
+
96
+ Uploads the given files to a S3 bucket as an APT repository.
97
+ ```
98
+
99
+ You can also delete packages from the APT repository. Please keep in mind that
100
+ this does NOT delete the .deb file itself, it only removes it from the list of
101
+ packages in the specified component, codename and architecture.
102
+
103
+ Now to delete the package:
104
+ ```console
105
+ $ deb-s3 delete my-deb-package --arch amd64 --bucket my-bucket --versions 1.0.0
106
+ >> Retrieving existing manifests
107
+ -- Deleting my-deb-package version 1.0.0
108
+ >> Uploading new manifests to S3
109
+ -- Transferring dists/stable/main/binary-amd64/Packages
110
+ -- Transferring dists/stable/main/binary-amd64/Packages.gz
111
+ -- Transferring dists/stable/Release
112
+ >> Update complete.
113
+ ```
114
+
115
+ ```
116
+ Usage:
117
+ deb-s3 delete PACKAGE
118
+
119
+ Options:
120
+ -a, [--arch=ARCH] # The architecture of the package in the APT repository.
121
+ [--versions=one two three] # The space-delimited versions of PACKAGE to delete. If not specified, ALL VERSIONS will be deleted. Fair warning. E.g. --versions "0.1 0.2 0.3"
122
+ -b, [--bucket=BUCKET] # The name of the S3 bucket to upload to.
123
+ [--prefix=PREFIX] # The path prefix to use when storing on S3.
124
+ -o, [--origin=ORIGIN] # The origin to use in the repository Release file.
125
+ [--suite=SUITE] # The suite to use in the repository Release file.
126
+ -c, [--codename=CODENAME] # The codename of the APT repository.
127
+ # Default: stable
128
+ -m, [--component=COMPONENT] # The component of the APT repository.
129
+ # Default: main
130
+ [--access-key-id=ACCESS_KEY_ID] # The access key for connecting to S3.
131
+ [--secret-access-key=SECRET_ACCESS_KEY] # The secret key for connecting to S3.
132
+ [--s3-region=S3_REGION] # The region for connecting to S3.
133
+ # Default: us-east-1
134
+ [--force-path-style], [--no-force-path-style] # Use S3 path style instead of subdomains.
135
+ [--proxy-uri=PROXY_URI] # The URI of the proxy to send service requests through.
136
+ -v, [--visibility=VISIBILITY] # The access policy for the uploaded files. Can be public, private, or authenticated.
137
+ # Default: public
138
+ [--sign=SIGN] # GPG Sign the Release file when uploading a package, or when verifying it after removing a package. Use --sign with your GPG key ID to use a specific key (--sign=6643C242C18FE05B).
139
+ [--gpg-options=GPG_OPTIONS] # Additional command line options to pass to GPG when signing.
140
+ -e, [--encryption], [--no-encryption] # Use S3 server side encryption.
141
+ -q, [--quiet], [--no-quiet] # Doesn't output information, just returns status appropriately.
142
+ -C, [--cache-control=CACHE_CONTROL] # Add cache-control headers to S3 objects.
143
+
144
+ Remove the package named PACKAGE. If --versions is not specified, deleteall versions of PACKAGE. Otherwise, only the specified versions will be deleted.
145
+ ```
146
+
147
+ You can also verify an existing APT repository on S3 using the `verify` command:
148
+
149
+ ```console
150
+ deb-s3 verify -b my-bucket
151
+ >> Retrieving existing manifests
152
+ >> Checking for missing packages in: stable/main i386
153
+ >> Checking for missing packages in: stable/main amd64
154
+ >> Checking for missing packages in: stable/main all
155
+ ```
156
+
157
+ ```
158
+ Usage:
159
+ deb-s3 verify
160
+
161
+ Options:
162
+ -f, [--fix-manifests], [--no-fix-manifests] # Whether to fix problems in manifests when verifying.
163
+ -b, [--bucket=BUCKET] # The name of the S3 bucket to upload to.
164
+ [--prefix=PREFIX] # The path prefix to use when storing on S3.
165
+ -o, [--origin=ORIGIN] # The origin to use in the repository Release file.
166
+ [--suite=SUITE] # The suite to use in the repository Release file.
167
+ -c, [--codename=CODENAME] # The codename of the APT repository.
168
+ # Default: stable
169
+ -m, [--component=COMPONENT] # The component of the APT repository.
170
+ # Default: main
171
+ [--access-key-id=ACCESS_KEY_ID] # The access key for connecting to S3.
172
+ [--secret-access-key=SECRET_ACCESS_KEY] # The secret key for connecting to S3.
173
+ [--s3-region=S3_REGION] # The region for connecting to S3.
174
+ # Default: us-east-1
175
+ [--force-path-style], [--no-force-path-style] # Use S3 path style instead of subdomains.
176
+ [--proxy-uri=PROXY_URI] # The URI of the proxy to send service requests through.
177
+ -v, [--visibility=VISIBILITY] # The access policy for the uploaded files. Can be public, private, or authenticated.
178
+ # Default: public
179
+ [--sign=SIGN] # GPG Sign the Release file when uploading a package, or when verifying it after removing a package. Use --sign with your GPG key ID to use a specific key (--sign=6643C242C18FE05B).
180
+ [--gpg-options=GPG_OPTIONS] # Additional command line options to pass to GPG when signing.
181
+ -e, [--encryption], [--no-encryption] # Use S3 server side encryption.
182
+ -q, [--quiet], [--no-quiet] # Doesn't output information, just returns status appropriately.
183
+ -C, [--cache-control=CACHE_CONTROL] # Add cache-control headers to S3 objects.
184
+
185
+ Verifies that the files in the package manifests exist
186
+ ```
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+ $:.unshift File.join(Pathname.new(__FILE__).realpath,'../../lib')
5
+
6
+ require 'rubygems'
7
+ require 'deb/s3/cli'
8
+
9
+ Deb::S3::CLI.start
10
+
@@ -0,0 +1,6 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Deb
3
+ module S3
4
+ VERSION = "0.11.0"
5
+ end
6
+ end
@@ -0,0 +1,618 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require "aws-sdk"
3
+ require "thor"
4
+
5
+ # Hack: aws requires this!
6
+ require "json"
7
+
8
+ require "deb/s3"
9
+ require "deb/s3/utils"
10
+ require "deb/s3/manifest"
11
+ require "deb/s3/package"
12
+ require "deb/s3/release"
13
+ require "deb/s3/lock"
14
+
15
+ class Deb::S3::CLI < Thor
16
+ class_option :bucket,
17
+ :type => :string,
18
+ :aliases => "-b",
19
+ :desc => "The name of the S3 bucket to upload to."
20
+
21
+ class_option :prefix,
22
+ :type => :string,
23
+ :desc => "The path prefix to use when storing on S3."
24
+
25
+ class_option :origin,
26
+ :type => :string,
27
+ :aliases => "-o",
28
+ :desc => "The origin to use in the repository Release file."
29
+
30
+ class_option :suite,
31
+ :type => :string,
32
+ :desc => "The suite to use in the repository Release file."
33
+
34
+ class_option :codename,
35
+ :default => "stable",
36
+ :type => :string,
37
+ :aliases => "-c",
38
+ :desc => "The codename of the APT repository."
39
+
40
+ class_option :component,
41
+ :default => "main",
42
+ :type => :string,
43
+ :aliases => "-m",
44
+ :desc => "The component of the APT repository."
45
+
46
+ class_option :section,
47
+ :type => :string,
48
+ :aliases => "-s",
49
+ :hide => true
50
+
51
+ class_option :access_key_id,
52
+ :type => :string,
53
+ :desc => "The access key for connecting to S3."
54
+
55
+ class_option :secret_access_key,
56
+ :type => :string,
57
+ :desc => "The secret key for connecting to S3."
58
+
59
+ class_option :session_token,
60
+ :type => :string,
61
+ :desc => "The (optional) session token for connecting to S3."
62
+
63
+ class_option :endpoint,
64
+ :type => :string,
65
+ :desc => "The URL endpoint to the S3 API."
66
+
67
+ class_option :s3_region,
68
+ :type => :string,
69
+ :desc => "The region for connecting to S3.",
70
+ :default => ENV["AWS_DEFAULT_REGION"] || "us-east-1"
71
+
72
+ class_option :force_path_style,
73
+ :default => false,
74
+ :type => :boolean,
75
+ :desc => "Use S3 path style instead of subdomains."
76
+
77
+ class_option :proxy_uri,
78
+ :type => :string,
79
+ :desc => "The URI of the proxy to send service requests through."
80
+
81
+ class_option :visibility,
82
+ :default => "public",
83
+ :type => :string,
84
+ :aliases => "-v",
85
+ :desc => "The access policy for the uploaded files. " +
86
+ "Can be public, private, or authenticated."
87
+
88
+ class_option :sign,
89
+ :type => :string,
90
+ :desc => "GPG Sign the Release file when uploading a package, " +
91
+ "or when verifying it after removing a package. " +
92
+ "Use --sign with your GPG key ID to use a specific key (--sign=6643C242C18FE05B)."
93
+
94
+ class_option :gpg_options,
95
+ :default => "",
96
+ :type => :string,
97
+ :desc => "Additional command line options to pass to GPG when signing."
98
+
99
+ class_option :encryption,
100
+ :default => false,
101
+ :type => :boolean,
102
+ :aliases => "-e",
103
+ :desc => "Use S3 server side encryption."
104
+
105
+ class_option :quiet,
106
+ :type => :boolean,
107
+ :aliases => "-q",
108
+ :desc => "Doesn't output information, just returns status appropriately."
109
+
110
+ class_option :cache_control,
111
+ :type => :string,
112
+ :aliases => "-C",
113
+ :desc => "Add cache-control headers to S3 objects."
114
+
115
+ desc "upload FILES",
116
+ "Uploads the given files to a S3 bucket as an APT repository."
117
+
118
+ option :arch,
119
+ :type => :string,
120
+ :aliases => "-a",
121
+ :desc => "The architecture of the package in the APT repository."
122
+
123
+ option :preserve_versions,
124
+ :default => false,
125
+ :type => :boolean,
126
+ :aliases => "-p",
127
+ :desc => "Whether to preserve other versions of a package " +
128
+ "in the repository when uploading one."
129
+
130
+ option :lock,
131
+ :default => false,
132
+ :type => :boolean,
133
+ :aliases => "-l",
134
+ :desc => "Whether to check for an existing lock on the repository " +
135
+ "to prevent simultaneous updates "
136
+
137
+ option :fail_if_exists,
138
+ :default => false,
139
+ :type => :boolean,
140
+ :desc => "Whether to overwrite any existing package that has the same " +
141
+ "filename in the pool or the same name and version in the manifest but " +
142
+ "different contents."
143
+
144
+ option :skip_package_upload,
145
+ :default => false,
146
+ :type => :boolean,
147
+ :desc => "Whether to skip all package uploads." +
148
+ "This is useful when hosting .deb files outside of the bucket."
149
+
150
+ def upload(*files)
151
+ if files.nil? || files.empty?
152
+ error("You must specify at least one file to upload")
153
+ end
154
+
155
+ # make sure all the files exists
156
+ if missing_file = files.find { |pattern| Dir.glob(pattern).empty? }
157
+ error("File '#{missing_file}' doesn't exist")
158
+ end
159
+
160
+ # configure AWS::S3
161
+ configure_s3_client
162
+
163
+ begin
164
+ if options[:lock]
165
+ log("Checking for existing lock file")
166
+ if Deb::S3::Lock.locked?(options[:codename], component, options[:arch], options[:cache_control])
167
+ lock = Deb::S3::Lock.current(options[:codename], component, options[:arch], options[:cache_control])
168
+ log("Repository is locked by another user: #{lock.user} at host #{lock.host}")
169
+ log("Attempting to obtain a lock")
170
+ Deb::S3::Lock.wait_for_lock(options[:codename], component, options[:arch], options[:cache_control])
171
+ end
172
+ log("Locking repository for updates")
173
+ Deb::S3::Lock.lock(options[:codename], component, options[:arch], options[:cache_control])
174
+ @lock_acquired = true
175
+ end
176
+
177
+ # retrieve the existing manifests
178
+ log("Retrieving existing manifests")
179
+ release = Deb::S3::Release.retrieve(options[:codename], options[:origin], options[:suite], options[:cache_control])
180
+ manifests = {}
181
+ release.architectures.each do |arch|
182
+ manifests[arch] = Deb::S3::Manifest.retrieve(options[:codename], component, arch, options[:cache_control], options[:fail_if_exists], options[:skip_package_upload])
183
+ end
184
+
185
+ packages_arch_all = []
186
+
187
+ # examine all the files
188
+ files.collect { |f| Dir.glob(f) }.flatten.each do |file|
189
+ log("Examining package file #{File.basename(file)}")
190
+ pkg = Deb::S3::Package.parse_file(file)
191
+
192
+ # copy over some options if they weren't given
193
+ arch = options[:arch] || pkg.architecture
194
+
195
+ # If they've specified an arch type that doesn't match the package let them know
196
+ if options.key?("arch") && options[:arch] != pkg.architecture
197
+ warn("You specified architecture #{options[:arch]} but package #{pkg.name} has architecture type of #{pkg.architecture}")
198
+ end
199
+
200
+ # validate we have them
201
+ error("No architcture given and unable to determine one for #{file}. " +
202
+ "Please specify one with --arch [i386|amd64|armhf].") unless arch
203
+
204
+ # If the arch is all and the list of existing manifests is none, then
205
+ # throw an error. This is mainly the case when initializing a brand new
206
+ # repository. With "all", we won't know which architectures they're using.
207
+ if arch == "all" && manifests.count == 0
208
+ error("Package #{File.basename(file)} had architecture \"all\", " +
209
+ "however noexisting package lists exist. This can often happen " +
210
+ "if the first package you are add to a new repository is an " +
211
+ "\"all\" architecture file. Please use --arch [i386|amd64|armhf] or " +
212
+ "another platform type to upload the file.")
213
+ end
214
+
215
+ # retrieve the manifest for the arch if we don't have it already
216
+ manifests[arch] ||= Deb::S3::Manifest.retrieve(options[:codename], component, arch, options[:cache_control], options[:fail_if_exists], options[:skip_package_upload])
217
+
218
+ # add package in manifests
219
+ begin
220
+ manifests[arch].add(pkg, options[:preserve_versions])
221
+ rescue Deb::S3::Utils::AlreadyExistsError => e
222
+ error("Preparing manifest failed because: #{e}")
223
+ end
224
+
225
+ # If arch is all, we must add this package in all arch available
226
+ if arch == 'all'
227
+ packages_arch_all << pkg
228
+ end
229
+ end
230
+
231
+ manifests.each do |arch, manifest|
232
+ next if arch == 'all'
233
+ packages_arch_all.each do |pkg|
234
+ begin
235
+ manifest.add(pkg, options[:preserve_versions], false)
236
+ rescue Deb::S3::Utils::AlreadyExistsError => e
237
+ error("Preparing manifest failed because: #{e}")
238
+ end
239
+ end
240
+ end
241
+
242
+ # upload the manifest
243
+ log("Uploading packages and new manifests to S3")
244
+ manifests.each_value do |manifest|
245
+ begin
246
+ manifest.write_to_s3 { |f| sublog("Transferring #{f}") }
247
+ rescue Deb::S3::Utils::AlreadyExistsError => e
248
+ error("Uploading manifest failed because: #{e}")
249
+ end
250
+ release.update_manifest(manifest)
251
+ end
252
+ release.write_to_s3 { |f| sublog("Transferring #{f}") }
253
+
254
+ log("Update complete.")
255
+ ensure
256
+ if options[:lock] && @lock_acquired
257
+ Deb::S3::Lock.unlock(options[:codename], component, options[:arch], options[:cache_control])
258
+ log("Lock released.")
259
+ end
260
+ end
261
+ end
262
+
263
+ desc "list", "Lists packages in given codename, component, and optionally architecture"
264
+
265
+ option :long,
266
+ :type => :boolean,
267
+ :aliases => '-l',
268
+ :desc => "Shows all package information in original format.",
269
+ :default => false
270
+
271
+ option :arch,
272
+ :type => :string,
273
+ :aliases => "-a",
274
+ :desc => "The architecture of the package in the APT repository."
275
+
276
+ def list
277
+ configure_s3_client
278
+
279
+ release = Deb::S3::Release.retrieve(options[:codename])
280
+ archs = release.architectures
281
+ archs &= [options[:arch]] if options[:arch] && options[:arch] != "all"
282
+ widths = [0, 0]
283
+ rows = archs.map { |arch|
284
+ manifest = Deb::S3::Manifest.retrieve(options[:codename], component,
285
+ arch, options[:cache_control],
286
+ false, false)
287
+ manifest.packages.map do |package|
288
+ if options[:long]
289
+ package.generate
290
+ else
291
+ [package.name, package.full_version, package.architecture].tap do |row|
292
+ row.each_with_index do |col, i|
293
+ widths[i] = [widths[i], col.size].max if widths[i]
294
+ end
295
+ end
296
+ end
297
+ end
298
+ }.flatten(1)
299
+
300
+ if options[:long]
301
+ $stdout.puts rows.join("\n")
302
+ else
303
+ rows.each do |row|
304
+ $stdout.puts "% -#{widths[0]}s % -#{widths[1]}s %s" % row
305
+ end
306
+ end
307
+ end
308
+
309
+ desc "show PACKAGE VERSION ARCH", "Shows information about a package."
310
+
311
+ def show(package_name, version, arch)
312
+ if version.nil?
313
+ error "You must specify the name of the package to show."
314
+ end
315
+ if version.nil?
316
+ error "You must specify the version of the package to show."
317
+ end
318
+ if arch.nil?
319
+ error "You must specify the architecture of the package to show."
320
+ end
321
+
322
+ configure_s3_client
323
+
324
+ # retrieve the existing manifests
325
+ manifest = Deb::S3::Manifest.retrieve(options[:codename], component, arch,
326
+ options[:cache_control], false, false)
327
+ package = manifest.packages.detect { |p|
328
+ p.name == package_name && p.full_version == version
329
+ }
330
+ if package.nil?
331
+ error "No such package found."
332
+ end
333
+
334
+ puts package.generate
335
+ end
336
+
337
+ desc "copy PACKAGE TO_CODENAME TO_COMPONENT ",
338
+ "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."
339
+
340
+ option :cache_control,
341
+ :type => :string,
342
+ :aliases => "-C",
343
+ :desc => "Add cache-control headers to S3 objects."
344
+
345
+ option :arch,
346
+ :type => :string,
347
+ :aliases => "-a",
348
+ :desc => "The architecture of the package in the APT repository."
349
+
350
+ option :versions,
351
+ :default => nil,
352
+ :type => :array,
353
+ :desc => "The space-delimited versions of PACKAGE to delete. If not " +
354
+ "specified, ALL VERSIONS will be deleted. Fair warning. " +
355
+ "E.g. --versions \"0.1 0.2 0.3\""
356
+
357
+ option :preserve_versions,
358
+ :default => false,
359
+ :type => :boolean,
360
+ :aliases => "-p",
361
+ :desc => "Whether to preserve other versions of a package " +
362
+ "in the repository when uploading one."
363
+
364
+ option :fail_if_exists,
365
+ :default => true,
366
+ :type => :boolean,
367
+ :desc => "Whether to overwrite any existing package that has the same " +
368
+ "filename in the pool or the same name and version in the manifest."
369
+
370
+ def copy(package_name, to_codename, to_component)
371
+ if package_name.nil?
372
+ error "You must specify a package name."
373
+ end
374
+ if to_codename.nil?
375
+ error "You must specify a codename to copy to."
376
+ end
377
+ if to_component.nil?
378
+ error "You must specify a component to copy to."
379
+ end
380
+
381
+ arch = options[:arch]
382
+ if arch.nil?
383
+ error "You must specify the architecture of the package to copy."
384
+ end
385
+
386
+ versions = options[:versions]
387
+ if versions.nil?
388
+ warn "===> WARNING: Copying all versions of #{package_name}"
389
+ else
390
+ log "Versions to copy: #{versions.join(', ')}"
391
+ end
392
+
393
+ configure_s3_client
394
+
395
+ # retrieve the existing manifests
396
+ log "Retrieving existing manifests"
397
+ from_manifest = Deb::S3::Manifest.retrieve(options[:codename],
398
+ component, arch,
399
+ options[:cache_control],
400
+ false, options[:skip_package_upload])
401
+ to_release = Deb::S3::Release.retrieve(to_codename)
402
+ to_manifest = Deb::S3::Manifest.retrieve(to_codename, to_component, arch,
403
+ options[:cache_control],
404
+ options[:fail_if_exists],
405
+ options[:skip_package_upload])
406
+ packages = from_manifest.packages.select { |p|
407
+ p.name == package_name &&
408
+ (versions.nil? || versions.include?(p.full_version))
409
+ }
410
+ if packages.size == 0
411
+ error "No packages found in repository."
412
+ end
413
+
414
+ packages.each do |package|
415
+ begin
416
+ to_manifest.add package, options[:preserve_versions], false
417
+ rescue Deb::S3::Utils::AlreadyExistsError => e
418
+ error("Preparing manifest failed because: #{e}")
419
+ end
420
+ end
421
+
422
+ begin
423
+ to_manifest.write_to_s3 { |f| sublog("Transferring #{f}") }
424
+ rescue Deb::S3::Utils::AlreadyExistsError => e
425
+ error("Copying manifest failed because: #{e}")
426
+ end
427
+ to_release.update_manifest(to_manifest)
428
+ to_release.write_to_s3 { |f| sublog("Transferring #{f}") }
429
+
430
+ log "Copy complete."
431
+ end
432
+
433
+ desc "delete PACKAGE",
434
+ "Remove the package named PACKAGE. If --versions is not specified, delete" +
435
+ "all versions of PACKAGE. Otherwise, only the specified versions will be " +
436
+ "deleted."
437
+
438
+ option :arch,
439
+ :type => :string,
440
+ :aliases => "-a",
441
+ :desc => "The architecture of the package in the APT repository."
442
+
443
+ option :versions,
444
+ :default => nil,
445
+ :type => :array,
446
+ :desc => "The space-delimited versions of PACKAGE to delete. If not " +
447
+ "specified, ALL VERSIONS will be deleted. Fair warning. " +
448
+ "E.g. --versions \"0.1 0.2 0.3\""
449
+
450
+ def delete(package)
451
+ if package.nil?
452
+ error("You must specify a package name.")
453
+ end
454
+
455
+ versions = options[:versions]
456
+ if versions.nil?
457
+ warn("===> WARNING: Deleting all versions of #{package}")
458
+ else
459
+ log("Versions to delete: #{versions.join(', ')}")
460
+ end
461
+
462
+ arch = options[:arch]
463
+ if arch.nil?
464
+ error("You must specify the architecture of the package to remove.")
465
+ end
466
+
467
+ configure_s3_client
468
+
469
+ # retrieve the existing manifests
470
+ log("Retrieving existing manifests")
471
+ release = Deb::S3::Release.retrieve(options[:codename], options[:origin], options[:suite])
472
+ manifest = Deb::S3::Manifest.retrieve(options[:codename], component, options[:arch], options[:cache_control], false, options[:skip_package_upload])
473
+
474
+ deleted = manifest.delete_package(package, versions)
475
+ if deleted.length == 0
476
+ if versions.nil?
477
+ error("No packages were deleted. #{package} not found.")
478
+ else
479
+ error("No packages were deleted. #{package} versions #{versions.join(', ')} could not be found.")
480
+ end
481
+ else
482
+ deleted.each { |p|
483
+ sublog("Deleting #{p.name} version #{p.full_version}")
484
+ }
485
+ end
486
+
487
+ log("Uploading new manifests to S3")
488
+ manifest.write_to_s3 {|f| sublog("Transferring #{f}") }
489
+ release.update_manifest(manifest)
490
+ release.write_to_s3 {|f| sublog("Transferring #{f}") }
491
+
492
+ log("Update complete.")
493
+ end
494
+
495
+
496
+ desc "verify", "Verifies that the files in the package manifests exist"
497
+
498
+ option :fix_manifests,
499
+ :default => false,
500
+ :type => :boolean,
501
+ :aliases => "-f",
502
+ :desc => "Whether to fix problems in manifests when verifying."
503
+
504
+ def verify
505
+ configure_s3_client
506
+
507
+ log("Retrieving existing manifests")
508
+ release = Deb::S3::Release.retrieve(options[:codename], options[:origin], options[:suite])
509
+
510
+ release.architectures.each do |arch|
511
+ log("Checking for missing packages in: #{options[:codename]}/#{options[:component]} #{arch}")
512
+ manifest = Deb::S3::Manifest.retrieve(options[:codename], component,
513
+ arch, options[:cache_control], false,
514
+ options[:skip_package_upload])
515
+ missing_packages = []
516
+
517
+ manifest.packages.each do |p|
518
+ unless Deb::S3::Utils.s3_exists? p.url_filename_encoded
519
+ sublog("The following packages are missing:\n\n") if missing_packages.empty?
520
+ puts(p.generate)
521
+ puts("")
522
+
523
+ missing_packages << p
524
+ end
525
+ end
526
+
527
+ if options[:sign] || (options[:fix_manifests] && !missing_packages.empty?)
528
+ log("Removing #{missing_packages.length} package(s) from the manifest...")
529
+ missing_packages.each { |p| manifest.packages.delete(p) }
530
+ manifest.write_to_s3 { |f| sublog("Transferring #{f}") }
531
+ release.update_manifest(manifest)
532
+ release.write_to_s3 { |f| sublog("Transferring #{f}") }
533
+
534
+ log("Update complete.")
535
+ end
536
+ end
537
+ end
538
+
539
+ private
540
+
541
+ def component
542
+ return @component if @component
543
+ @component = if (section = options[:section])
544
+ warn("===> WARNING: The --section/-s argument is " \
545
+ "deprecated, please use --component/-m.")
546
+ section
547
+ else
548
+ options[:component]
549
+ end
550
+ end
551
+
552
+ def puts(*args)
553
+ $stdout.puts(*args) unless options[:quiet]
554
+ end
555
+
556
+ def log(message)
557
+ puts ">> #{message}" unless options[:quiet]
558
+ end
559
+
560
+ def sublog(message)
561
+ puts " -- #{message}" unless options[:quiet]
562
+ end
563
+
564
+ def error(message)
565
+ $stderr.puts "!! #{message}" unless options[:quiet]
566
+ exit 1
567
+ end
568
+
569
+ def provider
570
+ access_key_id = options[:access_key_id]
571
+ secret_access_key = options[:secret_access_key]
572
+ session_token = options[:session_token]
573
+
574
+ if access_key_id.nil? ^ secret_access_key.nil?
575
+ error("If you specify one of --access-key-id or --secret-access-key, you must specify the other.")
576
+ end
577
+ static_credentials = {}
578
+ static_credentials[:access_key_id] = access_key_id if access_key_id
579
+ static_credentials[:secret_access_key] = secret_access_key if secret_access_key
580
+ static_credentials[:session_token] = session_token if session_token
581
+
582
+ static_credentials
583
+ end
584
+
585
+ def configure_s3_client
586
+ error("No value provided for required options '--bucket'") unless options[:bucket]
587
+
588
+ settings = {
589
+ :region => options[:s3_region],
590
+ :http_proxy => options[:proxy_uri],
591
+ :force_path_style => options[:force_path_style]
592
+ }
593
+ settings[:endpoint] = options[:endpoint] if options[:endpoint]
594
+ settings.merge!(provider)
595
+
596
+ Deb::S3::Utils.s3 = Aws::S3::Client.new(settings)
597
+ Deb::S3::Utils.bucket = options[:bucket]
598
+ Deb::S3::Utils.signing_key = options[:sign]
599
+ Deb::S3::Utils.gpg_options = options[:gpg_options]
600
+ Deb::S3::Utils.prefix = options[:prefix]
601
+ Deb::S3::Utils.encryption = options[:encryption]
602
+
603
+ # make sure we have a valid visibility setting
604
+ Deb::S3::Utils.access_policy =
605
+ case options[:visibility]
606
+ when "public"
607
+ "public-read"
608
+ when "private"
609
+ "private"
610
+ when "authenticated"
611
+ "authenticated-read"
612
+ when "bucket_owner"
613
+ "bucket-owner-full-control"
614
+ else
615
+ error("Invalid visibility setting given. Can be public, private, authenticated, or bucket_owner.")
616
+ end
617
+ end
618
+ end