vfs 0.0.4 → 0.1.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.
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