vfs-momolog 0.0.1
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/.gitignore +8 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/Rakefile +2 -0
- data/docs/basics.rb +116 -0
- data/docs/s3_backup.rb +29 -0
- data/docs/s3_backup/app/files/bos.png +0 -0
- data/docs/s3_basics.rb +19 -0
- data/docs/s3_sandbox.rb +24 -0
- data/docs/site/404.html +8 -0
- data/docs/site/basics.html +305 -0
- data/docs/site/index.html +8 -0
- data/docs/site/s3_backup.html +111 -0
- data/docs/site/s3_basics.html +84 -0
- data/docs/site/s3_sandbox.html +99 -0
- data/docs/site/ssh_basics.html +84 -0
- data/docs/site/ssh_deployment.html +125 -0
- data/docs/site/ssh_sandbox.html +103 -0
- data/docs/ssh_basics.rb +19 -0
- data/docs/ssh_deployment.rb +35 -0
- data/docs/ssh_deployment/app/app.rb +0 -0
- data/docs/ssh_sandbox.rb +28 -0
- data/lib/vfs.rb +18 -0
- data/lib/vfs/drivers/local.rb +180 -0
- data/lib/vfs/drivers/specification.rb +169 -0
- data/lib/vfs/entries/dir.rb +256 -0
- data/lib/vfs/entries/entry.rb +152 -0
- data/lib/vfs/entries/file.rb +155 -0
- data/lib/vfs/entries/universal_entry.rb +24 -0
- data/lib/vfs/entry_proxy.rb +42 -0
- data/lib/vfs/error.rb +4 -0
- data/lib/vfs/integration.rb +30 -0
- data/lib/vfs/path.rb +123 -0
- data/lib/vfs/version.rb +3 -0
- data/lib/vfs/vfs.rb +38 -0
- data/old/hash_fs.rb +216 -0
- data/old/hash_fs_spec.rb +10 -0
- data/readme.md +143 -0
- data/spec/container_spec.rb +31 -0
- data/spec/dir_spec.rb +253 -0
- data/spec/entry_spec.rb +42 -0
- data/spec/file_spec.rb +215 -0
- data/spec/misc_spec.rb +19 -0
- data/spec/path_spec.rb +127 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/storages/local_spec.rb +24 -0
- data/spec/storages/local_spec/emptygit +0 -0
- data/spec/universal_entry_spec.rb +69 -0
- data/todo.md +19 -0
- data/vfs.gemspec +17 -0
- metadata +105 -0
@@ -0,0 +1,256 @@
|
|
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
|
+
elsif path =~ /\*/
|
12
|
+
entries path
|
13
|
+
else
|
14
|
+
entry path
|
15
|
+
end
|
16
|
+
end
|
17
|
+
alias_method :/, :[]
|
18
|
+
|
19
|
+
|
20
|
+
#
|
21
|
+
# Attributes
|
22
|
+
#
|
23
|
+
alias_method :exist?, :dir?
|
24
|
+
|
25
|
+
|
26
|
+
#
|
27
|
+
# CRUD
|
28
|
+
#
|
29
|
+
def create options = {}
|
30
|
+
driver.open do
|
31
|
+
try = 0
|
32
|
+
begin
|
33
|
+
try += 1
|
34
|
+
driver.create_dir path
|
35
|
+
rescue StandardError => error
|
36
|
+
entry = self.entry
|
37
|
+
attrs = entry.get
|
38
|
+
if attrs and attrs[:file] #entry.exist?
|
39
|
+
entry.destroy
|
40
|
+
elsif attrs and attrs[:dir]
|
41
|
+
# dir already exist, no need to recreate it
|
42
|
+
return self
|
43
|
+
else
|
44
|
+
parent = self.parent
|
45
|
+
if parent.exist?
|
46
|
+
# some unknown error
|
47
|
+
raise error
|
48
|
+
else
|
49
|
+
parent.create(options)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
try < 2 ? retry : raise(error)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def destroy options = {}
|
60
|
+
destroy_entry :dir, :file
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
#
|
65
|
+
# Content
|
66
|
+
#
|
67
|
+
def entries *args, &block
|
68
|
+
raise "invalid arguments #{args.inspect}!" if args.size > 2
|
69
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
70
|
+
query = args.first
|
71
|
+
options[:bang] = true unless options.include? :bang
|
72
|
+
filter = options[:filter]
|
73
|
+
type_required = options[:type]
|
74
|
+
|
75
|
+
driver.open do
|
76
|
+
begin
|
77
|
+
list = []
|
78
|
+
# query option is optional and supported only for some drivers (local driver for example)
|
79
|
+
driver.each_entry path, query do |name, type|
|
80
|
+
# for performance reasons some drivers may return the type of entry as
|
81
|
+
# optionally evaluated callback.
|
82
|
+
type = type.call if (filter or type_required) and type.is_a?(Proc)
|
83
|
+
|
84
|
+
next if name == ''
|
85
|
+
next if filter and (filter != type)
|
86
|
+
|
87
|
+
entry = if type == :dir
|
88
|
+
dir(name)
|
89
|
+
elsif type == :file
|
90
|
+
file(name)
|
91
|
+
else
|
92
|
+
entry(name)
|
93
|
+
end
|
94
|
+
block ? block.call(entry) : (list << entry)
|
95
|
+
end
|
96
|
+
block ? nil : list
|
97
|
+
rescue StandardError => error
|
98
|
+
attrs = get
|
99
|
+
if attrs and attrs[:file]
|
100
|
+
raise Error, "can't query entries on File ('#{self}')!"
|
101
|
+
elsif attrs and attrs[:dir]
|
102
|
+
# some unknown error
|
103
|
+
raise error
|
104
|
+
else
|
105
|
+
# TODO2 remove :bang
|
106
|
+
raise Error, "'#{self}' not exist!" if options[:bang]
|
107
|
+
[]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
alias_method :each, :entries
|
113
|
+
|
114
|
+
def files *args, &block
|
115
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
116
|
+
|
117
|
+
options[:filter] = :file
|
118
|
+
args << options
|
119
|
+
entries *args, &block
|
120
|
+
end
|
121
|
+
|
122
|
+
def dirs *args, &block
|
123
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
124
|
+
|
125
|
+
options[:filter] = :dir
|
126
|
+
args << options
|
127
|
+
entries *args, &block
|
128
|
+
end
|
129
|
+
|
130
|
+
def include? name
|
131
|
+
entry[name].exist?
|
132
|
+
end
|
133
|
+
alias_method :has?, :include?
|
134
|
+
|
135
|
+
def empty?
|
136
|
+
catch :break do
|
137
|
+
entries{|e| throw :break, false}
|
138
|
+
true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
#
|
144
|
+
# Transfers
|
145
|
+
#
|
146
|
+
def copy_to to, options = {}
|
147
|
+
options[:bang] = true unless options.include? :bang
|
148
|
+
|
149
|
+
raise Error, "invalid argument, destination should be a Entry (#{to})!" unless to.is_a? Entry
|
150
|
+
raise Error, "you can't copy to itself" if self == to
|
151
|
+
|
152
|
+
target = if to.is_a? File
|
153
|
+
to.dir
|
154
|
+
elsif to.is_a? Dir
|
155
|
+
to.dir #(name)
|
156
|
+
elsif to.is_a? UniversalEntry
|
157
|
+
# raise "can't copy Dir to File ('#{self}')!" if to.file? and !options[:override]
|
158
|
+
to.dir #.create
|
159
|
+
else
|
160
|
+
raise "can't copy to unknown Entry!"
|
161
|
+
end
|
162
|
+
|
163
|
+
# efficient_dir_copy(target, options) || unefficient_dir_copy(target, options)
|
164
|
+
unefficient_dir_copy(target, options)
|
165
|
+
|
166
|
+
target
|
167
|
+
end
|
168
|
+
|
169
|
+
def move_to to, options = {}
|
170
|
+
copy_to to, options
|
171
|
+
destroy options
|
172
|
+
to
|
173
|
+
end
|
174
|
+
|
175
|
+
# class << self
|
176
|
+
# attr_accessor :dont_use_efficient_dir_copy
|
177
|
+
# end
|
178
|
+
|
179
|
+
protected
|
180
|
+
def unefficient_dir_copy to, options
|
181
|
+
to.create options
|
182
|
+
entries options.merge(type: true) do |e|
|
183
|
+
if e.is_a? Dir
|
184
|
+
e.copy_to to.dir(e.name), options
|
185
|
+
elsif e.is_a? File
|
186
|
+
e.copy_to to.file(e.name), options
|
187
|
+
else
|
188
|
+
raise 'internal error'
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
# def efficient_dir_copy to, options
|
195
|
+
# return false if self.class.dont_use_efficient_dir_copy
|
196
|
+
#
|
197
|
+
# driver.open do
|
198
|
+
# try = 0
|
199
|
+
# begin
|
200
|
+
# try += 1
|
201
|
+
# self.class.efficient_dir_copy(self, to, options[:override])
|
202
|
+
# rescue StandardError => error
|
203
|
+
# unknown_errors = 0
|
204
|
+
#
|
205
|
+
# attrs = get
|
206
|
+
# if attrs and attrs[:file]
|
207
|
+
# raise Error, "can't copy File as a Dir ('#{self}')!"
|
208
|
+
# elsif attrs and attrs[:dir]
|
209
|
+
# # some unknown error (but it also maybe caused by to be fixed error in 'to')
|
210
|
+
# unknown_errors += 1
|
211
|
+
# else
|
212
|
+
# raise Error, "'#{self}' not exist!" if options[:bang]
|
213
|
+
# return true
|
214
|
+
# end
|
215
|
+
#
|
216
|
+
# attrs = to.get
|
217
|
+
# if attrs and attrs[:file]
|
218
|
+
# if options[:override]
|
219
|
+
# to.destroy
|
220
|
+
# else
|
221
|
+
# raise Vfs::Error, "entry #{to} already exist!"
|
222
|
+
# end
|
223
|
+
# elsif attrs and attrs[:dir]
|
224
|
+
# unknown_errors += 1
|
225
|
+
# # if options[:override]
|
226
|
+
# # to.destroy
|
227
|
+
# # else
|
228
|
+
# # dir_already_exist = true
|
229
|
+
# # # raise Vfs::Error, "entry #{to} already exist!"
|
230
|
+
# # end
|
231
|
+
# else # parent not exist
|
232
|
+
# parent = to.parent
|
233
|
+
# if parent.exist?
|
234
|
+
# # some unknown error (but it also maybe caused by already fixed error in 'from')
|
235
|
+
# unknown_errors += 1
|
236
|
+
# else
|
237
|
+
# parent.create(options)
|
238
|
+
# end
|
239
|
+
# end
|
240
|
+
#
|
241
|
+
# raise error if unknown_errors > 1
|
242
|
+
# try < 2 ? retry : raise(error)
|
243
|
+
# end
|
244
|
+
# end
|
245
|
+
# end
|
246
|
+
#
|
247
|
+
# def self.efficient_dir_copy from, to, override
|
248
|
+
# from.driver.open{
|
249
|
+
# driver.respond_to?(:efficient_dir_copy) and driver.efficient_dir_copy(from, to, override)
|
250
|
+
# } or
|
251
|
+
# to.driver.open{
|
252
|
+
# driver.respond_to?(:efficient_dir_copy) and driver.efficient_dir_copy(from, to, override)
|
253
|
+
# }
|
254
|
+
# end
|
255
|
+
end
|
256
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Vfs
|
2
|
+
class Entry
|
3
|
+
attr_reader :driver, :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
|
+
@driver, @path = entry.driver, entry.path
|
10
|
+
else
|
11
|
+
driver, path = *args
|
12
|
+
@path_cache = Path.new path
|
13
|
+
@driver, @path = driver, path_cache.to_s
|
14
|
+
end
|
15
|
+
raise "driver not defined!" unless self.driver
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Navigation
|
20
|
+
#
|
21
|
+
def parent
|
22
|
+
Dir.new(driver, path_cache.parent)
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
#
|
27
|
+
# Transformations
|
28
|
+
#
|
29
|
+
def dir path = nil
|
30
|
+
if path
|
31
|
+
new_path = path_cache + path
|
32
|
+
Dir.new driver, new_path
|
33
|
+
else
|
34
|
+
Dir.new self
|
35
|
+
end
|
36
|
+
end
|
37
|
+
alias_method :to_dir, :dir
|
38
|
+
|
39
|
+
def file path = nil
|
40
|
+
if path
|
41
|
+
new_path = path_cache + path
|
42
|
+
File.new driver, new_path
|
43
|
+
else
|
44
|
+
File.new self
|
45
|
+
end
|
46
|
+
end
|
47
|
+
alias_method :to_file, :file
|
48
|
+
|
49
|
+
def entry path = nil
|
50
|
+
entry = if path
|
51
|
+
new_path = path_cache + path
|
52
|
+
klass = new_path.probably_dir? ? Dir : UniversalEntry
|
53
|
+
klass.new driver, new_path
|
54
|
+
else
|
55
|
+
UniversalEntry.new self
|
56
|
+
end
|
57
|
+
EntryProxy.new entry
|
58
|
+
end
|
59
|
+
alias_method :to_entry, :entry
|
60
|
+
|
61
|
+
|
62
|
+
#
|
63
|
+
# Attributes
|
64
|
+
#
|
65
|
+
def get attr_name = nil
|
66
|
+
attrs = driver.open{driver.attributes(path)}
|
67
|
+
(attr_name and attrs) ? attrs[attr_name] : attrs
|
68
|
+
end
|
69
|
+
|
70
|
+
def set options
|
71
|
+
# TODO2 set attributes
|
72
|
+
not_implemented
|
73
|
+
end
|
74
|
+
|
75
|
+
def dir?; !!get(:dir) end
|
76
|
+
def file?; !!get(:file) end
|
77
|
+
def created_at; get :created_at end
|
78
|
+
def updated_at; get :updated_at end
|
79
|
+
|
80
|
+
|
81
|
+
#
|
82
|
+
# Miscellaneous
|
83
|
+
#
|
84
|
+
def name
|
85
|
+
path_cache.name
|
86
|
+
end
|
87
|
+
|
88
|
+
def tmp &block
|
89
|
+
driver.open do
|
90
|
+
if block
|
91
|
+
driver.tmp do |path|
|
92
|
+
block.call Dir.new(driver, path)
|
93
|
+
end
|
94
|
+
else
|
95
|
+
Dir.new driver, driver.tmp
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def local?
|
101
|
+
driver.local?
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
#
|
106
|
+
# Utils
|
107
|
+
#
|
108
|
+
def inspect
|
109
|
+
"#{driver}#{':' unless driver.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
|
+
driver == other.driver and path == other.path
|
116
|
+
end
|
117
|
+
|
118
|
+
def hash
|
119
|
+
driver.hash + path.hash
|
120
|
+
end
|
121
|
+
|
122
|
+
def eql? other
|
123
|
+
return false unless other.class == self.class
|
124
|
+
driver.eql?(other.driver) and path.eql?(other.path)
|
125
|
+
end
|
126
|
+
|
127
|
+
def delete *args
|
128
|
+
raise "use :destroy!"
|
129
|
+
end
|
130
|
+
alias_method :remove, :delete
|
131
|
+
|
132
|
+
protected
|
133
|
+
def destroy_entry first = :file, second = :dir
|
134
|
+
driver.open do
|
135
|
+
begin
|
136
|
+
driver.send :"delete_#{first}", path
|
137
|
+
rescue StandardError => e
|
138
|
+
attrs = get
|
139
|
+
if attrs and attrs[first]
|
140
|
+
# some unknown error
|
141
|
+
raise e
|
142
|
+
elsif attrs and attrs[second]
|
143
|
+
driver.send :"delete_#{second}", path
|
144
|
+
else
|
145
|
+
# do nothing, entry already not exist
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
self
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,155 @@
|
|
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
|
+
driver.open do
|
15
|
+
begin
|
16
|
+
if block
|
17
|
+
driver.read_file path, &block
|
18
|
+
else
|
19
|
+
data = ""
|
20
|
+
driver.read_file(path){|buff| data << buff}
|
21
|
+
data
|
22
|
+
end
|
23
|
+
rescue StandardError => e
|
24
|
+
raise Vfs::Error, "can't read Dir #{self}!" if dir.exist?
|
25
|
+
attrs = get
|
26
|
+
if attrs and attrs[:file]
|
27
|
+
# unknown internal error
|
28
|
+
raise e
|
29
|
+
elsif attrs and 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
|
+
|
51
|
+
def write *args, &block
|
52
|
+
if block
|
53
|
+
options = args.first || {}
|
54
|
+
else
|
55
|
+
data, options = *args
|
56
|
+
data ||= ""
|
57
|
+
options ||= {}
|
58
|
+
end
|
59
|
+
raise "can't do :override and :append at the same time!" if options[:override] and options[:append]
|
60
|
+
|
61
|
+
driver.open do
|
62
|
+
try = 0
|
63
|
+
begin
|
64
|
+
try += 1
|
65
|
+
if block
|
66
|
+
driver.write_file(path, options[:append], &block)
|
67
|
+
else
|
68
|
+
driver.write_file(path, options[:append]){|writer| writer.write data}
|
69
|
+
end
|
70
|
+
rescue StandardError => error
|
71
|
+
parent = self.parent
|
72
|
+
if entry.exist?
|
73
|
+
entry.destroy
|
74
|
+
elsif !parent.exist?
|
75
|
+
parent.create(options)
|
76
|
+
else
|
77
|
+
# unknown error
|
78
|
+
raise error
|
79
|
+
end
|
80
|
+
|
81
|
+
try < 2 ? retry : raise(error)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
def append *args, &block
|
88
|
+
options = (args.last.is_a?(Hash) && args.pop) || {}
|
89
|
+
options[:append] = true
|
90
|
+
write(*(args << options), &block)
|
91
|
+
end
|
92
|
+
|
93
|
+
def update options = {}, &block
|
94
|
+
data = read options
|
95
|
+
write block.call(data), options
|
96
|
+
end
|
97
|
+
|
98
|
+
def destroy
|
99
|
+
destroy_entry
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
#
|
104
|
+
# Transfers
|
105
|
+
#
|
106
|
+
def copy_to to, options = {}
|
107
|
+
raise Error, "you can't copy to itself" if self == to
|
108
|
+
|
109
|
+
target = if to.is_a? File
|
110
|
+
to
|
111
|
+
elsif to.is_a? Dir
|
112
|
+
to.file #(name)
|
113
|
+
elsif to.is_a? UniversalEntry
|
114
|
+
to.file
|
115
|
+
else
|
116
|
+
raise "can't copy to unknown Entry!"
|
117
|
+
end
|
118
|
+
|
119
|
+
target.write options do |writer|
|
120
|
+
read(options){|buff| writer.write buff}
|
121
|
+
end
|
122
|
+
|
123
|
+
target
|
124
|
+
end
|
125
|
+
|
126
|
+
def move_to to
|
127
|
+
copy_to to
|
128
|
+
destroy
|
129
|
+
to
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
#
|
134
|
+
# Extra Stuff
|
135
|
+
#
|
136
|
+
def render *args
|
137
|
+
require 'tilt'
|
138
|
+
|
139
|
+
args.unshift Object.new if args.size == 1 and args.first.is_a?(Hash)
|
140
|
+
|
141
|
+
template = Tilt.new(path){read}
|
142
|
+
template.render *args
|
143
|
+
end
|
144
|
+
|
145
|
+
def size; get :size end
|
146
|
+
|
147
|
+
def basename
|
148
|
+
::File.basename(name, ::File.extname(name))
|
149
|
+
end
|
150
|
+
|
151
|
+
def extension
|
152
|
+
::File.extname(name).sub(/^\./, '')
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|