vfs 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/Rakefile +2 -2
  2. data/lib/vfs.rb +18 -0
  3. data/lib/vfs/entries/dir.rb +272 -0
  4. data/lib/vfs/entries/entry.rb +127 -0
  5. data/lib/vfs/entries/file.rb +185 -0
  6. data/lib/vfs/entries/universal_entry.rb +24 -0
  7. data/lib/vfs/entry_proxy.rb +38 -0
  8. data/lib/vfs/error.rb +4 -0
  9. data/lib/vfs/integration/string.rb +19 -0
  10. data/lib/vfs/path.rb +125 -0
  11. data/lib/vfs/storages/hash_fs.rb +194 -0
  12. data/lib/vfs/storages/local.rb +138 -0
  13. data/lib/vfs/storages/specification.rb +127 -0
  14. data/lib/vfs/support.rb +2 -0
  15. data/readme.md +110 -14
  16. data/spec/container_spec.rb +31 -0
  17. data/spec/dir_spec.rb +224 -0
  18. data/spec/entry_spec.rb +24 -0
  19. data/spec/file_spec.rb +189 -0
  20. data/spec/path_spec.rb +121 -0
  21. data/spec/spec_helper.rb +2 -9
  22. data/spec/storages/hash_fs_spec.rb +10 -0
  23. data/spec/storages/local_spec.rb +10 -0
  24. data/spec/universal_entry_spec.rb +42 -0
  25. metadata +25 -23
  26. data/lib/old/ssh.rb +0 -11
  27. data/lib/rsh.rb +0 -19
  28. data/lib/rsh/box.rb +0 -182
  29. data/lib/rsh/box/marks.rb +0 -29
  30. data/lib/rsh/drivers/abstract.rb +0 -15
  31. data/lib/rsh/drivers/local.rb +0 -48
  32. data/lib/rsh/drivers/ssh.rb +0 -147
  33. data/lib/rsh/gems.rb +0 -2
  34. data/lib/rsh/support.rb +0 -30
  35. data/spec/abstract_driver.rb +0 -82
  36. data/spec/abstract_driver/dir/dir2/file +0 -0
  37. data/spec/abstract_driver/local_file +0 -1
  38. data/spec/box_spec.rb +0 -109
  39. data/spec/box_spec/dir/dir2/file +0 -0
  40. data/spec/box_spec/local_file +0 -1
  41. data/spec/config.example.yml +0 -4
  42. data/spec/config.yml +0 -5
  43. data/spec/local_driver_spec.rb +0 -9
  44. data/spec/ssh_driver_spec.rb +0 -15
data/Rakefile CHANGED
@@ -2,8 +2,8 @@ require 'rake_ext'
2
2
 
3
3
  project(
4
4
  name: "vfs",
5
- version: "0.0.4",
6
- summary: "Tiny wrapper over Net::SSH/SFTP + small rake addon for cluster configuration management",
5
+ version: "0.1.0",
6
+ summary: "Virtual File System",
7
7
 
8
8
  author: "Alexey Petrushin",
9
9
  homepage: "http://github.com/alexeypetrushin/vfs"
data/lib/vfs.rb ADDED
@@ -0,0 +1,18 @@
1
+ %w(
2
+ support
3
+
4
+ path
5
+ error
6
+
7
+ entries/entry
8
+ entries/file
9
+ entries/dir
10
+ entries/universal_entry
11
+
12
+ entry_proxy
13
+
14
+ storages/hash_fs
15
+ storages/local
16
+
17
+ integration/string
18
+ ).each{|f| require "vfs/#{f}"}
@@ -0,0 +1,272 @@
1
+ module Vfs
2
+ class Dir < Entry
3
+ #
4
+ # Container
5
+ #
6
+ def [] path
7
+ path = path.to_s
8
+ if path =~ /.+[\/]$/
9
+ path = path.sub /\/$/, ''
10
+ dir path
11
+ else
12
+ entry path
13
+ end
14
+ end
15
+ alias_method :/, :[]
16
+
17
+
18
+ #
19
+ # Attributes
20
+ #
21
+ alias_method :exist?, :dir?
22
+
23
+
24
+ #
25
+ # CRUD
26
+ #
27
+ def create options = {}
28
+ storage.open_fs do |fs|
29
+ try = 0
30
+ begin
31
+ try += 1
32
+ fs.create_dir path
33
+ rescue StandardError => error
34
+ entry = self.entry
35
+ attrs = entry.get
36
+ if attrs[:file] #entry.exist?
37
+ if options[:override]
38
+ entry.destroy
39
+ else
40
+ raise Error, "entry #{self} already exist!"
41
+ end
42
+ elsif attrs[:dir]
43
+ # do nothing
44
+ else
45
+ parent = self.parent
46
+ if parent.exist?
47
+ # some unknown error
48
+ raise error
49
+ else
50
+ parent.create(options)
51
+ end
52
+ end
53
+
54
+ retry if try < 2
55
+ end
56
+ end
57
+ self
58
+ end
59
+ def create! options = {}
60
+ options[:override] = true
61
+ create options
62
+ end
63
+
64
+ def destroy options = {}
65
+ storage.open_fs do |fs|
66
+ begin
67
+ fs.delete_dir path
68
+ rescue StandardError => e
69
+ attrs = get
70
+ if attrs[:file]
71
+ if options[:force]
72
+ file.destroy
73
+ else
74
+ raise Error, "can't destroy File #{dir} (You are trying to destroy it as if it's a Dir)"
75
+ end
76
+ elsif attrs[:dir]
77
+ # unknown internal error
78
+ raise e
79
+ else
80
+ # do nothing, file already not exist
81
+ end
82
+ end
83
+ end
84
+ self
85
+ end
86
+ def destroy! options = {}
87
+ options[:force] = true
88
+ destroy options
89
+ end
90
+
91
+
92
+ #
93
+ # Content
94
+ #
95
+ def entries options = {}, &block
96
+ options[:bang] = true unless options.include? :bang
97
+ storage.open_fs do |fs|
98
+ begin
99
+ list = []
100
+ fs.each path do |name, type|
101
+ next if options[:filter] and options[:filter] != type
102
+ entry = if type == :dir
103
+ dir(name)
104
+ elsif type == :file
105
+ file(name)
106
+ else
107
+ raise 'invalid entry type!'
108
+ end
109
+ block ? block.call(entry) : (list << entry)
110
+ end
111
+ block ? nil : list
112
+ rescue StandardError => error
113
+ attrs = get
114
+ if attrs[:file]
115
+ raise Error, "can't query entries on File ('#{self}')!"
116
+ elsif attrs[:dir]
117
+ # unknown error
118
+ raise error
119
+ else
120
+ raise Error, "'#{self}' not exist!" if options[:bang]
121
+ []
122
+ end
123
+ end
124
+ end
125
+ end
126
+ alias_method :each, :entries
127
+
128
+ def files options = {}, &block
129
+ options[:filter] = :file
130
+ entries options, &block
131
+ end
132
+
133
+ def dirs options = {}, &block
134
+ options[:filter] = :dir
135
+ entries options, &block
136
+ end
137
+
138
+ def include? name
139
+ entry[name].exist?
140
+ end
141
+ alias_method :has?, :include?
142
+
143
+
144
+ #
145
+ # Transfers
146
+ #
147
+ def copy_to to, options = {}
148
+ options[:bang] = true unless options.include? :bang
149
+
150
+ raise Error, 'invalid argument' unless to.is_a? Entry
151
+ raise Error, "you can't copy to itself" if self == to
152
+
153
+ target = if to.is_a? File
154
+ raise Error, "can't copy Dir to File ('#{self}')!" unless options[:override]
155
+ to.dir
156
+ elsif to.is_a? Dir
157
+ to.dir #(name)
158
+ elsif to.is_a? UniversalEntry
159
+ # raise "can't copy Dir to File ('#{self}')!" if to.file? and !options[:override]
160
+ to.dir #.create
161
+ else
162
+ raise "can't copy to unknown Entry!"
163
+ end
164
+
165
+ storage.open_fs do |fs|
166
+ try = 0
167
+ begin
168
+ try += 1
169
+ self.class.efficient_dir_copy(self, target) || self.class.unefficient_dir_copy(self, target)
170
+ rescue StandardError => error
171
+ unknown_errors = 0
172
+
173
+ attrs = get
174
+ if attrs[:file]
175
+ raise Error, "can't copy File as a Dir ('#{self}')!"
176
+ elsif attrs[:dir]
177
+ # some unknown error (but it also maybe caused by to be fixed error in 'target')
178
+ unknown_errors += 1
179
+ else
180
+ raise Error, "'#{self}' not exist!" if options[:bang]
181
+ return target
182
+ end
183
+
184
+ attrs = target.get
185
+ if attrs[:file]
186
+ if options[:override]
187
+ to.destroy
188
+ else
189
+ raise Vfs::Error, "entry #{target} already exist!"
190
+ end
191
+ elsif attrs[:dir]
192
+ if options[:override]
193
+ to.destroy
194
+ else
195
+ raise Vfs::Error, "entry #{target} already exist!"
196
+ end
197
+ else
198
+ parent = to.parent
199
+ if parent.exist?
200
+ # some unknown error (but it also maybe caused by already fixed error in 'from')
201
+ unknown_errors += 1
202
+ else
203
+ parent.create(options)
204
+ end
205
+ end
206
+
207
+ raise error if unknown_errors > 1
208
+
209
+ retry if try < 2
210
+ end
211
+ end
212
+
213
+ target
214
+ end
215
+ def copy_to! to, options = {}
216
+ options[:override] = true
217
+ copy_to to, options
218
+ end
219
+
220
+ def move_to to, options = {}
221
+ copy_to to, options
222
+ destroy options
223
+ to
224
+ end
225
+ def move_to! to, options = {}
226
+ options[:override] = true
227
+ move_to to, options
228
+ end
229
+
230
+ protected
231
+ def self.unefficient_dir_copy from, to
232
+ from.storage.open_fs do |from_fs|
233
+ to.storage.open_fs do |to_fs|
234
+ to_fs.create_dir to.path
235
+ from_fs.each from.path do |name, type|
236
+ if type == :dir
237
+ unefficient_dir_copy from.dir(name), to.dir(name)
238
+ elsif type == :file
239
+ to_fs.write_file to.file(name).path, false do |writer|
240
+ from_fs.read_file from.file(name).path do |buff|
241
+ writer.call buff
242
+ end
243
+ end
244
+ else
245
+ raise 'invalid entry type!'
246
+ end
247
+ end
248
+ end
249
+ end
250
+
251
+ # target.create options
252
+ # entries do |e|
253
+ # if e.is_a? Dir
254
+ # e.copy_to target.dir(e.name), options
255
+ # elsif e.is_a? File
256
+ # e.copy_to target.file(e.name), options
257
+ # else
258
+ # raise 'internal error'
259
+ # end
260
+ # end
261
+ end
262
+
263
+ def self.efficient_dir_copy from, to
264
+ from.storage.open_fs{|fs|
265
+ fs.respond_to?(:efficient_dir_copy) and fs.efficient_dir_copy(from, to)
266
+ } or
267
+ to.storage.open_fs{|fs|
268
+ fs.respond_to?(:efficient_dir_copy) and fs.efficient_dir_copy(from, to)
269
+ }
270
+ end
271
+ end
272
+ end
@@ -0,0 +1,127 @@
1
+ module Vfs
2
+ class Entry
3
+ attr_reader :storage, :path, :path_cache
4
+
5
+ def initialize *args
6
+ if args.size == 1 and args.first.is_a? Entry
7
+ entry = args.first
8
+ @path_cache = entry.path_cache
9
+ @storage, @path = entry.storage, entry.path
10
+ else
11
+ storage, path = *args
12
+ @path_cache = Path.new path
13
+ @storage, @path = storage, path_cache.to_s
14
+ end
15
+ raise "storage not defined!" unless self.storage
16
+ end
17
+
18
+
19
+ #
20
+ # Navigation
21
+ #
22
+ def parent
23
+ Dir.new(storage, path_cache + '..')
24
+ end
25
+
26
+
27
+ #
28
+ # Transformations
29
+ #
30
+ def dir path = nil
31
+ if path
32
+ new_path = path_cache + path
33
+ Dir.new storage, new_path
34
+ else
35
+ Dir.new self
36
+ end
37
+ end
38
+ alias_method :to_dir, :dir
39
+
40
+ def file path = nil
41
+ if path
42
+ new_path = path_cache + path
43
+ File.new storage, new_path
44
+ else
45
+ File.new self
46
+ end
47
+ end
48
+ alias_method :to_file, :file
49
+
50
+ def entry path = nil
51
+ entry = if path
52
+
53
+ new_path = path_cache + path
54
+ klass = new_path.probably_dir? ? Dir : UniversalEntry
55
+ entry = klass.new storage, new_path
56
+ else
57
+ UniversalEntry.new self
58
+ end
59
+ EntryProxy.new entry
60
+ end
61
+ alias_method :to_entry, :entry
62
+
63
+
64
+ #
65
+ # Attributes
66
+ #
67
+ def get attr_name = nil
68
+ attrs = storage.open_fs{|fs| fs.attributes(path)}
69
+ attr_name ? attrs[attr_name] : attrs
70
+ end
71
+
72
+ def set options
73
+ not_implemented
74
+ end
75
+
76
+ def dir?
77
+ !!get(:dir)
78
+ end
79
+
80
+ def file?
81
+ !!get(:file)
82
+ end
83
+
84
+
85
+ #
86
+ # Micelaneous
87
+ #
88
+ def name
89
+ path_cache.name
90
+ end
91
+
92
+ def tmp &block
93
+ storage.open_fs do |fs|
94
+ if block
95
+ fs.tmp do |path|
96
+ block.call Dir.new(storage, path)
97
+ end
98
+ else
99
+ Dir.new storage, fs.tmp
100
+ end
101
+ end
102
+ end
103
+
104
+
105
+ #
106
+ # Utils
107
+ #
108
+ def inspect
109
+ "#{storage}#{':' unless storage.to_s.empty?}#{path}"
110
+ end
111
+ alias_method :to_s, :inspect
112
+
113
+ def == other
114
+ return false unless other.is_a? Entry
115
+ storage == other.storage and path == other.path
116
+ end
117
+
118
+ def hash
119
+ storage.hash + path.hash
120
+ end
121
+
122
+ def eql? other
123
+ return false unless other.class == self.class
124
+ storage.eql?(other.storage) and path.eql?(other.path)
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,185 @@
1
+ module Vfs
2
+ class File < Entry
3
+ #
4
+ # Attributes
5
+ #
6
+ alias_method :exist?, :file?
7
+
8
+
9
+ #
10
+ # CRUD
11
+ #
12
+ def read options = {}, &block
13
+ options[:bang] = true unless options.include? :bang
14
+ storage.open_fs do |fs|
15
+ begin
16
+ if block
17
+ fs.read_file path, &block
18
+ else
19
+ data = ""
20
+ fs.read_file(path){|buff| data << buff}
21
+ data
22
+ end
23
+ rescue StandardError => e
24
+ raise Vrs::Error, "can't read Dir #{self}!" if dir.exist?
25
+ attrs = get
26
+ if attrs[:file]
27
+ # unknown internal error
28
+ raise e
29
+ elsif attrs[:dir]
30
+ raise Error, "You are trying to read Dir '#{self}' as if it's a File!"
31
+ else
32
+ if options[:bang]
33
+ raise Error, "file #{self} not exist!"
34
+ else
35
+ block ? block.call('') : ''
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def content options = {}
43
+ read options
44
+ end
45
+
46
+ def create options = {}
47
+ write '', options
48
+ self
49
+ end
50
+ def create! options = {}
51
+ options[:override] = true
52
+ create options
53
+ end
54
+
55
+ def write *args, &block
56
+ storage.open_fs do |fs|
57
+ try = 0
58
+ begin
59
+ try += 1
60
+ if block
61
+ options = args.first || {}
62
+ else
63
+ data, options = *args
64
+ options ||= {}
65
+ end
66
+ raise "can't do :override and :append at the same time!" if options[:override] and options[:append]
67
+ if block
68
+ fs.write_file(path, options[:append], &block)
69
+ else
70
+ fs.write_file(path, options[:append]){|writer| writer.call data}
71
+ end
72
+ rescue StandardError => error
73
+ entry = self.entry
74
+ if entry.exist?
75
+ if options[:override]
76
+ entry.destroy
77
+ else
78
+ raise Error, "entry #{self} already exist!"
79
+ end
80
+ else
81
+ parent = self.parent
82
+ if parent.exist?
83
+ # some unknown error
84
+ raise error
85
+ else
86
+ parent.create(options)
87
+ end
88
+ end
89
+
90
+ retry if try < 2
91
+ end
92
+ end
93
+ self
94
+ end
95
+ def write! *args, &block
96
+ args << {} unless args.last.is_a? Hash
97
+ args.last[:override] = true
98
+ write *args, &block
99
+ end
100
+
101
+ def destroy options = {}
102
+ storage.open_fs do |fs|
103
+ begin
104
+ fs.delete_file path
105
+ self
106
+ rescue StandardError => e
107
+ attrs = get
108
+ if attrs[:dir]
109
+ if options[:force]
110
+ dir.destroy
111
+ else
112
+ raise Error, "can't destroy Dir #{dir} (you are trying to destroy it as if it's a File)"
113
+ end
114
+ elsif attrs[:file]
115
+ # unknown internal error
116
+ raise e
117
+ else
118
+ # do nothing, file already not exist
119
+ end
120
+ end
121
+ end
122
+ self
123
+ end
124
+ def destroy! options = {}
125
+ options[:force] = true
126
+ destroy options
127
+ end
128
+
129
+ def append *args, &block
130
+ if block
131
+ options = args.first || {}
132
+ else
133
+ data, options = *args
134
+ options ||= {}
135
+ end
136
+
137
+ options[:append] = true
138
+ write data, options, &block
139
+ end
140
+
141
+ def update options = {}, &block
142
+ options[:override] = true
143
+ data = read options
144
+ write block.call(data), options
145
+ end
146
+
147
+
148
+ #
149
+ # Transfers
150
+ #
151
+ def copy_to to, options = {}
152
+ raise Error, "you can't copy to itself" if self == to
153
+
154
+ target = if to.is_a? File
155
+ to
156
+ elsif to.is_a? Dir
157
+ to.file #(name)
158
+ elsif to.is_a? UniversalEntry
159
+ to.file
160
+ else
161
+ raise "can't copy to unknown Entry!"
162
+ end
163
+
164
+ target.write options do |writer|
165
+ read(options){|buff| writer.call buff}
166
+ end
167
+
168
+ target
169
+ end
170
+ def copy_to! to, options = {}
171
+ options[:override] = true
172
+ copy_to to, options
173
+ end
174
+
175
+ def move_to to, options = {}
176
+ copy_to to, options
177
+ destroy options
178
+ to
179
+ end
180
+ def move_to! to, options = {}
181
+ options[:override] = true
182
+ move_to to, options
183
+ end
184
+ end
185
+ end