memfs 0.5.0 → 2.0.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.
- checksums.yaml +5 -5
- data/.github/dependabot.yml +19 -0
- data/.github/workflows/ci.yml +64 -0
- data/.gitignore +1 -0
- data/.rspec +2 -2
- data/.rubocop.yml +81 -12
- data/CHANGELOG.md +41 -10
- data/Gemfile +19 -0
- data/Guardfile +5 -3
- data/README.md +7 -6
- data/Rakefile +4 -2
- data/bin/_guard-core +16 -0
- data/bin/coverage_summary +51 -0
- data/bin/guard +16 -0
- data/bin/rake +16 -0
- data/bin/rspec +16 -0
- data/bin/rubocop +16 -0
- data/lib/memfs/dir.rb +86 -21
- data/lib/memfs/fake/directory.rb +31 -3
- data/lib/memfs/fake/entry.rb +41 -25
- data/lib/memfs/fake/file/content.rb +6 -5
- data/lib/memfs/fake/file.rb +6 -5
- data/lib/memfs/fake/symlink.rb +2 -0
- data/lib/memfs/file/stat.rb +21 -14
- data/lib/memfs/file.rb +92 -77
- data/lib/memfs/file_system.rb +17 -12
- data/lib/memfs/filesystem_access.rb +2 -0
- data/lib/memfs/io.rb +183 -153
- data/lib/memfs/version.rb +3 -1
- data/lib/memfs.rb +112 -5
- data/memfs.gemspec +0 -14
- data/spec/fileutils_spec.rb +86 -58
- data/spec/memfs/dir_spec.rb +175 -27
- data/spec/memfs/fake/directory_spec.rb +8 -4
- data/spec/memfs/fake/entry_spec.rb +16 -10
- data/spec/memfs/fake/file/content_spec.rb +1 -1
- data/spec/memfs/fake/file_spec.rb +1 -1
- data/spec/memfs/fake/symlink_spec.rb +3 -3
- data/spec/memfs/file/stat_spec.rb +30 -15
- data/spec/memfs/file_spec.rb +271 -104
- data/spec/memfs/file_system_spec.rb +20 -19
- data/spec/memfs_spec.rb +67 -2
- data/spec/spec_helper.rb +40 -23
- metadata +17 -135
- data/.travis.yml +0 -6
data/lib/memfs/file.rb
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'forwardable'
|
|
2
4
|
require 'memfs/filesystem_access'
|
|
3
5
|
require 'memfs/io'
|
|
4
6
|
|
|
5
7
|
module MemFs
|
|
6
|
-
class File
|
|
8
|
+
class File < IO
|
|
7
9
|
extend FilesystemAccess
|
|
8
10
|
extend SingleForwardable
|
|
9
|
-
extend IO::ClassMethods
|
|
10
11
|
|
|
11
12
|
include Enumerable
|
|
12
13
|
include FilesystemAccess
|
|
13
|
-
include OriginalFile::Constants
|
|
14
|
-
include IO::InstanceMethods
|
|
15
14
|
|
|
15
|
+
PATH_SEPARATOR = '/'
|
|
16
16
|
ALT_SEPARATOR = nil
|
|
17
17
|
|
|
18
18
|
MODE_MAP = {
|
|
19
|
-
'r'
|
|
19
|
+
'r' => RDONLY,
|
|
20
20
|
'r+' => RDWR,
|
|
21
|
-
'w'
|
|
21
|
+
'w' => CREAT | TRUNC | WRONLY,
|
|
22
22
|
'w+' => CREAT | TRUNC | RDWR,
|
|
23
|
-
'a'
|
|
23
|
+
'a' => CREAT | APPEND | WRONLY,
|
|
24
24
|
'a+' => CREAT | APPEND | RDWR
|
|
25
|
-
}
|
|
25
|
+
}.freeze
|
|
26
26
|
|
|
27
27
|
SEPARATOR = '/'
|
|
28
28
|
SUCCESS = 0
|
|
@@ -30,46 +30,54 @@ module MemFs
|
|
|
30
30
|
@umask = nil
|
|
31
31
|
|
|
32
32
|
def_delegators :original_file_class,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
[
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
33
|
+
:basename,
|
|
34
|
+
:dirname,
|
|
35
|
+
:extname,
|
|
36
|
+
:fnmatch,
|
|
37
|
+
:join,
|
|
38
|
+
:path,
|
|
39
|
+
:split
|
|
40
|
+
|
|
41
|
+
%i[
|
|
42
|
+
blockdev?
|
|
43
|
+
chardev?
|
|
44
|
+
directory?
|
|
45
|
+
executable?
|
|
46
|
+
executable_real?
|
|
47
|
+
file?
|
|
48
|
+
grpowned?
|
|
49
|
+
owned?
|
|
50
|
+
pipe?
|
|
51
|
+
readable?
|
|
52
|
+
readable_real?
|
|
53
|
+
setgid?
|
|
54
|
+
setuid?
|
|
55
|
+
socket?
|
|
56
|
+
sticky?
|
|
57
|
+
writable?
|
|
58
|
+
writable_real?
|
|
59
|
+
zero?
|
|
60
60
|
].each do |query_method|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
# def directory?(path)
|
|
62
|
+
# stat_query(path, :directory?)
|
|
63
|
+
# end
|
|
64
|
+
define_singleton_method(query_method) do |path|
|
|
65
|
+
stat_query(path, query_method)
|
|
66
|
+
end
|
|
64
67
|
end
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
class << self; alias empty? zero?; end
|
|
70
|
+
|
|
71
|
+
%i[
|
|
72
|
+
world_readable?
|
|
73
|
+
world_writable?
|
|
69
74
|
].each do |query_method|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
# def directory?(path)
|
|
76
|
+
# stat_query(path, :directory?, false)
|
|
77
|
+
# end
|
|
78
|
+
define_singleton_method(query_method) do |path|
|
|
79
|
+
stat_query(path, query_method, force_boolean: false)
|
|
80
|
+
end
|
|
73
81
|
end
|
|
74
82
|
|
|
75
83
|
def self.absolute_path(path, dir_string = fs.pwd)
|
|
@@ -80,6 +88,10 @@ module MemFs
|
|
|
80
88
|
stat(path).atime
|
|
81
89
|
end
|
|
82
90
|
|
|
91
|
+
def self.birthtime(path)
|
|
92
|
+
stat(path).birthtime
|
|
93
|
+
end
|
|
94
|
+
|
|
83
95
|
def self.chmod(mode_int, *paths)
|
|
84
96
|
paths.each do |path|
|
|
85
97
|
fs.chmod mode_int, path
|
|
@@ -100,7 +112,7 @@ module MemFs
|
|
|
100
112
|
def self.exists?(path)
|
|
101
113
|
!!fs.find(path)
|
|
102
114
|
end
|
|
103
|
-
class << self;
|
|
115
|
+
class << self; alias exist? exists?; end
|
|
104
116
|
|
|
105
117
|
def self.expand_path(file_name, dir_string = fs.pwd)
|
|
106
118
|
original_file_class.expand_path(file_name, dir_string)
|
|
@@ -110,10 +122,12 @@ module MemFs
|
|
|
110
122
|
fs.find!(path) && lstat(path).ftype
|
|
111
123
|
end
|
|
112
124
|
|
|
113
|
-
class << self;
|
|
125
|
+
class << self; alias fnmatch? fnmatch; end
|
|
114
126
|
|
|
115
127
|
def self.identical?(path1, path2)
|
|
116
|
-
|
|
128
|
+
path1 = path1.path if path1.respond_to?(:path)
|
|
129
|
+
path2 = path2.path if path2.respond_to?(:path)
|
|
130
|
+
fs.find!(path1).dereferenced.equal? fs.find!(path2).dereferenced
|
|
117
131
|
rescue Errno::ENOENT
|
|
118
132
|
false
|
|
119
133
|
end
|
|
@@ -180,15 +194,13 @@ module MemFs
|
|
|
180
194
|
|
|
181
195
|
def self.size?(path)
|
|
182
196
|
file = fs.find(path)
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
false
|
|
187
|
-
end
|
|
197
|
+
size = file&.size.to_i
|
|
198
|
+
|
|
199
|
+
size.positive? ? size : false
|
|
188
200
|
end
|
|
189
201
|
|
|
190
202
|
def self.stat(path)
|
|
191
|
-
Stat.new(path, true)
|
|
203
|
+
Stat.new(path, dereference: true)
|
|
192
204
|
end
|
|
193
205
|
|
|
194
206
|
def self.symlink(old_name, new_name)
|
|
@@ -197,7 +209,7 @@ module MemFs
|
|
|
197
209
|
end
|
|
198
210
|
|
|
199
211
|
def self.symlink?(path)
|
|
200
|
-
lstat_query(path, :symlink?)
|
|
212
|
+
lstat_query?(path, :symlink?)
|
|
201
213
|
end
|
|
202
214
|
|
|
203
215
|
def self.truncate(path, length)
|
|
@@ -214,12 +226,10 @@ module MemFs
|
|
|
214
226
|
end
|
|
215
227
|
|
|
216
228
|
def self.unlink(*paths)
|
|
217
|
-
paths.each
|
|
218
|
-
fs.unlink(path)
|
|
219
|
-
end
|
|
229
|
+
paths.each { |path| fs.unlink(path) }
|
|
220
230
|
paths.size
|
|
221
231
|
end
|
|
222
|
-
class << self;
|
|
232
|
+
class << self; alias delete unlink; end
|
|
223
233
|
|
|
224
234
|
def self.utime(atime, mtime, *file_names)
|
|
225
235
|
file_names.each do |file_name|
|
|
@@ -229,32 +239,43 @@ module MemFs
|
|
|
229
239
|
file_names.size
|
|
230
240
|
end
|
|
231
241
|
|
|
232
|
-
attr_reader :path
|
|
242
|
+
attr_reader :path # rubocop:disable Lint/DuplicateMethods
|
|
233
243
|
|
|
244
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
234
245
|
def initialize(filename, mode = File::RDONLY, *perm_and_or_opt)
|
|
246
|
+
super()
|
|
247
|
+
|
|
235
248
|
opt = perm_and_or_opt.last.is_a?(Hash) ? perm_and_or_opt.pop : {}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
end
|
|
249
|
+
perm_and_or_opt.shift
|
|
250
|
+
|
|
251
|
+
fail ArgumentError, 'wrong number of arguments (4 for 1..3)' if perm_and_or_opt.any?
|
|
240
252
|
|
|
241
253
|
@path = filename
|
|
242
|
-
@external_encoding =
|
|
254
|
+
@external_encoding =
|
|
255
|
+
opt[:external_encoding] && Encoding.find(opt[:external_encoding])
|
|
243
256
|
|
|
244
257
|
self.closed = false
|
|
245
258
|
self.opening_mode = str_to_mode_int(mode)
|
|
246
259
|
|
|
247
260
|
fs.touch(filename) if create_file?
|
|
248
261
|
|
|
249
|
-
self.entry = fs.find(filename)
|
|
262
|
+
self.entry = fs.find!(filename)
|
|
263
|
+
# FIXME: this is an ugly way to ensure a symlink has a target
|
|
264
|
+
entry.dereferenced
|
|
250
265
|
|
|
266
|
+
entry.pos = 0 if entry.respond_to?(:pos=)
|
|
251
267
|
entry.content.clear if truncate_file?
|
|
252
268
|
end
|
|
269
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
253
270
|
|
|
254
271
|
def atime
|
|
255
272
|
File.atime(path)
|
|
256
273
|
end
|
|
257
274
|
|
|
275
|
+
def birthtime
|
|
276
|
+
File.birthtime(path)
|
|
277
|
+
end
|
|
278
|
+
|
|
258
279
|
def chmod(mode_int)
|
|
259
280
|
fs.chmod(mode_int, path)
|
|
260
281
|
SUCCESS
|
|
@@ -289,15 +310,9 @@ module MemFs
|
|
|
289
310
|
File.truncate(path, integer)
|
|
290
311
|
end
|
|
291
312
|
|
|
292
|
-
private
|
|
293
|
-
|
|
294
313
|
def self.dereference_name(path)
|
|
295
314
|
entry = fs.find(path)
|
|
296
|
-
|
|
297
|
-
entry.dereferenced_name
|
|
298
|
-
else
|
|
299
|
-
basename(path)
|
|
300
|
-
end
|
|
315
|
+
entry ? entry.dereferenced_name : basename(path)
|
|
301
316
|
end
|
|
302
317
|
private_class_method :dereference_name
|
|
303
318
|
|
|
@@ -321,16 +336,16 @@ module MemFs
|
|
|
321
336
|
end
|
|
322
337
|
private_class_method :original_file_class
|
|
323
338
|
|
|
324
|
-
def self.stat_query(path, query, force_boolean
|
|
339
|
+
def self.stat_query(path, query, force_boolean: true)
|
|
325
340
|
response = fs.find(path) && stat(path).public_send(query)
|
|
326
|
-
force_boolean ? !!
|
|
341
|
+
force_boolean ? !!response : response
|
|
327
342
|
end
|
|
328
343
|
private_class_method :stat_query
|
|
329
344
|
|
|
330
|
-
def self.lstat_query(path, query)
|
|
345
|
+
def self.lstat_query?(path, query)
|
|
331
346
|
response = fs.find(path) && lstat(path).public_send(query)
|
|
332
|
-
!!
|
|
347
|
+
!!response
|
|
333
348
|
end
|
|
334
|
-
private_class_method :lstat_query
|
|
349
|
+
private_class_method :lstat_query?
|
|
335
350
|
end
|
|
336
351
|
end
|
data/lib/memfs/file_system.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'singleton'
|
|
2
4
|
require 'memfs/fake/directory'
|
|
3
5
|
require 'memfs/fake/file'
|
|
@@ -7,29 +9,30 @@ module MemFs
|
|
|
7
9
|
class FileSystem
|
|
8
10
|
include Singleton
|
|
9
11
|
|
|
10
|
-
attr_accessor :
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
attr_accessor :registred_entries,
|
|
13
|
+
:root,
|
|
14
|
+
:working_directory
|
|
13
15
|
|
|
14
16
|
def basename(path)
|
|
15
17
|
File.basename(path)
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
def chdir(path
|
|
20
|
+
def chdir(path)
|
|
19
21
|
destination = find_directory!(path)
|
|
20
22
|
|
|
21
23
|
previous_directory = working_directory
|
|
22
24
|
self.working_directory = destination
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
yield if block_given?
|
|
25
27
|
ensure
|
|
26
|
-
self.working_directory = previous_directory if
|
|
28
|
+
self.working_directory = previous_directory if block_given?
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
def clear!
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
MemFs.reset_platform_root!
|
|
33
|
+
self.root = Fake::Directory.new(MemFs.platform_root)
|
|
34
|
+
mkdir File.join(MemFs.platform_root, 'tmp')
|
|
35
|
+
chdir MemFs.platform_root
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
def chmod(mode_int, file_name)
|
|
@@ -51,7 +54,9 @@ module MemFs
|
|
|
51
54
|
end
|
|
52
55
|
|
|
53
56
|
def find(path)
|
|
54
|
-
|
|
57
|
+
path = MemFs.normalize_path(path)
|
|
58
|
+
|
|
59
|
+
if MemFs.root_path?(path)
|
|
55
60
|
root
|
|
56
61
|
elsif dirname(path) == '.'
|
|
57
62
|
working_directory.find(path)
|
|
@@ -80,7 +85,7 @@ module MemFs
|
|
|
80
85
|
def getwd
|
|
81
86
|
working_directory.path
|
|
82
87
|
end
|
|
83
|
-
|
|
88
|
+
alias pwd getwd
|
|
84
89
|
|
|
85
90
|
def initialize
|
|
86
91
|
clear!
|
|
@@ -96,7 +101,7 @@ module MemFs
|
|
|
96
101
|
find_parent!(new_name).add_entry link
|
|
97
102
|
end
|
|
98
103
|
|
|
99
|
-
def mkdir(path, mode =
|
|
104
|
+
def mkdir(path, mode = 0o777)
|
|
100
105
|
fail Errno::EEXIST, path if find(path)
|
|
101
106
|
directory = Fake::Directory.new(path)
|
|
102
107
|
directory.mode = mode
|