em-fs 0.0.1 → 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.
- 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
|