module FakeFS::FileUtils
def cd(dir, &block)
def cd(dir, &block) FileSystem.chdir(dir, &block) end
def chmod(mode, list, _options = {})
def chmod(mode, list, _options = {}) list = Array(list) list.each do |f| if File.exist?(f) File.chmod(mode, f) else raise Errno::ENOENT, f.to_s end end list end
def chmod_R(mode, list, _options = {})
def chmod_R(mode, list, _options = {}) list = Array(list) list.each do |file| chmod(mode, file) [FileSystem.find_with_glob("#{file}/**/**")].flatten.each do |f| chmod(mode, f.to_s) end end list end
def chown(user, group, list, _options = {})
def chown(user, group, list, _options = {}) list = Array(list) list.each do |f| if File.exist?(f) uid = if user user.to_s =~ /\d+/ ? user.to_i : Etc.getpwnam(user).uid end gid = if group group.to_s =~ /\d+/ ? group.to_i : Etc.getgrnam(group).gid end File.chown(uid, gid, f) else raise Errno::ENOENT, f.to_s end end list end
def chown_R(user, group, list, _options = {})
def chown_R(user, group, list, _options = {}) list = Array(list) list.each do |file| chown(user, group, file) [FileSystem.find_with_glob("#{file}/**/**")].flatten.each do |f| chown(user, group, f.to_s) end end list end
def compare_file(file1, file2)
def compare_file(file1, file2) # we do a strict comparison of both files content File.readlines(file1) == File.readlines(file2) end
def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) cp_r( src, dest, preserve: preserve, dereference_root: dereference_root, remove_destination: remove_destination ) end
def copy_file(src, dest, _preserve = false, _dereference = true)
def copy_file(src, dest, _preserve = false, _dereference = true) # Not a perfect match, but similar to what regular FileUtils does. cp(src, dest) end
def cp(src, dest, options = {})
def cp(src, dest, options = {}) raise Errno::ENOTDIR, dest.to_s if src.is_a?(Array) && !File.directory?(dest) raise Errno::ENOENT, dest.to_s unless File.exist?(dest) || File.exist?(File.dirname(dest)) # handle `verbose' flag RealFileUtils.cp src, dest, **options.merge(noop: true) # handle `noop' flag return if options[:noop] Array(src).each do |source| dst_file = FileSystem.find(dest) src_file = FileSystem.find(source) raise Errno::ENOENT, source.to_s unless src_file if dst_file && File.directory?(dst_file) FileSystem.add( File.join(dest, File.basename(source)), src_file.entry.clone(dst_file) ) else FileSystem.delete(dest) FileSystem.add(dest, src_file.entry.clone) end end nil end
def cp_r(src, dest, options = {})
def cp_r(src, dest, options = {}) # handle `verbose' flag RealFileUtils.cp_r src, dest, **options.merge(noop: true) # handle `noop' flag return if options[:noop] Array(src).each do |source| dir = FileSystem.find(source) raise Errno::ENOENT, source.to_s unless dir new_dir = FileSystem.find(dest) raise Errno::EEXIST, dest.to_s if new_dir && !File.directory?(dest) raise Errno::ENOENT, dest.to_s if !new_dir && !FileSystem.find(dest.to_s + '/../') update_times = proc { |f| f.atime = f.mtime = Time.now } # This last bit is a total abuse and should be thought hard # about and cleaned up. if new_dir if src.to_s.end_with?('/.') dir.entries.each do |f| copy = f.clone(new_dir) walk_hierarchy(copy, &update_times) unless options[:preserve] new_dir[f.name] = copy end else copy = dir.entry.clone(new_dir) walk_hierarchy(copy, &update_times) unless options[:preserve] new_dir[dir.name] = copy end else copy = dir.entry.clone walk_hierarchy(copy, &update_times) unless options[:preserve] FileSystem.add(dest, copy) end end nil end
def ln_s(target, path, options = {})
def ln_s(target, path, options = {}) options = { force: false }.merge(options) raise(Errno::EEXIST, path.to_s) if FileSystem.find(path) && !options[:force] FileSystem.delete(path) if !options[:force] && !Dir.exist?(File.dirname(path)) raise Errno::ENOENT, path.to_s end FileSystem.add(path, FakeSymlink.new(target)) end
def ln_sf(target, path)
def ln_sf(target, path) ln_s(target, path, force: true) end
def mkdir(list, _ignored_options = {})
def mkdir(list, _ignored_options = {}) list = [list] unless list.is_a?(Array) list.each do |path| parent = path.to_s.split('/') parent.pop unless parent.join == '' || parent.join == '.' || FileSystem.find(parent.join('/')) raise Errno::ENOENT, path.to_s end raise Errno::EEXIST, path.to_s if FileSystem.find(path) FileSystem.add(path, FakeDir.new) end end
def mkdir_p(list, options = {})
def mkdir_p(list, options = {}) list = [list] unless list.is_a?(Array) list.each do |path| # FileSystem.add call adds all the necessary parent directories but # can't set their mode. Thus, we have to collect created directories # here and set the mode later. if options[:mode] created_dirs = [] dir = path until Dir.exist?(dir) created_dirs << dir dir = File.dirname(dir) end end FileSystem.add(path, FakeDir.new) next unless options[:mode] created_dirs.each do |d| File.chmod(options[:mode], d) end end end
def mv(src, dest, options = {})
def mv(src, dest, options = {}) # handle `verbose' flag RealFileUtils.mv src, dest, **options.merge(noop: true) # handle `noop' flag return if options[:noop] Array(src).each do |path| if (target = FileSystem.find(path)) dest_path = if File.directory?(dest) File.join(dest, File.basename(path)) else dest end if File.directory?(dest_path) raise Errno::EEXIST, dest_path.to_s unless options[:force] elsif File.directory?(File.dirname(dest_path)) FileSystem.delete(dest_path) FileSystem.delete(path) FileSystem.add(dest_path, target.entry.clone) else raise Errno::ENOENT, dest_path.to_s unless options[:force] end else raise Errno::ENOENT, path.to_s end end nil end
def remove_entry_secure(path, force = false)
def remove_entry_secure(path, force = false) rm_rf(path, force: force) end
def rm(list, options = {})
def rm(list, options = {}) Array(list).each do |path| FileSystem.delete(path) || (!options[:force] && raise(Errno::ENOENT, path.to_s)) end end
def rm_f(list, options = {})
def rm_f(list, options = {}) rm(list, options.merge(force: true)) end
def rm_rf(list, options = {})
def rm_rf(list, options = {}) rm_r(list, options.merge(force: true)) end
def rmdir(list, _options = {})
def rmdir(list, _options = {}) list = [list] unless list.is_a?(Array) list.each do |l| parent = l.to_s.split('/') parent.pop raise Errno::ENOENT, l.to_s unless parent.join == '' || FileSystem.find(parent.join('/')) raise Errno::ENOENT, l.to_s unless FileSystem.find(l) raise Errno::ENOTEMPTY, l.to_s unless FileSystem.find(l).empty? rm(l) end end
def touch(list, options = {})
def touch(list, options = {}) Array(list).each do |f| if (fs = FileSystem.find(f)) now = Time.now fs.mtime = options[:mtime] || now fs.atime = now else file = File.open(f, 'w') file.close if (mtime = options[:mtime]) fs = FileSystem.find(f) fs.mtime = mtime end end end end
def uptodate?(new, old_list)
def uptodate?(new, old_list) return false unless File.exist?(new) new_time = File.mtime(new) old_list.each do |old| if File.exist?(old) return false unless new_time > File.mtime(old) end end true end
def walk_hierarchy(entry, &block)
Walks through the file system hierarchy recursively, starting from the given entry,
def walk_hierarchy(entry, &block) yield entry if entry.is_a? FakeDir entry.entries.each { |child| walk_hierarchy(child, &block) } end end