dbox 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/History.txt
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
== 0.6.0 / 2011-11-24
|
2
|
+
* Major Enhancements
|
3
|
+
* Upgrade from Dropbox API v0 to v1.
|
4
|
+
* Storage of hashes of local files to alleviate problems with moving/copying directories causing files to be detected as modified.
|
5
|
+
* Handling of writes that would overwrite unsaved data (files are renamed).
|
6
|
+
* SSL support.
|
7
|
+
* Sync API.
|
8
|
+
|
9
|
+
== 0.5.3 / 2011-11-04
|
10
|
+
* Major Enhancements
|
11
|
+
* Tracking & returning of files that fail to sync.
|
12
|
+
* Better consistency during failure scenarios.
|
13
|
+
* Minor Enhancements
|
14
|
+
* Returning of exit status of 1 when failures occur.
|
15
|
+
* Bug Fixes
|
16
|
+
* Fixed incorrect handling of some Dropbox server errors.
|
17
|
+
|
18
|
+
== 0.5.2 / 2011-10-03
|
19
|
+
* Bug Fixes
|
20
|
+
* Fixed broken database migration.
|
21
|
+
|
22
|
+
== 0.5.1 / 2011-10-03
|
23
|
+
* Bug Fixes
|
24
|
+
* Fixed cascading deletes on directory deletion.
|
25
|
+
* Fixed support for moving/renaming local repository.
|
26
|
+
|
27
|
+
== 0.5.0 / 2011-09-19
|
28
|
+
* Major Enhancements
|
29
|
+
* Complete rewrite of metadata storage to use SQLite database.
|
30
|
+
* Streaming downloads.
|
31
|
+
* Parallelized downloads and uploads.
|
32
|
+
* Minor Enhancements
|
33
|
+
* Atomic saving of downloaded files to eliminate partial files if killed during download.
|
34
|
+
|
35
|
+
== 0.4.4 / 2011-06-28
|
36
|
+
* Minor Enhancements
|
37
|
+
* Detection of corrupt database.
|
38
|
+
* Added gem dependencies.
|
39
|
+
* Bug Fixes
|
40
|
+
* Fixed Ruby 1.9 support.
|
41
|
+
* Fixed DB corruption issue when hard killing process.
|
42
|
+
|
43
|
+
== 0.4.3 / 2011-05-18
|
44
|
+
* Minor Enhancements
|
45
|
+
* More robust DB saving to handle errors after partial pushes or pulls.
|
46
|
+
* Bug Fixes
|
47
|
+
* Fixed revision stamping.
|
48
|
+
* Fixed sorting of filenames in changelist.
|
49
|
+
|
50
|
+
== 0.4.2 / 2011-05-17
|
51
|
+
* Bug Fixes
|
52
|
+
* Fixed directories with certain characters: []{}*?.
|
53
|
+
* Fixed URL encoding.
|
54
|
+
|
55
|
+
== 0.4.1 / 2011-05-16
|
56
|
+
* Minor Enhancements
|
57
|
+
* Added Dbox.exists? to Ruby API.
|
58
|
+
* Improved logging.
|
59
|
+
|
60
|
+
== 0.4.0 / 2011-05-16
|
61
|
+
* Major Enhancements
|
62
|
+
* Added move API to rename remote folder.
|
63
|
+
|
64
|
+
== 0.3.0 / 2011-05-14
|
65
|
+
* Major Enhancements
|
66
|
+
* Added returning of changelist from push & pull operations.
|
67
|
+
* Improved error handling.
|
68
|
+
* Minor Enhancements
|
69
|
+
* Logging cleanup.
|
70
|
+
* Bug Fixes
|
71
|
+
* Fixed re-download after upload issue.
|
72
|
+
|
73
|
+
== 0.2.0 / 2011-05-14
|
74
|
+
* Major Enhancements
|
75
|
+
* Logging.
|
76
|
+
* Tests.
|
77
|
+
|
78
|
+
== 0.1.0 / 2011-05-13
|
79
|
+
* Inaugural Release
|
80
|
+
* Ruby API.
|
81
|
+
* Command-line client.
|
82
|
+
* Create, clone, pull, push support.
|
83
|
+
* Metadata database to track synchronized content.
|
data/README.md
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
dbox
|
2
2
|
====
|
3
3
|
|
4
|
-
|
4
|
+
Dropbox integration made easy.
|
5
5
|
|
6
|
-
|
6
|
+
Push and pull your Dropbox folders, with fine-grained control over what folder you are syncing, where you are syncing it to, and when you are doing it.
|
7
|
+
|
8
|
+
Take your pick: a command-line client or a Ruby API.
|
9
|
+
|
10
|
+
**IMPORTANT:** This is **not** an automated Dropbox client. It will exit after sucessfully pushing/pulling, so if you want regular updates, you can run it in cron, a loop, etc. If you do want to run it in a loop, take a look at [sample_polling_script.rb](http://github.com/kenpratt/dbox/blob/master/sample_polling_script.rb). You get deterministic control over what you want Dropbox to do and when you want it to happen.
|
7
11
|
|
8
12
|
|
9
13
|
Installation
|
@@ -17,7 +21,7 @@ $ gem install dbox
|
|
17
21
|
|
18
22
|
### Get developer keys
|
19
23
|
|
20
|
-
* Follow the instructions at https://www.dropbox.com/developers/quickstart to create a Dropbox development application, and copy the application keys. Unless you get your app approved for production status, these keys will only work with the account you create them under, so make sure you are logged in with the account you want to access from dbox
|
24
|
+
* Follow the instructions at https://www.dropbox.com/developers/quickstart to create a Dropbox development application, and copy the application keys. Unless you get your app approved for production status, these keys will only work with the account you create them under, so make sure you are logged in with the account you want to access from ```dbox```.
|
21
25
|
|
22
26
|
* Now either set the keys as environment variables:
|
23
27
|
|
@@ -26,7 +30,7 @@ $ export DROPBOX_APP_KEY=cmlrrjd3j0gbend
|
|
26
30
|
$ export DROPBOX_APP_SECRET=uvuulp75xf9jffl
|
27
31
|
```
|
28
32
|
|
29
|
-
* Or include them in calls to dbox
|
33
|
+
* Or include them in calls to ```dbox```:
|
30
34
|
|
31
35
|
```sh
|
32
36
|
$ DROPBOX_APP_KEY=cmlrrjd3j0gbend DROPBOX_APP_SECRET=uvuulp75xf9jffl dbox ...
|
@@ -53,7 +57,7 @@ $ export DROPBOX_AUTH_KEY=v4d7l1rez1czksn
|
|
53
57
|
$ export DROPBOX_AUTH_SECRET=pqej9rmnj0i1gcxr4
|
54
58
|
```
|
55
59
|
|
56
|
-
* Or include them in calls to dbox
|
60
|
+
* Or include them in calls to ```dbox```:
|
57
61
|
|
58
62
|
```sh
|
59
63
|
$ DROPBOX_AUTH_KEY=v4d7l1rez1czksn DROPBOX_AUTH_SECRET=pqej9rmnj0i1gcxr4 dbox ...
|
@@ -97,6 +101,12 @@ $ dbox pull [<local_path>]
|
|
97
101
|
$ dbox push [<local_path>]
|
98
102
|
```
|
99
103
|
|
104
|
+
#### Sync (pull changes from Dropbox, then push changes to Dropbox)
|
105
|
+
|
106
|
+
```sh
|
107
|
+
$ dbox sync [<local_path>]
|
108
|
+
```
|
109
|
+
|
100
110
|
#### Move (move/rename the Dropbox folder)
|
101
111
|
|
102
112
|
```sh
|
@@ -146,12 +156,20 @@ Oh, Hello
|
|
146
156
|
Using dbox from Ruby
|
147
157
|
--------------------
|
148
158
|
|
149
|
-
The Ruby clone, pull, and push APIs return a hash
|
159
|
+
The Ruby clone, pull, and push APIs return a hash of the changes made during that operation. If any failures were encountered while uploading or downloading from Dropbox, they will be shown in the ```:failed``` entry in the hash. Often, trying your operation again will resolve the failures as the Dropbox API occasionally returns errors for valid operations.
|
150
160
|
|
151
161
|
```ruby
|
152
|
-
{ :created => ["foo.txt"], :deleted => [], :updated => []
|
162
|
+
{ :created => ["foo.txt"], :deleted => [], :updated => [] :failed => [] }
|
153
163
|
```
|
154
164
|
|
165
|
+
If any conflicts occur where file contents would be lost, the conflicting file is renamed and the resulting hash has a ```:conflicts``` entry. On a push operation, the conflicting file being pushed will be renamed. On a pull, the existing file that would have been overwritten will be renamed and the downloaded file will take the name (as that will keep multiple clients in sync).
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
{ :created => [], :updated => [], :deleted => [], :conflicts => [{ :original => "foo.txt", :renamed => "foo (1).txt" }], :failed => [] }
|
169
|
+
```
|
170
|
+
|
171
|
+
The sync API returns a hash with two entries: ```:push``` and ```:pull```, which contain the change hashes for the two operations.
|
172
|
+
|
155
173
|
### Usage
|
156
174
|
|
157
175
|
#### Setup
|
@@ -186,6 +204,12 @@ Dbox.pull(local_path)
|
|
186
204
|
Dbox.push(local_path)
|
187
205
|
```
|
188
206
|
|
207
|
+
#### Sync (pull changes from Dropbox, then push changes to Dropbox)
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
Dbox.sync(local_path)
|
211
|
+
```
|
212
|
+
|
189
213
|
#### Move (move/rename the Dropbox folder)
|
190
214
|
|
191
215
|
```ruby
|
data/TODO.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
+
* Make Dbox case insentive on case sensitive filesystems, as Dropbox is case insensitive.
|
1
2
|
* Refactor threading in change detection in pull to use ParallelTasks?
|
2
3
|
* Saving SQLite db changes dir timestamp -- try to preserve it?
|
3
|
-
* Add a "sync" command that pushes and pulls in one go
|
4
4
|
* See if prepared statements speed up operations on large repos much
|
5
5
|
* Look down directory tree until you hit a .dbox.sqlite3 file so you can use commands from anywhere inside a tree (like git)
|
6
6
|
* Add support for partial push/pull (subtree push/pull)?
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/bin/dbox
CHANGED
@@ -14,6 +14,7 @@ Commands:
|
|
14
14
|
clone <remote_path> [<local_path>] Clone an existing Dropbox folder
|
15
15
|
pull [<local_path>] Pull chonges from Dropbox
|
16
16
|
push [<local_path>] Push changes to Dropbox
|
17
|
+
sync [<local_path>] Sync changes to Dropbox
|
17
18
|
move <new_remote_path> [<local_path>] Move the remote Dropbox folder to a new location
|
18
19
|
|
19
20
|
Environment varables needed for everything:
|
@@ -53,7 +54,7 @@ when "create", "clone"
|
|
53
54
|
|
54
55
|
res = Dbox.send(command, remote_path, local_path)
|
55
56
|
exit 1 if res[:failed].size > 0
|
56
|
-
when "pull", "push"
|
57
|
+
when "pull", "push", "sync"
|
57
58
|
# default to current directory
|
58
59
|
local_path = args[0] || "."
|
59
60
|
|
data/dbox.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "dbox"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.6.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ken Pratt"]
|
12
|
-
s.date = "2011-11-
|
12
|
+
s.date = "2011-11-24"
|
13
13
|
s.description = "An easy-to-use Dropbox client with fine-grained control over syncs."
|
14
14
|
s.email = "ken@kenpratt.net"
|
15
15
|
s.executables = ["dbox"]
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
]
|
20
20
|
s.files = [
|
21
21
|
".document",
|
22
|
+
"History.txt",
|
22
23
|
"LICENSE.txt",
|
23
24
|
"README.md",
|
24
25
|
"Rakefile",
|
@@ -28,23 +29,24 @@ Gem::Specification.new do |s|
|
|
28
29
|
"dbox.gemspec",
|
29
30
|
"lib/dbox.rb",
|
30
31
|
"lib/dbox/api.rb",
|
32
|
+
"lib/dbox/cacert.pem",
|
31
33
|
"lib/dbox/database.rb",
|
32
34
|
"lib/dbox/db.rb",
|
33
35
|
"lib/dbox/loggable.rb",
|
34
36
|
"lib/dbox/parallel_tasks.rb",
|
35
37
|
"lib/dbox/syncer.rb",
|
38
|
+
"lib/dbox/utils.rb",
|
36
39
|
"sample_polling_script.rb",
|
37
40
|
"spec/dbox_spec.rb",
|
38
41
|
"spec/spec_helper.rb",
|
39
|
-
"vendor/dropbox-
|
40
|
-
"vendor/dropbox-
|
41
|
-
"vendor/dropbox-
|
42
|
-
"vendor/dropbox-
|
43
|
-
"vendor/dropbox-
|
44
|
-
"vendor/dropbox-
|
45
|
-
"vendor/dropbox-
|
46
|
-
"vendor/dropbox-
|
47
|
-
"vendor/dropbox-client-ruby/test/util.rb"
|
42
|
+
"vendor/dropbox-ruby-sdk/CHANGELOG",
|
43
|
+
"vendor/dropbox-ruby-sdk/LICENSE",
|
44
|
+
"vendor/dropbox-ruby-sdk/README",
|
45
|
+
"vendor/dropbox-ruby-sdk/cli_example.rb",
|
46
|
+
"vendor/dropbox-ruby-sdk/dropbox_controller.rb",
|
47
|
+
"vendor/dropbox-ruby-sdk/gemspec.rb",
|
48
|
+
"vendor/dropbox-ruby-sdk/lib/dropbox_sdk.rb",
|
49
|
+
"vendor/dropbox-ruby-sdk/web_file_browser.rb"
|
48
50
|
]
|
49
51
|
s.homepage = "http://github.com/kenpratt/dbox"
|
50
52
|
s.licenses = ["MIT"]
|
data/lib/dbox.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
ROOT_PATH = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
2
2
|
$:.unshift File.join(ROOT_PATH, "lib")
|
3
|
-
$:.unshift File.join(ROOT_PATH, "vendor", "dropbox-
|
3
|
+
$:.unshift File.join(ROOT_PATH, "vendor", "dropbox-ruby-sdk", "lib")
|
4
4
|
|
5
|
-
require "
|
5
|
+
require "dropbox_sdk"
|
6
6
|
require "fileutils"
|
7
7
|
require "time"
|
8
8
|
require "yaml"
|
@@ -12,6 +12,7 @@ require "sqlite3"
|
|
12
12
|
require "active_support/core_ext/hash/indifferent_access"
|
13
13
|
|
14
14
|
require "dbox/loggable"
|
15
|
+
require "dbox/utils"
|
15
16
|
require "dbox/api"
|
16
17
|
require "dbox/database"
|
17
18
|
require "dbox/db"
|
@@ -53,6 +54,14 @@ module Dbox
|
|
53
54
|
Dbox::Syncer.push(local_path)
|
54
55
|
end
|
55
56
|
|
57
|
+
def self.sync(local_path)
|
58
|
+
log.debug "Syncing (local: #{local_path})"
|
59
|
+
res = {}
|
60
|
+
res[:pull] = pull(local_path)
|
61
|
+
res[:push] = push(local_path)
|
62
|
+
res
|
63
|
+
end
|
64
|
+
|
56
65
|
def self.move(new_remote_path, local_path)
|
57
66
|
log.debug "Moving (new remote: #{new_remote_path}, local: #{local_path})"
|
58
67
|
new_remote_path = clean_remote_path(new_remote_path)
|
data/lib/dbox/api.rb
CHANGED
@@ -9,19 +9,24 @@ module Dbox
|
|
9
9
|
include Loggable
|
10
10
|
|
11
11
|
def self.authorize
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
app_key = ENV["DROPBOX_APP_KEY"]
|
13
|
+
app_secret = ENV["DROPBOX_APP_SECRET"]
|
14
|
+
|
15
|
+
raise(ConfigurationError, "Please set the DROPBOX_APP_KEY environment variable to a Dropbox application key") unless app_key
|
16
|
+
raise(ConfigurationError, "Please set the DROPBOX_APP_SECRET environment variable to a Dropbox application secret") unless app_secret
|
17
|
+
|
18
|
+
auth = DropboxSession.new(app_key, app_secret)
|
19
|
+
puts "Please visit the following URL in your browser, log into Dropbox, and authorize the app you created.\n\n#{auth.get_authorize_url}\n\nWhen you have done so, press [ENTER] to continue."
|
15
20
|
STDIN.readline
|
16
21
|
res = auth.get_access_token
|
17
|
-
puts "export DROPBOX_AUTH_KEY=#{res.
|
22
|
+
puts "export DROPBOX_AUTH_KEY=#{res.key}"
|
18
23
|
puts "export DROPBOX_AUTH_SECRET=#{res.secret}"
|
19
24
|
puts
|
20
25
|
puts "This auth token will last for 10 years, or when you choose to invalidate it, whichever comes first."
|
21
26
|
puts
|
22
27
|
puts "Now either include these constants in yours calls to dbox, or set them as environment variables."
|
23
28
|
puts "In bash, including them in calls looks like:"
|
24
|
-
puts "$ DROPBOX_AUTH_KEY=#{res.
|
29
|
+
puts "$ DROPBOX_AUTH_KEY=#{res.key} DROPBOX_AUTH_SECRET=#{res.secret} dbox ..."
|
25
30
|
end
|
26
31
|
|
27
32
|
def self.connect
|
@@ -35,7 +40,6 @@ module Dbox
|
|
35
40
|
# IMPORTANT: API.new is private. Please use API.authorize or API.connect as the entry point.
|
36
41
|
private_class_method :new
|
37
42
|
def initialize
|
38
|
-
@conf = self.class.conf
|
39
43
|
end
|
40
44
|
|
41
45
|
def initialize_copy(other)
|
@@ -43,45 +47,57 @@ module Dbox
|
|
43
47
|
end
|
44
48
|
|
45
49
|
def connect
|
50
|
+
app_key = ENV["DROPBOX_APP_KEY"]
|
51
|
+
app_secret = ENV["DROPBOX_APP_SECRET"]
|
46
52
|
auth_key = ENV["DROPBOX_AUTH_KEY"]
|
47
53
|
auth_secret = ENV["DROPBOX_AUTH_SECRET"]
|
48
54
|
|
55
|
+
raise(ConfigurationError, "Please set the DROPBOX_APP_KEY environment variable to a Dropbox application key") unless app_key
|
56
|
+
raise(ConfigurationError, "Please set the DROPBOX_APP_SECRET environment variable to a Dropbox application secret") unless app_secret
|
49
57
|
raise(ConfigurationError, "Please set the DROPBOX_AUTH_KEY environment variable to an authenticated Dropbox session key") unless auth_key
|
50
58
|
raise(ConfigurationError, "Please set the DROPBOX_AUTH_SECRET environment variable to an authenticated Dropbox session secret") unless auth_secret
|
51
59
|
|
52
|
-
@
|
53
|
-
@
|
60
|
+
@session = DropboxSession.new(app_key, app_secret)
|
61
|
+
@session.set_access_token(auth_key, auth_secret)
|
62
|
+
@client = DropboxClient.new(@session, 'dropbox')
|
54
63
|
end
|
55
64
|
|
56
65
|
def run(path)
|
57
66
|
begin
|
58
67
|
res = yield
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
when Net::HTTPNotFound
|
65
|
-
raise RemoteMissing, "#{path} does not exist on Dropbox"
|
66
|
-
when Net::HTTPForbidden
|
67
|
-
raise RequestDenied, "Operation on #{path} denied"
|
68
|
-
when Net::HTTPNotModified
|
69
|
-
:not_modified
|
70
|
-
when true
|
71
|
-
true
|
72
|
-
else
|
73
|
-
raise RuntimeError, "Unexpected result: #{res.inspect}"
|
74
|
-
end
|
68
|
+
handle_response(path, res) { raise RuntimeError, "Unexpected result: #{res.inspect}" }
|
69
|
+
rescue DropboxNotModified => e
|
70
|
+
:not_modified
|
71
|
+
rescue DropboxAuthError => e
|
72
|
+
raise e
|
75
73
|
rescue DropboxError => e
|
76
|
-
|
77
|
-
|
74
|
+
handle_response(path, e.http_response) { raise ServerError, "Server error -- might be a hiccup, please try your request again (#{e.message})" }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def handle_response(path, res, &else_proc)
|
79
|
+
case res
|
80
|
+
when Hash
|
81
|
+
HashWithIndifferentAccess.new(res)
|
82
|
+
when String
|
83
|
+
res
|
84
|
+
when Net::HTTPNotFound
|
85
|
+
raise RemoteMissing, "#{path} does not exist on Dropbox"
|
86
|
+
when Net::HTTPForbidden
|
87
|
+
raise RequestDenied, "Operation on #{path} denied"
|
88
|
+
when Net::HTTPNotModified
|
89
|
+
:not_modified
|
90
|
+
when true
|
91
|
+
true
|
92
|
+
else
|
93
|
+
else_proc.call()
|
78
94
|
end
|
79
95
|
end
|
80
96
|
|
81
|
-
def metadata(path = "/", hash = nil)
|
97
|
+
def metadata(path = "/", hash = nil, list=true)
|
82
98
|
log.debug "Fetching metadata for #{path}"
|
83
99
|
run(path) do
|
84
|
-
res = @client.metadata(
|
100
|
+
res = @client.metadata(path, 10000, list, hash)
|
85
101
|
log.debug res.inspect
|
86
102
|
res
|
87
103
|
end
|
@@ -90,11 +106,14 @@ module Dbox
|
|
90
106
|
def create_dir(path)
|
91
107
|
log.info "Creating #{path}"
|
92
108
|
run(path) do
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
109
|
+
begin
|
110
|
+
@client.file_create_folder(path)
|
111
|
+
rescue DropboxError => e
|
112
|
+
if e.http_response.kind_of?(Net::HTTPForbidden)
|
113
|
+
raise RemoteAlreadyExists, "Either the directory at #{path} already exists, or it has invalid characters in the name"
|
114
|
+
else
|
115
|
+
raise e
|
116
|
+
end
|
98
117
|
end
|
99
118
|
end
|
100
119
|
end
|
@@ -102,67 +121,112 @@ module Dbox
|
|
102
121
|
def delete_dir(path)
|
103
122
|
log.info "Deleting #{path}"
|
104
123
|
run(path) do
|
105
|
-
@client.file_delete(
|
124
|
+
@client.file_delete(path)
|
106
125
|
end
|
107
126
|
end
|
108
127
|
|
109
|
-
def get_file(path,
|
128
|
+
def get_file(path, file_obj, stream=false)
|
110
129
|
log.info "Downloading #{path}"
|
111
|
-
|
112
|
-
|
130
|
+
unless stream
|
131
|
+
# just download directly using the get_file API
|
132
|
+
res = run(path) { @client.get_file(path) }
|
133
|
+
if res.kind_of?(String)
|
134
|
+
file_obj << res
|
135
|
+
true
|
136
|
+
else
|
137
|
+
raise DropboxError.new("Invalid response #{res.inspect}")
|
138
|
+
end
|
139
|
+
else
|
140
|
+
# use the media API to get a URL that we can stream from, and
|
141
|
+
# then stream the file to disk
|
142
|
+
res = run(path) { @client.media(path) }
|
143
|
+
url = res[:url] if res && res.kind_of?(Hash)
|
144
|
+
if url
|
145
|
+
streaming_download(url, file_obj)
|
146
|
+
else
|
147
|
+
get_file(path, file_obj, false)
|
148
|
+
end
|
113
149
|
end
|
114
150
|
end
|
115
151
|
|
116
|
-
def put_file(path, file_obj)
|
152
|
+
def put_file(path, file_obj, previous_revision=nil)
|
117
153
|
log.info "Uploading #{path}"
|
154
|
+
|
155
|
+
# temporary workaround for bug in Dropbox /put_files API where
|
156
|
+
# passing a valid older parent_rev causes a 500
|
157
|
+
if previous_revision
|
158
|
+
m = metadata(path)
|
159
|
+
if m && m[:rev] && m[:rev] != previous_revision
|
160
|
+
previous_revision = nil
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
118
164
|
run(path) do
|
119
|
-
|
120
|
-
name = File.basename(path)
|
121
|
-
@client.put_file(@conf["root"], escape_path(dir), name, file_obj)
|
165
|
+
@client.put_file(path, file_obj, false, previous_revision)
|
122
166
|
end
|
123
167
|
end
|
124
168
|
|
125
169
|
def delete_file(path)
|
126
170
|
log.info "Deleting #{path}"
|
127
171
|
run(path) do
|
128
|
-
@client.file_delete(
|
172
|
+
@client.file_delete(path)
|
129
173
|
end
|
130
174
|
end
|
131
175
|
|
132
176
|
def move(old_path, new_path)
|
133
177
|
log.info "Moving #{old_path} to #{new_path}"
|
134
178
|
run(old_path) do
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
179
|
+
begin
|
180
|
+
@client.file_move(old_path, new_path)
|
181
|
+
rescue DropboxError => e
|
182
|
+
if e.http_response.kind_of?(Net::HTTPForbidden)
|
183
|
+
raise RemoteAlreadyExists, "Error during move -- there may already be a Dropbox folder at #{new_path}"
|
184
|
+
else
|
185
|
+
raise e
|
186
|
+
end
|
140
187
|
end
|
141
188
|
end
|
142
189
|
end
|
143
190
|
|
144
|
-
def
|
145
|
-
|
191
|
+
def streaming_download(url, io)
|
192
|
+
url = URI.parse(url)
|
193
|
+
http = Net::HTTP.new(url.host, url.port)
|
194
|
+
http.use_ssl = true
|
195
|
+
|
196
|
+
req = Net::HTTP::Get.new(url.request_uri)
|
197
|
+
req["User-Agent"] = "OfficialDropboxRubySDK/#{Dropbox::SDK_VERSION}"
|
198
|
+
|
199
|
+
http.request(req) do |res|
|
200
|
+
if res.kind_of?(Net::HTTPSuccess)
|
201
|
+
# stream into given io
|
202
|
+
res.read_body {|chunk| io.write(chunk) }
|
203
|
+
true
|
204
|
+
else
|
205
|
+
raise DropboxError.new("Invalid response #{res}\n#{res.body}")
|
206
|
+
end
|
207
|
+
end
|
146
208
|
end
|
209
|
+
end
|
210
|
+
end
|
147
211
|
|
148
|
-
|
149
|
-
|
150
|
-
|
212
|
+
# monkey-patch DropboxSession to add SSL certificate checking, since the
|
213
|
+
# Dropbox Ruby SDK doesn't do it and doesn't have a place to hook into.
|
214
|
+
class DropboxSession
|
215
|
+
private
|
216
|
+
def do_http(uri, auth_token, request) # :nodoc:
|
217
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
218
|
+
http.use_ssl = true
|
151
219
|
|
152
|
-
|
153
|
-
|
220
|
+
# IMPORTANT: other than these two extra lines, this should be
|
221
|
+
# identical to the definition in dropbox_sdk.rb
|
222
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
223
|
+
http.ca_file = File.join(File.dirname(__FILE__), "cacert.pem")
|
154
224
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
"authorization_url" => "http://www.dropbox.com/0/oauth/authorize",
|
162
|
-
"root" => "dropbox",
|
163
|
-
"consumer_key" => app_key,
|
164
|
-
"consumer_secret" => app_secret
|
165
|
-
}
|
166
|
-
end
|
225
|
+
request.add_field('Authorization', build_auth_header(auth_token))
|
226
|
+
|
227
|
+
#We use this to better understand how developers are using our SDKs.
|
228
|
+
request['User-Agent'] = "OfficialDropboxRubySDK/#{Dropbox::SDK_VERSION}"
|
229
|
+
|
230
|
+
http.request(request)
|
167
231
|
end
|
168
232
|
end
|