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.
@@ -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
@@ -2,8 +2,30 @@ module EventMachine
2
2
  class File
3
3
  class Stat
4
4
 
5
- STAT_REGEX = /(\d+) (\d+) (\d+) (\d+) (\h+) '([\w\/ ]+)' (\d+) (\d+) (\d+) '(.+)' '(.+)' (\d+) (\d+) (\h+) (\h+) (\d+) (\d+) (\d+) (\d+) (\d+)/.freeze
6
- STAT_FORMAT = "%a %b %B %d %f '%F' %g %h %i '%m' '%n' %o %s %t %T %u %W %X %Y %Z"
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[6]
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[11],
50
- mountpoint: m[10],
51
- atime: Time.at(Integer(m[18], 10)),
52
- blksize: Integer(m[3], 10),
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: Integer(m[7], 10),
60
- ino: Integer(m[9], 10),
61
- mode: Integer(m[1], 8),
62
- mtime: Time.at(Integer(m[19], 10)),
63
- nlink: Integer(m[8], 10),
64
- size: Integer(m[13], 10),
65
- uid: Integer(m[16], 10)
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, :mountpoint, :atime, :blksize, :blocks, :ctime,
73
- :dev, :dev_major, :dev_minor, :ftype, :gid, :ino, :mtime,
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
@@ -1,5 +1,5 @@
1
1
  module EventMachine
2
2
  class FS
3
- VERSION = "0.0.1"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -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
@@ -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 427272 512 2050 81a4 'regular file' 100 1 2623327 '/' '/home/arthur/test' 4096 218759168 0 0 1000 0 1340357826 1340357846 1340357846 802h 2050d"
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.1
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: 392820138852039063
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: 392820138852039063
169
+ hash: 4225417122368326630
170
170
  requirements: []
171
171
  rubyforge_project:
172
172
  rubygems_version: 1.8.24