cloudapp 2.0.0.beta.4 → 2.0.0.beta.5

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 (50) hide show
  1. data/Gemfile.lock +12 -19
  2. data/README.md +60 -6
  3. data/Rakefile +1 -19
  4. data/bin/cloudapp +48 -0
  5. data/cloudapp.gemspec +11 -42
  6. data/lib/cloudapp/authorized.rb +14 -0
  7. data/lib/cloudapp/collection_json.rb +86 -3
  8. data/lib/cloudapp/credentials.rb +115 -0
  9. data/lib/cloudapp/service.rb +43 -146
  10. data/lib/cloudapp.rb +1 -3
  11. data/man/cloudapp.1 +100 -0
  12. data/man/cloudapp.1.html +157 -0
  13. data/man/cloudapp.1.ronn +56 -0
  14. metadata +24 -69
  15. data/CHANGELOG.md +0 -34
  16. data/lib/cloudapp/authorized_representation.rb +0 -17
  17. data/lib/cloudapp/collection_json/item.rb +0 -20
  18. data/lib/cloudapp/collection_json/representation.rb +0 -74
  19. data/lib/cloudapp/collection_json/template.rb +0 -17
  20. data/lib/cloudapp/collection_json/tint.rb +0 -11
  21. data/lib/cloudapp/drop.rb +0 -37
  22. data/lib/cloudapp/drop_collection.rb +0 -37
  23. data/spec/cassettes/account_token.yml +0 -88
  24. data/spec/cassettes/create_bookmark.yml +0 -132
  25. data/spec/cassettes/create_bookmark_with_name.yml +0 -133
  26. data/spec/cassettes/create_bookmark_with_privacy.yml +0 -133
  27. data/spec/cassettes/list_drops.yml +0 -87
  28. data/spec/cassettes/list_drops_with_bad_token.yml +0 -45
  29. data/spec/cassettes/list_drops_with_filter.yml +0 -129
  30. data/spec/cassettes/list_drops_with_limit.yml +0 -129
  31. data/spec/cassettes/purge_drops.yml +0 -466
  32. data/spec/cassettes/setup_drops.yml +0 -620
  33. data/spec/cassettes/token_for_account.yml +0 -88
  34. data/spec/cassettes/token_for_account_with_bad_credentials.yml +0 -86
  35. data/spec/cassettes/upload_file.yml +0 -276
  36. data/spec/cassettes/upload_file_with_name.yml +0 -278
  37. data/spec/cassettes/upload_file_with_privacy.yml +0 -277
  38. data/spec/cassettes/view_drop.yml +0 -45
  39. data/spec/cloudapp/authorized_representation_spec.rb +0 -32
  40. data/spec/cloudapp/collection_json/item_spec.rb +0 -45
  41. data/spec/cloudapp/collection_json/representation_spec.rb +0 -118
  42. data/spec/cloudapp/collection_json/template_spec.rb +0 -53
  43. data/spec/cloudapp/drop_collection_spec.rb +0 -127
  44. data/spec/cloudapp/drop_spec.rb +0 -142
  45. data/spec/cloudapp/service_spec.rb +0 -335
  46. data/spec/helper.rb +0 -8
  47. data/spec/integration_spec.rb +0 -68
  48. data/spec/support/files/favicon.ico +0 -0
  49. data/spec/support/stub_class_or_module.rb +0 -22
  50. data/spec/support/vcr.rb +0 -24
data/Gemfile.lock CHANGED
@@ -1,22 +1,22 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cloudapp (2.0.0.beta.2)
4
+ cloudapp (2.0.0.beta.5)
5
5
  leadlight (~> 0.0.7)
6
+ netrc (~> 0.7.7)
6
7
  typhoeus (~> 0.3.3)
7
8
 
8
9
  GEM
9
10
  remote: http://rubygems.org/
10
11
  specs:
11
12
  addressable (2.2.8)
12
- crack (0.3.1)
13
- diff-lcs (1.1.3)
14
13
  fail-fast (1.0.0)
15
14
  faraday (0.8.1)
16
15
  multipart-post (~> 1.1)
17
16
  fattr (2.2.1)
18
17
  hookr (1.1.1)
19
18
  fail-fast (= 1.0.0)
19
+ hpricot (0.8.6)
20
20
  leadlight (0.0.7)
21
21
  addressable (~> 2.2.0)
22
22
  faraday (= 0.8.1)
@@ -29,21 +29,16 @@ GEM
29
29
  mime-types (1.19)
30
30
  multi_json (1.0.4)
31
31
  multipart-post (1.1.5)
32
- rake (0.9.2.2)
33
- rspec (2.11.0)
34
- rspec-core (~> 2.11.0)
35
- rspec-expectations (~> 2.11.0)
36
- rspec-mocks (~> 2.11.0)
37
- rspec-core (2.11.1)
38
- rspec-expectations (2.11.2)
39
- diff-lcs (~> 1.1.3)
40
- rspec-mocks (2.11.2)
32
+ mustache (0.99.4)
33
+ netrc (0.7.7)
34
+ rake (10.0.3)
35
+ rdiscount (1.6.8)
36
+ ronn (0.7.3)
37
+ hpricot (>= 0.8.2)
38
+ mustache (>= 0.7.0)
39
+ rdiscount (>= 1.5.8)
41
40
  typhoeus (0.3.3)
42
41
  mime-types
43
- vcr (2.0.1)
44
- webmock (1.8.9)
45
- addressable (>= 2.2.7)
46
- crack (>= 0.1.7)
47
42
 
48
43
  PLATFORMS
49
44
  ruby
@@ -51,6 +46,4 @@ PLATFORMS
51
46
  DEPENDENCIES
52
47
  cloudapp!
53
48
  rake
54
- rspec
55
- vcr (~> 2.0.0)
56
- webmock
49
+ ronn
data/README.md CHANGED
@@ -1,14 +1,68 @@
1
- # CloudApp Ruby Client [![Build Status](https://secure.travis-ci.org/cloudapp/cloudapp.png)](http://travis-ci.org/cloudapp/cloudapp)
1
+ # CloudApp CLI
2
2
 
3
- Interact with the [CloudApp API][] from Ruby.
3
+ Experience all the pleasures of sharing with [CloudApp][] from your terminal.
4
+
5
+ [cloudapp]: http://getcloudapp.com
4
6
 
5
- [cloudapp api]: http://developer.getcloudapp.com
6
7
 
7
8
  ## Requirements
8
9
 
9
- `cloudapp` requires Ruby 1.9.2 or greater.
10
+ `cloudapp` requires Ruby 1.9.2 or greater. Windows is not yet supported. If
11
+ you're willing to lend a hand, we'd love to officially support it.
12
+
13
+
14
+ ## Getting Started
15
+
16
+ ``` bash
17
+ $ gem install cloudapp --pre
18
+ $ cloudapp upload screenshot.png
19
+ $ cloudapp bookmark http://getcloudapp.com
20
+ ```
21
+
22
+ ## Commands
23
+
24
+ ### cloudapp upload
25
+
26
+ ``` bash
27
+ $ cloudapp upload screenshot.png
28
+ http://cl.ly/abc123
29
+ ```
30
+
31
+ ### cloudapp bookmark
32
+
33
+ ``` bash
34
+ $ cloudapp bookmark http://getcloudapp.com
35
+ http://cl.ly/abc123
36
+ ```
37
+
38
+ ## Wish List
39
+
40
+ A few simple commands to allow scripting and input from other Unix programs
41
+ would be ideal.
42
+
43
+ ### Phase: Next
44
+
45
+ - Share several files: `cloudapp upload *.png`
46
+ - Bookmark several links: `cloudapp bookmark http://douglasadams.com http://zombo.com`
47
+ - Handle bookmarks from STDIN: `pbpaste | cloudapp bookmark`
48
+ - Handle files from STDIN: `find *.png | cloudapp upload`
49
+ - Download a drop: `cloudapp download http://cl.ly/abc123`
50
+
51
+ ### Phase: Unstoppable
52
+
53
+ - Archive and share several files: `cloudapp upload --archive *.png`
54
+ - Encrypt and share a file: `cloudapp upload --encrypt launch_codes.txt`
55
+ - Download and decrypt and encrypted drop: `cloudapp download --key=def456 http://cl.ly/abc123`
56
+
57
+ ### Phase: World Domination
10
58
 
59
+ While we're dreaming, what could you do if `cloudapp` had a database of all your
60
+ drops? Bonus points for a light weight daemon that kept everything in sync at
61
+ all times.
11
62
 
12
- ## Usage
63
+ - Find all your screen shots: `cloudapp list /^screen ?shot.*\.png$/`
64
+ - Trash all your stale drops: `cloudapp delete --last-viewed="> 1 month ago"`
65
+ - See your drop views in real time: `cloudapp --tail`
13
66
 
14
- _Usage from Ruby is still a work in progress._
67
+ There's bound to be a better way to express some of these commands, but you get
68
+ the picture.
data/Rakefile CHANGED
@@ -37,24 +37,6 @@ def replace_header(head, header_name)
37
37
  head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
38
38
  end
39
39
 
40
- #############################################################################
41
- #
42
- # Standard tasks
43
- #
44
- #############################################################################
45
-
46
- require 'rspec'
47
- require 'rspec/core/rake_task'
48
-
49
- desc "Run all specs"
50
- task RSpec::Core::RakeTask.new('spec')
51
- task :default => "spec"
52
-
53
- desc 'Run non-integration specs'
54
- RSpec::Core::RakeTask.new('spec:unit') do |t|
55
- t.rspec_opts = "--tag ~integration"
56
- end
57
-
58
40
  #############################################################################
59
41
  #
60
42
  # Custom tasks (add your own tasks here)
@@ -79,7 +61,7 @@ task :release => :build do
79
61
  sh "git tag v#{version}"
80
62
  sh "git push origin master"
81
63
  sh "git push origin v#{version}"
82
- sh "gem push pkg/#{name}-#{version}.gem"
64
+ sh "gem push pkg/#{gem_file}"
83
65
  end
84
66
 
85
67
  desc "Build #{gem_file} into the pkg directory"
data/bin/cloudapp ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'cloudapp/credentials'
4
+ require 'cloudapp/service'
5
+
6
+ def service
7
+ CloudApp::Service.using_token Credentials.token
8
+ end
9
+
10
+ def error error
11
+ puts "ERROR: #{error}"
12
+ exit 1
13
+ end
14
+
15
+ def validate_url url
16
+ error 'URL missing' if url.nil?
17
+ error "#{ url } doesn't look like a valid URL" unless url =~ URI.regexp
18
+ end
19
+
20
+ def validate_file file
21
+ error "File doesn't exist" if file.is_a? Errno::ENOENT
22
+ error 'File missing' if file.nil? or file == STDIN
23
+ end
24
+
25
+
26
+ while service.root.unauthorized?
27
+ Credentials.new.ask_for_and_save_credentials
28
+ end
29
+
30
+ link = ARGV.delete('--direct') || ARGV.delete('-d') ? :embed : :canonical
31
+
32
+ case ARGV.shift
33
+ when 'bookmark'
34
+ link = :canonical # No such thing as an embed link for a bookmark.
35
+ url = ARGV.shift
36
+ validate_url url
37
+ puts service.bookmark(url).link(link)
38
+ when 'upload'
39
+ file = ARGF.file rescue $!
40
+ validate_file file
41
+ puts service.upload(file).link(link)
42
+ else
43
+ puts <<EOS
44
+ Usage:
45
+ cloudapp bookmark http://getcloudapp.com
46
+ cloudapp upload screenshot.png
47
+ EOS
48
+ end
data/cloudapp.gemspec CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'cloudapp'
16
- s.version = '2.0.0.beta.4'
17
- s.date = '2012-08-25'
16
+ s.version = '2.0.0.beta.5'
17
+ s.date = '2012-12-17'
18
18
  s.rubyforge_project = 'cloudapp'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -34,7 +34,7 @@ Gem::Specification.new do |s|
34
34
  s.require_paths = %w[lib]
35
35
 
36
36
  ## If your gem includes any executables, list them here.
37
- # s.executables = ["cloudapp"]
37
+ s.executables = ["cloudapp"]
38
38
 
39
39
  ## Specify any RDoc options here. You'll want to add your README and
40
40
  ## LICENSE files to the extra_rdoc_files list.
@@ -43,66 +43,35 @@ Gem::Specification.new do |s|
43
43
 
44
44
  ## List your runtime dependencies here. Runtime dependencies are those
45
45
  ## that are needed for an end user to actually USE your code.
46
+ s.add_dependency 'netrc', '~> 0.7.7'
46
47
  s.add_dependency 'leadlight', '~> 0.0.7'
47
48
  s.add_dependency 'typhoeus', '~> 0.3.3'
48
49
 
49
50
  ## List your development dependencies here. Development dependencies are
50
51
  ## those that are only needed during development
51
52
  s.add_development_dependency 'rake'
52
- s.add_development_dependency 'rspec'
53
- s.add_development_dependency 'vcr', '~> 2.0.0'
54
- s.add_development_dependency 'webmock'
53
+ s.add_development_dependency 'ronn'
55
54
 
56
55
  ## Leave this section as-is. It will be automatically generated from the
57
56
  ## contents of your Git repository via the gemspec task. DO NOT REMOVE
58
57
  ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
59
58
  # = MANIFEST =
60
59
  s.files = %w[
61
- CHANGELOG.md
62
60
  Gemfile
63
61
  Gemfile.lock
64
62
  MIT-LICENSE
65
63
  README.md
66
64
  Rakefile
65
+ bin/cloudapp
67
66
  cloudapp.gemspec
68
67
  lib/cloudapp.rb
69
- lib/cloudapp/authorized_representation.rb
68
+ lib/cloudapp/authorized.rb
70
69
  lib/cloudapp/collection_json.rb
71
- lib/cloudapp/collection_json/item.rb
72
- lib/cloudapp/collection_json/representation.rb
73
- lib/cloudapp/collection_json/template.rb
74
- lib/cloudapp/collection_json/tint.rb
75
- lib/cloudapp/drop.rb
76
- lib/cloudapp/drop_collection.rb
70
+ lib/cloudapp/credentials.rb
77
71
  lib/cloudapp/service.rb
78
- spec/cassettes/account_token.yml
79
- spec/cassettes/create_bookmark.yml
80
- spec/cassettes/create_bookmark_with_name.yml
81
- spec/cassettes/create_bookmark_with_privacy.yml
82
- spec/cassettes/list_drops.yml
83
- spec/cassettes/list_drops_with_bad_token.yml
84
- spec/cassettes/list_drops_with_filter.yml
85
- spec/cassettes/list_drops_with_limit.yml
86
- spec/cassettes/purge_drops.yml
87
- spec/cassettes/setup_drops.yml
88
- spec/cassettes/token_for_account.yml
89
- spec/cassettes/token_for_account_with_bad_credentials.yml
90
- spec/cassettes/upload_file.yml
91
- spec/cassettes/upload_file_with_name.yml
92
- spec/cassettes/upload_file_with_privacy.yml
93
- spec/cassettes/view_drop.yml
94
- spec/cloudapp/authorized_representation_spec.rb
95
- spec/cloudapp/collection_json/item_spec.rb
96
- spec/cloudapp/collection_json/representation_spec.rb
97
- spec/cloudapp/collection_json/template_spec.rb
98
- spec/cloudapp/drop_collection_spec.rb
99
- spec/cloudapp/drop_spec.rb
100
- spec/cloudapp/service_spec.rb
101
- spec/helper.rb
102
- spec/integration_spec.rb
103
- spec/support/files/favicon.ico
104
- spec/support/stub_class_or_module.rb
105
- spec/support/vcr.rb
72
+ man/cloudapp.1
73
+ man/cloudapp.1.html
74
+ man/cloudapp.1.ronn
106
75
  ]
107
76
  # = MANIFEST =
108
77
 
@@ -0,0 +1,14 @@
1
+ require 'leadlight'
2
+
3
+ module CloudApp
4
+ module Authorized
5
+ Tint = Leadlight::Tint.new 'authorized', status: [ :success, 401 ] do
6
+ extend CloudApp::Authorized::Representation
7
+ end
8
+
9
+ module Representation
10
+ def unauthorized?() __response__.status == 401 end
11
+ def authorized?() not unauthorized? end
12
+ end
13
+ end
14
+ end
@@ -1,3 +1,86 @@
1
- require 'cloudapp/collection_json/item'
2
- require 'cloudapp/collection_json/representation'
3
- require 'cloudapp/collection_json/template'
1
+ module CloudApp
2
+ module CollectionJson
3
+ Tint = Leadlight::Tint.new 'collection+json', status: [ :success, 401 ] do
4
+ match_content_type 'application/vnd.collection+json'
5
+ extend CloudApp::CollectionJson::Representation
6
+ end
7
+
8
+ module Representation
9
+ extend Forwardable
10
+
11
+ def self.extended representation
12
+ Collection.new(representation).links.each do |link|
13
+ representation.add_link link.href, link.rel
14
+ end
15
+ end
16
+
17
+ def fill_template attributes
18
+ collection.template.fill(attributes)
19
+ end
20
+
21
+ def collection
22
+ Collection.new(self)
23
+ end
24
+
25
+ def_delegators :collection, :template, :item
26
+
27
+ class Item < SimpleDelegator
28
+ def links
29
+ fetch('links', []).map {|link| Item.new(link) }
30
+ end
31
+
32
+ def link rel
33
+ links.find {|link| link.rel == rel.to_s }.href
34
+ end
35
+
36
+ def href() fetch('href') end
37
+ def rel() fetch('rel') end
38
+ def data
39
+ data = {}
40
+ fetch('data').each do |datum|
41
+ data[datum.fetch('name')] = datum.fetch('value')
42
+ end
43
+ data
44
+ end
45
+ end
46
+
47
+ class Collection < Item
48
+ def initialize representation
49
+ super representation.fetch('collection')
50
+ end
51
+
52
+ def template() Template.new(fetch('template'), href) end
53
+ def items
54
+ fetch('items').map {|item| Item.new(item) }
55
+ end
56
+
57
+ def item
58
+ items.first
59
+ end
60
+ end
61
+
62
+ class Template < Item
63
+ attr_reader :href
64
+
65
+ def initialize item, href
66
+ @href = href
67
+ super item
68
+ end
69
+
70
+ def enctype() fetch('enctype') end
71
+
72
+ def fill key, value
73
+ return self unless data.has_key?(key)
74
+ new_data = fetch('data').map {|datum|
75
+ if datum.fetch('name') == key
76
+ datum = datum.merge 'value' => value
77
+ end
78
+ datum
79
+ }
80
+ new_item = self.merge('data' => new_data)
81
+ Template.new new_item, href
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,115 @@
1
+ # Taken from the heroku gem.
2
+ # https://github.com/heroku/heroku/blob/master/lib/heroku/auth.rb
3
+ require 'netrc'
4
+
5
+ class Credentials
6
+ def self.token
7
+ new.credentials.last
8
+ end
9
+
10
+ def netrc_path
11
+ default = Netrc.default_path
12
+ encrypted = default + ".gpg"
13
+ if File.exists?(encrypted)
14
+ encrypted
15
+ else
16
+ default
17
+ end
18
+ end
19
+
20
+ def netrc
21
+ @netrc ||= begin
22
+ File.exists?(netrc_path) && Netrc.read(netrc_path)
23
+ rescue => error
24
+ if error.message =~ /^Permission bits for/
25
+ perm = File.stat(netrc_path).mode & 0777
26
+ abort("Permissions #{perm} for '#{netrc_path}' are too open. You should run `chmod 0600 #{netrc_path}` so that your credentials are NOT accessible by others.")
27
+ else
28
+ raise error
29
+ end
30
+ end
31
+ end
32
+
33
+ def credentials=(credentials) @credentials = credentials end
34
+ def credentials()
35
+ (@credentials ||= read_credentials) || ask_for_and_save_credentials
36
+ end
37
+
38
+ def read_credentials
39
+ # TODO: convert legacy credentials to netrc
40
+ # if File.exists?(legacy_credentials_path)
41
+ # @api, @client = nil
42
+ # @credentials = File.read(legacy_credentials_path).split("\n")
43
+ # write_credentials
44
+ # FileUtils.rm_f(legacy_credentials_path)
45
+ # end
46
+
47
+ # read netrc credentials if they exist
48
+ self.credentials = netrc['api.getcloudapp.com'] if netrc
49
+ end
50
+
51
+ def write_credentials
52
+ FileUtils.mkdir_p(File.dirname(netrc_path))
53
+ FileUtils.touch(netrc_path)
54
+ FileUtils.chmod(0600, netrc_path)
55
+ netrc['api.getcloudapp.com'] = credentials
56
+ netrc.save
57
+ end
58
+
59
+ def delete_credentials
60
+ # TODO: delete legacy credentials
61
+ # if File.exists?(legacy_credentials_path)
62
+ # FileUtils.rm_f(legacy_credentials_path)
63
+ # end
64
+ if netrc
65
+ netrc.delete('api.getcloudapp.com')
66
+ netrc.save
67
+ end
68
+ self.credentials = nil
69
+ end
70
+
71
+ def ask_for_and_save_credentials
72
+ self.credentials = ask_for_credentials
73
+ write_credentials
74
+ credentials
75
+ end
76
+
77
+ def ask_for_credentials
78
+ puts "Enter your CloudApp credentials."
79
+
80
+ print "Email: "
81
+ email = ask
82
+
83
+ print "Password (typing will be hidden): "
84
+ password = ask_for_password
85
+
86
+ # TODO: Remove this dependency on Service.
87
+ token = CloudApp::Service.token_for_account email, password
88
+ unless token
89
+ puts "Incorrect email or password."
90
+ puts
91
+ delete_credentials
92
+ return ask_for_credentials
93
+ end
94
+
95
+ [ email, token ]
96
+ end
97
+
98
+ def ask() $stdin.gets.to_s.strip end
99
+ def ask_for_password
100
+ echo_off
101
+ password = ask
102
+ puts
103
+ echo_on
104
+ return password
105
+ end
106
+
107
+ def echo_on() with_tty { system "stty echo" } end
108
+ def echo_off() with_tty { system "stty -echo" } end
109
+ def with_tty(&block)
110
+ return unless $stdin.isatty
111
+ yield
112
+ rescue
113
+ # fails on windows
114
+ end
115
+ end