odisk 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +27 -0
- data/README.md +150 -0
- data/bin/odisk +184 -0
- data/lib/odisk.rb +46 -0
- data/lib/odisk/copier.rb +74 -0
- data/lib/odisk/crypter.rb +40 -0
- data/lib/odisk/diff.rb +81 -0
- data/lib/odisk/digest.rb +85 -0
- data/lib/odisk/digester.rb +33 -0
- data/lib/odisk/dir.rb +10 -0
- data/lib/odisk/dirsyncjob.rb +25 -0
- data/lib/odisk/fetcher.rb +54 -0
- data/lib/odisk/file.rb +18 -0
- data/lib/odisk/info.rb +40 -0
- data/lib/odisk/link.rb +18 -0
- data/lib/odisk/planner.rb +309 -0
- data/lib/odisk/remote.rb +45 -0
- data/lib/odisk/statfixer.rb +102 -0
- data/lib/odisk/statjob.rb +32 -0
- data/lib/odisk/syncjob.rb +25 -0
- data/lib/odisk/syncstarter.rb +37 -0
- data/lib/odisk/version.rb +5 -0
- metadata +135 -0
data/lib/odisk/remote.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
module ODisk
|
3
|
+
# Just a way to keep the data associated with a remote site together one
|
4
|
+
# Object.
|
5
|
+
class Remote
|
6
|
+
attr_accessor :user
|
7
|
+
attr_accessor :host
|
8
|
+
attr_accessor :dir
|
9
|
+
attr_accessor :pass_file
|
10
|
+
|
11
|
+
def initialize()
|
12
|
+
@user = nil
|
13
|
+
@host = nil
|
14
|
+
@dir = nil
|
15
|
+
@pass_file = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# Expects a string as input of the form user@remote.com:dir:passphrase_file
|
19
|
+
def update(str)
|
20
|
+
u, x = str.strip().split('@')
|
21
|
+
h, t, p = x.split(':')
|
22
|
+
@user = u if @user.nil? && u.is_a?(String) && !u.empty?
|
23
|
+
@host = h if @host.nil? && h.is_a?(String) && !h.empty?
|
24
|
+
@dir = t if @dir.nil? && t.is_a?(String) && !t.empty?
|
25
|
+
@pass_file = p if @pass_file.nil? && p.is_a?(String) && !p.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def complete?()
|
29
|
+
!(@user.nil? || @host.nil? || @dir.nil? || @pass_file.nil?)
|
30
|
+
end
|
31
|
+
|
32
|
+
def okay?()
|
33
|
+
!(@user.nil? || @host.nil? || @dir.nil?)
|
34
|
+
end
|
35
|
+
|
36
|
+
def encrypt?()
|
37
|
+
!@pass_file.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s()
|
41
|
+
"#{user}@#{host}:#{@dir}:#{@pass_file}"
|
42
|
+
end
|
43
|
+
|
44
|
+
end # Remote
|
45
|
+
end # ODisk
|
@@ -0,0 +1,102 @@
|
|
1
|
+
|
2
|
+
module ODisk
|
3
|
+
class StatFixer < ::Opee::Collector
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
super(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def set_options(options)
|
10
|
+
super(options)
|
11
|
+
@dir_queue = options[:dir_queue]
|
12
|
+
@copy_queue = options[:copy_queue]
|
13
|
+
@crypt_queue = options[:crypt_queue]
|
14
|
+
@inputs = options[:inputs]
|
15
|
+
@fixer = options[:fixer]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def job_key(job)
|
21
|
+
if job.is_a?(StatJob)
|
22
|
+
job.key()
|
23
|
+
elsif job.is_a?(String)
|
24
|
+
::File.dirname(job)
|
25
|
+
else
|
26
|
+
raise "Invalid path for StatFixer"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_token(job, token, path_id)
|
31
|
+
# StatJob or String (a file path) can be received
|
32
|
+
if job.is_a?(StatJob)
|
33
|
+
if token.nil?
|
34
|
+
job.digest.entries.each do |e|
|
35
|
+
fix_stats(::File.join(job.path, e.name), e) unless job.mods.include?(e.name)
|
36
|
+
end
|
37
|
+
elsif token.is_a?(Array)
|
38
|
+
until (path = token.pop).nil?
|
39
|
+
name = ::File.basename(path)
|
40
|
+
fix_stats(path, job.digest.entries[name])
|
41
|
+
job.mods.delete(name)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
raise "Expected StatFixer token to be an Array or nil"
|
45
|
+
end
|
46
|
+
token = job
|
47
|
+
else
|
48
|
+
if token.nil?
|
49
|
+
token = [job]
|
50
|
+
elsif token.is_a?(Array)
|
51
|
+
token << job
|
52
|
+
elsif token.is_a?(StatJob)
|
53
|
+
name = ::File.basename(job)
|
54
|
+
fix_stats(job, token.digest[name])
|
55
|
+
token.mods.delete(name)
|
56
|
+
else
|
57
|
+
raise "Expected StatFixer token to be an Array, StatJob, or nil"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
token
|
61
|
+
end
|
62
|
+
|
63
|
+
def complete?(job, token)
|
64
|
+
result = token.is_a?(StatJob) ? token.complete?(token) : false
|
65
|
+
::Opee::Env.info("complete?(#{job}, #{token}) => #{result}")
|
66
|
+
result
|
67
|
+
end
|
68
|
+
|
69
|
+
def keep_going(job)
|
70
|
+
# done, nothing left to do
|
71
|
+
# TBD tell progress about the completion
|
72
|
+
end
|
73
|
+
|
74
|
+
def fix_stats(path, info)
|
75
|
+
e = Digest.create_info(path)
|
76
|
+
diff = Diff.new(e, info)
|
77
|
+
unless e == info
|
78
|
+
h = {}
|
79
|
+
diff.fill_hash(nil, h, true)
|
80
|
+
h.each do |attr,val|
|
81
|
+
case attr
|
82
|
+
when :mtime
|
83
|
+
::File.utime(info.mtime, info.mtime, path) unless info.is_a?(::ODisk::Link)
|
84
|
+
when :owner
|
85
|
+
owner = Etc.getpwnam(info.owner).uid
|
86
|
+
group = Etc.getgrnam(info.group).gid
|
87
|
+
::File::lchown(owner, group, path)
|
88
|
+
when :group
|
89
|
+
owner = Etc.getpwnam(info.owner).uid
|
90
|
+
group = Etc.getgrnam(info.group).gid
|
91
|
+
::File::lchown(owner, group, path)
|
92
|
+
when :mode
|
93
|
+
::File::lchmod(val[1], path)
|
94
|
+
else
|
95
|
+
# ignore?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end # StatFixer
|
102
|
+
end # ODisk
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
module ODisk
|
3
|
+
class StatJob < ::Opee::Job
|
4
|
+
|
5
|
+
attr_reader :path
|
6
|
+
attr_reader :mods
|
7
|
+
attr_accessor :digest
|
8
|
+
|
9
|
+
def initialize(path, digest)
|
10
|
+
@path = path
|
11
|
+
@digest = digest
|
12
|
+
@mods = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_mod(name)
|
16
|
+
@mods << name
|
17
|
+
end
|
18
|
+
|
19
|
+
def key()
|
20
|
+
@path
|
21
|
+
end
|
22
|
+
|
23
|
+
def complete?(token)
|
24
|
+
@mods.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s()
|
28
|
+
"<StatJob:#{@path} [#{@mods.join(',')}]>"
|
29
|
+
end
|
30
|
+
|
31
|
+
end # StatJob
|
32
|
+
end # ODisk
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
module ODisk
|
3
|
+
class SyncJob < ::Opee::Job
|
4
|
+
|
5
|
+
STATS = 0
|
6
|
+
REMOVE = 1
|
7
|
+
COPY = 2
|
8
|
+
|
9
|
+
# location of master
|
10
|
+
OREFS = 0 # encrypted master
|
11
|
+
LOCAL = 1
|
12
|
+
REMOTE = 2
|
13
|
+
|
14
|
+
attr_reader :path
|
15
|
+
attr_reader :master
|
16
|
+
attr_reader :op
|
17
|
+
|
18
|
+
def initialize(rel_path, master, op)
|
19
|
+
@path = rel_path
|
20
|
+
@master = master
|
21
|
+
@op = op
|
22
|
+
end
|
23
|
+
|
24
|
+
end # SyncJob
|
25
|
+
end # ODisk
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
module ODisk
|
3
|
+
class SyncStarter < ::Opee::Actor
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
@digester = nil
|
7
|
+
@fetcher = nil
|
8
|
+
super(options)
|
9
|
+
@dir_queue.ask(:ready, self)
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_options(options)
|
13
|
+
super(options)
|
14
|
+
@dir_queue = options[:dir_queue]
|
15
|
+
@digester = options[:digester]
|
16
|
+
@fetcher = options[:fetcher]
|
17
|
+
@collector = options[:collector]
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def start(path)
|
23
|
+
::Opee::Env.info("start sync for #{path}")
|
24
|
+
job = DirSyncJob.new(path)
|
25
|
+
@fetcher.ask(:fetch, job) unless @fetcher.nil?
|
26
|
+
@digester.ask(:create, job) unless @digester.nil?
|
27
|
+
|
28
|
+
top = (path.nil? || path.empty?) ? $local_top : ::File.join($local_top, path)
|
29
|
+
prev_path = ::File.join(top, '.odisk', 'digest.json')
|
30
|
+
job.previous_digest = ::Oj.load_file(prev_path, mode: :object) if ::File.file?(prev_path)
|
31
|
+
@collector.ask(:collect, job, :starter) unless @collector.nil?
|
32
|
+
# ready for another
|
33
|
+
@dir_queue.ask(:ready, self)
|
34
|
+
end
|
35
|
+
|
36
|
+
end # SyncStarter
|
37
|
+
end # ODisk
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: odisk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Peter Ohler
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: opee
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: oj
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: net-ssh
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
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: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: net-sftp
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Remote Encrypted File Synchronization, oDisk
|
79
|
+
email: peter@ohler.com
|
80
|
+
executables:
|
81
|
+
- odisk
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files:
|
84
|
+
- README.md
|
85
|
+
files:
|
86
|
+
- lib/odisk/copier.rb
|
87
|
+
- lib/odisk/crypter.rb
|
88
|
+
- lib/odisk/diff.rb
|
89
|
+
- lib/odisk/digest.rb
|
90
|
+
- lib/odisk/digester.rb
|
91
|
+
- lib/odisk/dir.rb
|
92
|
+
- lib/odisk/dirsyncjob.rb
|
93
|
+
- lib/odisk/fetcher.rb
|
94
|
+
- lib/odisk/file.rb
|
95
|
+
- lib/odisk/info.rb
|
96
|
+
- lib/odisk/link.rb
|
97
|
+
- lib/odisk/planner.rb
|
98
|
+
- lib/odisk/remote.rb
|
99
|
+
- lib/odisk/statfixer.rb
|
100
|
+
- lib/odisk/statjob.rb
|
101
|
+
- lib/odisk/syncjob.rb
|
102
|
+
- lib/odisk/syncstarter.rb
|
103
|
+
- lib/odisk/version.rb
|
104
|
+
- lib/odisk.rb
|
105
|
+
- LICENSE
|
106
|
+
- README.md
|
107
|
+
- bin/odisk
|
108
|
+
homepage: http://www.ohler.com/odisk
|
109
|
+
licenses: []
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options:
|
112
|
+
- --main
|
113
|
+
- README.md
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
requirements: []
|
129
|
+
rubyforge_project: odisk
|
130
|
+
rubygems_version: 1.8.23
|
131
|
+
signing_key:
|
132
|
+
specification_version: 3
|
133
|
+
summary: Remote Encrypted File Synchronization, oDisk
|
134
|
+
test_files: []
|
135
|
+
has_rdoc: true
|