dropbox-folder-sync 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ InstalledFiles
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dropbox-folder-sync.gemspec
4
+ gemspec
5
+ gem "rake"
6
+ gem "thor"
7
+ gem "dropbox-sdk"
8
+ gem "launchy"
9
+ gem "keystorage"
10
+
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dropbox-folder-sync (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.2.7)
10
+ dropbox-sdk (1.3)
11
+ json
12
+ json (1.6.5)
13
+ keystorage (0.4.7)
14
+ launchy (2.0.5)
15
+ addressable (~> 2.2.6)
16
+ rake (0.9.2.2)
17
+ thor (0.14.6)
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ dropbox-folder-sync!
24
+ dropbox-sdk
25
+ keystorage
26
+ launchy
27
+ rake
28
+ thor
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Yoshihiro TAKAHARA
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ DropboxFolderSync
2
+ =================
3
+
4
+ Sync Dropbox Folder with Local directory via Dropbox API.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'dropbox-folder-sync'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install dropbox-folder-sync
19
+
20
+ ## Usage
21
+
22
+ ### Register your own app
23
+
24
+ > https://www.dropbox.com/developers/apps
25
+
26
+ and set env vars.
27
+
28
+ export DROPBOX_FOLDER_SYNC_APP_KEY='app-key-form-dropbox'
29
+ export DROPBOX_FOLDER_SYNC_APP_SECRET='secret key here'
30
+
31
+
32
+ ### Login and link with Dropbox
33
+
34
+ Usage:
35
+ $ dropbox-folder login [NAME]
36
+
37
+ *NAME* is identifer of Dropbox account. Please name your own easy to understand. *default* is used as name if not specified.
38
+
39
+ ### Synchronize
40
+
41
+ Usage:
42
+ $ dropbox-folder sync [NAME:]/PATH/TO/REMOTE /PATH/TO/LOCAL
43
+
44
+ Options:
45
+ -i, [--interval=sec] # sync interval (seconds) , default = 1
46
+
47
+
48
+ ### Logout and unlink from Dropbox
49
+
50
+ Usage:
51
+ $ dropbox-folder logout [NAME]
52
+
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__),'..','lib')))
4
+ require 'dropbox-folder-sync'
5
+ DropboxFolderSync::CLI.start
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/dropbox-folder-sync/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Yoshihiro TAKAHARA"]
6
+ gem.email = ["y.takahara@gmail.com"]
7
+ gem.description = %q{Sync Dropbox folder with local directory}
8
+ gem.summary = %q{Sync Dropbox folder with local directory }
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "dropbox-folder-sync"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = DropboxFolderSync::VERSION
17
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ module DropboxFolderSync
5
+ autoload :VERSION, "dropbox-folder-sync/version"
6
+ autoload :CLI, "dropbox-folder-sync/cli"
7
+ end
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ # $:.unshift(File.expand_path(File.join(File.dirname(__FILE__),'..')))
4
+ require 'dropbox_sdk'
5
+ require 'launchy'
6
+ require 'keystorage'
7
+
8
+ class DropboxFolderSync::App
9
+ APP_KEY = ENV['DROPBOX_FOLDER_SYNC_APP_KEY']
10
+ APP_SECRET = ENV['DROPBOX_FOLDER_SYNC_APP_SECRET']
11
+
12
+ def initialize
13
+ unless (APP_KEY and APP_SECRET)
14
+ raise "set env vars 'DROPBOX_FOLDER_SYNC_APP_KEY' and 'DROPBOX_FOLDER_SYNC_APP_SECRET'"
15
+ end
16
+ @session = DropboxSession.new(APP_KEY, APP_SECRET)
17
+ end
18
+
19
+ def login name
20
+ key = Keystorage.get("DROPBOX_APP_"+APP_KEY+"_USER_KEY",name)
21
+ secret = Keystorage.get("DROPBOX_APP_"+APP_KEY+"_USER_SECRET",name)
22
+ if key and secret
23
+ @session.set_access_token(key,secret)
24
+ @session.get_access_token rescue {}
25
+ return true if @session.authorized?
26
+ end
27
+
28
+ @session.get_request_token
29
+ authorize_url = @session.get_authorize_url
30
+ puts "Login: [#{name}] ---> #{authorize_url}"
31
+ Launchy.open authorize_url
32
+ while 1
33
+ @session.get_access_token rescue {}
34
+ break if @session.authorized?
35
+ sleep 1
36
+ end
37
+ Keystorage.set("DROPBOX_APP_"+APP_KEY+"_USER_KEY",name,@session.access_token.key.to_s)
38
+ Keystorage.set("DROPBOX_APP_"+APP_KEY+"_USER_SECRET",name,@session.access_token.secret.to_s)
39
+ true
40
+ end
41
+
42
+ def logout name
43
+ Keystorage.delete("DROPBOX_APP_"+APP_KEY+"_USER_KEY",name)
44
+ Keystorage.delete("DROPBOX_APP_"+APP_KEY+"_USER_SECRET",name)
45
+ true
46
+ end
47
+
48
+ def log(message)
49
+ puts message
50
+ end
51
+
52
+ def local_file_meta(path)
53
+ { :path => path,
54
+ :modified => File.mtime(path),
55
+ :id_dir => File.directory?(path)}
56
+ end
57
+
58
+ def remote_path local
59
+ @remote_root+local[@local_root.length..-1]
60
+ end
61
+
62
+ def local_path remote
63
+ @local_root+remote[@remote_root.length..-1]
64
+ end
65
+
66
+ def remote_delta cur
67
+ delta = @client.delta(cur)
68
+ cur = delta["cursor"]
69
+
70
+ if delta["reset"] == "true"
71
+ @local_files = {}
72
+ Dir::glob(@local_root + "/**/*").each { |path|
73
+ @local_files[path] = local_file_meta(path)
74
+ }
75
+ end
76
+
77
+ delta["entries"].each { |path,meta|
78
+ local = local_path(path)
79
+ if path == @remote_root or /^#{@remote_root}\// =~ path
80
+ unless meta
81
+ if File.exists?(local)
82
+ log "remove #{local}"
83
+ FileUtils.remove_entry(local)
84
+ @local_files.reject! { |k,v| k == local }
85
+ if File.directory?(local)
86
+ @local_files.reject! { |k,v| /^#{local}\/.*/ =~ k }
87
+ end
88
+ end
89
+ next
90
+ end
91
+
92
+ if meta["is_dir"] #dir
93
+ log "----> #{local}"
94
+ FileUtils.mkdir_p local unless File.exists?(local)
95
+ else #file
96
+ out = @client.get_file(path)
97
+ open(local, 'w'){|f| f.puts out }
98
+ log "----> #{local}"
99
+ end
100
+ @local_files[local] = local_file_meta(local)
101
+ end
102
+ } # delta
103
+ cur
104
+ end
105
+
106
+ def check_local_modified
107
+ # check local modified
108
+ Dir::glob(@local_root + "/**/*").each { |path|
109
+ remote = remote_path(path)
110
+ # new file
111
+ unless @local_files.include?(path)
112
+ @local_files[path] = local_file_meta(path)
113
+ log "<---- #{path}"
114
+ if File.file?(path)
115
+ @client.put_file(remote, open(path))
116
+ elsif File.directory?(path)
117
+ @client.file_create_folder(remote)
118
+ end
119
+ next
120
+ end
121
+
122
+ # modified
123
+ if File.file?(path) and File.mtime(path) > @local_files[path][:modified]
124
+ @local_files[path] = local_file_meta(path)
125
+ @client.put_file(remote, open(path))
126
+ end
127
+ }
128
+ end
129
+
130
+ def check_local_removed
131
+ # check removed
132
+ @local_files.each { |path,v|
133
+ unless File.exists?(path)
134
+ log "remote delete #{path}"
135
+ @local_files.reject! { |k,v| k == path }
136
+ @client.file_delete(remote_path(path))
137
+ end
138
+ }
139
+ end
140
+
141
+ def sync(remote,local,options)
142
+ name,@remote_root = parse_remote(remote)
143
+ @local_root = path_normalize(File.expand_path(local))
144
+ login(name) unless @session.authorized?
145
+ @client = DropboxClient.new(@session, :dropbox)
146
+ log "#{@remote_root} <---> #{@local_root}"
147
+ @local_files = {}
148
+ cur = nil
149
+ while true
150
+ cur = remote_delta(cur)
151
+ check_local_modified
152
+ check_local_removed
153
+ sleep options[:interval]
154
+ end
155
+ end
156
+
157
+ def path_normalize path
158
+ path = "/" + path if path[0,1] != "/"
159
+ path = path[0,path.length - 1] if path[-1,1] == "/"
160
+ path
161
+ end
162
+
163
+ def parse_remote remote
164
+ name = "default"
165
+ if /^([^\/]+):(.*)/ =~ remote
166
+ name = $1
167
+ remote = $2
168
+ end
169
+ [name,path_normalize(remote)]
170
+ end
171
+
172
+ class << self
173
+ def sync remote,local,options
174
+ new.sync(remote,local,options)
175
+ end
176
+ def login name
177
+ new.login(name)
178
+ end
179
+ def logout name
180
+ new.logout(name)
181
+ end
182
+ end
183
+
184
+ end
185
+
186
+ if $0 == __FILE__
187
+
188
+ end
189
+
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ # $:.unshift(File.expand_path(File.join(File.dirname(__FILE__),'..')))
4
+ require 'thor'
5
+ require 'dropbox-folder-sync/app'
6
+ class DropboxFolderSync::CLI < Thor
7
+
8
+ desc 'login [NAME]', "Login and Link with Dropbox account."
9
+ def login name="default"
10
+ DropboxFolderSync::App.login(name)
11
+ end
12
+
13
+ desc 'logout [NAME]', "Logout and unink from Dropbox account."
14
+ def logout name="default"
15
+ DropboxFolderSync::App.logout(name)
16
+ end
17
+
18
+ desc 'sync [NAME:]/PATH/TO/DROPBOX /PATH/TO/REMOTE', "Sync local directory with Dropbox"
19
+ method_option :interval, :type => :numeric, :aliases => "-i", :desc => "Sync interval (sec)", :default => 1
20
+ def sync remote,local
21
+ DropboxFolderSync::App.sync(remote,local,options)
22
+ end
23
+ end
24
+
25
+ if $0 == __FILE__
26
+
27
+ end
28
+
@@ -0,0 +1,3 @@
1
+ module DropboxFolderSync
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dropbox-folder-sync
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Yoshihiro TAKAHARA
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-04-01 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: Sync Dropbox folder with local directory
22
+ email:
23
+ - y.takahara@gmail.com
24
+ executables:
25
+ - dropbox-folder
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - .gitignore
32
+ - Gemfile
33
+ - Gemfile.lock
34
+ - LICENSE
35
+ - README.md
36
+ - Rakefile
37
+ - bin/dropbox-folder
38
+ - dropbox-folder-sync.gemspec
39
+ - lib/dropbox-folder-sync.rb
40
+ - lib/dropbox-folder-sync/app.rb
41
+ - lib/dropbox-folder-sync/cli.rb
42
+ - lib/dropbox-folder-sync/version.rb
43
+ homepage: ""
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options: []
48
+
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ hash: 3
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.8.12
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Sync Dropbox folder with local directory
76
+ test_files: []
77
+