cloudapp 2.0.0.beta.5 → 2.0.0.beta.6
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.
- data/Gemfile.lock +12 -1
- data/README.md +23 -22
- data/bin/cloudapp +32 -12
- data/cloudapp.gemspec +16 -5
- data/lib/cloudapp/cli/prompt.rb +34 -0
- data/lib/cloudapp/collection_json/collection.rb +21 -0
- data/lib/cloudapp/collection_json/item.rb +26 -0
- data/lib/cloudapp/collection_json/template.rb +26 -0
- data/lib/cloudapp/collection_json.rb +5 -60
- data/lib/cloudapp/credentials.rb +15 -97
- data/lib/cloudapp/service.rb +8 -2
- data/lib/cloudapp.rb +1 -1
- data/man/cloudapp.1 +2 -2
- data/man/cloudapp.1.html +2 -2
- data/man/cloudapp.1.ronn +2 -2
- data/spec/cloudapp/authorized_spec.rb +19 -0
- data/spec/cloudapp/collection_json/collection_spec.rb +69 -0
- data/spec/cloudapp/collection_json/item_spec.rb +55 -0
- data/spec/cloudapp/collection_json/template_spec.rb +35 -0
- data/spec/cloudapp/credentials_spec.rb +61 -0
- metadata +43 -2
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cloudapp (2.0.0.beta.
|
4
|
+
cloudapp (2.0.0.beta.6)
|
5
5
|
leadlight (~> 0.0.7)
|
6
|
+
mime-types (~> 1.19)
|
6
7
|
netrc (~> 0.7.7)
|
7
8
|
typhoeus (~> 0.3.3)
|
8
9
|
|
@@ -10,6 +11,7 @@ GEM
|
|
10
11
|
remote: http://rubygems.org/
|
11
12
|
specs:
|
12
13
|
addressable (2.2.8)
|
14
|
+
diff-lcs (1.1.3)
|
13
15
|
fail-fast (1.0.0)
|
14
16
|
faraday (0.8.1)
|
15
17
|
multipart-post (~> 1.1)
|
@@ -37,6 +39,14 @@ GEM
|
|
37
39
|
hpricot (>= 0.8.2)
|
38
40
|
mustache (>= 0.7.0)
|
39
41
|
rdiscount (>= 1.5.8)
|
42
|
+
rspec (2.12.0)
|
43
|
+
rspec-core (~> 2.12.0)
|
44
|
+
rspec-expectations (~> 2.12.0)
|
45
|
+
rspec-mocks (~> 2.12.0)
|
46
|
+
rspec-core (2.12.2)
|
47
|
+
rspec-expectations (2.12.1)
|
48
|
+
diff-lcs (~> 1.1.3)
|
49
|
+
rspec-mocks (2.12.0)
|
40
50
|
typhoeus (0.3.3)
|
41
51
|
mime-types
|
42
52
|
|
@@ -47,3 +57,4 @@ DEPENDENCIES
|
|
47
57
|
cloudapp!
|
48
58
|
rake
|
49
59
|
ronn
|
60
|
+
rspec
|
data/README.md
CHANGED
@@ -15,20 +15,38 @@ you're willing to lend a hand, we'd love to officially support it.
|
|
15
15
|
|
16
16
|
``` bash
|
17
17
|
$ gem install cloudapp --pre
|
18
|
-
$ cloudapp upload screenshot.png
|
19
18
|
$ cloudapp bookmark http://getcloudapp.com
|
19
|
+
$ cloudapp upload screenshot.png
|
20
|
+
$ cloudapp upload --direct screenshot.png
|
21
|
+
```
|
22
|
+
|
23
|
+
For a good time, install `gem-man` and read the man page or
|
24
|
+
[read it online][man].
|
25
|
+
|
26
|
+
[man]: http://cloudapp.github.com/cloudapp
|
27
|
+
|
28
|
+
|
29
|
+
``` bash
|
30
|
+
$ gem install gem-man
|
31
|
+
$ gem man cloudapp
|
20
32
|
```
|
21
33
|
|
22
34
|
## Commands
|
23
35
|
|
24
|
-
### cloudapp upload
|
36
|
+
### cloudapp upload `<file>`
|
37
|
+
|
38
|
+
Upload `<file>` and print its link to standard out. Use the `--direct` flag to
|
39
|
+
print the file's direct link which is suitable for use in places that expect a
|
40
|
+
link to a file like an HTML IMG tag.
|
25
41
|
|
26
42
|
``` bash
|
27
43
|
$ cloudapp upload screenshot.png
|
28
44
|
http://cl.ly/abc123
|
29
45
|
```
|
30
46
|
|
31
|
-
### cloudapp bookmark
|
47
|
+
### cloudapp bookmark `<url>`
|
48
|
+
|
49
|
+
Bookmark `<url>` and print its link to standard out.
|
32
50
|
|
33
51
|
``` bash
|
34
52
|
$ cloudapp bookmark http://getcloudapp.com
|
@@ -40,29 +58,12 @@ http://cl.ly/abc123
|
|
40
58
|
A few simple commands to allow scripting and input from other Unix programs
|
41
59
|
would be ideal.
|
42
60
|
|
43
|
-
### Phase: Next
|
44
|
-
|
45
61
|
- Share several files: `cloudapp upload *.png`
|
46
62
|
- Bookmark several links: `cloudapp bookmark http://douglasadams.com http://zombo.com`
|
47
63
|
- Handle bookmarks from STDIN: `pbpaste | cloudapp bookmark`
|
48
|
-
- Handle files from STDIN: `find *.png | cloudapp upload`
|
49
64
|
- 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
65
|
- Encrypt and share a file: `cloudapp upload --encrypt launch_codes.txt`
|
55
66
|
- Download and decrypt and encrypted drop: `cloudapp download --key=def456 http://cl.ly/abc123`
|
56
67
|
|
57
|
-
|
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.
|
62
|
-
|
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`
|
66
|
-
|
67
|
-
There's bound to be a better way to express some of these commands, but you get
|
68
|
-
the picture.
|
68
|
+
There's be a better way to express some of these commands, but you get the
|
69
|
+
picture.
|
data/bin/cloudapp
CHANGED
@@ -1,30 +1,47 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'cloudapp/credentials'
|
4
|
+
require 'cloudapp/cli/prompt'
|
4
5
|
require 'cloudapp/service'
|
5
6
|
|
6
7
|
def service
|
7
|
-
CloudApp::Service.using_token
|
8
|
+
CloudApp::Service.using_token token
|
9
|
+
end
|
10
|
+
|
11
|
+
def token
|
12
|
+
Credentials.token
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid_token?
|
16
|
+
!token.nil? and service.root.authorized?
|
8
17
|
end
|
9
18
|
|
10
19
|
def error error
|
11
20
|
puts "ERROR: #{error}"
|
12
|
-
exit
|
21
|
+
exit 9
|
13
22
|
end
|
14
23
|
|
15
|
-
def
|
24
|
+
def valid_url? url
|
16
25
|
error 'URL missing' if url.nil?
|
17
26
|
error "#{ url } doesn't look like a valid URL" unless url =~ URI.regexp
|
27
|
+
true
|
18
28
|
end
|
19
29
|
|
20
|
-
def
|
30
|
+
def valid_file? file
|
21
31
|
error "File doesn't exist" if file.is_a? Errno::ENOENT
|
22
32
|
error 'File missing' if file.nil? or file == STDIN
|
33
|
+
not file.closed?
|
34
|
+
end
|
35
|
+
|
36
|
+
def next_file
|
37
|
+
ARGF.file rescue $!
|
23
38
|
end
|
24
39
|
|
25
40
|
|
26
|
-
while
|
27
|
-
|
41
|
+
while not valid_token?
|
42
|
+
credentials = CloudApp::CLI::Prompt.new.ask_for_credentials
|
43
|
+
token = CloudApp::Service.token_for_account *credentials
|
44
|
+
Credentials.save_token token
|
28
45
|
end
|
29
46
|
|
30
47
|
link = ARGV.delete('--direct') || ARGV.delete('-d') ? :embed : :canonical
|
@@ -32,13 +49,16 @@ link = ARGV.delete('--direct') || ARGV.delete('-d') ? :embed : :canonical
|
|
32
49
|
case ARGV.shift
|
33
50
|
when 'bookmark'
|
34
51
|
link = :canonical # No such thing as an embed link for a bookmark.
|
35
|
-
url
|
36
|
-
|
37
|
-
|
52
|
+
while url = ARGV.shift
|
53
|
+
break unless valid_url? url
|
54
|
+
puts service.bookmark(url).link(link)
|
55
|
+
end
|
38
56
|
when 'upload'
|
39
|
-
file =
|
40
|
-
|
41
|
-
|
57
|
+
while file = next_file
|
58
|
+
break unless valid_file? file
|
59
|
+
puts service.upload(file).link(link)
|
60
|
+
ARGF.skip
|
61
|
+
end
|
42
62
|
else
|
43
63
|
puts <<EOS
|
44
64
|
Usage:
|
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.
|
17
|
-
s.date = '2012-12-
|
16
|
+
s.version = '2.0.0.beta.6'
|
17
|
+
s.date = '2012-12-23'
|
18
18
|
s.rubyforge_project = 'cloudapp'
|
19
19
|
|
20
20
|
## Make sure your summary is short. The description may be as long
|
@@ -43,14 +43,16 @@ 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',
|
47
|
-
s.add_dependency 'leadlight',
|
48
|
-
s.add_dependency '
|
46
|
+
s.add_dependency 'netrc', '~> 0.7.7'
|
47
|
+
s.add_dependency 'leadlight', '~> 0.0.7'
|
48
|
+
s.add_dependency 'mime-types', '~> 1.19'
|
49
|
+
s.add_dependency 'typhoeus', '~> 0.3.3'
|
49
50
|
|
50
51
|
## List your development dependencies here. Development dependencies are
|
51
52
|
## those that are only needed during development
|
52
53
|
s.add_development_dependency 'rake'
|
53
54
|
s.add_development_dependency 'ronn'
|
55
|
+
s.add_development_dependency 'rspec'
|
54
56
|
|
55
57
|
## Leave this section as-is. It will be automatically generated from the
|
56
58
|
## contents of your Git repository via the gemspec task. DO NOT REMOVE
|
@@ -66,12 +68,21 @@ Gem::Specification.new do |s|
|
|
66
68
|
cloudapp.gemspec
|
67
69
|
lib/cloudapp.rb
|
68
70
|
lib/cloudapp/authorized.rb
|
71
|
+
lib/cloudapp/cli/prompt.rb
|
69
72
|
lib/cloudapp/collection_json.rb
|
73
|
+
lib/cloudapp/collection_json/collection.rb
|
74
|
+
lib/cloudapp/collection_json/item.rb
|
75
|
+
lib/cloudapp/collection_json/template.rb
|
70
76
|
lib/cloudapp/credentials.rb
|
71
77
|
lib/cloudapp/service.rb
|
72
78
|
man/cloudapp.1
|
73
79
|
man/cloudapp.1.html
|
74
80
|
man/cloudapp.1.ronn
|
81
|
+
spec/cloudapp/authorized_spec.rb
|
82
|
+
spec/cloudapp/collection_json/collection_spec.rb
|
83
|
+
spec/cloudapp/collection_json/item_spec.rb
|
84
|
+
spec/cloudapp/collection_json/template_spec.rb
|
85
|
+
spec/cloudapp/credentials_spec.rb
|
75
86
|
]
|
76
87
|
# = MANIFEST =
|
77
88
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Lovingly borrowed from the heroku gem:
|
2
|
+
# https://github.com/heroku/heroku/blob/master/lib/heroku/auth.rb
|
3
|
+
module CloudApp
|
4
|
+
module CLI
|
5
|
+
class Prompt
|
6
|
+
def ask_for_credentials
|
7
|
+
puts "Sign into CloudApp."
|
8
|
+
print "Email: "
|
9
|
+
email = ask
|
10
|
+
print "Password (typing will be hidden): "
|
11
|
+
password = ask_for_password
|
12
|
+
[ email, password ]
|
13
|
+
end
|
14
|
+
|
15
|
+
def ask() $stdin.gets.to_s.strip end
|
16
|
+
def ask_for_password
|
17
|
+
echo_off
|
18
|
+
password = ask
|
19
|
+
puts
|
20
|
+
echo_on
|
21
|
+
return password
|
22
|
+
end
|
23
|
+
|
24
|
+
def echo_on() with_tty { system "stty echo" } end
|
25
|
+
def echo_off() with_tty { system "stty -echo" } end
|
26
|
+
def with_tty(&block)
|
27
|
+
return unless $stdin.isatty
|
28
|
+
yield
|
29
|
+
rescue
|
30
|
+
# fails on windows
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'cloudapp/collection_json/item'
|
2
|
+
require 'cloudapp/collection_json/template'
|
3
|
+
|
4
|
+
module CloudApp
|
5
|
+
module CollectionJson
|
6
|
+
class Collection < Item
|
7
|
+
def initialize representation
|
8
|
+
super representation.fetch('collection')
|
9
|
+
end
|
10
|
+
|
11
|
+
def item() items.first end
|
12
|
+
def items
|
13
|
+
fetch('items', []).map {|item| Item.new(item) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def template
|
17
|
+
Template.new(fetch('template'), href)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module CloudApp
|
4
|
+
module CollectionJson
|
5
|
+
class Item < SimpleDelegator
|
6
|
+
def href() fetch('href') end
|
7
|
+
def rel() fetch('rel') end
|
8
|
+
|
9
|
+
def links
|
10
|
+
fetch('links', []).map {|link| Item.new(link) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def link rel
|
14
|
+
links.find {|link| link.rel == rel.to_s }.href
|
15
|
+
end
|
16
|
+
|
17
|
+
def data
|
18
|
+
data = {}
|
19
|
+
fetch('data').each do |datum|
|
20
|
+
data[datum.fetch('name')] = datum.fetch('value')
|
21
|
+
end
|
22
|
+
data
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'cloudapp/collection_json/item'
|
2
|
+
|
3
|
+
module CloudApp
|
4
|
+
module CollectionJson
|
5
|
+
class Template < Item
|
6
|
+
attr_reader :href
|
7
|
+
|
8
|
+
def initialize item, href
|
9
|
+
@href = href
|
10
|
+
super item
|
11
|
+
end
|
12
|
+
|
13
|
+
def fill key, value
|
14
|
+
return self unless data.has_key? key
|
15
|
+
new_data = fetch('data').map {|datum|
|
16
|
+
if datum.fetch('name') == key
|
17
|
+
datum = datum.merge('value' => value)
|
18
|
+
end
|
19
|
+
datum
|
20
|
+
}
|
21
|
+
new_item = self.merge('data' => new_data)
|
22
|
+
Template.new new_item, href
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'cloudapp/collection_json/item'
|
2
|
+
require 'cloudapp/collection_json/collection'
|
3
|
+
require 'cloudapp/collection_json/template'
|
4
|
+
|
1
5
|
module CloudApp
|
2
6
|
module CollectionJson
|
3
7
|
Tint = Leadlight::Tint.new 'collection+json', status: [ :success, 401 ] do
|
@@ -7,6 +11,7 @@ module CloudApp
|
|
7
11
|
|
8
12
|
module Representation
|
9
13
|
extend Forwardable
|
14
|
+
def_delegators :collection, :template, :item
|
10
15
|
|
11
16
|
def self.extended representation
|
12
17
|
Collection.new(representation).links.each do |link|
|
@@ -21,66 +26,6 @@ module CloudApp
|
|
21
26
|
def collection
|
22
27
|
Collection.new(self)
|
23
28
|
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
29
|
end
|
85
30
|
end
|
86
31
|
end
|
data/lib/cloudapp/credentials.rb
CHANGED
@@ -1,115 +1,33 @@
|
|
1
|
-
# Taken from the heroku gem.
|
2
|
-
# https://github.com/heroku/heroku/blob/master/lib/heroku/auth.rb
|
3
1
|
require 'netrc'
|
4
2
|
|
5
3
|
class Credentials
|
6
|
-
|
7
|
-
new.credentials.last
|
8
|
-
end
|
4
|
+
attr_reader :netrc
|
9
5
|
|
10
|
-
def
|
11
|
-
|
12
|
-
encrypted = default + ".gpg"
|
13
|
-
if File.exists?(encrypted)
|
14
|
-
encrypted
|
15
|
-
else
|
16
|
-
default
|
17
|
-
end
|
6
|
+
def initialize netrc
|
7
|
+
@netrc = netrc
|
18
8
|
end
|
19
9
|
|
20
|
-
def netrc
|
21
|
-
|
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
|
10
|
+
def self.token netrc = Netrc.read
|
11
|
+
new(netrc).token
|
31
12
|
end
|
32
13
|
|
33
|
-
def
|
34
|
-
|
35
|
-
(@credentials ||= read_credentials) || ask_for_and_save_credentials
|
14
|
+
def self.save_token token, netrc = Netrc.read
|
15
|
+
new(netrc).save_token token
|
36
16
|
end
|
37
17
|
|
38
|
-
def
|
39
|
-
|
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
|
18
|
+
def token
|
19
|
+
credentials.last
|
49
20
|
end
|
50
21
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
FileUtils.chmod(0600, netrc_path)
|
55
|
-
netrc['api.getcloudapp.com'] = credentials
|
22
|
+
def save_token token
|
23
|
+
return if token.nil? or token =~ /^\s*$/
|
24
|
+
netrc['api.getcloudapp.com'] = [ 'api@getcloudapp.com', token ]
|
56
25
|
netrc.save
|
57
26
|
end
|
58
27
|
|
59
|
-
|
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
|
28
|
+
private
|
106
29
|
|
107
|
-
def
|
108
|
-
|
109
|
-
def with_tty(&block)
|
110
|
-
return unless $stdin.isatty
|
111
|
-
yield
|
112
|
-
rescue
|
113
|
-
# fails on windows
|
30
|
+
def credentials
|
31
|
+
Array netrc['api.getcloudapp.com']
|
114
32
|
end
|
115
33
|
end
|
data/lib/cloudapp/service.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'leadlight'
|
2
2
|
require 'cloudapp/authorized'
|
3
3
|
require 'cloudapp/collection_json'
|
4
|
+
require 'mime/types'
|
4
5
|
require 'uri'
|
5
6
|
|
6
7
|
module CloudApp
|
7
8
|
class Service
|
8
9
|
Leadlight.build_service self do
|
9
|
-
url '
|
10
|
+
url 'https://api.getcloudapp.com'
|
10
11
|
tints << CloudApp::CollectionJson::Tint
|
11
12
|
tints << CloudApp::Authorized::Tint
|
12
13
|
|
@@ -70,7 +71,7 @@ module CloudApp
|
|
70
71
|
|
71
72
|
def upload_file(path, template)
|
72
73
|
file = File.open path
|
73
|
-
file_io = Faraday::UploadIO.new file,
|
74
|
+
file_io = Faraday::UploadIO.new file, mime_type_for(path)
|
74
75
|
template = template.fill('file', file_io)
|
75
76
|
uri = Addressable::URI.parse template.href
|
76
77
|
|
@@ -87,5 +88,10 @@ module CloudApp
|
|
87
88
|
end
|
88
89
|
end
|
89
90
|
end
|
91
|
+
|
92
|
+
def mime_type_for path
|
93
|
+
MIME::Types.type_for(File.basename(path)).first ||
|
94
|
+
'application/octet-stream'
|
95
|
+
end
|
90
96
|
end
|
91
97
|
end
|
data/lib/cloudapp.rb
CHANGED
data/man/cloudapp.1
CHANGED
@@ -19,7 +19,7 @@ Upload a file or share a bookmark with CloudApp\. The drop\'s share link will be
|
|
19
19
|
.
|
20
20
|
.TP
|
21
21
|
\fB\-d\fR, \fB\-\-direct\fR
|
22
|
-
Print the drop\'s direct link after creation\. The direct link is suitable for use in places that expect a link to a file
|
22
|
+
Print the drop\'s direct link after creation\. The direct link is suitable for use in places that expect a link to a file like an HTML IMG tag\.
|
23
23
|
.
|
24
24
|
.SH "EXIT STATUS"
|
25
25
|
cloudapp may return one of several error codes if it encouters problems\.
|
@@ -31,7 +31,7 @@ cloudapp may return one of several error codes if it encouters problems\.
|
|
31
31
|
\fB1\fR File exceeds the limits of the account\'s plan
|
32
32
|
.
|
33
33
|
.IP "\(bu" 4
|
34
|
-
\fB9\fR
|
34
|
+
\fB9\fR Some horrible, unexpected thing has happened
|
35
35
|
.
|
36
36
|
.IP "" 0
|
37
37
|
.
|
data/man/cloudapp.1.html
CHANGED
@@ -94,7 +94,7 @@ printed to standard output. Account credentials are stored in <code>~/.netrc</co
|
|
94
94
|
|
95
95
|
<dl>
|
96
96
|
<dt><code>-d</code>, <code>--direct</code></dt><dd>Print the drop's direct link after creation. The direct link is suitable for
|
97
|
-
use in places that expect a link to a file
|
97
|
+
use in places that expect a link to a file like an HTML IMG tag.</dd>
|
98
98
|
</dl>
|
99
99
|
|
100
100
|
|
@@ -105,7 +105,7 @@ use in places that expect a link to a file content like an HTML IMG tag.</dd>
|
|
105
105
|
<ul>
|
106
106
|
<li><code>0</code> Success</li>
|
107
107
|
<li><code>1</code> File exceeds the limits of the account's plan</li>
|
108
|
-
<li><code>9</code>
|
108
|
+
<li><code>9</code> Some horrible, unexpected thing has happened</li>
|
109
109
|
</ul>
|
110
110
|
|
111
111
|
|
data/man/cloudapp.1.ronn
CHANGED
@@ -15,7 +15,7 @@ printed to standard output. Account credentials are stored in `~/.netrc`.
|
|
15
15
|
|
16
16
|
- `-d`, `--direct`:
|
17
17
|
Print the drop's direct link after creation. The direct link is suitable for
|
18
|
-
use in places that expect a link to a file
|
18
|
+
use in places that expect a link to a file like an HTML IMG tag.
|
19
19
|
|
20
20
|
## EXIT STATUS
|
21
21
|
|
@@ -23,7 +23,7 @@ cloudapp may return one of several error codes if it encouters problems.
|
|
23
23
|
|
24
24
|
- `0` Success
|
25
25
|
- `1` File exceeds the limits of the account's plan
|
26
|
-
- `9`
|
26
|
+
- `9` Some horrible, unexpected thing has happened
|
27
27
|
|
28
28
|
## FILES
|
29
29
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'cloudapp/authorized'
|
2
|
+
|
3
|
+
describe CloudApp::Authorized::Representation do
|
4
|
+
let(:representation) { stub :representation, __response__: response }
|
5
|
+
let(:response) { stub :response, status: status }
|
6
|
+
subject { representation.extend described_class }
|
7
|
+
|
8
|
+
context 'an unauthorized response' do
|
9
|
+
let(:status) { 401 }
|
10
|
+
it { should be_unauthorized }
|
11
|
+
it { should_not be_authorized }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'a success response' do
|
15
|
+
let(:status) { 200 }
|
16
|
+
it { should_not be_unauthorized }
|
17
|
+
it { should be_authorized }
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'cloudapp/collection_json/collection'
|
2
|
+
|
3
|
+
describe CloudApp::CollectionJson::Collection do
|
4
|
+
let(:collection) { described_class.new(data) }
|
5
|
+
subject { collection }
|
6
|
+
|
7
|
+
describe 'the collection item' do
|
8
|
+
let(:data) {{ 'collection' => { 'href' => 'http://href.com' }}}
|
9
|
+
its(:href) { should eq 'http://href.com' }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#items' do
|
13
|
+
let(:data) {{
|
14
|
+
'collection' => {
|
15
|
+
'items' => [
|
16
|
+
{ 'href' => 'http://one.com' },
|
17
|
+
{ 'href' => 'http://two.com' } ]}
|
18
|
+
}}
|
19
|
+
subject { collection.items }
|
20
|
+
|
21
|
+
it { should be_an Array }
|
22
|
+
it { should have(2).items }
|
23
|
+
|
24
|
+
it 'returns an array of Items' do
|
25
|
+
subject.each do |item|
|
26
|
+
item.should be_an CloudApp::CollectionJson::Item
|
27
|
+
end
|
28
|
+
|
29
|
+
item = subject.first
|
30
|
+
item.href.should eq 'http://one.com'
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with no items' do
|
34
|
+
let(:data) {{ 'collection' => {} }}
|
35
|
+
it { should be_empty }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#item' do
|
40
|
+
let(:data) {{
|
41
|
+
'collection' => {
|
42
|
+
'items' => [
|
43
|
+
{ 'href' => 'http://one.com' },
|
44
|
+
{ 'href' => 'http://two.com' } ]}}}
|
45
|
+
subject { collection.item }
|
46
|
+
|
47
|
+
it { should eq collection.items.first }
|
48
|
+
|
49
|
+
context 'with no items' do
|
50
|
+
let(:data) {{ 'collection' => {} }}
|
51
|
+
it { should be_nil }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#template' do
|
56
|
+
let(:data) {{
|
57
|
+
'collection' => {
|
58
|
+
'href' => 'http://href.com',
|
59
|
+
'template' => {
|
60
|
+
'data' => [
|
61
|
+
{ 'name' => 'first_name', 'value' => '' },
|
62
|
+
{ 'name' => 'last_name', 'value' => '' } ]}}}}
|
63
|
+
subject { collection.template }
|
64
|
+
|
65
|
+
it { should be_an CloudApp::CollectionJson::Template }
|
66
|
+
its(:href) { should eq 'http://href.com' }
|
67
|
+
its(:data) { should eq 'first_name' => '', 'last_name' => '' }
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'cloudapp/collection_json/item'
|
2
|
+
|
3
|
+
describe CloudApp::CollectionJson::Item do
|
4
|
+
subject { described_class.new(data) }
|
5
|
+
|
6
|
+
describe '#href' do
|
7
|
+
let(:data) {{ 'href' => 'http://getcloudapp.com' }}
|
8
|
+
its(:href) { should eq 'http://getcloudapp.com' }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#rel' do
|
12
|
+
let(:data) {{ 'rel' => 'relation' }}
|
13
|
+
its(:rel) { should eq 'relation' }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#links' do
|
17
|
+
subject { described_class.new(data).links }
|
18
|
+
let(:data) {{ 'links' => [
|
19
|
+
{ 'rel' => 'self', 'href' => 'http://self.com' },
|
20
|
+
{ 'rel' => 'next', 'href' => 'http://next.com' }] }}
|
21
|
+
|
22
|
+
it { should be_an Array }
|
23
|
+
it { should have(2).items }
|
24
|
+
|
25
|
+
it 'returns an array of Items' do
|
26
|
+
subject.each do |item|
|
27
|
+
item.should be_a described_class
|
28
|
+
end
|
29
|
+
|
30
|
+
item = subject.first
|
31
|
+
item.rel.should eq 'self'
|
32
|
+
item.href.should eq 'http://self.com'
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'with no links' do
|
36
|
+
let(:data) { {} }
|
37
|
+
it { should be_empty }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#link' do
|
42
|
+
subject { described_class.new(data).link('next') }
|
43
|
+
let(:data) {{ 'links' => [
|
44
|
+
{ 'rel' => 'self', 'href' => 'http://self.com' },
|
45
|
+
{ 'rel' => 'next', 'href' => 'http://next.com' }] }}
|
46
|
+
|
47
|
+
it { should eq 'http://next.com' }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#data' do
|
51
|
+
let(:data) {{ 'data' => [{ 'name' => 'first_name', 'value' => 'Arthur' },
|
52
|
+
{ 'name' => 'last_name', 'value' => 'Dent' }] }}
|
53
|
+
its(:data) { should eq 'first_name' => 'Arthur', 'last_name' => 'Dent' }
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'cloudapp/collection_json/template'
|
2
|
+
|
3
|
+
describe CloudApp::CollectionJson::Template do
|
4
|
+
let(:template) { described_class.new(data, 'http://href.com') }
|
5
|
+
subject { template }
|
6
|
+
|
7
|
+
describe 'the template item' do
|
8
|
+
let(:data) {{ 'data' => [
|
9
|
+
{ 'name' => 'first_name', 'value' => '' },
|
10
|
+
{ 'name' => 'last_name', 'value' => '' } ]}}
|
11
|
+
|
12
|
+
its(:href) { should eq 'http://href.com' }
|
13
|
+
its(:data) { should eq 'first_name' => '', 'last_name' => '' }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#fill' do
|
17
|
+
let(:data) {{ 'data' => [
|
18
|
+
{ 'name' => 'first_name', 'value' => '' },
|
19
|
+
{ 'name' => 'last_name', 'value' => '' } ]}}
|
20
|
+
subject { template.fill('first_name', 'Arthur') }
|
21
|
+
|
22
|
+
it { should be_a described_class }
|
23
|
+
it { should_not eq template }
|
24
|
+
|
25
|
+
it 'fills the datum' do
|
26
|
+
subject.data.fetch('first_name').should eq 'Arthur'
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'a nonexistent key' do
|
30
|
+
it 'does nothing' do
|
31
|
+
subject.fill('bad', 'value').should eq subject
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'cloudapp/credentials'
|
2
|
+
|
3
|
+
describe Credentials do
|
4
|
+
describe '.token' do
|
5
|
+
let(:netrc) { stub :netrc, :[] => %w( arthur@dent.com towel ) }
|
6
|
+
subject { Credentials.token(netrc) }
|
7
|
+
it { should eq 'towel' }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#token' do
|
11
|
+
let(:netrc) { stub :netrc, :[] => %w( arthur@dent.com towel ) }
|
12
|
+
subject { Credentials.new(netrc).token }
|
13
|
+
|
14
|
+
it { should eq 'towel' }
|
15
|
+
|
16
|
+
it 'fetches token from netrc' do
|
17
|
+
netrc.should_receive(:[]).with('api.getcloudapp.com').once
|
18
|
+
subject
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'without saved token' do
|
22
|
+
let(:netrc) { stub :netrc, :[] => nil }
|
23
|
+
it { should be_nil }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '.save_token' do
|
28
|
+
let(:netrc) { stub :netrc, :[]= => nil }
|
29
|
+
|
30
|
+
it 'saves the token' do
|
31
|
+
netrc.should_receive(:save).once.ordered
|
32
|
+
Credentials.save_token 'new token', netrc
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#save_token' do
|
37
|
+
let(:netrc) { stub :netrc }
|
38
|
+
subject { Credentials.new(netrc) }
|
39
|
+
|
40
|
+
it 'saves the token' do
|
41
|
+
credentials = [ 'api@getcloudapp.com', 'new token' ]
|
42
|
+
netrc.should_receive(:[]=).with('api.getcloudapp.com', credentials)
|
43
|
+
.once.ordered
|
44
|
+
netrc.should_receive(:save).once.ordered
|
45
|
+
subject.save_token 'new token'
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'ignores a nil token' do
|
49
|
+
netrc.should_not_receive(:[]=)
|
50
|
+
netrc.should_not_receive(:save)
|
51
|
+
subject.save_token nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'ignores an empty token' do
|
55
|
+
netrc.should_not_receive(:[]=)
|
56
|
+
netrc.should_not_receive(:save)
|
57
|
+
subject.save_token ''
|
58
|
+
subject.save_token ' '
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudapp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.beta.
|
4
|
+
version: 2.0.0.beta.6
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: netrc
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: 0.0.7
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: mime-types
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.19'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.19'
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: typhoeus
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,6 +107,22 @@ dependencies:
|
|
91
107
|
- - ! '>='
|
92
108
|
- !ruby/object:Gem::Version
|
93
109
|
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rspec
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
94
126
|
description: Experience all the pleasures of sharing with CloudApp now in your terminal.
|
95
127
|
email: larry@marburger.cc
|
96
128
|
executables:
|
@@ -109,12 +141,21 @@ files:
|
|
109
141
|
- cloudapp.gemspec
|
110
142
|
- lib/cloudapp.rb
|
111
143
|
- lib/cloudapp/authorized.rb
|
144
|
+
- lib/cloudapp/cli/prompt.rb
|
112
145
|
- lib/cloudapp/collection_json.rb
|
146
|
+
- lib/cloudapp/collection_json/collection.rb
|
147
|
+
- lib/cloudapp/collection_json/item.rb
|
148
|
+
- lib/cloudapp/collection_json/template.rb
|
113
149
|
- lib/cloudapp/credentials.rb
|
114
150
|
- lib/cloudapp/service.rb
|
115
151
|
- man/cloudapp.1
|
116
152
|
- man/cloudapp.1.html
|
117
153
|
- man/cloudapp.1.ronn
|
154
|
+
- spec/cloudapp/authorized_spec.rb
|
155
|
+
- spec/cloudapp/collection_json/collection_spec.rb
|
156
|
+
- spec/cloudapp/collection_json/item_spec.rb
|
157
|
+
- spec/cloudapp/collection_json/template_spec.rb
|
158
|
+
- spec/cloudapp/credentials_spec.rb
|
118
159
|
homepage: https://github.com/cloudapp/cloudapp
|
119
160
|
licenses: []
|
120
161
|
post_install_message:
|