[ruby-dev:10465] fileutils.rb
From:
Minero Aoki <aamine@...>
Date:
2000-07-31 10:29:46 UTC
List:
ruby-dev #10465
あおきです。
ちょっと前に話が出た fileutils.rb を書きました。試してみてください。
# きっと、バグがある
-------------------------------------------------------------------
あおきみねろう
=begin
= fileutils.rb
Copyright (c) 2000 Minero Aoki <aamine@dp.u-netsurf.ne.jp>
This program is free software.
You can distribute/modify this program under the terms of
the Ruby Distribute Lisence.
= Classes
== module FileUtils, FileUtils::Normal
=== Module Functions
---- cd( dirname )
---- cd( dirname ) {|dirname| .... }
chdir(2) to DIRNAME.
If this method is called as iterator, chdir(2) to old dirctory
after the block execution finished.
---- pwd
---- getwd
gets name of working dirctory.
same to Dir.pwd
---- is_newer?( newer, *older )
---- uptodate?( newer, *older )
checks if "newer" is newer than all "older".
---- is_older?( older, *newer )
checks if "older" is older than all "newer".
---- mkdir( *dirs )
makes directories "dirs".
---- mkdir_p( *dirs )
makes dirctories "dirs" and all its path directories.
For expample,
mkdir_p '/usr/local/bin/ruby'
causes to make
* /usr
* /usr/local
* /usr/local/bin
* /usr/local/bin/ruby
if it is not exist.
---- ln( old, new )
---- ln( old, old ..., dir )
makes hard link "new" which links to "old".
---- ln_s( file, file ..., dir )
makes symbolic link "new" which links to "old".
---- cp( file, file ..., dir )
copies file(s) "file" to "to".
---- cp_r( file, file ..., dir )
copies file(s) "file" to "to".
If "file" is a directory, this method copies its all contents
recursively.
---- mv( file, file ..., dir )
moves file(s) "file" to "to".
---- rm( *files )
removes "files". This method can't remove directory.
---- rm_f( *files )
forced to remove "files".
---- rm_rf( *files )
forced to remove "file".
If "file" is a directory, this method removes its all contents
recursively.
---- cmp( a, b )
---- identical?( a, b )
returns true if file "a" and "b" is identical.
---- install( from, to, mode = <from's> )
If "from" is not same to "to", copy it.
---- chmod( mode, *files )
changes mode of "files" to "mode".
== FileUtils::Verbose
This class has all methods of FileUtils::Normal and it works as
same, but outputs messages before action. You can also pass
verbose flag to all methods, as last argument (default is "true").
== FileUtils::NoWrite
This class has all methods of FileUtils::Normal but never
changes files.
=end
module FileUtils
#
# FileUtils::Normal
#
Normal = self
module_function
def cd( dn )
if iterator? then
pre = Dir.pwd
begin
Dir.chdir dn
yield dn
ensure
Dir.chdir pre
end
else
Dir.chdir dn
end
end
alias chdir cd
def pwd
Dir.pwd
end
alias getwd pwd
def is_newer?( new, *fnames )
fnames.each do |old|
return false unless FileTest.exist? new
return false unless File.ctime(new) >= File.ctime(old)
end
true
end
alias uptodate? is_newer?
def is_older?( old, *fnames )
fnames.each do |old|
return true unless FileTest.exist? old
return false unless File.ctime(new) >= File.ctime(old)
end
true
end
def mkdir( *args )
args.flatten!
args.each do |dn|
Dir.mkdir dn unless FileTest.directory? dn
end
end
def mkdir_p( *args )
args.flatten!
stack = []
dn = nil
args.each do |dn|
until FileTest.directory? dn do
stack.push dn
dn = File.dirname(dn)
end
stack.reverse_each do |dn|
Dir.mkdir dn
end
stack.clear
end
end
def ln( *args )
FUPrivate.each_src_dest( args ) do |from, to|
File.link from, to
end
end
def ln_s( old, new )
FUPrivate.each_src_dest( args ) do |from, to|
File.symlink from, to
end
end
def cp( *args )
size = s = w = nil
FUPrivate.each_src_dest( args ) do |from, to|
FUPrivate.copy from, to
end
end
def cp_r( *args )
FUPrivate.each_src_dest( args ) do |from, to|
if FileTest.directory? from then
unless FileTest.directory? to then
Dir.mkdir to
end
FUPrivate.do_cp_r from, '.', to
else
FUPrivate.copy from, to
end
end
end
def mv( *args )
FUPrivate.each_src_dest( args ) do |from, to|
st = File.stat( from )
if File::ALT_SEPARATOR then
File.unlink to
end
begin
File.rename from, to
rescue
if FileTest.symlink? from then
File.symlink File.readlink(from), to
File.unlink from
else
FUPrivate.copy from, to
File.unlink from
File.utime st.atime, st.mtime, to
begin
File.chown st.uid, st.gid, to
rescue
;
end
end
end
end
end
def rm( *files )
files.flatten!
files.each do |fn|
File.unlink fn
end
end
def rm_f( *files )
files.flatten!
files.each do |fn|
FUPrivate.rmf fn
end
end
def rm_rf( *files )
files.flatten!
files.each do |fn|
if FileTest.directory? fn then
FUPrivate.do_rm_rf fn
else
FUPrivate.rmf fn
end
end
end
def cmp( filea, fileb )
stra = strb = nil
size = File.size( filea )
if File.size( fileb ) != size then
return true
end
if size > FUPrivate::TOO_BIG then
size = FUPrivate::TOO_BIG
elsif size < 512 then
size = 1024
end
File.open( filea ) {|a| a.binmode
File.open( fileb ) {|b| b.binmode
begin
while stra == strb do
stra = a.read( size )
strb = b.read( size )
unless stra and strb then
if stra.nil? and strb.nil? then
return true
end
end
end
rescue EOFError
;
end
} }
false
end
alias identical? cmp
def install( from, to, mode = nil )
dest = FUPrivate.destfn( from, to )
unless FileTest.exist? dest and cmp( from, dest ) then
File.chmod 0777, fn
File.unlink fn
FUPrivate.copy from, dest
File.chmod mode, dest if mode
end
end
def update_file( fname, upd )
str = nil
if FileTest.file? fname then
File.open( fname ) {|f| str = f.read }
end
if not str or str != upd then
File.open( fname, 'w' ) do |f|
f.write upd
end
end
end
def chmod( mode, *args )
args.flatten!
File.chmod mode, *args
end
def touch( *args )
args.flatten!
t = Time.now
File.utime t, t, *args
end
#end # module Normal
module FUPrivate
TOO_BIG = 2 * 1024 * 1024 # 2 MB
class << self
def each_src_dest( args )
args.flatten!
case args.size
when 2
from, to = args
if FileTest.directory? to then
yield from, (to[-1,1] == '/' ? to : to + '/') + File.basename(from)
else
yield args
end
when 0, 1
raise ArgumentError, "wrong # of arguments #{args.size} for >=2"
else
dir = args.pop
unless FileTest.directory? dir then
raise ArgumentError, "must be dir: #{dir}"
end
unless dir[-1,1] == '/' then
dir << '/'
end
args.each do |fn|
yield fn, dir + File.basename(fn)
end
end
end
def destfn( from, to )
if FileTest.directory? to then
(to[-1,1] == '/' ? to : to + '/') + File.basename(from)
else
to
end
end
def copy( from, to )
mod = File.stat( from ).mode
size = s = w = nil
File.open( from ) {|rf| rf.binmode
File.open( to, 'w' ) {|wf| wf.binmode
size = File.size( from )
if size > TOO_BIG then
size = TOO_BIG
elsif size < 512 then
size = 1024
end
s = nil
begin
while true do
s = rf.sysread( size )
w = wf.syswrite( s )
while w < s.size do
w += wf.syswrite( s[ w, s.size - w ] )
end
end
rescue EOFError
File.chmod mod, to
end
} }
end
def do_cp_r( base, abs, to )
dirs = nil
Dir.open( "#{base}/#{abs}" ) {|d| dirs = d.to_a }
dirs.each do |fn|
if FileTest.directory? fn then
next if /\A\.\.?\z/ === fn
Dir.mkdir "#{to}/#{abs}/#{fn}"
do_cp_r base, "#{abs}/#{fn}", to
else
copy "#{base}/#{abs}/#{fn}", "#{to}/#{abs}/#{fn}"
end
end
end
def rmf( fn )
if FileTest.exist? fn and not FileTest.directory? fn then
File.chmod 0777, fn
File.unlink fn
end
end
def do_rm_rf( dn )
Dir.foreach( dn ) do |fn|
next if /\A\.\.?\z/ === fn
fn = "#{dn}/#{fn}"
if FileTest.directory? fn then
do_rm_rf fn
else
rmf fn
end
end
Dir.rmdir dn
end
def getflag( arr )
arr.flatten!
if arr.last == true or arr.last == false then
arr.pop
else
true
end
end
end; end
#
# FileUtils::Verbose
#
module Verbose
@fileutils_op = FileUtils::Normal
@fileutils_output = $stderr
@fileutils_label = 'futils: '
def futilsmsg( msg )
@fileutils_label ||= 'futils: '
@fileutils_output ||= $stderr
@fileutils_output.puts @fileutils_label + msg
end
module_function :futilsmsg
private_class_method :futilsmsg
attr_accessor :fileutils_op
attr_accessor :fileutils_output
attr_accessor :fileutils_label
module_function
def cd( dirname, verbose = true, &block )
futilsmsg "cd #{dirname}" if verbose
(@fileutils_op ||= FileUtils::Normal).cd dirname, &block
futilsmsg "cd #{Dir.pwd}" if verbose and block
end
alias chdir cd
def pwd( verbose = true )
futilsmsg 'pwd' if verbose
Dir.pwd
end
alias getwd pwd
class << self
def delegate( name )
name = name.id2name
if name[-1,1] != '?' then
outname = name.sub( '_', ' -' )
else
outname = name
end
module_eval %^
def #{name}( *args )
futilsmsg "#{outname} \#{args.join ' '}" if FUPrivate.getflag(args)
(@fileutils_op ||= FileUtils::Normal).#{name} *args
end
module_function :#{name}
^
end
end
delegate :is_newer?
delegate :is_older?
alias uptodate? is_newer?
delegate :mkdir
delegate :mkdir_p
delegate :rmdir
alias mkpath mkdir_p
delegate :ln
delegate :ln_s
delegate :cp
delegate :cp_r
delegate :mv
delegate :rm
delegate :rm_f
delegate :rm_rf
def cmp( a, b, verbose = true )
futilsmsg "cmp #{a} #{b}" if verbose
(@fileutils_op ||= FileUtils::Normal).cmp a, b
end
alias identical? cmp
def install( from, to, mode = nil, verbose = true )
futilsmsg "install #{mode ? '%o ' % mode : ''}#{from} #{to}" if verbose
(@fileutils_op ||= FileUtils::Normal).install from, to, mode
end
def update_file( fname, upd, verbose = true )
futilsmsg "update #{to}" if verbose
(@fileutils_op ||= FileUtils::Normal).update_file fname, upd
end
def chmod( mode, *args )
futilsmsg sprintf('chmod %o %s',
mode, args.join(' ')) if FUPrivate.getflag(args)
(@fileutils_op ||= FileUtils::Normal).chmod mode, *args
end
delegate :touch
end # module Verbose
#
# FileUtils::NoWrite
#
module NoWrite
extend FileTest
include FileTest
class << self
def delegate( fname, exec )
str = %-
def #{fname.id2name}( *args, &block )
#{if exec then
'FileUtils::Normal.' + fname.id2name + '( *args, &block )'
else
''
end}
end
-
module_eval str, __FILE__, @line
@line += 1
end
end
@line = __LINE__
delegate :cd ,true
delegate :pwd ,true
delegate :getwd ,true
delegate :uptodate? ,true
delegate :is_newer? ,true
delegate :is_older? ,true
delegate :mkdir ,false
delegate :mkdir_p ,false
delegate :ln ,false
delegate :ln_s ,false
delegate :cp ,false
delegate :cp_r ,false
delegate :mv ,false
delegate :rm ,false
delegate :rm_f ,false
delegate :rm_rf ,false
delegate :cmp ,true
delegate :identical? ,true
delegate :install ,false
delegate :update_file ,false
delegate :chmod ,false
delegate :touch ,false
end # module Noop
end
= fileutils.rb
Copyright (c) 2000 Minero Aoki <aamine@dp.u-netsurf.ne.jp>
This program is free software.
You can distribute/modify this program under the terms of
the Ruby Distribute Lisence.
== module FileUtils::Simple
=== モジュールメソッド
---- cd( dirname )
---- cd( dirname ) {|dirname| .... }
ディレクトリ dirname に移動します。
イテレータとして呼ばれた時はブロック終了後に
元のディレクトリに戻ります。
---- pwd
---- getwd
カレントディレクトリの名前を返します。
Dir.pwd と同じです。
---- is_newer?( newer, *older )
newer が全ての older より新しいとき真。
存在しないファイルは無限に古いとみなされます。
---- is_older?( older, *newer )
older が全ての newer より古いとき真。
存在しないファイルは無限に古いとみなされます。
---- mkdir( *dirs )
ディレクトリ dirs を作成します。
---- mkdir_p( *dirs )
ディレクトリ *dirs とそのパスのディレクトリを全て作成します。
例えば mkdir_p '/usr/local/bin/ruby' は /、/usr、/usr/local、
/usr/local/bin、/usr/local/bi/ruby の全てを(なければ)作成します。
---- ln( old, new )
---- ln( file, file ..., dir )
old へのハードリンク new を作成します。
三つ以上の引数を与えたときはディレクトリ dir の中に
その他のファイルへのリンクを作成します。
---- ln_s( old, new )
---- ln_s( file, file ..., dir )
old へのシンボリックリンク new を作成します。
三つ以上の引数を与えたときはディレクトリ dir の中に
その他のファイルへのリンクを作成します。
---- cp( from, to )
---- cp( file, file ..., dir )
from を to にコピーします。to がディレクトリなら to/from に
コピーします。三つ以上の引数を与えたときはディレクトリ dir の
中にその他のファイルをコピーします。
---- cp_r( from, to )
---- cp_r( file, file ..., dir )
from を to にコピーします。to がディレクトリなら to/from に
コピーします。ディレクトリも再帰的にコピーできます。また、
三つ以上の引数を与えたときはディレクトリ dir の中にその他の
ファイルをコピーします。
---- mv( from, to )
---- mv( file, file ..., dir )
from を to に移動します。to がディレクトリなら to/from に
移動します。三つ以上の引数を与えたときはディレクトリ dir の
中にその他のファイルを移動します。
---- rm( file, file ... )
引数に与えたファイルを消去します。
---- rm_f( file. file ... )
引数に与えたファイルを所有しているなら rm より確実に消去します。
また、ファイルが存在しなくても例外を発生しません。
---- cmp( a, b )
---- identical?( a, b )
ファイル a と b が同じなら真。
---- install( from, to, mode = <from's> )
from と to の内容が違うときだけ from を to にコピーします。
そのさいモードを mode に設定します。
---- chmod( mode, file, file ... )
ファイル file のモードを mode に変えます。
mode は八進数を使って chmod 0644, fname のように与えます。
== FileUtils::Verbose
FileUtils::Normal と同じメソッドが定義されており全く同じ
動作をしますが、実行前にしようとしていることを表示します。
=== メソッド
---- fileutils_op
---- fileutils_op=( operator )
メソッドを転送するオブジェクトです。
デフォルトは FileUtils::Normal です。
---- fileutils_output
---- fileutils_output=( out )
メッセージを出力するオブジェクトです。
out は puts を持っていなければいけません。
デフォルトは stderr です。
---- fileutils_label
---- fileutils_label=( str )
メッセージの最初につくラベルです。
デフォルトは 'futils: ' です。
== FileUtils::NoWrite
FileUtils::Normal と同じメソッドが定義されていますが、
実際にファイルを変更する操作は実行しません。