vfs 0.4.8 → 0.5.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/Rakefile DELETED
@@ -1,11 +0,0 @@
1
- require 'rake_ext'
2
-
3
- project(
4
- name: "vfs",
5
- gem: true,
6
- summary: "Virtual File System - simple and unified API over different storages (Local, S3, SFTP, ...)",
7
- # version: '0.4.0',
8
-
9
- author: "Alexey Petrushin",
10
- homepage: "http://alexeypetrushin.github.com/vfs"
11
- )
data/readme.md DELETED
@@ -1,143 +0,0 @@
1
- **Documentation:** http://alexeypetrushin.github.com/vfs
2
-
3
- Virtual File System provides **clean, simple and unified API over different storages** (Local File System, AWS S3, SFTP, ...).
4
-
5
- - very simple and intuitive API.
6
- - same API for different storages.
7
- - work simultaneously with multiple storages.
8
- - small codebase, easy to learn and extend.
9
- - driver implementation is very simple, it is easy to create new drivers.
10
-
11
- Such unified API is possible because although the API of storages are different the core concept are almost the same.
12
-
13
- Install Vfs with Rubygems:
14
-
15
- gem install vfs
16
-
17
- Once installed, You can proceed with the [basic example][basics], there's also [S3 version][s3_basics] and [SFTP version][ssh_basics] (also [S3 backup][s3_backup] and [SSH/SFTP deployment][ssh_deployment] examples availiable).
18
-
19
- You can report bugs and discuss features on the [issues page][issues].
20
-
21
- ## Sample
22
-
23
- ``` ruby
24
- # Preparing sandbox for our sample and cleaning it before starting
25
- # (ignore the `$sandbox` variable, it's needed to reuse this code in S3 and SSH samples).
26
- require 'vfs'
27
- sandbox = $sandbox || '/tmp/vfs_sandbox'.to_dir.destroy
28
-
29
- # Creating simple Hello World project.
30
- project = sandbox['hello_world']
31
-
32
- # Writing readme file (note that parent dirs where created automatically).
33
- project['readme.txt'].write 'My App'
34
-
35
- # We can assign files and dirs to variables, now the `readme` variable refers to our readme.txt file.
36
- readme = project['readme.txt']
37
-
38
- # Let's ensure that it's all ok with our readme file and check its attributes.
39
- p readme.name # => readme.txt
40
- p [readme.basename, readme.extension] # => ['readme', 'txt']
41
- p readme.path # => /.../readme.txt
42
- p readme.exist? # => true
43
- p readme.file? # => true
44
- p readme.dir? # => false
45
- p readme.size # => 6
46
- p readme.created_at # => 2011-09-09 13:20:43 +0400
47
- p readme.updated_at # => 2011-09-09 13:20:43 +0400
48
-
49
- # Reading - You can read all at once or do it sequentially (input stream
50
- # will be automatically splitted into chunks of reasonable size).
51
- p readme.read # => "My shiny App"
52
- readme.read{|chunk| p chunk} # => "My shiny App"
53
-
54
- # The same for writing - write all at once or do it sequentially
55
- # (if there's no file it will be created, if it exists it will be rewriten).
56
- readme.write "My App v2"
57
- readme.write{|stream| stream.write "My App v3"}
58
- p readme.read # => "My shiny App v3"
59
-
60
- # Appending content to existing file.
61
- readme.append "How to install ..."
62
- p readme.size # => 27
63
-
64
- # Copying and Moving. It also works exactly the same
65
- # way if You copy or move files and dirs to other storages.
66
- readme.copy_to project['docs/readme.txt']
67
- p project['docs/readme.txt'].exist? # => true
68
- p readme.exist? # => true
69
-
70
- readme.move_to project['docs/readme.txt']
71
- p project['docs/readme.txt'].exist? # => true
72
- p readme.exist? # => false
73
-
74
- # Let's add empty Rakefile to our project.
75
- project['Rakefile'].write
76
-
77
- # Operations with directories - checking our project exists and not empty.
78
- p project.exist? # => true
79
- p project.empty? # => false
80
-
81
- # Listing dir content. There are two versions of methods -
82
- # without block the result will be Array of Entries, with block
83
- # it will iterate over directory sequentially.
84
- p project.entries # => [/.../docs, /.../Rakefile]
85
- p project.files # => [/.../Rakefile]
86
- p project.dirs # => [/.../docs]
87
- project.entries do |entry| # => ["docs", false]
88
- p [entry.name, entry.file?] # => ["Rakefile", true]
89
- end
90
- p project.include?('Rakefile') # => true
91
-
92
- # You can also use glob (if storage support it).
93
- if project.driver.local?
94
- p project.entries('**/Rake*') # => [/.../Rakefile]
95
- p project['**/Rake*'] # => [/.../Rakefile]
96
- end
97
-
98
- # The result of dir listing is just an array of Entries, so
99
- # You can use it to do interesting things. For example this code will
100
- # calculates the size of sources in our project.
101
- if project.driver.local?
102
- project['**/*.rb'].collect(&:size).reduce(0, :+)
103
- end
104
-
105
- # Copying and moving - let's create another project by cloning our hello_world.
106
- project.copy_to sandbox['another_project']
107
- p sandbox['another_project'].entries # => [/.../docs, .../Rakefile]
108
-
109
- # Cleaning sandbox.
110
- sandbox.destroy
111
- ```
112
-
113
- ## Integration with [Vos][vos] (Virtual Operating System)
114
-
115
- Vfs can be used toghether with the Virtual Operating System Tool, and while the Vfs covers all the I/O operations the Vos provides support for remote command execution.
116
- You can use this combination to fully control remote machines, for example - I'm using it to manage my production servers (setup, administration, deployment, migration, ...).
117
-
118
- For more details please go to [Vos][vos] project page.
119
- You can also take look at the actual configuration I'm using to control my servers [My Cluster][my_cluster] (in conjunction with small configuration tool [Cluster Management][cluster_management]).
120
-
121
- # Why?
122
-
123
- To easy my work: with local FS, remote FS, and some specific systems like Hadoop DFS.
124
-
125
- Because the API of standard File/Dir/FileUtils classes are just terrible. And there's the reason for it - the goal of thouse tools is to provide 1-to-1 clone of underlying OS API, instead of provididing handy tool.
126
-
127
- And if you want to use remote FS - things are getting even worse and more complicated (Net::SSH & Net::SFTP use a little
128
- different API than local FS, and you has to remember all thouse little quirks).
129
-
130
- ## License
131
-
132
- Copyright (c) Alexey Petrushin http://petrush.in, released under the MIT license.
133
-
134
- [vos]: http://github.com/alexeypetrushin/vos
135
- [cluster_management]: http://github.com/alexeypetrushin/cluster_management
136
- [my_cluster]: http://github.com/alexeypetrushin/my_cluster
137
-
138
- [basics]: http://alexeypetrushin.github.com/vfs/basics.html
139
- [s3_basics]: http://alexeypetrushin.github.com/vfs/s3_basics.html
140
- [s3_backup]: http://alexeypetrushin.github.com/vfs/s3_backup.html
141
- [ssh_basics]: http://alexeypetrushin.github.com/vfs/ssh_basics.html
142
- [ssh_deployment]: http://alexeypetrushin.github.com/vfs/ssh_deployment.html
143
- [issues]: https://github.com/alexeypetrushin/vfs/issues
@@ -1,31 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Container' do
4
- with_test_dir
5
-
6
- it "should threat paths as UniversalEntry except it ends with '/'" do
7
- test_dir.should_receive(:entry).with('tmp/a/b')
8
- test_dir['tmp/a/b']
9
-
10
- test_dir.should_receive(:dir).with('tmp/a/b')
11
- test_dir['tmp/a/b/']
12
- end
13
-
14
- it '/' do
15
- test_dir[:some_path].should == test_dir / :some_path
16
- test_dir[:some_path][:another_path].should == test_dir / :some_path / :another_path
17
- end
18
-
19
- it "UniversalEntry should be wrapped inside of proxy, Dir and File should not" do
20
- -> {test_dir.dir.proxy?}.should raise_error(NoMethodError)
21
- -> {test_dir.file.proxy?}.should raise_error(NoMethodError)
22
- test_dir.entry.proxy?.should be_true
23
- end
24
-
25
- it "sometimes it also should inexplicitly guess that path is a Dir instead of UniversalEntry (but still wrap it inside of Proxy)" do
26
-
27
- dir = test_dir['tmp/a/..']
28
- dir.proxy?.should be_true
29
- dir.should be_a(Vfs::Dir)
30
- end
31
- end
data/spec/dir_spec.rb DELETED
@@ -1,253 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Dir' do
4
- with_test_dir
5
-
6
- before do
7
- @path = test_dir['a/b/c']
8
- end
9
-
10
- describe 'existence' do
11
- it "should check only dirs" do
12
- @path.should_not exist
13
- @path.file.create
14
- @path.should be_file
15
- @path.dir.should_not exist
16
- @path.dir.create
17
- @path.should be_dir
18
- @path.dir.should exist
19
- end
20
- end
21
-
22
- it "should not respond to read and write methods" do
23
- -> {@path.dir.read}.should raise_error(NoMethodError)
24
- -> {@path.dir.write}.should raise_error(NoMethodError)
25
- end
26
-
27
- describe 'create' do
28
- it 'should be chainable' do
29
- @path.dir.create.should == @path
30
- end
31
-
32
- it 'should create parent dirs if not exists' do
33
- @path.parent.should_not exist
34
- @path.dir.create
35
- @path.should be_dir
36
- end
37
-
38
- it 'should silently exit if dir already exist' do
39
- @path.dir.create
40
- @path.dir.create
41
- end
42
-
43
- it 'should override existing file' do
44
- @path.file.create
45
- @path.should be_file
46
- @path.dir.create
47
- @path.should be_dir
48
- end
49
-
50
- it 'should not override existing dir with content' do
51
- dir = @path.dir
52
- dir.create
53
- file = dir.file :file
54
- file.create
55
- file.should exist
56
-
57
- dir.create
58
- file.should exist
59
- end
60
- end
61
-
62
- describe 'destroying' do
63
- it "should destroy a file" do
64
- @path.file.create
65
- @path.dir.destroy
66
- @path.entry.should_not exist
67
- end
68
-
69
- it "shouldn't raise if dir not exist" do
70
- @path.dir.destroy
71
- end
72
-
73
- it 'should destroy recursivelly' do
74
- dir = @path.dir
75
- dir.create
76
- dir.file(:file).write 'something'
77
- dir.dir(:dir).create.tap do |dir|
78
- dir.file(:file2).write 'something2'
79
- end
80
-
81
- dir.destroy
82
- dir.should_not exist
83
- end
84
-
85
- it 'should be chainable' do
86
- @path.dir.destroy.should == @path
87
- end
88
- end
89
-
90
- describe 'entries, files, dirs' do
91
- before do
92
- @path.dir('dir').create
93
- @path.dir('dir/another_dir').create
94
- @path.file('file').create
95
- end
96
-
97
- it 'entries' do
98
- -> {@path['non_existing'].entries}.should raise_error(Vfs::Error, /not exist/)
99
- @path['non_existing'].entries(bang: false).should == []
100
- @path.entries.to_set.should be_eql([@path.entry('dir'), @path.entry('file')].to_set)
101
- list = []
102
- @path.entries{|e| list << e}
103
- list.to_set.should be_eql([@path.entry('dir'), @path.entry('file')].to_set)
104
- end
105
-
106
- it 'entries with type' do
107
- @path.entries(type: true).to_set.should be_eql([@path.dir('dir'), @path.file('file')].to_set)
108
- end
109
-
110
- it "glob search support" do
111
- @path.dir('dir_a').create
112
- @path.file('file_a').create
113
- @path.dir('dir_b').create
114
- @path.entries('*_a').collect(&:name).sort.should == %w(dir_a file_a)
115
- end
116
-
117
- it 'should raise error if trying :entries on file' do
118
- @path.file('some_file').create
119
- -> {@path.dir('some_file').entries}.should raise_error(/File/)
120
- end
121
-
122
- it 'files' do
123
- @path.files.should be_eql([@path.file('file')])
124
- end
125
-
126
- it 'dirs' do
127
- @path.dirs.should be_eql([@path.dir('dir')])
128
- end
129
-
130
- it 'has? & include?' do
131
- @path.include?('dir').should be_true
132
- @path.include?('dir/another_dir').should be_true
133
- @path.include?('file').should be_true
134
- @path.include?('non_existing').should be_false
135
- end
136
-
137
- it 'empty?' do
138
- @path.empty?.should be_false
139
- @path.dir('empty_dir').create.empty?.should be_true
140
- end
141
-
142
- it "should threat ['**/*.rb'] as glob" do
143
- @path['**/*nother*'].first.name.should == 'another_dir'
144
- end
145
- end
146
-
147
- describe 'copying' do
148
- before do
149
- @from = @path.dir
150
- @from.create
151
- @from.file('file').write 'something'
152
- @from.dir('dir').create.tap do |dir|
153
- dir.file('file2').write 'something2'
154
- end
155
- end
156
-
157
- it 'should not copy to itself' do
158
- -> {@from.copy_to @from}.should raise_error(Vfs::Error, /itself/)
159
- end
160
-
161
- shared_examples_for 'copy_to behavior' do
162
- it 'should copy to file and overwrite it' do
163
- @from.copy_to @to.file
164
- @to['file'].read.should == 'something'
165
- end
166
-
167
- it 'should override files' do
168
- @from.copy_to @to
169
-
170
- @from['dir/file2'].write 'another'
171
- @from.copy_to @to
172
- @to['dir/file2'].read.should == 'another'
173
- end
174
-
175
- it 'should copy to UniversalEntry (and overwrite)' do
176
- @from.copy_to @to.entry
177
-
178
- @from.copy_to @to.entry
179
- @to['file'].read.should == 'something'
180
- end
181
-
182
- it "shouldn't delete existing content of directory" do
183
- @to.dir.create
184
- @to.file('existing_file').write 'existing_content'
185
- @to.dir('existing_dir').create
186
- @to.file('dir/existing_file2').write 'existing_content2'
187
-
188
- @from.copy_to @to
189
- # copied files
190
- @to['file'].read.should == 'something'
191
- @to['dir/file2'].read.should == 'something2'
192
- # shouldn't delete already existing files
193
- @to.file('existing_file').read.should == 'existing_content'
194
- @to.dir('existing_dir').should exist
195
- @to.file('dir/existing_file2').read.should == 'existing_content2'
196
- end
197
-
198
- it 'should be chainable' do
199
- @from.copy_to(@to).should == @to
200
- end
201
-
202
- it "should override without deleting other files" do
203
- @from.copy_to(@to).should == @to
204
- @to.file('other_file').write 'other'
205
-
206
- @from.copy_to(@to).should == @to
207
- @to.file('other_file').read.should == 'other'
208
- end
209
-
210
- it "should raise error if try to copy file as dir" do
211
- dir = @from.dir 'file'
212
- dir.file?.should be_true
213
- -> {dir.copy_to @to}.should raise_error(Vfs::Error)
214
- end
215
- end
216
-
217
- describe 'general copy' do
218
- it_should_behave_like 'copy_to behavior'
219
-
220
- before do
221
- # prevenging usage of :efficient_dir_copy
222
- # Vfs::Dir.dont_use_efficient_dir_copy = true
223
-
224
- @to = test_dir['to']
225
- end
226
- # after do
227
- # Vfs::Dir.dont_use_efficient_dir_copy = false
228
- # end
229
- end
230
-
231
- # describe 'effective copy' do
232
- # it_should_behave_like 'copy_to behavior'
233
- #
234
- # before do
235
- # @to = test_dir['to']
236
- # end
237
- # end
238
- end
239
-
240
- describe 'moving' do
241
- it 'move_to' do
242
- from, to = @path.file('from'), @path.file('to')
243
- from.should_receive(:copy_to).with(to)
244
- from.should_receive(:destroy).with()
245
- from.move_to to
246
- end
247
-
248
- it 'should be chainable' do
249
- from, to = @path.dir('from').create, @path.dir('to')
250
- from.move_to(to).should == to
251
- end
252
- end
253
- end
data/spec/entry_spec.rb DELETED
@@ -1,42 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Entry' do
4
- with_test_dir
5
-
6
- before do
7
- @path = test_dir['a/b/c']
8
- end
9
-
10
- it "name" do
11
- @path.name.should == 'c'
12
- end
13
-
14
- it "string integration" do
15
- '/'.to_entry.path.should == '/'
16
- 'a'.to_entry.path.should == "./a"
17
- end
18
-
19
- it 'tmp' do
20
- tmp = test_dir.tmp
21
- tmp.should be_dir
22
- tmp.destroy
23
-
24
- tmp = nil
25
- test_dir.tmp do |path|
26
- tmp = path
27
- tmp.should be_dir
28
- end
29
- tmp.should_not exist
30
- end
31
-
32
- it 'should respond to local?' do
33
- test_dir.should respond_to(:local?)
34
- end
35
-
36
- it 'created_at, updated_at, size' do
37
- file = test_dir.file('file').write 'data'
38
- file.created_at.class.should == Time
39
- file.updated_at.class.should == Time
40
- file.size.should == 4
41
- end
42
- end