lib/pa/cmd.rb in pa-1.0.3 vs lib/pa/cmd.rb in pa-1.1.3

- old
+ new

@@ -7,420 +7,512 @@ === Example rm path # it's clear: remove a file rmdir path # it's clear: remove a directory =end class Pa -module ClassMethods::Cmd + module Cmd + extend Util::Concern + module ClassMethods + # link + # + # @overload ln(src, dest) + # @overload ln([src,..], directory) + # + # @param [Array<String>, String] src_s support globbing + # @param [String,Pa] dest + # @param [Hash] o option + # @option o [Boolean] :force overwrite if exists. + # @return [nil] + def ln(src_s, dest, o={}) + _ln(File.method(:link), src_s, dest, o) + end - # chroot - # @see {Dir.chroot} - # - # @param [String] path - # @return [nil] - def chroot(path) Dir.chroot(get(path)) end + # ln force + # + # @see ln + # @return [nil] + def ln_f(src_s, dest, o) + o[:force]=true + _ln(File.method(:link), src_s, dest, o) + end - # touch a blank file - # - # @overload touch(*paths, o={}) - # @param [String] *paths - # @param [Hash] o option - # @option o [Fixnum,String] :mode - # @option o [Boolean] :mkdir auto mkdir if path contained directory not exists. - # @option o [Boolean] :force - # @return [nil] - def touch(*args) paths, o = args.extract_options; _touch(*paths, o) end + # symbol link + # + # @see ln + # @return [nil] + def symln(src_s, dest, o) + _ln(File.method(:symlink), src_s, dest, o) + end + alias symlink ln - # touch force - # @see touch - # - # @overload touch_f(*paths, o={}) - # @return [nil] - def touch_f(*args) paths, o = args.extract_options; o[:force]=true; _touch(*paths, o) end + # symln force + # + # @see ln + # @return [nil] + def symln_f(src_s, dest, o) + o[:force]=true + _ln(File.method(:symlink), src_s, dest, o) + end - def _touch(paths, o) - o[:mode] ||= 0644 - paths.map!{|v|get(v)} - paths.each {|path| - if File.exists?(path) - o[:force] ? next : raise(Errno::EEXIST, "File exist -- #{path}") - end - mkdir(File.dirname(p)) if o[:mkdir] + # @see File.readlink + def readlink(path) + File.readlink(get(path)) + end - if win32? - # win32 BUG. must f.write("") then file can be deleted. - File.open(p, "w"){|f| f.chmod(o[:mode]); f.write("")} - else - File.open(p, "w"){|f| f.chmod(o[:mode])} - end - } - end - private :_touch - # make a directory - # - # @overload mkdir(*paths, o={}) - # @param [String, Pa] *paths - # @param [Hash] o option - # @option o [Fixnum] :mode - # @option o [Boolean] :force - # @return [nil] - def mkdir(*args) paths, o = args.extract_options; _mkdir(paths, o) end + # change directory + # + # @param [String,Pa] path + def cd(path=ENV["HOME"], &blk) + ::Dir.chdir(get(path), &blk) + end - # mkdir force - # @see mkdir - # - # @overload mkdir_f(*paths, o={}) - # @return [nil] - def mkdir_f(*args) paths, o = args.extract_options; o[:force]=true; _mkdir(paths, o) end + # chroot + # @see {Dir.chroot} + # + # @param [String] path + # @return [nil] + def chroot(path) + ::Dir.chroot(get(path)) + end - def _mkdir(paths, o) - o[:mode] ||= 0744 - paths.map!{|v|get(v)} - paths.each {|p| - if File.exists?(p) - o[:force] ? next : raise(Errno::EEXIST, "File exist -- #{p}") - end + # touch a blank file + # + # @overload touch(*paths, o={}) + # @param [String] *paths + # @param [Hash] o option + # @option o [Fixnum,String] :mode + # @option o [Boolean] :mkdir auto mkdir if path contained directory not exists. + # @option o [Boolean] :force + # @return [nil] + def touch(*args) + paths, o = Util.extract_options(args) + _touch(*paths, o) + end - stack = [] - until p == stack.last - break if File.exists?(p) - stack << p - p = File.dirname(p) - end + # touch force + # @see touch + # + # @overload touch_f(*paths, o={}) + # @return [nil] + def touch_f(*args) + paths, o = Util.extract_options(args) + o[:force]=true + _touch(*paths, o) + end - stack.reverse.each do |path| - Dir.mkdir(path) - File.chmod(o[:mode], path) - end - } - end - private :_mkdir + # make a directory + # + # @overload mkdir(*paths, o={}) + # @param [String, Pa] *paths + # @param [Hash] o option + # @option o [Fixnum] :mode + # @option o [Boolean] :force + # @return [nil] + def mkdir(*args) + paths, o = Util.extract_options(args) + _mkdir(paths, o) + end - # make temp directory - # - # @param [Hash] o options - # @option o [Symbol] :prefix ("") - # @option o [Symbol] :suffix ("") - # @option o [Symbol] :tmpdir (ENV["TEMP"]) - # @return [String] path - def mktmpdir(o={}, &blk) - p = _mktmpname(o) - File.mkdir(p) - begin blk.call(p) ensure Dir.delete(p) end if blk - p - end # def mktmpdir + # mkdir force + # @see mkdir + # + # @overload mkdir_f(*paths, o={}) + # @return [nil] + def mkdir_f(*args) + paths, o = Util.extract_options(args) + o[:force]=true + _mkdir(paths, o) + end - def home(user=nil) Dir.home end + # make temp directory + # + # @param [Hash] o options + # @option o [Symbol] :prefix ("") + # @option o [Symbol] :suffix ("") + # @option o [Symbol] :tmpdir (ENV["TEMP"]) + # @return [String] path + def mktmpdir(o={}, &blk) + p = _mktmpname(o) + File.mkdir(p) + begin blk.call(p) ensure ::Dir.delete(p) end if blk + p + end # def mktmpdir - # make temp file - # @see mktmpdir - # - # @param [Hash] o options - # @return [String] path - def mktmpfile(o={}, &blk) - p = _mktmpname(o) - begin blk.call(p) ensure File.delete(p) end if blk - p - end # mktmpfile + def home(user=nil) + ::Dir.home + end - def _mktmpname(o={}) - # :prefix :suffix :tmpdir - # $$-(time*100_000).to_i.to_s(36) - # parse o - o[:dir] ||= ENV["TEMP"] - o[:prefix] ||= "" - o[:suffix] ||= "" + # make temp file + # @see mktmpdir + # + # @param [Hash] o options + # @return [String] path + def mktmpfile(o={}, &blk) + p = _mktmpname(o) + begin + blk.call(p) + ensure + File.delete(p) + end if blk + p + end # mktmpfile - # begin - collision = 0 - path = "#{o[:dir]}/#{o[:prefix]}#{$$}-#{(Time.time*100_000).to_i.to_s(36)}" - orgi_path = path.dup - while File.exists?(path) - path = orgi_path+ collision.to_s - collision +=1 - end - path << o[:suffix] - path - end # def mktmpname - private :_mktmpname + # rm file only + # + # @param [String] *paths support globbing + # @return [nil] + def rm(*paths) + paths, o = Util.extract_options(paths) + glob(*paths) { |pa| + if File.directory?(pa.p) + if o[:force] + next + else + raise Errno::EISDIR, "is a directory -- #{pa.p}" + end + end + next if pa.directory? + File.delete(pa.p) + } + end - # rm file only - # - # @param [String] *paths support globbing - # @return [nil] - def rm *paths - paths, o = paths.extract_options - glob(*paths) { |pa| - if File.directory?(pa.p) - if o[:force]; next else raise Errno::EISDIR, "is a directory -- #{pa.p}" end - end - next if pa.directory? - File.delete(pa.p) - } - end + def rm_f(*paths) + paths, o = Util.extract_options(paths) + o[:force] = true + rm *paths, o + end - def rm_f *paths - paths, o = paths.extract_options - o[:force] = true - rm *paths, o - end + # rm directory only. still remove if directory is not empty. + # + # @param [String] *paths support globbing + # @return [nil] + def rmdir(*paths) + paths, o = Util.extract_options(paths) + glob(*paths) { |pa| + if not File.directory?(pa.p) + if o[:force] + next + else + raise Errno::ENOTDIR, "not a directory -- #{pa.p}" + end + end + _rmdir(pa) + } + end - # rm directory only. still remove if directory is not empty. - # - # @param [String] *paths support globbing - # @return [nil] - def rmdir *paths - paths, o = paths.extract_options - glob(*paths) { |pa| - if not File.directory?(pa.p) - if o[:force]; next else raise Errno::ENOTDIR, "not a directory -- #{pa.p}" end - end - _rmdir(pa) - } - end + def rmdir_f(*paths) + paths, o = Util.extract_options(paths) + o[:force] = true + rmdir *paths, o + end - def rmdir_f *paths - paths, o = paths.extract_options - o[:force] = true - rmdir *paths, o - end + # rm recusive, rm both file and directory + # + # @see rm + # @return [nil] + def rm_r(*paths) + glob(*paths){ |pa| + File.directory?(pa.p) ? _rmdir(pa) : File.delete(pa.p) + } + end + alias rm_rf rm_r - # rm recusive, rm both file and directory - # - # @see rm - # @return [nil] - def rm_r *paths - glob(*paths){ |pa| - File.directory?(pa.p) ? _rmdir(pa) : File.delete(pa.p) - } - end - alias rm_rf rm_r + # rm_if(path) if condition is true + # + # @example + # Pa.rm_if '/tmp/**/*.rb' do |pa| + # pa.name == 'old' + # end + # + # @param [String] *paths support globbing + # @yield [path] + # @yieldparam [Pa] path + # @yieldreturn [Boolean] rm_r path if true + # @return [nil] + def rm_if(*paths, &blk) + glob(*paths) do |pa| + rm_r pa if blk.call(pa) + end + end + # copy + # + # cp file dir + # cp 'a', 'dir' #=> dir/a + # cp 'a', 'dir/a' #=> dir/a + # + # cp file1 file2 .. dir + # cp ['a','b'], 'dir' #=> dir/a dir/b + # + # @example + # cp '*', 'dir' do |src, dest, o| + # skip if src.name=~'.o$' + # dest.replace 'dirc' if src.name=="foo" + # yield # use yield to do the actuactal cp work + # end + # + # @overload cp(src_s, dest, o) + # @param [Array<String>, String] src_s support globbing + # @param [String,Pa] dest + # @param [Hash] o option + # @option o [Boolean] :mkdir mkdir(dest) if dest not exists. + # @option o [Boolean] :verbose puts cmd when execute + # @option o [Boolean] :folsymlink follow symlink + # @option o [Boolean] :force force dest file if dest is a file + # @option o [Boolean] :special special copy, when cp a directory, only mkdir, not cp the directory's content, usefull in Pa.each_r + # @return [nil] + # @overload cp(src_s, dest, o) + # @yield [src,dest,o] + # @return [nil] + def cp(src_s, dest, o={}, &blk) + srcs = glob(*Util.wrap_array(src_s)).map{|v| v.path} + dest = Pa.get(dest) - # rm_if(path) if condition is true - # - # @example - # Pa.rm_if '/tmp/**/*.rb' do |pa| - # pa.name == 'old' - # end - # - # @param [String] *paths support globbing - # @yield [path] - # @yieldparam [Pa] path - # @yieldreturn [Boolean] rm_r path if true - # @return [nil] - def rm_if(*paths, &blk) - glob(*paths) do |pa| - rm_r pa if blk.call(pa) - end - end + if o[:mkdir] and (not File.exists?(dest)) + Pa.mkdir dest + end - # I'm recusive - # param@ [Pa] path - def _rmdir(pa, o={}) - return if not File.exists?(pa.p) - pa.each {|pa1| - File.directory?(pa1.p) ? _rmdir(pa1, o) : File.delete(pa1.p) - } - File.directory?(pa.p) ? Dir.rmdir(pa.p) : File.delete(pa.p) - end - private :_rmdir + # cp file1 file2 .. dir + if srcs.size>1 and (not File.directory?(dest)) + raise Errno::ENOTDIR, "dest not a directory when cp more than one src -- #{dest}" + end - # copy - # - # cp file dir - # cp 'a', 'dir' #=> dir/a - # cp 'a', 'dir/a' #=> dir/a - # - # cp file1 file2 .. dir - # cp ['a','b'], 'dir' #=> dir/a dir/b - # - # @example - # cp '*', 'dir' do |src, dest, o| - # skip if src.name=~'.o$' - # dest.replace 'dirc' if src.name=="foo" - # yield # use yield to do the actuactal cp work - # end - # - # @overload cp(src_s, dest, o) - # @param [Array<String>, String] src_s support globbing - # @param [String,Pa] dest - # @param [Hash] o option - # @option o [Boolean] :mkdir mkdir(dest) if dest not exists. - # @option o [Boolean] :verbose puts cmd when execute - # @option o [Boolean] :folsymlink follow symlink - # @option o [Boolean] :force force dest file if dest is a file - # @option o [Boolean] :special special copy, when cp a directory, only mkdir, not cp the directory's content, usefull in Pa.each_r - # @return [nil] - # @overload cp(src_s, dest, o) - # @yield [src,dest,o] - # @return [nil] - def cp(src_s, dest, o={}, &blk) - srcs = glob(*Array.wrap(src_s)).map{|v| v.path} - dest = Pa.get(dest) + srcs.each do |src| + dest1 = File.directory?(dest) ? File.join(dest, File.basename(src)) : dest - if o[:mkdir] and (not File.exists?(dest)) - Pa.mkdir dest - end + if blk + blk.call src, dest1, o, proc{_copy(src, dest1, o)} + else + _copy src, dest1, o + end - # cp file1 file2 .. dir - if srcs.size>1 and (not File.directory?(dest)) - raise Errno::ENOTDIR, "dest not a directory when cp more than one src -- #{dest}" - end + end + end - srcs.each do |src| - dest1 = File.directory?(dest) ? File.join(dest, File.basename(src)) : dest + def cp_f(src_s, dest, o={}, &blk) + o[:force] = true + cp src_s, dest, o, &blk + end - if blk - blk.call src, dest1, o, proc{_copy(src, dest1, o)} - else - _copy src, dest1, o - end - end - end + # a rename util + # + # @example + # + # Pa.rename('/home/guten.jpg') {|pa| pa.name+'_1'+pa.fext} # => '/home/guten_1.jpg' + # Pa('/home/guten.jpg').rename {|pa| pa.name+'_1'+pa.fext} # => <#Pa('/home/guten_1.jpg')> + # + # @param [String,Pa] src + # @yieldparam [Pa] pa + # @yieldreturn [String] fname + # @return [String,Pa] # Pa.rename return String. Pa#rename return Pa. + def rename(src, &blk) + src = Pa(src) + fname = blk.call(src) + src.dir.join(fname).path + end - def cp_f src_s, dest, o={}, &blk - o[:force] = true - cp src_s, dest, o, &blk - end + # move, use rename for same device. and cp for cross device. + # @see cp + # + # @param [Hash] o option + # @option o [Boolean] :verbose + # @option o [Boolean] :mkdir + # @option o [Boolean] :fore + # @return [nil] + def mv(src_s, dest, o={}, &blk) + srcs = glob(*Util.wrap_array(src_s)).map{|v| get(v)} + dest = get(dest) - # I'm recursive - # - # @param [String] src - # @param [String] dest - def _copy(src, dest, o={}) - raise Errno::EEXIST, "dest exists -- #{dest}" if File.exists?(dest) and (not o[:force]) + if o[:mkdir] and (not File.exists?(dest)) + mkdir dest + end - case type=File.ftype(src) + # mv file1 file2 .. dir + if srcs.size>1 and (not File.directory?(dest)) + raise Errno::ENOTDIR, "dest not a directory when mv more than one src -- #{dest}" + end - when "file", "socket" - puts "cp #{src} #{dest}" if o[:verbose] - File.copy_stream(src, dest) + srcs.each do |src| + dest1 = File.directory?(dest) ? File.join(dest, File.basename(src)) : dest - when "directory" - begin - Pa.mkdir dest - puts "mkdir #{dest}" if o[:verbose] - rescue Errno::EEXIST - end + if blk + blk.call src, dest1, o, proc{_move(src, dest1, o)} + else + _move src, dest1, o + end - return if o[:special] + end + end - each(src) { |pa| - _copy(pa.p, File.join(dest, File.basename(pa.p)), o) - } + def mv_f(src_s, dest, o={}, &blk) + o[:force] = true + mv src_s, dest, o, &blk + end - when "link" # symbol link - if o[:folsymlink] - _copy(Pa.readlink(src), dest) - else - Pa.symln(Pa.readlink(src), dest, force: true) - puts "symlink #{src} #{dest}" if o[:verbose] - end + # I'm recusive + # + # _move "file", "dir/file" + # + # @param [String] src + # @param [String] dest + def _move(src, dest, o) + raise Errno::EEXIST, "dest exists -- #{dest}" if File.exists?(dest) and (not o[:force]) - when "unknow" - raise EUnKnownType, "Can't handle unknow type(#{:type}) -- #{src}" - end + # :force. mv "dir", "dira" and 'dira' exists and is a directory. + if File.exists?(dest) and File.directory?(dest) + ls(src) { |pa| + dest1 = File.join(dest, File.basename(pa.p)) + _move pa.p, dest1, o + } + Pa.rm_r src - # chmod chown utime - src_stat = o[:folsymlink] ? File.stat(src) : File.lstat(src) - begin - File.chmod(src_stat.mode, dest) - #File.chown(src_stat.uid, src_stat.gid, dest) - File.utime(src_stat.atime, src_stat.mtime, dest) - rescue Errno::ENOENT - end - end # _copy - private :_copy + else + begin + Pa.rm_r dest if o[:force] and File.exists?(dest) + puts "rename #{src} #{dest}" if o[:verbose] + File.rename(src, dest) + rescue Errno::EXDEV # cross-device + _copy(src, dest, o) + Pa.rm_r src + end - # a rename util - # - # @example - # - # Pa.rename('/home/guten.jpg') {|pa| pa.name+'_1'+pa.fext} # => '/home/guten_1.jpg' - # Pa('/home/guten.jpg').rename {|pa| pa.name+'_1'+pa.fext} # => <#Pa('/home/guten_1.jpg')> - # - # @param [String,Pa] src - # @yieldparam [Pa] pa - # @yieldreturn [String] fname - # @return [String,Pa] # Pa.rename return String. Pa#rename return Pa. - def rename src, &blk - src = Pa(src) - fname = blk.call(src) - src.dir_pa.join(fname).path - end + end + end # def _move - # move, use rename for same device. and cp for cross device. - # @see cp - # - # @param [Hash] o option - # @option o [Boolean] :verbose - # @option o [Boolean] :mkdir - # @option o [Boolean] :fore - # @return [nil] - def mv(src_s, dest, o={}, &blk) - srcs = glob(*Array.wrap(src_s)).map{|v| get(v)} - dest = get(dest) + def _touch(paths, o) + o[:mode] ||= 0644 + paths.map!{|v|get(v)} + paths.each {|path| + if File.exists?(path) + o[:force] ? next : raise(Errno::EEXIST, "File exist -- #{path}") + end - if o[:mkdir] and (not File.exists?(dest)) - mkdir dest - end + mkdir(File.dirname(p)) if o[:mkdir] - # mv file1 file2 .. dir - if srcs.size>1 and (not File.directory?(dest)) - raise Errno::ENOTDIR, "dest not a directory when mv more than one src -- #{dest}" - end + if win32? + # win32 BUG. must f.write("") then file can be deleted. + File.open(p, "w"){|f| f.chmod(o[:mode]); f.write("")} + else + File.open(p, "w"){|f| f.chmod(o[:mode])} + end + } + end - srcs.each do |src| - dest1 = File.directory?(dest) ? File.join(dest, File.basename(src)) : dest + # @param [Array,String,#path] src_s + # @param [String,#path] dest + def _ln(method, src_s, dest, o={}) + dest = get(dest) + glob(*Util.wrap_array(src_s)) {|src| + src = get(src) + dest = File.join(dest, File.basename(src)) if File.directory?(dest) + Pa.rm_r(dest) if o[:force] and File.exists?(dest) + method.call(src, dest) + } + end - if blk - blk.call src, dest1, o, proc{_move(src, dest1, o)} - else - _move src, dest1, o - end + def _mkdir(paths, o) + o[:mode] ||= 0744 + paths.map!{|v|get(v)} + paths.each {|p| + if File.exists?(p) + o[:force] ? next : raise(Errno::EEXIST, "File exist -- #{p}") + end - end - end + stack = [] + until p == stack.last + break if File.exists?(p) + stack << p + p = File.dirname(p) + end - def mv_f src_s, dest, o={}, &blk - o[:force] = true - mv src_s, dest, o, &blk - end + stack.reverse.each do |path| + ::Dir.mkdir(path) + File.chmod(o[:mode], path) + end + } + end - # I'm recusive - # - # _move "file", "dir/file" - # - # @param [String] src - # @param [String] dest - def _move(src, dest, o) - raise Errno::EEXIST, "dest exists -- #{dest}" if File.exists?(dest) and (not o[:force]) + def _mktmpname(o={}) + # :prefix :suffix :tmpdir + # $$-(time*100_000).to_i.to_s(36) + # parse o + o[:dir] ||= ENV["TEMP"] + o[:prefix] ||= "" + o[:suffix] ||= "" - # :force. mv "dir", "dira" and 'dira' exists and is a directory. - if File.exists?(dest) and File.directory?(dest) - ls(src) { |pa| - dest1 = File.join(dest, File.basename(pa.p)) - _move pa.p, dest1, o - } - Pa.rm_r src + # begin + collision = 0 + path = "#{o[:dir]}/#{o[:prefix]}#{$$}-#{(Time.time*100_000).to_i.to_s(36)}" + orgi_path = path.dup + while File.exists?(path) + path = orgi_path+ collision.to_s + collision +=1 + end + path << o[:suffix] - else - begin - Pa.rm_r dest if o[:force] and File.exists?(dest) - puts "rename #{src} #{dest}" if o[:verbose] - File.rename(src, dest) - rescue Errno::EXDEV # cross-device - _copy(src, dest, o) - Pa.rm_r src - end + path + end # def mktmpname - end - end # def _move - private :_move + # I'm recusive + # param@ [Pa] path + def _rmdir(pa, o={}) + return if not File.exists?(pa.p) + pa.each {|pa1| + File.directory?(pa1.p) ? _rmdir(pa1, o) : File.delete(pa1.p) + } + File.directory?(pa.p) ? ::Dir.rmdir(pa.p) : File.delete(pa.p) + end + # I'm recursive + # + # @param [String] src + # @param [String] dest + def _copy(src, dest, o={}) + raise Errno::EEXIST, "dest exists -- #{dest}" if File.exists?(dest) and (not o[:force]) -end + case type=File.ftype(src) + + when "file", "socket" + puts "cp #{src} #{dest}" if o[:verbose] + File.copy_stream(src, dest) + + when "directory" + begin + Pa.mkdir dest + puts "mkdir #{dest}" if o[:verbose] + rescue Errno::EEXIST + end + + return if o[:special] + + each(src) { |pa| + _copy(pa.p, File.join(dest, File.basename(pa.p)), o) + } + + when "link" # symbol link + if o[:folsymlink] + _copy(Pa.readlink(src), dest) + else + Pa.symln(Pa.readlink(src), dest, force: true) + puts "symlink #{src} #{dest}" if o[:verbose] + end + + when "unknow" + raise EUnKnownType, "Can't handle unknow type(#{:type}) -- #{src}" + end + + # chmod chown utime + src_stat = o[:folsymlink] ? File.stat(src) : File.lstat(src) + begin + File.chmod(src_stat.mode, dest) + #File.chown(src_stat.uid, src_stat.gid, dest) + File.utime(src_stat.atime, src_stat.mtime, dest) + rescue Errno::ENOENT + end + end # _copy + end + end end