vfs 0.4.8 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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