deb-s3 0.7.1 → 0.8.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: 904679e411b5fa26a8eee92c48460b742e6c1418
4
- data.tar.gz: eef06f5681d0871f579ef3beb24c249f467bf2ac
3
+ metadata.gz: 7e1bc9874f303cb3ec4a83a5dd1edf8948bf62bd
4
+ data.tar.gz: d2a16561f73b2dfd0c324f99a4336a6082f5a0e3
5
5
  SHA512:
6
- metadata.gz: a8d5260d87f9bd394f82eb5c45f44361152bacff274b3cb95127b44da0a6561c185b2891c904d45658acc1da4b52a33a9317e1de0b73131bff9c999a0305dcf5
7
- data.tar.gz: 1df2e5e2a552a983b71a17e76679a1b25a4f0415f77983fb1c6af5a6b0956eb6faffd9744a8128d76fb575a03e94af582f46e4a30da945a5958da910cadfdd19
6
+ metadata.gz: 54c58ff8308b6c8a1f219df3fbb21d6a9693917f2a853b1be44269443f84f5ffc4ff66e6270d23c98651adb8c430dddc9351eccca317b60279d7977112e2c272
7
+ data.tar.gz: c1a01cae8a4b91996e8d919cf41a8a2c8a4e6abe4ceb2c90496081fa5f9f77430472bb39067f65feaa5bf40305bf84043aa6f74bff0b9db234af868708e929c1
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  `deb-s3` is a simple utility to make creating and managing APT repositories on
6
6
  S3.
7
7
 
8
- Most existing existing guides on using S3 to host an APT repository have you
8
+ Most existing guides on using S3 to host an APT repository have you
9
9
  using something like [reprepro](http://mirrorer.alioth.debian.org/) to generate
10
10
  the repository file structure, and then [s3cmd](http://s3tools.org/s3cmd) to
11
11
  sync the files to S3.
@@ -61,18 +61,33 @@ Usage:
61
61
  deb-s3 upload FILES
62
62
 
63
63
  Options:
64
- -a, [--arch=ARCH] # The architecture of the package in the APT repository.
65
- [--sign=SIGN] # Sign the Release file. Use --sign with your key ID to use a specific key.
66
- -p, [--preserve-versions] # Whether to preserve other versions of a package in the repository when uploading one.
67
- -b, [--bucket=BUCKET] # The name of the S3 bucket to upload to.
68
- -c, [--codename=CODENAME] # The codename of the APT repository.
69
- # Default: stable
70
- -m, [--component=COMPONENT] # The component of the APT repository.
71
- # Default: main
72
- [--access-key-id=ACCESS_KEY] # The access key for connecting to S3.
73
- [--secret-access-key=SECRET_KEY] # The secret key for connecting to S3.
74
- -v, [--visibility=VISIBILITY] # The access policy for the uploaded files. Can be public, private, or authenticated.
75
- # Default: public
64
+ -a, [--arch=ARCH] # The architecture of the package in the APT repository.
65
+ -p, [--preserve-versions], [--no-preserve-versions] # Whether to preserve other versions of a package in the repository when uploading one.
66
+ -l, [--lock], [--no-lock] # Whether to check for an existing lock on the repository to prevent simultaneous updates
67
+ [--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.
68
+ -b, [--bucket=BUCKET] # The name of the S3 bucket to upload to.
69
+ [--prefix=PREFIX] # The path prefix to use when storing on S3.
70
+ -o, [--origin=ORIGIN] # The origin to use in the repository Release file.
71
+ [--suite=SUITE] # The suite to use in the repository Release file.
72
+ -c, [--codename=CODENAME] # The codename of the APT repository.
73
+ # Default: stable
74
+ -m, [--component=COMPONENT] # The component of the APT repository.
75
+ # Default: main
76
+ [--access-key-id=ACCESS_KEY_ID] # The access key for connecting to S3.
77
+ [--secret-access-key=SECRET_ACCESS_KEY] # The secret key for connecting to S3.
78
+ [--endpoint=ENDPOINT] # The region endpoint for connecting to S3.
79
+ # Default: s3.amazonaws.com
80
+ [--force-path-style], [--no-force-path-style] # Use S3 path style instead of subdomains.
81
+ [--proxy-uri=PROXY_URI] # The URI of the proxy to send service requests through.
82
+ [--use-ssl], [--no-use-ssl] # Whether to use HTTP or HTTPS for request transport.
83
+ # Default: true
84
+ -v, [--visibility=VISIBILITY] # The access policy for the uploaded files. Can be public, private, or authenticated.
85
+ # Default: public
86
+ [--sign=SIGN] # Sign the Release file when uploading a package, or when verifying it after removing a package. Use --sign with your key ID to use a specific key.
87
+ [--gpg-options=GPG_OPTIONS] # Additional command line options to pass to GPG when signing.
88
+ -e, [--encryption], [--no-encryption] # Use S3 server side encryption.
89
+ -q, [--quiet], [--no-quiet] # Doesn't output information, just returns status appropriately.
90
+ -C, [--cache-control=CACHE_CONTROL] # Add cache-control headers to S3 objects.
76
91
 
77
92
  Uploads the given files to a S3 bucket as an APT repository.
78
93
  ```
@@ -83,7 +98,7 @@ packages in the specified component, codename and architecture.
83
98
 
84
99
  Now to delete the package:
85
100
  ```console
86
- $ deb-s3 delete --arch amd64 --bucket my-bucket --versions 1.0.0 my-deb-package
101
+ $ deb-s3 delete my-deb-package --arch amd64 --bucket my-bucket --versions 1.0.0
87
102
  >> Retrieving existing manifests
88
103
  -- Deleting my-deb-package version 1.0.0
89
104
  >> Uploading new manifests to S3
@@ -91,8 +106,41 @@ $ deb-s3 delete --arch amd64 --bucket my-bucket --versions 1.0.0 my-deb-package
91
106
  -- Transferring dists/stable/main/binary-amd64/Packages.gz
92
107
  -- Transferring dists/stable/Release
93
108
  >> Update complete.
109
+ ```
94
110
 
95
- ````
111
+ ```
112
+ Usage:
113
+ deb-s3 delete PACKAGE
114
+
115
+ Options:
116
+ -a, [--arch=ARCH] # The architecture of the package in the APT repository.
117
+ [--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"
118
+ -b, [--bucket=BUCKET] # The name of the S3 bucket to upload to.
119
+ [--prefix=PREFIX] # The path prefix to use when storing on S3.
120
+ -o, [--origin=ORIGIN] # The origin to use in the repository Release file.
121
+ [--suite=SUITE] # The suite to use in the repository Release file.
122
+ -c, [--codename=CODENAME] # The codename of the APT repository.
123
+ # Default: stable
124
+ -m, [--component=COMPONENT] # The component of the APT repository.
125
+ # Default: main
126
+ [--access-key-id=ACCESS_KEY_ID] # The access key for connecting to S3.
127
+ [--secret-access-key=SECRET_ACCESS_KEY] # The secret key for connecting to S3.
128
+ [--endpoint=ENDPOINT] # The region endpoint for connecting to S3.
129
+ # Default: s3.amazonaws.com
130
+ [--force-path-style], [--no-force-path-style] # Use S3 path style instead of subdomains.
131
+ [--proxy-uri=PROXY_URI] # The URI of the proxy to send service requests through.
132
+ [--use-ssl], [--no-use-ssl] # Whether to use HTTP or HTTPS for request transport.
133
+ # Default: true
134
+ -v, [--visibility=VISIBILITY] # The access policy for the uploaded files. Can be public, private, or authenticated.
135
+ # Default: public
136
+ [--sign=SIGN] # Sign the Release file when uploading a package, or when verifying it after removing a package. Use --sign with your key ID to use a specific key.
137
+ [--gpg-options=GPG_OPTIONS] # Additional command line options to pass to GPG when signing.
138
+ -e, [--encryption], [--no-encryption] # Use S3 server side encryption.
139
+ -q, [--quiet], [--no-quiet] # Doesn't output information, just returns status appropriately.
140
+ -C, [--cache-control=CACHE_CONTROL] # Add cache-control headers to S3 objects.
141
+
142
+ Remove the package named PACKAGE. If --versions is not specified, deleteall versions of PACKAGE. Otherwise, only the specified versions will be deleted.
143
+ ```
96
144
 
97
145
  You can also verify an existing APT repository on S3 using the `verify` command:
98
146
 
@@ -109,18 +157,30 @@ Usage:
109
157
  deb-s3 verify
110
158
 
111
159
  Options:
112
- -f, [--fix-manifests] # Whether to fix problems in manifests when verifying.
113
- [--sign=SIGN] # Sign the Release file. Use --sign with your key ID to use a specific key.
114
- -b, [--bucket=BUCKET] # The name of the S3 bucket to upload to.
115
- -c, [--codename=CODENAME] # The codename of the APT repository.
116
- # Default: stable
117
- -m, [--component=COMPONENT] # The component of the APT repository.
118
- # Default: main
119
- [--access-key-id=ACCESS_KEY] # The access key for connecting to S3.
120
- [--secret-access-key=SECRET_KEY] # The secret key for connecting to S3.
121
- -v, [--visibility=VISIBILITY] # The access policy for the uploaded files. Can be public, private, or authenticated.
122
- # Default: public
160
+ -f, [--fix-manifests], [--no-fix-manifests] # Whether to fix problems in manifests when verifying.
161
+ -b, [--bucket=BUCKET] # The name of the S3 bucket to upload to.
162
+ [--prefix=PREFIX] # The path prefix to use when storing on S3.
163
+ -o, [--origin=ORIGIN] # The origin to use in the repository Release file.
164
+ [--suite=SUITE] # The suite to use in the repository Release file.
165
+ -c, [--codename=CODENAME] # The codename of the APT repository.
166
+ # Default: stable
167
+ -m, [--component=COMPONENT] # The component of the APT repository.
168
+ # Default: main
169
+ [--access-key-id=ACCESS_KEY_ID] # The access key for connecting to S3.
170
+ [--secret-access-key=SECRET_ACCESS_KEY] # The secret key for connecting to S3.
171
+ [--endpoint=ENDPOINT] # The region endpoint for connecting to S3.
172
+ # Default: s3.amazonaws.com
173
+ [--force-path-style], [--no-force-path-style] # Use S3 path style instead of subdomains.
174
+ [--proxy-uri=PROXY_URI] # The URI of the proxy to send service requests through.
175
+ [--use-ssl], [--no-use-ssl] # Whether to use HTTP or HTTPS for request transport.
176
+ # Default: true
177
+ -v, [--visibility=VISIBILITY] # The access policy for the uploaded files. Can be public, private, or authenticated.
178
+ # Default: public
179
+ [--sign=SIGN] # Sign the Release file when uploading a package, or when verifying it after removing a package. Use --sign with your key ID to use a specific key.
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.
123
184
 
124
185
  Verifies that the files in the package manifests exist
125
186
  ```
126
-
@@ -1,6 +1,6 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module Deb
3
3
  module S3
4
- VERSION = "0.7.1"
4
+ VERSION = "0.8.0"
5
5
  end
6
6
  end
@@ -10,6 +10,7 @@ require "deb/s3/utils"
10
10
  require "deb/s3/manifest"
11
11
  require "deb/s3/package"
12
12
  require "deb/s3/release"
13
+ require "deb/s3/lock"
13
14
 
14
15
  class Deb::S3::CLI < Thor
15
16
  class_option :bucket,
@@ -60,6 +61,11 @@ class Deb::S3::CLI < Thor
60
61
  :desc => "The region endpoint for connecting to S3.",
61
62
  :default => "s3.amazonaws.com"
62
63
 
64
+ class_option :force_path_style,
65
+ :default => false,
66
+ :type => :boolean,
67
+ :desc => "Use S3 path style instead of subdomains."
68
+
63
69
  class_option :proxy_uri,
64
70
  :type => :string,
65
71
  :desc => "The URI of the proxy to send service requests through."
@@ -78,20 +84,20 @@ class Deb::S3::CLI < Thor
78
84
 
79
85
  class_option :sign,
80
86
  :type => :string,
81
- :desc => "Sign the Release file when uploading a package," +
82
- "or when verifying it after removing a package." +
87
+ :desc => "Sign the Release file when uploading a package, " +
88
+ "or when verifying it after removing a package. " +
83
89
  "Use --sign with your key ID to use a specific key."
84
90
 
85
91
  class_option :gpg_options,
86
92
  :default => "",
87
93
  :type => :string,
88
- :desc => "Additional command line options to pass to GPG when signing"
94
+ :desc => "Additional command line options to pass to GPG when signing."
89
95
 
90
96
  class_option :encryption,
91
97
  :default => false,
92
98
  :type => :boolean,
93
99
  :aliases => "-e",
94
- :desc => "Use S3 server side encryption"
100
+ :desc => "Use S3 server side encryption."
95
101
 
96
102
  class_option :quiet,
97
103
  :type => :boolean,
@@ -101,7 +107,7 @@ class Deb::S3::CLI < Thor
101
107
  class_option :cache_control,
102
108
  :type => :string,
103
109
  :aliases => "-C",
104
- :desc => "Add cache-control headers to S3 objects"
110
+ :desc => "Add cache-control headers to S3 objects."
105
111
 
106
112
  desc "upload FILES",
107
113
  "Uploads the given files to a S3 bucket as an APT repository."
@@ -118,6 +124,19 @@ class Deb::S3::CLI < Thor
118
124
  :desc => "Whether to preserve other versions of a package " +
119
125
  "in the repository when uploading one."
120
126
 
127
+ option :lock,
128
+ :default => false,
129
+ :type => :boolean,
130
+ :aliases => "-l",
131
+ :desc => "Whether to check for an existing lock on the repository " +
132
+ "to prevent simultaneous updates "
133
+
134
+ option :fail_if_exists,
135
+ :default => false,
136
+ :type => :boolean,
137
+ :desc => "Whether to overwrite any existing package that has the same " +
138
+ "filename in the pool or the same name and version in the manifest."
139
+
121
140
  def upload(*files)
122
141
  if files.nil? || files.empty?
123
142
  error("You must specify at least one file to upload")
@@ -131,67 +150,104 @@ class Deb::S3::CLI < Thor
131
150
  # configure AWS::S3
132
151
  configure_s3_client
133
152
 
134
- # retrieve the existing manifests
135
- log("Retrieving existing manifests")
136
- release = Deb::S3::Release.retrieve(options[:codename], options[:origin], options[:suite], options[:cache_control])
137
- manifests = {}
138
- release.architectures.each do |arch|
139
- manifests[arch] = Deb::S3::Manifest.retrieve(options[:codename], component, arch, options[:cache_control])
140
- end
153
+ begin
154
+ if options[:lock]
155
+ log("Checking for existing lock file")
156
+ if Deb::S3::Lock.locked?(options[:codename], component, options[:arch], options[:cache_control])
157
+ lock = Deb::S3::Lock.current(options[:codename], component, options[:arch], options[:cache_control])
158
+ log("Repository is locked by another user: #{lock.user} at host #{lock.host}")
159
+ log("Attempting to obtain a lock")
160
+ Deb::S3::Lock.wait_for_lock(options[:codename], component, options[:arch], options[:cache_control])
161
+ end
162
+ log("Locking repository for updates")
163
+ Deb::S3::Lock.lock(options[:codename], component, options[:arch], options[:cache_control])
164
+ @lock_acquired = true
165
+ end
141
166
 
142
- packages_arch_all = []
143
-
144
- # examine all the files
145
- files.collect { |f| Dir.glob(f) }.flatten.each do |file|
146
- log("Examining package file #{File.basename(file)}")
147
- pkg = Deb::S3::Package.parse_file(file)
148
-
149
- # copy over some options if they weren't given
150
- arch = options[:arch] || pkg.architecture
151
-
152
- # validate we have them
153
- error("No architcture given and unable to determine one for #{file}. " +
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.")
167
+ # retrieve the existing manifests
168
+ log("Retrieving existing manifests")
169
+ release = Deb::S3::Release.retrieve(options[:codename], options[:origin], options[:suite], options[:cache_control])
170
+ manifests = {}
171
+ release.architectures.each do |arch|
172
+ manifests[arch] = Deb::S3::Manifest.retrieve(options[:codename], component, arch, options[:cache_control], options[:fail_if_exists])
165
173
  end
166
174
 
167
- # retrieve the manifest for the arch if we don't have it already
168
- manifests[arch] ||= Deb::S3::Manifest.retrieve(options[:codename], component, arch, options[:cache_control])
175
+ packages_arch_all = []
176
+
177
+ # examine all the files
178
+ files.collect { |f| Dir.glob(f) }.flatten.each do |file|
179
+ log("Examining package file #{File.basename(file)}")
180
+ pkg = Deb::S3::Package.parse_file(file)
181
+
182
+ # copy over some options if they weren't given
183
+ arch = options[:arch] || pkg.architecture
184
+
185
+ # If they've specified an arch type that doesn't match the package let them know
186
+ if options.key?("arch") && options[:arch] != pkg.architecture
187
+ warn("You specified architecture #{options[:arch]} but package #{pkg.name} has architecture type of #{pkg.architecture}")
188
+ end
189
+
190
+ # validate we have them
191
+ error("No architcture given and unable to determine one for #{file}. " +
192
+ "Please specify one with --arch [i386|amd64|armhf].") unless arch
193
+
194
+ # If the arch is all and the list of existing manifests is none, then
195
+ # throw an error. This is mainly the case when initializing a brand new
196
+ # repository. With "all", we won't know which architectures they're using.
197
+ if arch == "all" && manifests.count == 0
198
+ error("Package #{File.basename(file)} had architecture \"all\", " +
199
+ "however noexisting package lists exist. This can often happen " +
200
+ "if the first package you are add to a new repository is an " +
201
+ "\"all\" architecture file. Please use --arch [i386|amd64|armhf] or " +
202
+ "another platform type to upload the file.")
203
+ end
204
+
205
+ # retrieve the manifest for the arch if we don't have it already
206
+ manifests[arch] ||= Deb::S3::Manifest.retrieve(options[:codename], component, arch, options[:cache_control], options[:fail_if_exists])
169
207
 
170
- # add package in manifests
171
- manifests[arch].add(pkg, options[:preserve_versions])
208
+ # add package in manifests
209
+ begin
210
+ manifests[arch].add(pkg, options[:preserve_versions])
211
+ rescue Deb::S3::Utils::AlreadyExistsError => e
212
+ error("Preparing manifest failed because: #{e}")
213
+ end
172
214
 
173
- # If arch is all, we must add this package in all arch available
174
- if arch == 'all'
175
- packages_arch_all << pkg
215
+ # If arch is all, we must add this package in all arch available
216
+ if arch == 'all'
217
+ packages_arch_all << pkg
218
+ end
176
219
  end
177
- end
178
220
 
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)
221
+ manifests.each do |arch, manifest|
222
+ next if arch == 'all'
223
+ packages_arch_all.each do |pkg|
224
+ begin
225
+ manifest.add(pkg, options[:preserve_versions], false)
226
+ rescue Deb::S3::Utils::AlreadyExistsError => e
227
+ error("Preparing manifest failed because: #{e}")
228
+ end
229
+ end
183
230
  end
184
- end
185
231
 
186
- # upload the manifest
187
- log("Uploading packages and new manifests to S3")
188
- manifests.each_value do |manifest|
189
- manifest.write_to_s3 { |f| sublog("Transferring #{f}") }
190
- release.update_manifest(manifest)
191
- end
192
- release.write_to_s3 { |f| sublog("Transferring #{f}") }
232
+ # upload the manifest
233
+ log("Uploading packages and new manifests to S3")
234
+ manifests.each_value do |manifest|
235
+ begin
236
+ manifest.write_to_s3 { |f| sublog("Transferring #{f}") }
237
+ rescue Deb::S3::Utils::AlreadyExistsError => e
238
+ error("Uploading manifest failed because: #{e}")
239
+ end
240
+ release.update_manifest(manifest)
241
+ end
242
+ release.write_to_s3 { |f| sublog("Transferring #{f}") }
193
243
 
194
- log("Update complete.")
244
+ log("Update complete.")
245
+ ensure
246
+ if options[:lock] && @lock_acquired
247
+ Deb::S3::Lock.unlock(options[:codename], component, options[:arch], options[:cache_control])
248
+ log("Lock released.")
249
+ end
250
+ end
195
251
  end
196
252
 
197
253
  desc "list", "Lists packages in given codename, component, and optionally architecture"
@@ -199,7 +255,7 @@ class Deb::S3::CLI < Thor
199
255
  option :long,
200
256
  :type => :boolean,
201
257
  :aliases => '-l',
202
- :desc => "Shows all package information in original format",
258
+ :desc => "Shows all package information in original format.",
203
259
  :default => false
204
260
 
205
261
  option :arch,
@@ -216,7 +272,8 @@ class Deb::S3::CLI < Thor
216
272
  widths = [0, 0]
217
273
  rows = archs.map { |arch|
218
274
  manifest = Deb::S3::Manifest.retrieve(options[:codename], component,
219
- arch, options[:cache_control])
275
+ arch, options[:cache_control],
276
+ false)
220
277
  manifest.packages.map do |package|
221
278
  if options[:long]
222
279
  package.generate
@@ -256,7 +313,7 @@ class Deb::S3::CLI < Thor
256
313
 
257
314
  # retrieve the existing manifests
258
315
  manifest = Deb::S3::Manifest.retrieve(options[:codename], component, arch,
259
- options[:cache_control])
316
+ options[:cache_control], false)
260
317
  package = manifest.packages.detect { |p|
261
318
  p.name == package_name && p.full_version == version
262
319
  }
@@ -273,7 +330,7 @@ class Deb::S3::CLI < Thor
273
330
  option :cache_control,
274
331
  :type => :string,
275
332
  :aliases => "-C",
276
- :desc => "Add cache-control headers to S3 objects"
333
+ :desc => "Add cache-control headers to S3 objects."
277
334
 
278
335
  option :arch,
279
336
  :type => :string,
@@ -283,8 +340,8 @@ class Deb::S3::CLI < Thor
283
340
  option :versions,
284
341
  :default => nil,
285
342
  :type => :array,
286
- :desc => "The space-delimited versions of PACKAGE to delete. If not" +
287
- "specified, ALL VERSIONS will be deleted. Fair warning." +
343
+ :desc => "The space-delimited versions of PACKAGE to delete. If not " +
344
+ "specified, ALL VERSIONS will be deleted. Fair warning. " +
288
345
  "E.g. --versions \"0.1 0.2 0.3\""
289
346
 
290
347
  option :preserve_versions,
@@ -294,6 +351,12 @@ class Deb::S3::CLI < Thor
294
351
  :desc => "Whether to preserve other versions of a package " +
295
352
  "in the repository when uploading one."
296
353
 
354
+ option :fail_if_exists,
355
+ :default => true,
356
+ :type => :boolean,
357
+ :desc => "Whether to overwrite any existing package that has the same " +
358
+ "filename in the pool or the same name and version in the manifest."
359
+
297
360
  def copy(package_name, to_codename, to_component)
298
361
  if package_name.nil?
299
362
  error "You must specify a package name."
@@ -323,10 +386,12 @@ class Deb::S3::CLI < Thor
323
386
  log "Retrieving existing manifests"
324
387
  from_manifest = Deb::S3::Manifest.retrieve(options[:codename],
325
388
  component, arch,
326
- options[:cache_control])
389
+ options[:cache_control],
390
+ false)
327
391
  to_release = Deb::S3::Release.retrieve(to_codename)
328
392
  to_manifest = Deb::S3::Manifest.retrieve(to_codename, to_component, arch,
329
- options[:cache_control])
393
+ options[:cache_control],
394
+ options[:fail_if_exists])
330
395
  packages = from_manifest.packages.select { |p|
331
396
  p.name == package_name &&
332
397
  (versions.nil? || versions.include?(p.full_version))
@@ -336,10 +401,18 @@ class Deb::S3::CLI < Thor
336
401
  end
337
402
 
338
403
  packages.each do |package|
339
- to_manifest.add package, options[:preserve_versions], false
404
+ begin
405
+ to_manifest.add package, options[:preserve_versions], false
406
+ rescue Deb::S3::Utils::AlreadyExistsError => e
407
+ error("Preparing manifest failed because: #{e}")
408
+ end
340
409
  end
341
410
 
342
- to_manifest.write_to_s3 { |f| sublog("Transferring #{f}") }
411
+ begin
412
+ to_manifest.write_to_s3 { |f| sublog("Transferring #{f}") }
413
+ rescue Deb::S3::Utils::AlreadyExistsError => e
414
+ error("Copying manifest failed because: #{e}")
415
+ end
343
416
  to_release.update_manifest(to_manifest)
344
417
  to_release.write_to_s3 { |f| sublog("Transferring #{f}") }
345
418
 
@@ -359,8 +432,8 @@ class Deb::S3::CLI < Thor
359
432
  option :versions,
360
433
  :default => nil,
361
434
  :type => :array,
362
- :desc => "The space-delimited versions of PACKAGE to delete. If not" +
363
- "specified, ALL VERSIONS will be deleted. Fair warning." +
435
+ :desc => "The space-delimited versions of PACKAGE to delete. If not " +
436
+ "specified, ALL VERSIONS will be deleted. Fair warning. " +
364
437
  "E.g. --versions \"0.1 0.2 0.3\""
365
438
 
366
439
  def delete(package)
@@ -385,7 +458,7 @@ class Deb::S3::CLI < Thor
385
458
  # retrieve the existing manifests
386
459
  log("Retrieving existing manifests")
387
460
  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])
461
+ manifest = Deb::S3::Manifest.retrieve(options[:codename], component, options[:arch], options[:cache_control], false)
389
462
 
390
463
  deleted = manifest.delete_package(package, versions)
391
464
  if deleted.length == 0
@@ -396,7 +469,7 @@ class Deb::S3::CLI < Thor
396
469
  end
397
470
  else
398
471
  deleted.each { |p|
399
- sublog("Deleting #{p.name} version #{p.version}")
472
+ sublog("Deleting #{p.name} version #{p.full_version}")
400
473
  }
401
474
  end
402
475
 
@@ -426,7 +499,7 @@ class Deb::S3::CLI < Thor
426
499
  release.architectures.each do |arch|
427
500
  log("Checking for missing packages in: #{options[:codename]}/#{options[:component]} #{arch}")
428
501
  manifest = Deb::S3::Manifest.retrieve(options[:codename], component,
429
- arch, options[:cache_control])
502
+ arch, options[:cache_control], false)
430
503
  missing_packages = []
431
504
 
432
505
  manifest.packages.each do |p|
@@ -502,7 +575,8 @@ class Deb::S3::CLI < Thor
502
575
  settings = {
503
576
  :s3_endpoint => options[:endpoint],
504
577
  :proxy_uri => options[:proxy_uri],
505
- :use_ssl => options[:use_ssl]
578
+ :use_ssl => options[:use_ssl],
579
+ :s3_force_path_style => options[:force_path_style]
506
580
  }
507
581
  settings.merge!(provider.credentials)
508
582
 
@@ -522,8 +596,10 @@ class Deb::S3::CLI < Thor
522
596
  :private
523
597
  when "authenticated"
524
598
  :authenticated_read
599
+ when "bucket_owner"
600
+ :bucket_owner_full_control
525
601
  else
526
- error("Invalid visibility setting given. Can be public, private, or authenticated.")
602
+ error("Invalid visibility setting given. Can be public, private, authenticated, or bucket_owner.")
527
603
  end
528
604
  end
529
605
  end
@@ -0,0 +1,58 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require "tempfile"
3
+ require "socket"
4
+ require "etc"
5
+
6
+ class Deb::S3::Lock
7
+ attr_accessor :user
8
+ attr_accessor :host
9
+
10
+ def initialize
11
+ @user = nil
12
+ @host = nil
13
+ end
14
+
15
+ class << self
16
+ def locked?(codename, component = nil, architecture = nil, cache_control = nil)
17
+ Deb::S3::Utils.s3_exists?(lock_path(codename, component, architecture, cache_control))
18
+ end
19
+
20
+ def wait_for_lock(codename, component = nil, architecture = nil, cache_control = nil, max_attempts=60, wait=10)
21
+ attempts = 0
22
+ while self.locked?(codename, component, architecture, cache_control) do
23
+ attempts += 1
24
+ throw "Unable to obtain a lock after #{max_attempts}, giving up." if attempts > max_attempts
25
+ sleep(wait)
26
+ end
27
+ end
28
+
29
+ def lock(codename, component = nil, architecture = nil, cache_control = nil)
30
+ lockfile = Tempfile.new("lockfile")
31
+ lockfile.write("#{Etc.getlogin}@#{Socket.gethostname}")
32
+ lockfile.close
33
+
34
+ Deb::S3::Utils.s3_store(lockfile.path,
35
+ lock_path(codename, component, architecture, cache_control),
36
+ "text/plain",
37
+ cache_control)
38
+ end
39
+
40
+ def unlock(codename, component = nil, architecture = nil, cache_control = nil)
41
+ Deb::S3::Utils.s3_remove(lock_path(codename, component, architecture, cache_control))
42
+ end
43
+
44
+ def current(codename, component = nil, architecture = nil, cache_control = nil)
45
+ lock_content = Deb::S3::Utils.s3_read(lock_path(codename, component, architecture, cache_control))
46
+ lock_content = lock_content.split('@')
47
+ lock = Deb::S3::Lock.new
48
+ lock.user = lock_content[0]
49
+ lock.host = lock_content[1] if lock_content.size > 1
50
+ lock
51
+ end
52
+
53
+ private
54
+ def lock_path(codename, component = nil, architecture = nil, cache_control = nil)
55
+ "dists/#{codename}/#{component}/binary-#{architecture}/lockfile"
56
+ end
57
+ end
58
+ end
@@ -11,6 +11,7 @@ class Deb::S3::Manifest
11
11
  attr_accessor :component
12
12
  attr_accessor :cache_control
13
13
  attr_accessor :architecture
14
+ attr_accessor :fail_if_exists
14
15
 
15
16
  attr_accessor :files
16
17
 
@@ -24,10 +25,11 @@ class Deb::S3::Manifest
24
25
  @architecture = nil
25
26
  @files = {}
26
27
  @cache_control = ""
28
+ @fail_if_exists = false
27
29
  end
28
30
 
29
31
  class << self
30
- def retrieve(codename, component, architecture, cache_control)
32
+ def retrieve(codename, component, architecture, cache_control, fail_if_exists)
31
33
  m = if s = Deb::S3::Utils.s3_read("dists/#{codename}/#{component}/binary-#{architecture}/Packages")
32
34
  self.parse_packages(s)
33
35
  else
@@ -38,6 +40,7 @@ class Deb::S3::Manifest
38
40
  m.component = component
39
41
  m.architecture = architecture
40
42
  m.cache_control = cache_control
43
+ m.fail_if_exists = fail_if_exists
41
44
  m
42
45
  end
43
46
 
@@ -52,6 +55,9 @@ class Deb::S3::Manifest
52
55
  end
53
56
 
54
57
  def add(pkg, preserve_versions, needs_uploading=true)
58
+ if self.fail_if_exists
59
+ packages.each { |p| raise AlreadyExistsError, "package #{pkg.name}_#{pkg.full_version} already exists with different filename (#{p.url_filename})" if p.name == pkg.name && p.full_version == pkg.full_version && File.basename(p.url_filename) != File.basename(pkg.filename) }
60
+ end
55
61
  if preserve_versions
56
62
  packages.delete_if { |p| p.name == pkg.name && p.full_version == pkg.full_version }
57
63
  else
@@ -69,7 +75,7 @@ class Deb::S3::Manifest
69
75
  if p.name != pkg
70
76
  p
71
77
  # Also include the packages not matching a specified version
72
- elsif (!versions.nil? and p.name == pkg and !versions.include?(p.version) and !versions.include?("#{p.version}-#{p.iteration}"))
78
+ elsif (!versions.nil? and p.name == pkg and !versions.include?(p.version) and !versions.include?("#{p.version}-#{p.iteration}") and !versions.include?(p.full_version))
73
79
  p
74
80
  end
75
81
  }
@@ -88,7 +94,7 @@ class Deb::S3::Manifest
88
94
  # store any packages that need to be stored
89
95
  @packages_to_be_upload.each do |pkg|
90
96
  yield pkg.url_filename if block_given?
91
- s3_store(pkg.filename, pkg.url_filename, 'application/octet-stream; charset=binary')
97
+ s3_store(pkg.filename, pkg.url_filename, 'application/octet-stream; charset=binary', self.cache_control, self.fail_if_exists)
92
98
  end
93
99
 
94
100
  # generate the Packages file
@@ -97,7 +103,7 @@ class Deb::S3::Manifest
97
103
  pkgs_temp.close
98
104
  f = "dists/#{@codename}/#{@component}/binary-#{@architecture}/Packages"
99
105
  yield f if block_given?
100
- s3_store(pkgs_temp.path, f, 'binary/octet-stream; charset=binary', self.cache_control)
106
+ s3_store(pkgs_temp.path, f, 'text/plain; charset=UTF-8', self.cache_control)
101
107
  @files["#{@component}/binary-#{@architecture}/Packages"] = hashfile(pkgs_temp.path)
102
108
  pkgs_temp.unlink
103
109
 
@@ -56,7 +56,7 @@ class Deb::S3::Package
56
56
  end
57
57
 
58
58
  def extract_control(package)
59
- if system("which dpkg &> /dev/null")
59
+ if system("which dpkg > /dev/null 2>&1")
60
60
  `dpkg -f #{package}`
61
61
  else
62
62
  # ar fails to find the control.tar.gz tarball within the .deb
@@ -98,7 +98,7 @@ class Deb::S3::Release
98
98
  release_tmp.puts self.generate
99
99
  release_tmp.close
100
100
  yield self.filename if block_given?
101
- s3_store(release_tmp.path, self.filename, 'binary/octet-stream; charset=binary', self.cache_control)
101
+ s3_store(release_tmp.path, self.filename, 'text/plain; charset=UTF-8', self.cache_control)
102
102
 
103
103
  # sign the file, if necessary
104
104
  if Deb::S3::Utils.signing_key
@@ -130,7 +130,7 @@ class Deb::S3::Release
130
130
  def validate_others
131
131
  to_apply = []
132
132
  self.components.each do |comp|
133
- %w(amd64 i386).each do |arch|
133
+ %w(amd64 i386 armhf).each do |arch|
134
134
  next if self.files.has_key?("#{comp}/binary-#{arch}/Packages")
135
135
 
136
136
  m = Deb::S3::Manifest.new
@@ -22,6 +22,7 @@ module Deb::S3::Utils
22
22
  def encryption= v; @encryption = v end
23
23
 
24
24
  class SafeSystemError < RuntimeError; end
25
+ class AlreadyExistsError < RuntimeError; end
25
26
 
26
27
  def safesystem(*args)
27
28
  success = system(*args)
@@ -63,7 +64,7 @@ module Deb::S3::Utils
63
64
  Deb::S3::Utils.s3.buckets[Deb::S3::Utils.bucket].objects[s3_path(path)].read
64
65
  end
65
66
 
66
- def s3_store(path, filename=nil, content_type='application/octet-stream; charset=binary', cache_control=nil)
67
+ def s3_store(path, filename=nil, content_type='application/octet-stream; charset=binary', cache_control=nil, fail_if_exists=false)
67
68
  filename = File.basename(path) unless filename
68
69
  obj = Deb::S3::Utils.s3.buckets[Deb::S3::Utils.bucket].objects[s3_path(filename)]
69
70
 
@@ -72,6 +73,7 @@ module Deb::S3::Utils
72
73
  # check if the object already exists
73
74
  if obj.exists?
74
75
  return if (file_md5.to_s == obj.etag.gsub('"', '') or file_md5.to_s == obj.metadata['md5'])
76
+ raise AlreadyExistsError, "file #{obj.public_url} already exists with different contents" if fail_if_exists
75
77
  end
76
78
 
77
79
  options = {:acl => Deb::S3::Utils.access_policy, :content_type => content_type, :metadata => {'md5' => file_md5}}
metadata CHANGED
@@ -1,71 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deb-s3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.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: 2015-03-12 00:00:00.000000000 Z
11
+ date: 2016-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.18.0
19
+ version: 0.19.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.18.0
26
+ version: 0.19.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: aws-sdk
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.18'
33
+ version: '1.66'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.18'
40
+ version: '1.66'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '5'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '11'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '11'
69
69
  description: Easily create and manage an APT repository on S3.
70
70
  email: ken@invalidlogic.com
71
71
  executables:
@@ -73,18 +73,20 @@ executables:
73
73
  extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
+ - README.md
77
+ - bin/deb-s3
78
+ - lib/deb/s3.rb
79
+ - lib/deb/s3/cli.rb
80
+ - lib/deb/s3/lock.rb
81
+ - lib/deb/s3/manifest.rb
82
+ - lib/deb/s3/package.rb
76
83
  - lib/deb/s3/release.rb
77
84
  - lib/deb/s3/templates/package.erb
78
85
  - lib/deb/s3/templates/release.erb
79
- - lib/deb/s3/package.rb
80
- - lib/deb/s3/cli.rb
81
- - lib/deb/s3/manifest.rb
82
86
  - lib/deb/s3/utils.rb
83
- - lib/deb/s3.rb
84
- - bin/deb-s3
85
- - README.md
86
87
  homepage: http://invalidlogic.com/
87
- licenses: []
88
+ licenses:
89
+ - MIT
88
90
  metadata: {}
89
91
  post_install_message:
90
92
  rdoc_options: []
@@ -92,17 +94,17 @@ require_paths:
92
94
  - lib
93
95
  required_ruby_version: !ruby/object:Gem::Requirement
94
96
  requirements:
95
- - - '>='
97
+ - - ">="
96
98
  - !ruby/object:Gem::Version
97
- version: '0'
99
+ version: 1.9.3
98
100
  required_rubygems_version: !ruby/object:Gem::Requirement
99
101
  requirements:
100
- - - '>='
102
+ - - ">="
101
103
  - !ruby/object:Gem::Version
102
104
  version: '0'
103
105
  requirements: []
104
106
  rubyforge_project:
105
- rubygems_version: 2.0.14
107
+ rubygems_version: 2.4.5.1
106
108
  signing_key:
107
109
  specification_version: 4
108
110
  summary: Easily create and manage an APT repository on S3.