ruby-changes:50591
From: mame <ko1@a...>
Date: Tue, 13 Mar 2018 17:18:08 +0900 (JST)
Subject: [ruby-changes:50591] mame:r62739 (trunk): Add FileUtils#cp_lr
mame 2018-03-13 17:18:03 +0900 (Tue, 13 Mar 2018) New Revision: 62739 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=62739 Log: Add FileUtils#cp_lr * lib/fileutils.rb: Add FileUtils#cp_lr. This method creates hard links of each file from directory to another directory recursively. This patch is based on Thomas Sawyers and Zachary Scott. [Feature #4189] [ruby-core:33820] Modified files: trunk/NEWS trunk/lib/fileutils.rb trunk/test/fileutils/test_fileutils.rb Index: lib/fileutils.rb =================================================================== --- lib/fileutils.rb (revision 62738) +++ lib/fileutils.rb (revision 62739) @@ -297,6 +297,39 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L297 # # :call-seq: + # FileUtils.cp_lr(src, dest, noop: nil, verbose: nil, dereference_root: true, remove_destination: false) + # + # Hard link +src+ to +dest+. If +src+ is a directory, this method links + # all its contents recursively. If +dest+ is a directory, links + # +src+ to +dest/src+. + # + # +src+ can be a list of files. + # + # # Installing ruby library "mylib" under the site_ruby + # FileUtils.rm_r site_ruby + '/mylib', :force => true + # FileUtils.cp_lr 'lib/', site_ruby + '/mylib' + # + # # Examples of copying several files to target directory. + # FileUtils.cp_lr %w(mail.rb field.rb debug/), site_ruby + '/tmail' + # FileUtils.cp_lr Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true + # + # # If you want to copy all contents of a directory instead of the + # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y, + # # use following code. + # FileUtils.cp_lr 'src/.', 'dest' # cp_r('src', 'dest') makes src/dest, but this doesn't. + # + def cp_lr(src, dest, noop: nil, verbose: nil, + dereference_root: true, remove_destination: false) + fu_output_message "cp -lr#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose + return if noop + fu_each_src_dest(src, dest) do |s, d| + link_entry s, d, dereference_root, remove_destination + end + end + module_function :cp_lr + + # + # :call-seq: # FileUtils.ln_s(target, link, force: nil, noop: nil, verbose: nil) # FileUtils.ln_s(target, dir, force: nil, noop: nil, verbose: nil) # FileUtils.ln_s(targets, dir, force: nil, noop: nil, verbose: nil) @@ -342,6 +375,26 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L375 module_function :ln_sf # + # Hard links a file system entry +src+ to +dest+. + # If +src+ is a directory, this method links its contents recursively. + # + # Both of +src+ and +dest+ must be a path name. + # +src+ must exist, +dest+ must not exist. + # + # If +dereference_root+ is true, this method dereference tree root. + # + # If +remove_destination+ is true, this method removes each destination file before copy. + # + def link_entry(src, dest, dereference_root = false, remove_destination = false) + Entry_.new(src, nil, dereference_root).traverse do |ent| + destent = Entry_.new(dest, ent.rel, false) + File.unlink destent.path if remove_destination && File.file?(destent.path) + ent.link destent.path + end + end + module_function :link_entry + + # # Copies a file content +src+ to +dest+. If +dest+ is a directory, # copies +src+ to +dest/src+. # @@ -1252,6 +1305,22 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L1305 end end + def link(dest) + case + when directory? + if !File.exist?(dest) and descendant_directory?(dest, path) + raise ArgumentError, "cannot link directory %s to itself %s" % [path, dest] + end + begin + Dir.mkdir dest + rescue + raise unless File.directory?(dest) + end + else + File.link path(), dest + end + end + def copy(dest) lstat case Index: NEWS =================================================================== --- NEWS (revision 62738) +++ NEWS (revision 62739) @@ -102,6 +102,12 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L102 * erb command's -S option is deprecated, which will be removed in the next version. +* FileUtils + + * New method: + + * FileUtils#cp_lr [Feature #4189] + * Matrix * New method: Index: test/fileutils/test_fileutils.rb =================================================================== --- test/fileutils/test_fileutils.rb (revision 62738) +++ test/fileutils/test_fileutils.rb (revision 62739) @@ -449,6 +449,45 @@ class TestFileUtils < Test::Unit::TestCa https://github.com/ruby/ruby/blob/trunk/test/fileutils/test_fileutils.rb#L449 cp_r 'tmp/src', 'tmp/dest/', remove_destination: true end if have_symlink? + def test_cp_lr + check_singleton :cp_lr + + cp_lr 'data', 'tmp' + TARGETS.each do |fname| + assert_same_file fname, "tmp/#{fname}" + end + + # a/* -> b/* + mkdir 'tmp/cpr_src' + mkdir 'tmp/cpr_dest' + File.open('tmp/cpr_src/a', 'w') {|f| f.puts 'a' } + File.open('tmp/cpr_src/b', 'w') {|f| f.puts 'b' } + File.open('tmp/cpr_src/c', 'w') {|f| f.puts 'c' } + mkdir 'tmp/cpr_src/d' + cp_lr 'tmp/cpr_src/.', 'tmp/cpr_dest' + assert_same_file 'tmp/cpr_src/a', 'tmp/cpr_dest/a' + assert_same_file 'tmp/cpr_src/b', 'tmp/cpr_dest/b' + assert_same_file 'tmp/cpr_src/c', 'tmp/cpr_dest/c' + assert_directory 'tmp/cpr_dest/d' + my_rm_rf 'tmp/cpr_src' + my_rm_rf 'tmp/cpr_dest' + + bug3588 = '[ruby-core:31360]' + mkdir 'tmp2' + assert_nothing_raised(ArgumentError, bug3588) do + cp_lr 'tmp', 'tmp2' + end + assert_directory 'tmp2/tmp' + assert_raise(ArgumentError, bug3588) do + cp_lr 'tmp2', 'tmp2/new_tmp2' + end + + bug12892 = '[ruby-core:77885] [Bug #12892]' + assert_raise(Errno::ENOENT, bug12892) do + cp_lr 'non/existent', 'tmp' + end + end if have_hardlink? + def test_mv check_singleton :mv -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/