odisk 0.2.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/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
|