1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#!/usr/bin/ruby
target_directory = true
noop = false
force = false
quiet = false
until ARGV.empty?
case ARGV[0]
when '-n'
noop = true
when '-f'
force = true
when '-T'
target_directory = false
when '-q'
quiet = true
else
break
end
ARGV.shift
end
unless ARGV.size == 2
abort "usage: #{$0} src destdir"
end
src, dest = ARGV
require 'fileutils'
include FileUtils
unless respond_to?(:ln_sr)
def ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil)
options = "#{force ? 'f' : ''}#{target_directory ? '' : 'T'}"
dest = File.path(dest)
srcs = Array(src)
link = proc do |s, target_dir_p = true|
s = File.path(s)
if target_dir_p
d = File.join(destdirs = dest, File.basename(s))
else
destdirs = File.dirname(d = dest)
end
destdirs = fu_split_path(File.realpath(destdirs))
if fu_starting_path?(s)
srcdirs = fu_split_path((File.realdirpath(s) rescue File.expand_path(s)))
base = fu_relative_components_from(srcdirs, destdirs)
s = File.join(*base)
else
srcdirs = fu_clean_components(*fu_split_path(s))
base = fu_relative_components_from(fu_split_path(Dir.pwd), destdirs)
while srcdirs.first&. == ".." and base.last&.!=("..") and !fu_starting_path?(base.last)
srcdirs.shift
base.pop
end
s = File.join(*base, *srcdirs)
end
fu_output_message "ln -s#{options} #{s} #{d}" if verbose
next if noop
remove_file d, true if force
File.symlink s, d
end
case srcs.size
when 0
when 1
link[srcs[0], target_directory && File.directory?(dest)]
else
srcs.each(&link)
end
end
def fu_split_path(path)
path = File.path(path)
list = []
until (parent, base = File.split(path); parent == path or parent == ".")
list << base
path = parent
end
list << path
list.reverse!
end
def fu_relative_components_from(target, base) #:nodoc:
i = 0
while target[i]&.== base[i]
i += 1
end
Array.new(base.size-i, '..').concat(target[i..-1])
end
def fu_clean_components(*comp)
comp.shift while comp.first == "."
return comp if comp.empty?
clean = [comp.shift]
path = File.join(*clean, "") # ending with File::SEPARATOR
while c = comp.shift
if c == ".." and clean.last != ".." and !(fu_have_symlink? && File.symlink?(path))
clean.pop
path.sub!(%r((?<=\A|/)[^/]+/\z), "")
else
clean << c
path << c << "/"
end
end
clean
end
if fu_windows?
def fu_starting_path?(path)
path&.start_with?(%r(\w:|/))
end
else
def fu_starting_path?(path)
path&.start_with?("/")
end
end
end
if File.respond_to?(:symlink)
if quiet and File.identical?(src, dest)
exit
end
begin
ln_sr(src, dest, verbose: true, target_directory: target_directory, force: force, noop: noop)
rescue NotImplementedError, Errno::EPERM, Errno::EACCES
else
exit
end
end
cp_r(src, dest)
|