cloudapp-power-cli 1.0.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.
Files changed (5) hide show
  1. data/Gemfile +3 -0
  2. data/README.md +77 -0
  3. data/bin/cloudapp +506 -0
  4. data/cloudapp-power-cli.gemspec +17 -0
  5. metadata +62 -0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # cloudapp-power-cli
2
+
3
+ A powerful CLI for [CloudApp](http://getcloudapp.com/) written in Ruby, formerly named *cloudapp-cli* that makes the complete CloudApp API available on command line.
4
+
5
+ **[Works with regenwolken](https://github.com/posativ/regenwolken)**
6
+
7
+ ## Installation
8
+
9
+ Install it via:
10
+
11
+ gem install cloudapp-power-cli
12
+
13
+ ## Usage
14
+
15
+ Register:
16
+
17
+ cloudapp register us3r passw0rd
18
+
19
+ Configuration of persistent login data:
20
+
21
+ cloudapp login us3r passw0rd
22
+
23
+ (Note: If you tell it so e.g. via the above command or during `cloudapp register`, the cli will save your login data to '~/.cloudapp-cli' to prevent you from specifing it on every call.)
24
+
25
+ Use per-call login data (**no** login data will be written to disk at all):
26
+
27
+ cloudapp -u user:pwd command...
28
+
29
+ Other Operations:
30
+
31
+ cloudapp account # show your account details (-v shows even more)
32
+
33
+ cloudapp list # list first page of drops (5 per page)
34
+
35
+ cloudapp list -p 2 -n 10 # list second page of drops with 10 drops per page
36
+
37
+ cloudapp list -a # list all your drops (first 100 ^^)
38
+
39
+ cloudapp upload drumandbass.ogg # upload a file
40
+
41
+ cloudapp upload --private topsecret.pdf # upload a file as private
42
+
43
+ cloudapp bookmark heise http://heise.de/ # creates an alias
44
+
45
+ cloudapp bookmark http://google.com/ # the url will be the alias' name
46
+
47
+ cloudapp download dZ69 # download a drop to current directory
48
+
49
+ cloudapp view dZ69 # view details of a drop (more details with -v)
50
+
51
+ cloudapp change username thenewname # changes e-mail and updates the local credentials, too
52
+
53
+ cloudapp change password thenewpwd # changes password and updates the local credentials, too
54
+
55
+ cloudapp change privacy private # change default security of _new_ drops to private (public is the other option)
56
+
57
+ cloudapp private dZ69 # change a drop to private
58
+
59
+ cloudapp rename dZ69 UserGuide.txt # rename a drop
60
+
61
+ cloudapp delete dZ69 # delete a drop
62
+
63
+ cloudapp recover dZ69 # recover a drop
64
+
65
+ cloudapp search Screenshot # list all items with "Screenshot" in name or redirect url (for bookmarks)
66
+
67
+ cloudapp search "^.*rb$" # since the term is effectively a regex you could do many magic for filtering
68
+
69
+ cloudapp gc-view GIFT1234 # view gift card details
70
+
71
+ cloudapp gc-redeem GIFT1234 # redeem a gift card
72
+
73
+ Note: If you want to specify arguments (e.g. item IDs or file names) with a leading dash, the Option Parser will claim about an unknown option - than you should insert an double-dash followed by a space in front of the argument with the leading dash.
74
+
75
+ ## Credits
76
+
77
+ To [posativ](https://github.com/posativ) for testing and bug reporting!
data/bin/cloudapp ADDED
@@ -0,0 +1,506 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'date'
5
+ require 'optparse'
6
+ require 'uri'
7
+ require 'yaml'
8
+
9
+ require 'rubygems'
10
+ require 'cloudapp_api'
11
+
12
+ LIST_TIME_FMT = '%d.%m.%y %H:%M'
13
+ VIEW_TIME_FMT = '%d. %b %Y %H:%M:%S'
14
+ ACC_TIME_FMT = VIEW_TIME_FMT
15
+
16
+ ITEM_TYPES = [:image, :bookmark, :text, :archive, :audio, :video, :unknown]
17
+
18
+ # just a guess to make output format prettier
19
+ HASH_LENGTH = 10
20
+
21
+ # low level errors
22
+ LOW_ERRORS = [
23
+ #TimeoutError, EOFError, Errno::ETIMEDOUT, Errno::ECONNREFUSED,
24
+ Errno::EPIPE, Errno::EINVAL
25
+ ]
26
+
27
+ module CloudApp
28
+ class Drop
29
+ def slug
30
+ url.split(/\//).last
31
+ end
32
+
33
+ # patch for cloudapp_api supporting custom domains
34
+ def self.find(id)
35
+ res = get "http://#{$domain}/#{id}"
36
+ res.ok? ? Drop.new(res) : bad_response(res)
37
+ end
38
+ end
39
+ end
40
+
41
+ class Module
42
+ def subclasses
43
+ classes = []
44
+ ObjectSpace.each_object do |klass|
45
+ next unless Module === klass
46
+ classes << klass if self > klass
47
+ end
48
+ classes
49
+ end
50
+ end
51
+
52
+ class String
53
+ def json2time
54
+ # offset should be zero since this is assumed to be UTC
55
+ dt = DateTime.strptime(self, "%Y-%m-%dT%H:%M:%SZ")
56
+ Time.utc(dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec)
57
+ # "2011-09-24T08:49:14Z"
58
+ end
59
+
60
+ def localtime
61
+ json2time.localtime
62
+ end
63
+
64
+ def json2fmtlocaltime(fmt)
65
+ json2time.localtime.strftime(fmt)
66
+ end
67
+ end
68
+
69
+ class Time
70
+ # HACK: this is a hack to ensure older httparty then 0.8.0 will work too
71
+ def json2fmtlocaltime(fmt)
72
+ localtime.strftime(fmt)
73
+ end
74
+ end
75
+
76
+ def args?(n=2)
77
+ if ARGV.length < n
78
+ puts @opts
79
+ abort "Wrong number of arguments given!"
80
+ end
81
+ end
82
+
83
+ # only use bold colors (1;) for those on black on white screens
84
+ def cyan; if @options[:colors]; "\e[1;36m" else "" end end
85
+ def green; if @options[:colors]; "\e[1;32m" else "" end end
86
+ def red; if @options[:colors]; "\e[1;31m" else "" end end
87
+ def rst; if @options[:colors]; "\e[0m" else "" end end
88
+
89
+ def print_long(drop)
90
+ list_flags = ''
91
+ if drop.private; list_flags += [green, 'p', rst].join else list_flags += '-' end
92
+ if !drop.deleted_at.nil?; list_flags += [red, 'd', rst].join else list_flags += '-' end
93
+ if not drop.redirect_url.nil?
94
+ list_name = ["-> ", cyan, drop.redirect_url, rst].join
95
+ # prepend the drop's name, if it's different from the url
96
+ # (which should only happen if you specify it by hand)
97
+ list_name = [cyan, drop.name, rst, " ", list_name].join if drop.name != drop.redirect_url
98
+ elsif drop.item_type == 'image'
99
+ list_name = [green, drop.name, rst].join
100
+ else
101
+ list_name = drop.name
102
+ end
103
+ format("%-#{HASH_LENGTH}s %s %-9s %-10s %-#{8 + $domain.length + HASH_LENGTH}s %s",
104
+ drop.slug, list_flags, drop.item_type,
105
+ drop.updated_at.json2fmtlocaltime(LIST_TIME_FMT),
106
+ drop.url, list_name)
107
+ end
108
+
109
+ def fetch(url, limit = 3)
110
+ raise ArgumentError, 'HTTP redirection too deep' if limit == 0
111
+
112
+ response = Net::HTTP.get_response(URI.parse(url))
113
+ case response
114
+ when Net::HTTPSuccess then response
115
+ when Net::HTTPRedirection then fetch(response['location'], limit-1)
116
+ else response.error! end
117
+ end
118
+
119
+ def load_config
120
+ if @options.key?(:creds)
121
+ u,p = @options[:creds].split(':')
122
+ return {'username' => u, 'password' => p}
123
+ end
124
+ if !File.exists?($config_file)
125
+ abort "Login required! Please save your login via ´login´ or use ´-u´ option."
126
+ end
127
+ YAML.load_file($config_file)
128
+ end
129
+
130
+ def save_config(config)
131
+ if File.exists?($config_file)
132
+ config = YAML.load_file($config_file).merge(config)
133
+ end
134
+ File.open($config_file, 'w+') do |f| YAML.dump(config, f) end
135
+ end
136
+
137
+ def load_service_url
138
+ return @options[:service_url] if @options.key?(:service_url)
139
+ if File.exists?($config_file)
140
+ config = YAML.load_file($config_file)
141
+ return config['service_url'] if config['service_url']
142
+ end
143
+ "http://my.cl.ly"
144
+ end
145
+
146
+ # main starts here
147
+
148
+ @options = {:colors => true}
149
+
150
+ @opts = OptionParser.new do |opts|
151
+ opts.banner = "Usage: cloudapp [options] command [arguments]\n\n"
152
+ opts.banner += "Commands:\n"
153
+ opts.banner += " register USERNAME PASSWORD\n"
154
+ opts.banner += " login [USERNAME] [PASSWORD]\n"
155
+ opts.banner += " service [URL]\n"
156
+ opts.banner += " change (username|password|privacy) NEWVALUE\n"
157
+ opts.banner += " account\n"
158
+ opts.banner += " list\n"
159
+ opts.banner += " upload FILE\n"
160
+ opts.banner += " bookmark [NAME] LINK\n"
161
+ opts.banner += " download SLUG\n"
162
+ opts.banner += " view SLUG\n"
163
+ opts.banner += " delete SLUG\n"
164
+ opts.banner += " recover SLUG\n"
165
+ opts.banner += " rename SLUG NAME\n"
166
+ opts.banner += " private SLUG\n"
167
+ opts.banner += " public SLUG\n"
168
+ opts.banner += " search NAME\n"
169
+ opts.banner += " gc-view CODE\n"
170
+ opts.banner += " gc-redeem CODE\n"
171
+ opts.banner += " auto-purge HOURS\n"
172
+ opts.banner += "\nOptions:\n"
173
+
174
+ opts.on('-u CREDS', 'Specify credentials as USER:PASS') do |u| @options[:creds] = u end
175
+ opts.on('-p PAGE', Integer, 'Show page with nr. PAGE in `list` (default: 1)') do |p| @options[:page] = p if p > 0 end
176
+ opts.on('-n ITEMSPP', Integer, 'Show ITEMSPP items per page in `list` (default: 5)') do |n| @options[:per_page] = n if n > 0 end
177
+ opts.on('-t TYPE', '--type TYPE', ITEM_TYPES, 'Show only items of TYPE in `list`') do |t| @options[:type] = t end
178
+ opts.on('-s SOURCE', '--source SOURCE', 'Show only items from SOURCE in ´list´') do |s| @options[:source] = s end
179
+ opts.on('-d', '--deleted', 'Show deleted items in ´list´ too') do |d| @options[:deleted] = true end
180
+ opts.on('-a', '--all', 'Show all items of an account at once in `list` (overrides -p, -n)') do |a| @options[:all] = true end
181
+ opts.on('--private', 'Do private upload') do |priv| @options[:private] = true end
182
+ opts.on('--public', 'Do public upload') do |pub| @options[:public] = true end
183
+ opts.on('--disable-colors', 'Disables colors') do |dis| @options[:colors] = false end
184
+ opts.on('--service URL', 'Specify service URL') do |url| @options[:service_url] = url end
185
+ opts.on('-y', '--yes', 'Answer all questions with yes (useful e.g. in scripts)') do |y| @options[:yes] = true end
186
+ opts.on('-v', '--verbose', 'Enables verbose mode on some commands (currently view, account)') do |v| @options[:verbose] = true end
187
+ opts.on('-h', '-?', '--help', 'Display this screen') do
188
+ puts opts
189
+ exit
190
+ end
191
+ end
192
+
193
+ @opts.parse!
194
+
195
+ $config_file = File.join(ENV['HOME'], '.cloudapp-cli')
196
+
197
+ # HACK: inject our service url as HTTParty base_uri into
198
+ # all subclasses of CloudApp::Base
199
+ service_url = load_service_url
200
+ CloudApp::Base.subclasses.each do |c|
201
+ c.base_uri service_url
202
+ end
203
+
204
+ case ARGV.first
205
+ when nil
206
+ puts @opts
207
+ exit
208
+ when 'login'
209
+ if ARGV[1] and ARGV[2]
210
+ client = CloudApp::Client.new
211
+ client.authenticate(ARGV[1], ARGV[2])
212
+ save = true
213
+ begin
214
+ CloudApp::Account.find
215
+ rescue => ex
216
+ save = false
217
+ end
218
+ if !save
219
+ if @options[:yes]
220
+ puts "Saving login though it seems incorrect."
221
+ save = true
222
+ elsif $stdin.tty?
223
+ print "Your new login seems to be incorrect, save anyways? (y/n): "
224
+ answer = $stdin.gets
225
+ case answer
226
+ when "y\n"
227
+ save = true
228
+ else
229
+ puts "You didn't answer with 'y', done nothing."
230
+ end
231
+ end
232
+ end
233
+ if save
234
+ # set
235
+ save_config({'username' => ARGV[1], 'password' => ARGV[2]})
236
+ puts 'Account login saved.'
237
+ end
238
+ else
239
+ # get
240
+ config = load_config
241
+ puts "Current login:"
242
+ puts " Username: #{config['username']}"
243
+ puts " Password: #{config['password']}"
244
+ end
245
+ exit 0
246
+ when 'register'
247
+ args? 3
248
+ begin
249
+ acc = CloudApp::Account.create :email => ARGV[1], :password => ARGV[2], :accept_tos => true
250
+ rescue CloudApp::ResponseError => ex
251
+ abort "Username already registered!" if ex.code == 406
252
+ abort "Server rejected request because of invalid username/email or password!" if ex.code = 422
253
+ abort "Registration failed (#{ex.to_s}) - may be a bug"
254
+ rescue => ex
255
+ abort "Registration failed (#{ex.to_s})"
256
+ end
257
+ puts "Successfully registered!\nYour account has been activated instantly, happy clouding!" if not acc.activated_at.nil?
258
+ puts "Successfully registered but your account isn't currently activated." if acc.activated_at.nil?
259
+ if @options[:yes]
260
+ puts "Saving login to local login storage #{$config_file}."
261
+ save_config({'username' => ARGV[1], 'password' => ARGV[2]})
262
+ elsif $stdin.tty?
263
+ if File.exists?($config_file)
264
+ print "Do you want to overwrite your local login storage #{$config_file}? (y/n): "
265
+ else
266
+ print "Do you want to save your login to #{$config_file} for automated use? (y/n): "
267
+ end
268
+ answer = $stdin.gets
269
+ case answer
270
+ when "y\n"
271
+ save_config({'username' => ARGV[1], 'password' => ARGV[2]})
272
+ puts "Account registered and login saved."
273
+ else
274
+ puts "You didn't answer with 'y', done nothing."
275
+ end
276
+ end
277
+ exit 0
278
+ when 'service'
279
+ if ARGV[1]
280
+ uri = ARGV[1]
281
+ uri = 'http://' + uri if URI.parse(ARGV[1]).scheme.nil?
282
+ if (uri =~ URI::regexp).nil?
283
+ puts "Your new service is not a valid URL, done nothing."
284
+ else
285
+ # set
286
+ save_config({'service_url' => uri})
287
+ puts "New service saved."
288
+ end
289
+ else
290
+ # get
291
+ puts "Current service: #{service_url}"
292
+ end
293
+ exit 0
294
+ end
295
+
296
+ config = load_config
297
+
298
+ @client = CloudApp::Client.new
299
+
300
+ # all following commands need authentication
301
+ @client.authenticate(config['username'], config['password'])
302
+ begin
303
+ @acc = CloudApp::Account.find
304
+ $domain = @acc.domain.nil? ? 'cl.ly' : @acc.domain
305
+ rescue CloudApp::ResponseError => ex
306
+ abort "Incorrect login!" if ex.code == 403
307
+ abort "Your account hasn't been activated!" if ex.code == 409
308
+ abort "Authentication unexpectedly failed: #{ex.to_s}\n #{ex.backtrace.join("\n ")}"
309
+ end
310
+
311
+ begin
312
+ case ARGV.first
313
+ when 'list'
314
+ topt = {:page => 1, :per_page => 5}
315
+
316
+ topt[:page] = @options[:page] if @options.key?(:page)
317
+ topt[:per_page] = @options[:per_page] if @options.key?(:per_page)
318
+ # HACK: 100 items should be enough for everyone!
319
+ topt[:page], topt[:per_page] = 1, 100 if @options[:all]
320
+ topt[:type] = @options[:type] if @options.key?(:type)
321
+ topt[:deleted] = @options[:deleted] if @options.key?(:deleted)
322
+ topt[:source] = @options[:source] if @options.key?(:source)
323
+
324
+ # caption
325
+ puts format("%-#{HASH_LENGTH}s %s", "SLUG", "p=private, d=deleted")
326
+
327
+ @client.drops(topt).each do |drop|
328
+ puts print_long(drop)
329
+ end
330
+
331
+ when 'view'
332
+ args?
333
+ drop = @client.drop ARGV[1]
334
+ puts "Details for #{drop.slug}:"
335
+ puts " Name: #{drop.name}"
336
+ puts " Type: #{drop.item_type}"
337
+ puts " URL: #{drop.url}"
338
+ puts " Privacy: #{drop.private ? 'private' : 'public'}"
339
+ puts " Views: #{drop.view_counter}"
340
+ puts " Redirect: #{drop.redirect_url}" if !drop.redirect_url.nil?
341
+ puts " Created: #{drop.created_at.json2fmtlocaltime(VIEW_TIME_FMT)}"
342
+ puts " Updated: #{drop.updated_at.json2fmtlocaltime(VIEW_TIME_FMT)}"
343
+ puts " Deleted: #{drop.deleted_at.json2fmtlocaltime(VIEW_TIME_FMT)}" if !drop.deleted_at.nil?
344
+ puts " Href: #{drop.href}" if @options[:verbose]
345
+ puts " Source: #{drop.source}" if @options[:verbose]
346
+
347
+ when 'change'
348
+ args? 3
349
+ case ARGV[1]
350
+ when 'username'
351
+ CloudApp::Account.update :email => ARGV[2], :current_password => config['password']
352
+ # only update local credential storage when current creds *not* given via command line
353
+ if @options[:creds].nil?
354
+ save_config({'username' => ARGV[2]})
355
+ puts "Login changed, updated #{$config_file}."
356
+ end
357
+ when 'password'
358
+ CloudApp::Account.update :password => ARGV[2], :current_password => config['password']
359
+ # only update local credential storage when current creds *not* given via command line
360
+ if @options[:creds].nil?
361
+ save_config({'password' => ARGV[2]})
362
+ puts "Login changed, updated #{$config_file}."
363
+ end
364
+ when 'privacy'
365
+ CloudApp::Account.update :private_items => (ARGV[2] == 'private')
366
+ end
367
+
368
+ when 'account'
369
+ # use @acc and stats
370
+ stats = CloudApp::Account.stats
371
+ puts "Account '#{config[:username]}':"
372
+ puts " ID: #{@acc.id}"
373
+ puts " Username: #{@acc.email}"
374
+ puts " Default privacy: #{@acc.private_items ? 'private' : 'public'}"
375
+ puts " Subscription: #{@acc.subscribed ? 'yes' : 'no'}" +
376
+ (@acc.subscribed ? " (expires: #{@acc.subscription_expires_at})" : '')
377
+ puts " Domain: #{@acc.domain}"
378
+ puts " Domain homepage: #{@acc.domain_home_page}"
379
+ puts " Created: #{@acc.created_at.json2fmtlocaltime(ACC_TIME_FMT)}"
380
+ puts " Updated: #{@acc.updated_at.json2fmtlocaltime(ACC_TIME_FMT)}" if @options[:verbose]
381
+ puts " Activated: #{@acc.activated_at.json2fmtlocaltime(ACC_TIME_FMT)}" if @options[:verbose]
382
+ puts
383
+ puts "Stats:"
384
+ puts " Nr. of items: #{stats[:items]}"
385
+ puts " Nr. of total views: #{stats[:views]}"
386
+
387
+ when 'upload'
388
+ args?
389
+ # TODO: Notify the user when exceeding upload limits
390
+ begin
391
+ if @options[:private]
392
+ drop = @client.upload ARGV[1], :private => true
393
+ elsif @options[:public]
394
+ drop = @client.upload ARGV[1], :private => false
395
+ else
396
+ drop = @client.upload ARGV[1]
397
+ end
398
+ puts "#{drop.url}"
399
+ rescue *LOW_ERRORS => ex
400
+ abort "Upload failed maybe due to too large file or server limits!"
401
+ end
402
+
403
+ when 'bookmark'
404
+ if ARGV.length == 2
405
+ drop = @client.bookmark ARGV[1], ARGV[1]
406
+ puts "Created bookmark #{drop.slug}, URL:\n#{drop.url}"
407
+ else
408
+ args? 3
409
+ drop = @client.bookmark ARGV[1], ARGV[2]
410
+ puts "Created bookmark #{drop.slug}, URL:\n#{drop.url}"
411
+ end
412
+
413
+ when 'private'
414
+ args?
415
+ drop = @client.privacy ARGV[1], true
416
+ puts "#{drop.slug} is now private"
417
+
418
+ when 'public'
419
+ args?
420
+ drop = @client.privacy ARGV[1], false
421
+ puts "#{drop.slug} is now public"
422
+
423
+ when 'delete','remove'
424
+ args?
425
+ drop = @client.delete ARGV[1]
426
+ puts "Moved #{drop.slug} into trash"
427
+
428
+ when 'recover'
429
+ args?
430
+ drop = @client.recover ARGV[1]
431
+ puts "Recovered #{drop.slug} from trash"
432
+
433
+ when 'rename'
434
+ args? 3
435
+ drop = @client.rename ARGV[1], ARGV[2]
436
+ puts "#{ARGV[1]} renamed to #{ARGV[2]}"
437
+
438
+ when 'download'
439
+ args?
440
+ drop = @client.drop ARGV[1]
441
+ if drop.item_type == 'bookmark'
442
+ abort "Cannot download bookmarks!"
443
+ end
444
+ # File name filtering - this build up from a union of NTFS, FAT, HFS, ext3
445
+ file_name = drop.name.gsub(/[\x00\/\\:\*\?\"<>\|\^]/, '_')
446
+ if File.exists?(file_name)
447
+ abort "Target file '#{file_name}' already exists! Canceling..."
448
+ end
449
+ res = fetch(drop.content_url)
450
+ File.open(file_name, 'w') do |file|
451
+ file.write(res.body)
452
+ end
453
+ puts "Downloaded #{drop.slug} as '#{file_name}'."
454
+
455
+ when 'search'
456
+ args?
457
+ @client.drops({:page => 1, :per_page => 100}).each do |drop|
458
+ # check drop.name and drop.redirect_url
459
+ if drop.name.match(ARGV[1]) or (!drop.redirect_url.nil? and drop.redirect_url.match(ARGV[1]))
460
+ puts print_long(drop)
461
+ end
462
+ end
463
+
464
+ when 'gc-view'
465
+ args?
466
+ gift = CloudApp::GiftCard.find ARGV[1]
467
+ puts "Details for gift card #{gift.code}:"
468
+ puts " ID: #{gift.id}"
469
+ puts " Plan: #{gift.plan}"
470
+ puts " Months: #{gift.months}"
471
+ puts " Href: #{gift.href}"
472
+ puts " Created: #{gift.created_at.json2fmtlocaltime(VIEW_TIME_FMT)}"
473
+ puts " Updated: #{gift.updated_at.json2fmtlocaltime(VIEW_TIME_FMT)}" if @options[:verbose]
474
+ puts " Redeemed: #{gift.redeemed_at.json2fmtlocaltime(VIEW_TIME_FMT)}" if !gift.redeemed_at.nil?
475
+ puts " Effective: #{gift.effective_at.json2fmtlocaltime(VIEW_TIME_FMT)}" if !gift.effective_at.nil?
476
+ puts " Expires: #{gift.expires_at.json2fmtlocaltime(VIEW_TIME_FMT)}" if !gift.expires_at.nil?
477
+
478
+ when 'gc-redeem'
479
+ args?
480
+ gift = CloudApp::GiftCard.redeem ARGV[1]
481
+ puts "Redeemed gift card #{gift.code}"
482
+
483
+ when 'auto-purge'
484
+ args?
485
+ hours = ARGV[1].to_i
486
+ abort "Hours given are negative" if hours < 0
487
+ puts "Request to delete all items created more than #{hours} hours ago from now"
488
+ latest = Time.now - hours*60*60
489
+ @client.drops({:page => 1, :per_page => 1000}).each do |drop|
490
+ if drop.created_at.localtime < latest
491
+ puts "Deleting #{drop.slug}"
492
+ @client.delete drop.slug
493
+ end
494
+ end
495
+ puts "Done"
496
+
497
+ else
498
+ puts @opts
499
+ abort "Unknown command!"
500
+ end
501
+ rescue CloudApp::ResponseError => ex
502
+ abort "Item not found!" if ex.code == 404
503
+ abort "File too large! (#{ex.to_s})" if ex.code == 413
504
+ abort "Your account hasn't been activated!" if ex.code == 409
505
+ abort "#{ARGV.first} unexpectedly failed: #{ex.to_s}\n #{ex.backtrace.join("\n ")}"
506
+ end
@@ -0,0 +1,17 @@
1
+
2
+ Gem::Specification.new do |s|
3
+ s.name = "cloudapp-power-cli"
4
+ s.version = "1.0.0"
5
+ s.summary = "A powerful CLI for CloudApp written in Ruby."
6
+ s.description = "A powerful CLI for CloudApp that makes the complete CloudApp API available on command line and works with Regenwolken."
7
+ s.author = "Christian Nicolai"
8
+ s.email = "cn@mycrobase.de"
9
+ s.license = "Apache License Version 2.0"
10
+ s.homepage = "https://github.com/cmur2/cloudapp-power-cli"
11
+
12
+ s.files = `git ls-files`.split($/)
13
+ s.executables = ["cloudapp"]
14
+ s.require_paths = ["lib"]
15
+
16
+ s.add_runtime_dependency "cloudapp_api"
17
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudapp-power-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Christian Nicolai
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-29 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cloudapp_api
16
+ requirement: &79873160 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *79873160
25
+ description: A powerful CLI for CloudApp that makes the complete CloudApp API available
26
+ on command line and works with Regenwolken.
27
+ email: cn@mycrobase.de
28
+ executables:
29
+ - cloudapp
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - Gemfile
34
+ - README.md
35
+ - bin/cloudapp
36
+ - cloudapp-power-cli.gemspec
37
+ homepage: https://github.com/cmur2/cloudapp-power-cli
38
+ licenses:
39
+ - Apache License Version 2.0
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 1.8.6
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: A powerful CLI for CloudApp written in Ruby.
62
+ test_files: []