dbox 0.5.3 → 0.6.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.
- data/History.txt +83 -0
- data/README.md +31 -7
- data/TODO.txt +1 -1
- data/VERSION +1 -1
- data/bin/dbox +2 -1
- data/dbox.gemspec +13 -11
- data/lib/dbox.rb +11 -2
- data/lib/dbox/api.rb +130 -66
- data/lib/dbox/cacert.pem +3376 -0
- data/lib/dbox/database.rb +106 -8
- data/lib/dbox/syncer.rb +103 -86
- data/lib/dbox/utils.rb +82 -0
- data/spec/dbox_spec.rb +201 -0
- data/spec/spec_helper.rb +2 -2
- data/vendor/dropbox-ruby-sdk/CHANGELOG +29 -0
- data/vendor/{dropbox-client-ruby → dropbox-ruby-sdk}/LICENSE +1 -1
- data/vendor/dropbox-ruby-sdk/README +7 -0
- data/vendor/dropbox-ruby-sdk/cli_example.rb +197 -0
- data/vendor/dropbox-ruby-sdk/dropbox_controller.rb +57 -0
- data/vendor/dropbox-ruby-sdk/gemspec.rb +25 -0
- data/vendor/dropbox-ruby-sdk/lib/dropbox_sdk.rb +690 -0
- data/vendor/dropbox-ruby-sdk/web_file_browser.rb +184 -0
- metadata +16 -14
- data/vendor/dropbox-client-ruby/README +0 -17
- data/vendor/dropbox-client-ruby/Rakefile +0 -41
- data/vendor/dropbox-client-ruby/config/testing.json.example +0 -16
- data/vendor/dropbox-client-ruby/lib/dropbox.rb +0 -259
- data/vendor/dropbox-client-ruby/manifest +0 -9
- data/vendor/dropbox-client-ruby/test/authenticator_test.rb +0 -53
- data/vendor/dropbox-client-ruby/test/client_test.rb +0 -100
- data/vendor/dropbox-client-ruby/test/util.rb +0 -21
data/lib/dbox/utils.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module Dbox
|
2
|
+
module Utils
|
3
|
+
def times_equal?(t1, t2)
|
4
|
+
time_to_s(t1) == time_to_s(t2)
|
5
|
+
end
|
6
|
+
|
7
|
+
def time_to_s(t)
|
8
|
+
case t
|
9
|
+
when Time
|
10
|
+
# matches dropbox time format
|
11
|
+
t.utc.strftime("%a, %d %b %Y %H:%M:%S +0000")
|
12
|
+
when String
|
13
|
+
t
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse_time(t)
|
18
|
+
case t
|
19
|
+
when Time
|
20
|
+
t
|
21
|
+
when String
|
22
|
+
Time.parse(t)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# assumes local_path is defined
|
27
|
+
def local_to_relative_path(path)
|
28
|
+
if path.include?(local_path)
|
29
|
+
path.sub(local_path, "").sub(/^\//, "")
|
30
|
+
else
|
31
|
+
raise BadPath, "Not a local path: #{path}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# assumes remote_path is defined
|
36
|
+
def remote_to_relative_path(path)
|
37
|
+
if path.include?(remote_path)
|
38
|
+
path.sub(remote_path, "").sub(/^\//, "")
|
39
|
+
else
|
40
|
+
raise BadPath, "Not a remote path: #{path}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# assumes local_path is defined
|
45
|
+
def relative_to_local_path(path)
|
46
|
+
if path && path.length > 0
|
47
|
+
File.join(local_path, path)
|
48
|
+
else
|
49
|
+
local_path
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# assumes remote_path is defined
|
54
|
+
def relative_to_remote_path(path)
|
55
|
+
if path && path.length > 0
|
56
|
+
File.join(remote_path, path)
|
57
|
+
else
|
58
|
+
remote_path
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def calculate_hash(filepath)
|
63
|
+
begin
|
64
|
+
Digest::MD5.file(filepath).to_s
|
65
|
+
rescue Errno::EISDIR
|
66
|
+
nil
|
67
|
+
rescue Errno::ENOENT
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def find_nonconflicting_path(filepath)
|
73
|
+
proposed = filepath
|
74
|
+
while File.exists?(proposed)
|
75
|
+
dir, p = File.split(proposed)
|
76
|
+
p = p.sub(/^(.*?)( \((\d+)\))?(\..*?)?$/) { "#{$1} (#{$3 ? $3.to_i + 1 : 1})#{$4}" }
|
77
|
+
proposed = File.join(dir, p)
|
78
|
+
end
|
79
|
+
proposed
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/spec/dbox_spec.rb
CHANGED
@@ -122,6 +122,101 @@ describe Dbox do
|
|
122
122
|
Dbox.pull(@local).should eql(:created => ["subdir", "subdir/one.txt"], :deleted => ["foo.txt"], :updated => ["", "baz.txt"], :failed => [])
|
123
123
|
Dbox.pull(@local).should eql(:created => [], :deleted => [], :updated => [], :failed => [])
|
124
124
|
end
|
125
|
+
|
126
|
+
it "should be able to download a bunch of files at the same time" do
|
127
|
+
Dbox.create(@remote, @local)
|
128
|
+
@alternate = "#{ALTERNATE_LOCAL_TEST_PATH}/#{@name}"
|
129
|
+
Dbox.clone(@remote, @alternate)
|
130
|
+
|
131
|
+
# generate 20 x 100kB files
|
132
|
+
20.times do
|
133
|
+
make_file "#{@alternate}/#{randname}.txt", 100
|
134
|
+
end
|
135
|
+
|
136
|
+
Dbox.push(@alternate)
|
137
|
+
|
138
|
+
res = Dbox.pull(@local)
|
139
|
+
res[:deleted].should eql([])
|
140
|
+
res[:updated].should eql([""])
|
141
|
+
res[:failed].should eql([])
|
142
|
+
res[:created].size.should eql(20)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should be able to pull a series of updates to the same file" do
|
146
|
+
Dbox.create(@remote, @local)
|
147
|
+
@alternate = "#{ALTERNATE_LOCAL_TEST_PATH}/#{@name}"
|
148
|
+
Dbox.clone(@remote, @alternate)
|
149
|
+
|
150
|
+
make_file "#{@local}/hello.txt"
|
151
|
+
Dbox.push(@local)
|
152
|
+
Dbox.pull(@alternate).should eql(:created => ["hello.txt"], :deleted => [], :updated => [""], :failed => [])
|
153
|
+
make_file "#{@local}/hello.txt"
|
154
|
+
Dbox.push(@local)
|
155
|
+
Dbox.pull(@alternate).should eql(:created => [], :deleted => [], :updated => ["", "hello.txt"], :failed => [])
|
156
|
+
make_file "#{@local}/hello.txt"
|
157
|
+
Dbox.push(@local)
|
158
|
+
Dbox.pull(@alternate).should eql(:created => [], :deleted => [], :updated => ["", "hello.txt"], :failed => [])
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should handle conflicting pulls of new files gracefully" do
|
162
|
+
Dbox.create(@remote, @local)
|
163
|
+
@alternate = "#{ALTERNATE_LOCAL_TEST_PATH}/#{@name}"
|
164
|
+
Dbox.clone(@remote, @alternate)
|
165
|
+
|
166
|
+
make_file "#{@local}/hello.txt"
|
167
|
+
Dbox.push(@local)
|
168
|
+
|
169
|
+
make_file "#{@alternate}/hello.txt"
|
170
|
+
Dbox.pull(@alternate).should eql(:created => ["hello.txt"], :deleted => [], :updated => [""], :conflicts => [{:original => "hello.txt", :renamed => "hello (1).txt"}], :failed => [])
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should handle conflicting pulls of updated files gracefully" do
|
174
|
+
Dbox.create(@remote, @local)
|
175
|
+
@alternate = "#{ALTERNATE_LOCAL_TEST_PATH}/#{@name}"
|
176
|
+
Dbox.clone(@remote, @alternate)
|
177
|
+
|
178
|
+
make_file "#{@local}/hello.txt"
|
179
|
+
Dbox.push(@local)
|
180
|
+
Dbox.pull(@alternate).should eql(:created => ["hello.txt"], :deleted => [], :updated => [""], :failed => [])
|
181
|
+
|
182
|
+
make_file "#{@local}/hello.txt"
|
183
|
+
Dbox.push(@local)
|
184
|
+
|
185
|
+
make_file "#{@alternate}/hello.txt"
|
186
|
+
Dbox.pull(@alternate).should eql(:created => [], :deleted => [], :updated => ["", "hello.txt"], :conflicts => [{:original => "hello.txt", :renamed => "hello (1).txt"}], :failed => [])
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should deal with all sorts of weird filenames when renaming due to conflicts on pull" do
|
190
|
+
Dbox.create(@remote, @local)
|
191
|
+
@alternate = "#{ALTERNATE_LOCAL_TEST_PATH}/#{@name}"
|
192
|
+
Dbox.clone(@remote, @alternate)
|
193
|
+
|
194
|
+
make_file "#{@local}/hello.txt"
|
195
|
+
make_file "#{@local}/hello (1).txt"
|
196
|
+
make_file "#{@local}/goodbye.txt"
|
197
|
+
Dbox.push(@local)
|
198
|
+
|
199
|
+
make_file "#{@alternate}/hello.txt"
|
200
|
+
make_file "#{@alternate}/hello (1).txt"
|
201
|
+
make_file "#{@alternate}/hello (3).txt"
|
202
|
+
make_file "#{@alternate}/hello (4).txt"
|
203
|
+
make_file "#{@alternate}/hello (test).txt"
|
204
|
+
make_file "#{@alternate}/goodbye.txt"
|
205
|
+
make_file "#{@alternate}/goodbye (1).txt"
|
206
|
+
make_file "#{@alternate}/goodbye (2).txt"
|
207
|
+
make_file "#{@alternate}/goodbye (3).txt"
|
208
|
+
make_file "#{@alternate}/goodbye ().txt"
|
209
|
+
|
210
|
+
# there's a race condition, so the output could be one of two things
|
211
|
+
res = Dbox.pull(@alternate)
|
212
|
+
res[:created].should eql(["goodbye.txt", "hello (1).txt", "hello.txt"])
|
213
|
+
res[:updated].should eql([""])
|
214
|
+
res[:deleted].should eql([])
|
215
|
+
res[:failed].should eql([])
|
216
|
+
c = (res[:conflicts] == [{:original => "goodbye.txt", :renamed => "goodbye (4).txt"}, {:original => "hello (1).txt", :renamed => "hello (5).txt"}, {:original => "hello.txt", :renamed => "hello (2).txt"}]) ||
|
217
|
+
(res[:conflicts] == [{:original => "goodbye.txt", :renamed => "goodbye (4).txt"}, {:original => "hello (1).txt", :renamed => "hello (2).txt"}, {:original => "hello.txt", :renamed => "hello (5).txt"}])
|
218
|
+
c.should be_true
|
219
|
+
end
|
125
220
|
end
|
126
221
|
|
127
222
|
describe "#push" do
|
@@ -230,6 +325,112 @@ describe Dbox do
|
|
230
325
|
rm_rf @local
|
231
326
|
Dbox.clone(@remote, @local).should eql(:created => [crazy_name1, File.join(crazy_name1, "foo.txt")], :deleted => [], :updated => [""], :failed => [])
|
232
327
|
end
|
328
|
+
|
329
|
+
it "should be able to upload a bunch of files at the same time" do
|
330
|
+
Dbox.create(@remote, @local)
|
331
|
+
|
332
|
+
# generate 20 x 100kB files
|
333
|
+
20.times do
|
334
|
+
make_file "#{@local}/#{randname}.txt", 100
|
335
|
+
end
|
336
|
+
|
337
|
+
res = Dbox.push(@local)
|
338
|
+
res[:deleted].should eql([])
|
339
|
+
res[:updated].should eql([])
|
340
|
+
res[:failed].should eql([])
|
341
|
+
res[:created].size.should eql(20)
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should be able to push a series of updates to the same file" do
|
345
|
+
Dbox.create(@remote, @local)
|
346
|
+
|
347
|
+
make_file "#{@local}/hello.txt"
|
348
|
+
Dbox.push(@local).should eql(:created => ["hello.txt"], :deleted => [], :updated => [], :failed => [])
|
349
|
+
make_file "#{@local}/hello.txt"
|
350
|
+
Dbox.push(@local).should eql(:created => [], :deleted => [], :updated => ["hello.txt"], :failed => [])
|
351
|
+
make_file "#{@local}/hello.txt"
|
352
|
+
Dbox.push(@local).should eql(:created => [], :deleted => [], :updated => ["hello.txt"], :failed => [])
|
353
|
+
end
|
354
|
+
|
355
|
+
it "should handle conflicting pushes of new files gracefully" do
|
356
|
+
Dbox.create(@remote, @local)
|
357
|
+
|
358
|
+
@alternate = "#{ALTERNATE_LOCAL_TEST_PATH}/#{@name}"
|
359
|
+
Dbox.clone(@remote, @alternate)
|
360
|
+
|
361
|
+
make_file "#{@local}/hello.txt"
|
362
|
+
Dbox.push(@local).should eql(:created => ["hello.txt"], :deleted => [], :updated => [], :failed => [])
|
363
|
+
|
364
|
+
make_file "#{@alternate}/hello.txt"
|
365
|
+
Dbox.push(@alternate).should eql(:created => [], :deleted => [], :updated => [], :conflicts => [{:original => "hello.txt", :renamed => "hello (1).txt"}], :failed => [])
|
366
|
+
end
|
367
|
+
|
368
|
+
it "should handle conflicting pushes of updated files gracefully" do
|
369
|
+
Dbox.create(@remote, @local)
|
370
|
+
make_file "#{@local}/hello.txt"
|
371
|
+
Dbox.push(@local)
|
372
|
+
|
373
|
+
@alternate = "#{ALTERNATE_LOCAL_TEST_PATH}/#{@name}"
|
374
|
+
Dbox.clone(@remote, @alternate)
|
375
|
+
|
376
|
+
make_file "#{@local}/hello.txt"
|
377
|
+
Dbox.push(@local).should eql(:created => [], :deleted => [], :updated => ["hello.txt"], :failed => [])
|
378
|
+
|
379
|
+
make_file "#{@alternate}/hello.txt"
|
380
|
+
Dbox.push(@alternate).should eql(:created => [], :deleted => [], :updated => [], :conflicts => [{:original => "hello.txt", :renamed => "hello (1).txt"}], :failed => [])
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
describe "#sync" do
|
385
|
+
it "should fail if the local dir is missing" do
|
386
|
+
expect { Dbox.sync(@local) }.to raise_error(Dbox::DatabaseError)
|
387
|
+
end
|
388
|
+
|
389
|
+
it "should be able to sync basic changes" do
|
390
|
+
Dbox.create(@remote, @local)
|
391
|
+
@alternate = "#{ALTERNATE_LOCAL_TEST_PATH}/#{@name}"
|
392
|
+
Dbox.clone(@remote, @alternate)
|
393
|
+
|
394
|
+
Dbox.sync(@local).should eql(:pull => { :created => [], :deleted => [], :updated => [], :failed => [] },
|
395
|
+
:push => { :created => [], :deleted => [], :updated => [], :failed => [] })
|
396
|
+
Dbox.sync(@alternate).should eql(:pull => { :created => [], :deleted => [], :updated => [], :failed => [] },
|
397
|
+
:push => { :created => [], :deleted => [], :updated => [], :failed => [] })
|
398
|
+
|
399
|
+
make_file "#{@local}/hello.txt"
|
400
|
+
Dbox.sync(@local).should eql(:pull => { :created => [], :deleted => [], :updated => [], :failed => [] },
|
401
|
+
:push => { :created => ["hello.txt"], :deleted => [], :updated => [], :failed => [] })
|
402
|
+
Dbox.sync(@alternate).should eql(:pull => { :created => ["hello.txt"], :deleted => [], :updated => [""], :failed => [] },
|
403
|
+
:push => { :created => [], :deleted => [], :updated => [], :failed => [] })
|
404
|
+
end
|
405
|
+
|
406
|
+
it "should be able to sync complex changes" do
|
407
|
+
Dbox.create(@remote, @local)
|
408
|
+
@alternate = "#{ALTERNATE_LOCAL_TEST_PATH}/#{@name}"
|
409
|
+
Dbox.clone(@remote, @alternate)
|
410
|
+
|
411
|
+
Dbox.sync(@local).should eql(:pull => { :created => [], :deleted => [], :updated => [], :failed => [] },
|
412
|
+
:push => { :created => [], :deleted => [], :updated => [], :failed => [] })
|
413
|
+
Dbox.sync(@alternate).should eql(:pull => { :created => [], :deleted => [], :updated => [], :failed => [] },
|
414
|
+
:push => { :created => [], :deleted => [], :updated => [], :failed => [] })
|
415
|
+
|
416
|
+
make_file "#{@local}/hello.txt"
|
417
|
+
make_file "#{@local}/goodbye.txt"
|
418
|
+
make_file "#{@local}/so_long.txt"
|
419
|
+
make_file "#{@alternate}/hello.txt"
|
420
|
+
make_file "#{@alternate}/farewell.txt"
|
421
|
+
Dbox.sync(@local).should eql(:pull => { :created => [], :deleted => [], :updated => [], :failed => [] },
|
422
|
+
:push => { :created => ["goodbye.txt", "hello.txt", "so_long.txt"], :deleted => [], :updated => [], :failed => [] })
|
423
|
+
Dbox.sync(@alternate).should eql(:pull => { :created => ["goodbye.txt", "hello.txt", "so_long.txt"], :deleted => [], :updated => [""], :failed => [], :conflicts => [{ :renamed => "hello (1).txt", :original => "hello.txt" }] },
|
424
|
+
:push => { :created => ["farewell.txt", "hello (1).txt"], :deleted => [], :updated => [], :failed => [] })
|
425
|
+
|
426
|
+
make_file "#{@alternate}/farewell.txt"
|
427
|
+
make_file "#{@alternate}/goodbye.txt"
|
428
|
+
make_file "#{@alternate}/au_revoir.txt"
|
429
|
+
Dbox.sync(@alternate).should eql(:pull => { :created => [], :deleted => [], :updated => [""], :failed => [] },
|
430
|
+
:push => { :created => ["au_revoir.txt"], :deleted => [], :updated => ["farewell.txt", "goodbye.txt"], :failed => [] })
|
431
|
+
Dbox.sync(@local).should eql(:pull => { :created => ["au_revoir.txt", "farewell.txt", "hello (1).txt"], :deleted => [], :updated => ["", "goodbye.txt"], :failed => [] },
|
432
|
+
:push => { :created => [], :deleted => [], :updated => [], :failed => [] })
|
433
|
+
end
|
233
434
|
end
|
234
435
|
|
235
436
|
describe "#move" do
|
data/spec/spec_helper.rb
CHANGED
@@ -36,8 +36,8 @@ def log
|
|
36
36
|
LOGGER
|
37
37
|
end
|
38
38
|
|
39
|
-
def make_file(filepath)
|
40
|
-
|
39
|
+
def make_file(filepath, size_in_kb=1)
|
40
|
+
`dd if=/dev/urandom of="#{filepath.gsub('"','\"')}" bs=1024 count=#{size_in_kb} 1>/dev/null 2>/dev/null`
|
41
41
|
end
|
42
42
|
|
43
43
|
RSpec::Matchers.define :exist do
|
@@ -0,0 +1,29 @@
|
|
1
|
+
1.1 (2011-10-17)
|
2
|
+
* Various bug fixes found during beta period
|
3
|
+
* Improved documentation
|
4
|
+
* Improved module structure
|
5
|
+
* Removed dependency on the oauth module, using plaintext authentication over https
|
6
|
+
|
7
|
+
1.0 (2011-8-16)
|
8
|
+
* Backwards compatibility broken
|
9
|
+
- Changed interface
|
10
|
+
- Change 'sandbox' references to 'app_folder'
|
11
|
+
* Updated SDK to Dropbox API Version 1, supporting all calls
|
12
|
+
- Added 'rev' parameter to metadata and get_file
|
13
|
+
- Added 'parent_rev' parameter to put_file
|
14
|
+
- Added search, share, media, revisions, and restore
|
15
|
+
- put_file uses /files_put instead of multipart POST
|
16
|
+
- Removed methods for calls that were removed from v1 of the REST API
|
17
|
+
* Changed return format for calls
|
18
|
+
- On error (non-200 response), an exception is raised
|
19
|
+
- On success, the JSON is parsed and a Hash is returned
|
20
|
+
* Updated examples
|
21
|
+
- Improved CLI example
|
22
|
+
- Added a Ruby on Rails 3 controller example
|
23
|
+
- Added a web based file browser/uploader that uses Sinatra
|
24
|
+
* put_file no longer takes a "name" arugment, only takes a full path
|
25
|
+
* Removed reliance on config files
|
26
|
+
* Assorted bugfixes and improvements
|
27
|
+
* All calls are now made over SSL
|
28
|
+
* Fully documented code for RDoc generation
|
29
|
+
* Added a CHANGELOG
|
@@ -0,0 +1,7 @@
|
|
1
|
+
Getting started with the Dropbox Ruby SDK:
|
2
|
+
1. Install json and oauth ruby gems with:
|
3
|
+
gem install json oauth
|
4
|
+
2. Edit cli_example.rb to to include your APP_KEY and APP_SECRET
|
5
|
+
3. Try running the example app: 'ruby clie_example.rb'.
|
6
|
+
4. See dropbox_controller.rb for an example Ruby on Rails controller. It needs an APP_KEY and APP_SECRET set too.
|
7
|
+
5. Check out the dropbox website for reference and help! http://dropbox.com/developers_beta
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require './lib/dropbox_sdk'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
####
|
5
|
+
# An example app using the Dropbox API Ruby Client
|
6
|
+
# This ruby script sets up a basic command line interface (CLI)
|
7
|
+
# that prompts a user to authenticate on the web, then
|
8
|
+
# allows them to type commands to manipulate their dropbox.
|
9
|
+
####
|
10
|
+
|
11
|
+
# You must use your Dropbox App key and secret to use the API.
|
12
|
+
# Find this at https://www.dropbox.com/developers
|
13
|
+
APP_KEY = ''
|
14
|
+
APP_SECRET = ''
|
15
|
+
ACCESS_TYPE = :app_folder #The two valid values here are :app_folder and :dropbox
|
16
|
+
#The default is :app_folder, but your application might be
|
17
|
+
#set to have full :dropbox access. Check your app at
|
18
|
+
#https://www.dropbox.com/developers/apps
|
19
|
+
|
20
|
+
class DropboxCLI
|
21
|
+
LOGIN_REQUIRED = %w{put get cp mv rm ls mkdir info logout search}
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
if APP_KEY == '' or APP_SECRET == ''
|
25
|
+
puts "You must set your APP_KEY and APP_SECRET in cli_example.rb!"
|
26
|
+
puts "Find this in your apps page at https://www.dropbox.com/developers/"
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
@session = DropboxSession.new(APP_KEY, APP_SECRET)
|
31
|
+
@client = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def login
|
35
|
+
########
|
36
|
+
# Instead of going to a authorize URL, you can set a access token key and secret
|
37
|
+
# from a previous session
|
38
|
+
########
|
39
|
+
# @session.set_access_token('key', 'secret')
|
40
|
+
|
41
|
+
if @session.authorized?
|
42
|
+
puts "already logged in!"
|
43
|
+
else
|
44
|
+
|
45
|
+
# grab the request token for session
|
46
|
+
@session.get_request_token
|
47
|
+
|
48
|
+
authorize_url = @session.get_authorize_url
|
49
|
+
puts "Got a request token. Your request token key is #{@session.request_token.key} and your token secret is #{@session.request_token.secret}"
|
50
|
+
|
51
|
+
# make the user log in and authorize this token
|
52
|
+
puts "AUTHORIZING", authorize_url, "Please visit that web page and hit 'Allow', then hit Enter here."
|
53
|
+
gets
|
54
|
+
|
55
|
+
# get the access token from the server. Its then stored in the session.
|
56
|
+
@session.get_access_token
|
57
|
+
|
58
|
+
end
|
59
|
+
puts "You are logged in. Your access token key is #{@session.access_token.key} your secret is #{@session.access_token.secret}"
|
60
|
+
@client = DropboxClient.new(@session, ACCESS_TYPE)
|
61
|
+
end
|
62
|
+
|
63
|
+
def command_loop
|
64
|
+
puts "Enter a command or 'help' or 'exit'"
|
65
|
+
command_line = ''
|
66
|
+
while command_line.strip != 'exit'
|
67
|
+
begin
|
68
|
+
execute_dropbox_command(command_line)
|
69
|
+
rescue RuntimeError => e
|
70
|
+
puts "Command Line Error! #{e.class}: #{e}"
|
71
|
+
puts e.backtrace
|
72
|
+
end
|
73
|
+
print '> '
|
74
|
+
command_line = gets.strip
|
75
|
+
end
|
76
|
+
puts 'goodbye'
|
77
|
+
exit(0)
|
78
|
+
end
|
79
|
+
|
80
|
+
def execute_dropbox_command(cmd_line)
|
81
|
+
command = cmd_line.split
|
82
|
+
method = command.first
|
83
|
+
if LOGIN_REQUIRED.include? method
|
84
|
+
if @client
|
85
|
+
send(method.to_sym, command)
|
86
|
+
else
|
87
|
+
puts 'must be logged in; type \'login\' to get started.'
|
88
|
+
end
|
89
|
+
elsif ['login', 'help'].include? method
|
90
|
+
send(method.to_sym)
|
91
|
+
else
|
92
|
+
if command.first && !command.first.strip.empty?
|
93
|
+
puts 'invalid command. type \'help\' to see commands.'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def logout(command)
|
99
|
+
@session.clear_access_token
|
100
|
+
puts "You are logged out."
|
101
|
+
@client = nil
|
102
|
+
end
|
103
|
+
|
104
|
+
def put(command)
|
105
|
+
fname = command[1]
|
106
|
+
|
107
|
+
#If the user didn't specifiy the file name, just use the name of the file on disk
|
108
|
+
if command[2]
|
109
|
+
new_name = command[2]
|
110
|
+
else
|
111
|
+
new_name = File.basename(fname)
|
112
|
+
end
|
113
|
+
|
114
|
+
if fname && !fname.empty? && File.exists?(fname) && (File.ftype(fname) == 'file') && File.stat(fname).readable?
|
115
|
+
#This is where we call the the Dropbox Client
|
116
|
+
pp @client.put_file(new_name, open(fname))
|
117
|
+
else
|
118
|
+
puts "couldn't find the file #{ fname }"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def get(command)
|
123
|
+
dest = command[2]
|
124
|
+
if !command[1] || command[1].empty?
|
125
|
+
puts "please specify item to get"
|
126
|
+
elsif !dest || dest.empty?
|
127
|
+
puts "please specify full local path to dest, i.e. the file to write to"
|
128
|
+
elsif File.exists?(dest)
|
129
|
+
puts "error: File #{dest} already exists."
|
130
|
+
else
|
131
|
+
src = clean_up(command[1])
|
132
|
+
out = @client.get_file('/' + src)
|
133
|
+
open(dest, 'w'){|f| f.puts out }
|
134
|
+
puts "wrote file #{dest}."
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def mkdir(command)
|
139
|
+
pp @client.file_create_folder(command[1])
|
140
|
+
end
|
141
|
+
|
142
|
+
def thumbnail(command)
|
143
|
+
command[2] ||= 'small'
|
144
|
+
pp @client.thumbnail(command[1], command[2])
|
145
|
+
end
|
146
|
+
|
147
|
+
def cp(command)
|
148
|
+
src = clean_up(command[1])
|
149
|
+
dest = clean_up(command[2])
|
150
|
+
pp @client.file_copy(src, dest)
|
151
|
+
end
|
152
|
+
|
153
|
+
def mv(command)
|
154
|
+
src = clean_up(command[1])
|
155
|
+
dest = clean_up(command[2])
|
156
|
+
pp @client.file_move(src, dest)
|
157
|
+
end
|
158
|
+
|
159
|
+
def rm(command)
|
160
|
+
pp @client.file_delete(clean_up(command[1]))
|
161
|
+
end
|
162
|
+
|
163
|
+
def search(command)
|
164
|
+
resp = @client.search('/',clean_up(command[1]))
|
165
|
+
|
166
|
+
for item in resp
|
167
|
+
puts item['path']
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def info(command)
|
172
|
+
pp @client.account_info
|
173
|
+
end
|
174
|
+
|
175
|
+
def ls(command)
|
176
|
+
command[1] = '/' + clean_up(command[1] || '')
|
177
|
+
resp = @client.metadata(command[1])
|
178
|
+
|
179
|
+
if resp['contents'].length > 0
|
180
|
+
for item in resp['contents']
|
181
|
+
puts item['path']
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def help
|
187
|
+
puts "commands are: login #{LOGIN_REQUIRED.join(' ')} help exit"
|
188
|
+
end
|
189
|
+
|
190
|
+
def clean_up(str)
|
191
|
+
return str.gsub(/^\/+/, '') if str
|
192
|
+
str
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
cli = DropboxCLI.new
|
197
|
+
cli.command_loop
|