em-fs 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/em-fs/dir/glob.rb +74 -0
- data/lib/em-fs/file/stat.rb +38 -27
- data/lib/em-fs/version.rb +1 -1
- data/spec/dir/glob_spec.rb +181 -0
- data/spec/file/stat_spec.rb +1 -5
- metadata +3 -3
data/lib/em-fs/dir/glob.rb
CHANGED
@@ -2,6 +2,80 @@ module EventMachine
|
|
2
2
|
class Dir
|
3
3
|
class Glob
|
4
4
|
|
5
|
+
FORMAT = "%m %D '%y' %G %n %i '%p' %s %U %A@ %T@ %C@\\n"
|
6
|
+
|
7
|
+
def initialize pattern
|
8
|
+
@weight = nil
|
9
|
+
parse pattern
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse pattern
|
13
|
+
root = []
|
14
|
+
|
15
|
+
*path, name = pattern.split(::File::SEPARATOR)
|
16
|
+
|
17
|
+
if name.index("*").nil?
|
18
|
+
path << name
|
19
|
+
name = "*"
|
20
|
+
end
|
21
|
+
|
22
|
+
root << path.shift while path[0] and path[0].index("*").nil?
|
23
|
+
|
24
|
+
@name = name
|
25
|
+
@path = path.join(::File::SEPARATOR).gsub '**', '*'
|
26
|
+
@root = root.join(::File::SEPARATOR)
|
27
|
+
|
28
|
+
if path.length == 0
|
29
|
+
@weight = 1
|
30
|
+
end
|
31
|
+
|
32
|
+
@root = '.' if @root == ''
|
33
|
+
end
|
34
|
+
|
35
|
+
def each options = {}, &block
|
36
|
+
options = {
|
37
|
+
depth: :inf
|
38
|
+
}.merge options
|
39
|
+
EM::SystemCommand.execute find_command(options) do |on|
|
40
|
+
on.stdout.line do |line|
|
41
|
+
block.call File::Stat.parse line
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def each_entry options = {}, &block
|
47
|
+
options = {
|
48
|
+
depth: 1
|
49
|
+
}.merge options
|
50
|
+
each options do |stat|
|
51
|
+
block.call ::File.basename(stat.path)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def each_path options = {}, &block
|
56
|
+
options = {
|
57
|
+
depth: :inf
|
58
|
+
}.merge options
|
59
|
+
each options do |stat|
|
60
|
+
block.call stat.path
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def find_command options = {}
|
66
|
+
options = {
|
67
|
+
depth: (@weight || :inf)
|
68
|
+
}.merge options
|
69
|
+
|
70
|
+
builder = EM::SystemCommand::Builder.new 'find'
|
71
|
+
builder << @root
|
72
|
+
builder << [ :path, @path ] unless @path == "*" or @path == ''
|
73
|
+
builder << [ :name, @name ] unless @name == "*"
|
74
|
+
builder << [ :maxdepth, options[:depth] ] unless options[:depth] == :inf
|
75
|
+
builder << [ :printf, FORMAT ]
|
76
|
+
builder.to_s.gsub(/-+(\w)/, "-\\1")
|
77
|
+
end
|
78
|
+
|
5
79
|
end
|
6
80
|
end
|
7
81
|
end
|
data/lib/em-fs/file/stat.rb
CHANGED
@@ -2,8 +2,30 @@ module EventMachine
|
|
2
2
|
class File
|
3
3
|
class Stat
|
4
4
|
|
5
|
-
STAT_REGEX = /(\d+) (\d+)
|
6
|
-
|
5
|
+
STAT_REGEX = /(\d+) (\d+) '([\w\/ ]+)' (\d+) (\d+) (\d+) '(.+)' (\d+) (\d+) ([\d.]+) ([\d.]+) ([\d.]+)/.freeze
|
6
|
+
|
7
|
+
# access rights octal
|
8
|
+
# ---number of blocks allocated
|
9
|
+
# ---the size in bytes of each block reported by %b
|
10
|
+
# device number in decimal
|
11
|
+
# ---raw mode in hex
|
12
|
+
# file type
|
13
|
+
# group id
|
14
|
+
# number of hardlinks
|
15
|
+
# inode number
|
16
|
+
# ---mount point
|
17
|
+
# file name
|
18
|
+
# ---optimal IO transfer size hint
|
19
|
+
# total size in bytes
|
20
|
+
# --major device type in hex
|
21
|
+
# --minor device type in hex
|
22
|
+
# user id
|
23
|
+
# --time of birth
|
24
|
+
# time of last access
|
25
|
+
# time of last mod
|
26
|
+
# time of last change
|
27
|
+
STAT_FORMAT =
|
28
|
+
"%a %d '%F' %g %h %i '%n' %s %u %X %Y %Z"
|
7
29
|
|
8
30
|
# Types
|
9
31
|
S_IFBLK = 0b00000001 # block device
|
@@ -35,7 +57,7 @@ module EventMachine
|
|
35
57
|
# @return [EM::File::Stat] The file stat object.
|
36
58
|
def parse str
|
37
59
|
if m = str.match(STAT_REGEX)
|
38
|
-
ftype = case m[
|
60
|
+
ftype = case m[3]
|
39
61
|
when 'block device' then S_IFBLK
|
40
62
|
when 'character device' then S_IFCHR
|
41
63
|
when 'directory' then S_IFDIR
|
@@ -46,43 +68,32 @@ module EventMachine
|
|
46
68
|
else
|
47
69
|
S_UNKNOWN
|
48
70
|
end
|
49
|
-
EM::File::Stat.new path: m[
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
blocks: Integer(m[2], 10),
|
54
|
-
ctime: Time.at(Integer(m[20], 10)),
|
55
|
-
dev: Integer(m[4], 10),
|
56
|
-
dev_major: Integer(m[14], 8),
|
57
|
-
dev_minor: Integer(m[15], 8),
|
71
|
+
EM::File::Stat.new path: m[7],
|
72
|
+
atime: Time.at(Integer(m[10].split('.')[0], 10)),
|
73
|
+
ctime: Time.at(Integer(m[12].split('.')[0], 10)),
|
74
|
+
dev: Integer(m[2], 10),
|
58
75
|
ftype: ftype,
|
59
|
-
gid:
|
60
|
-
ino:
|
61
|
-
mode:
|
62
|
-
mtime: Time.at(Integer(m[
|
63
|
-
nlink: Integer(m[
|
64
|
-
size:
|
65
|
-
uid:
|
76
|
+
gid: Integer(m[4], 10),
|
77
|
+
ino: Integer(m[6], 10),
|
78
|
+
mode: Integer(m[1], 8),
|
79
|
+
mtime: Time.at(Integer(m[11].split('.')[0], 10)),
|
80
|
+
nlink: Integer(m[5], 10),
|
81
|
+
size: Integer(m[8], 10),
|
82
|
+
uid: Integer(m[9], 10)
|
66
83
|
else
|
67
84
|
raise "Unable to parse stat string: #{str}"
|
68
85
|
end
|
69
86
|
end
|
70
87
|
end
|
71
88
|
|
72
|
-
attr_reader :path, :
|
73
|
-
:
|
74
|
-
:nlink, :size, :uid
|
89
|
+
attr_reader :path, :atime, :ctime, :dev, :ftype, :gid,
|
90
|
+
:ino, :mtime, :nlink, :size, :uid
|
75
91
|
|
76
92
|
def initialize val = {}
|
77
93
|
@path = val[:path]
|
78
|
-
@mountpoint = val[:mountpoint]
|
79
94
|
@atime = val[:atime]
|
80
|
-
@blksize = val[:blksize]
|
81
|
-
@blocks = val[:blocks]
|
82
95
|
@ctime = val[:ctime]
|
83
96
|
@dev = val[:dev]
|
84
|
-
@dev_major = val[:dev_major]
|
85
|
-
@dev_minor = val[:dev_minor]
|
86
97
|
@ftype = val[:ftype]
|
87
98
|
@gid = val[:gid]
|
88
99
|
@ino = val[:ino]
|
data/lib/em-fs/version.rb
CHANGED
data/spec/dir/glob_spec.rb
CHANGED
@@ -1,5 +1,186 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'spec_helper'
|
2
3
|
|
3
4
|
describe EM::Dir::Glob do
|
5
|
+
before :all do
|
6
|
+
dirs = [ 'a', 'b/a', 'b/b', 'c/a/a', 'c/a/b' ].map { |p|
|
7
|
+
File.join(SPEC_ROOT, 'data', p)
|
8
|
+
}
|
9
|
+
files = [ 'a/x', 'b/x', 'b/a/x', 'b/a/y', 'b/a/z' ].map { |p|
|
10
|
+
File.join(SPEC_ROOT, 'data', p)
|
11
|
+
}
|
12
|
+
FileUtils.touch files
|
13
|
+
FileUtils.mkdir_p dirs
|
14
|
+
end
|
4
15
|
|
16
|
+
describe '#find_command' do
|
17
|
+
it 'should parse relative pattern' do
|
18
|
+
cmd = EM::Dir['./*.rb'].send :find_command
|
19
|
+
cmd.should == "find . -name '*.rb' -maxdepth 1 -printf '%m %D '\\''%y'\\'' %G %n %i '\\''%p'\\'' %s %U %A@ %T@ %C@\\n'"
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should parse relative pattern with path wildcard' do
|
23
|
+
cmd = EM::Dir['./**/*.rb'].send :find_command
|
24
|
+
cmd.should == "find . -name '*.rb' -printf '%m %D '\\''%y'\\'' %G %n %i '\\''%p'\\'' %s %U %A@ %T@ %C@\\n'"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#each' do
|
29
|
+
context 'with depth = 0' do
|
30
|
+
before :all do
|
31
|
+
@entries = []
|
32
|
+
pattern = File.join(SPEC_ROOT, 'data', '**', '*')
|
33
|
+
EM.run do
|
34
|
+
cmd = EM::Dir[pattern].each depth: 1 do |entry|
|
35
|
+
@entries << entry.path
|
36
|
+
end
|
37
|
+
|
38
|
+
cmd.exit do
|
39
|
+
EM.stop_event_loop
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should execute the block for each entry' do
|
45
|
+
@entries.should == [
|
46
|
+
"/home/arthur/projects/em-fs/spec/data",
|
47
|
+
"/home/arthur/projects/em-fs/spec/data/b",
|
48
|
+
"/home/arthur/projects/em-fs/spec/data/c",
|
49
|
+
"/home/arthur/projects/em-fs/spec/data/test2",
|
50
|
+
"/home/arthur/projects/em-fs/spec/data/test",
|
51
|
+
"/home/arthur/projects/em-fs/spec/data/a",
|
52
|
+
"/home/arthur/projects/em-fs/spec/data/test3"
|
53
|
+
]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'with depth = 2' do
|
58
|
+
before :all do
|
59
|
+
@entries = []
|
60
|
+
pattern = File.join(SPEC_ROOT, 'data', '**', '*')
|
61
|
+
EM.run do
|
62
|
+
cmd = EM::Dir[pattern].each depth: 2 do |entry|
|
63
|
+
@entries << entry.path
|
64
|
+
end
|
65
|
+
|
66
|
+
cmd.exit do
|
67
|
+
EM.stop_event_loop
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should execute the block for each entry and directory´s entry' do
|
73
|
+
@entries.should == [
|
74
|
+
"/home/arthur/projects/em-fs/spec/data",
|
75
|
+
"/home/arthur/projects/em-fs/spec/data/b",
|
76
|
+
"/home/arthur/projects/em-fs/spec/data/b/b",
|
77
|
+
"/home/arthur/projects/em-fs/spec/data/b/x",
|
78
|
+
"/home/arthur/projects/em-fs/spec/data/b/a",
|
79
|
+
"/home/arthur/projects/em-fs/spec/data/c",
|
80
|
+
"/home/arthur/projects/em-fs/spec/data/c/a",
|
81
|
+
"/home/arthur/projects/em-fs/spec/data/test2",
|
82
|
+
"/home/arthur/projects/em-fs/spec/data/test",
|
83
|
+
"/home/arthur/projects/em-fs/spec/data/a",
|
84
|
+
"/home/arthur/projects/em-fs/spec/data/a/x",
|
85
|
+
"/home/arthur/projects/em-fs/spec/data/test3"
|
86
|
+
]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'with depth = :inf' do
|
91
|
+
before :all do
|
92
|
+
@entries = []
|
93
|
+
pattern = File.join(SPEC_ROOT, 'data', '**', '*')
|
94
|
+
EM.run do
|
95
|
+
cmd = EM::Dir[pattern].each depth: :inf do |entry|
|
96
|
+
@entries << entry.path
|
97
|
+
end
|
98
|
+
|
99
|
+
cmd.exit do
|
100
|
+
EM.stop_event_loop
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should execute the block for each entry in tree' do
|
106
|
+
@entries.should == [
|
107
|
+
"/home/arthur/projects/em-fs/spec/data",
|
108
|
+
"/home/arthur/projects/em-fs/spec/data/b",
|
109
|
+
"/home/arthur/projects/em-fs/spec/data/b/b",
|
110
|
+
"/home/arthur/projects/em-fs/spec/data/b/x",
|
111
|
+
"/home/arthur/projects/em-fs/spec/data/b/a",
|
112
|
+
"/home/arthur/projects/em-fs/spec/data/b/a/x",
|
113
|
+
"/home/arthur/projects/em-fs/spec/data/b/a/z",
|
114
|
+
"/home/arthur/projects/em-fs/spec/data/b/a/y",
|
115
|
+
"/home/arthur/projects/em-fs/spec/data/c",
|
116
|
+
"/home/arthur/projects/em-fs/spec/data/c/a",
|
117
|
+
"/home/arthur/projects/em-fs/spec/data/c/a/b",
|
118
|
+
"/home/arthur/projects/em-fs/spec/data/c/a/a",
|
119
|
+
"/home/arthur/projects/em-fs/spec/data/test2",
|
120
|
+
"/home/arthur/projects/em-fs/spec/data/test",
|
121
|
+
"/home/arthur/projects/em-fs/spec/data/a",
|
122
|
+
"/home/arthur/projects/em-fs/spec/data/a/x",
|
123
|
+
"/home/arthur/projects/em-fs/spec/data/test3"
|
124
|
+
]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe '#each_entry' do
|
130
|
+
before :all do
|
131
|
+
@entries = []
|
132
|
+
pattern = File.join(SPEC_ROOT, 'data', '**', '*')
|
133
|
+
EM.run do
|
134
|
+
cmd = EM::Dir[pattern].each_entry do |entry|
|
135
|
+
@entries << entry
|
136
|
+
end
|
137
|
+
|
138
|
+
cmd.exit do
|
139
|
+
EM.stop_event_loop
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should execute a block with file name for each entry' do
|
145
|
+
@entries.should == [ "data", "b", "c", "test2", "test", "a", "test3" ]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe '#each_path' do
|
150
|
+
before :all do
|
151
|
+
@entries = []
|
152
|
+
pattern = File.join(SPEC_ROOT, 'data', '**', '*')
|
153
|
+
EM.run do
|
154
|
+
cmd = EM::Dir[pattern].each_path do |path|
|
155
|
+
@entries << path
|
156
|
+
end
|
157
|
+
|
158
|
+
cmd.exit do
|
159
|
+
EM.stop_event_loop
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should execute a block with full path for each entry' do
|
165
|
+
@entries.should == [
|
166
|
+
"/home/arthur/projects/em-fs/spec/data",
|
167
|
+
"/home/arthur/projects/em-fs/spec/data/b",
|
168
|
+
"/home/arthur/projects/em-fs/spec/data/b/b",
|
169
|
+
"/home/arthur/projects/em-fs/spec/data/b/x",
|
170
|
+
"/home/arthur/projects/em-fs/spec/data/b/a",
|
171
|
+
"/home/arthur/projects/em-fs/spec/data/b/a/x",
|
172
|
+
"/home/arthur/projects/em-fs/spec/data/b/a/z",
|
173
|
+
"/home/arthur/projects/em-fs/spec/data/b/a/y",
|
174
|
+
"/home/arthur/projects/em-fs/spec/data/c",
|
175
|
+
"/home/arthur/projects/em-fs/spec/data/c/a",
|
176
|
+
"/home/arthur/projects/em-fs/spec/data/c/a/b",
|
177
|
+
"/home/arthur/projects/em-fs/spec/data/c/a/a",
|
178
|
+
"/home/arthur/projects/em-fs/spec/data/test2",
|
179
|
+
"/home/arthur/projects/em-fs/spec/data/test",
|
180
|
+
"/home/arthur/projects/em-fs/spec/data/a",
|
181
|
+
"/home/arthur/projects/em-fs/spec/data/a/x",
|
182
|
+
"/home/arthur/projects/em-fs/spec/data/test3"
|
183
|
+
]
|
184
|
+
end
|
185
|
+
end
|
5
186
|
end
|
data/spec/file/stat_spec.rb
CHANGED
@@ -4,18 +4,14 @@ describe EM::File::Stat do
|
|
4
4
|
describe '.parse' do
|
5
5
|
context 'parsed stat' do
|
6
6
|
subject do
|
7
|
-
EM::File::Stat.parse "644
|
7
|
+
EM::File::Stat.parse "644 2050 'regular file' 100 1 2623327 '/home/arthur/test' 218759168 1000 1340357826 1340357846 1340357846"
|
8
8
|
end
|
9
9
|
|
10
10
|
its(:atime) { should == Time.at(1340357826) }
|
11
|
-
its(:blksize) { should == 512 }
|
12
11
|
its(:blockdev?) { should == false }
|
13
|
-
its(:blocks) { should == 427272 }
|
14
12
|
its(:chardev?) { should == false }
|
15
13
|
its(:ctime) { should == Time.at(1340357846) }
|
16
14
|
its(:dev) { should == 2050 }
|
17
|
-
its(:dev_major) { should == 0 }
|
18
|
-
its(:dev_minor) { should == 0 }
|
19
15
|
its(:directory?) { should == false }
|
20
16
|
its(:executable?) { should == false }
|
21
17
|
its(:executable_real?) { should == false }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-fs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -157,7 +157,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
157
157
|
version: '0'
|
158
158
|
segments:
|
159
159
|
- 0
|
160
|
-
hash:
|
160
|
+
hash: 4225417122368326630
|
161
161
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
162
|
none: false
|
163
163
|
requirements:
|
@@ -166,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
166
|
version: '0'
|
167
167
|
segments:
|
168
168
|
- 0
|
169
|
-
hash:
|
169
|
+
hash: 4225417122368326630
|
170
170
|
requirements: []
|
171
171
|
rubyforge_project:
|
172
172
|
rubygems_version: 1.8.24
|