1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/tool/ln_sr.rb

121 lines
2.8 KiB
Ruby
Raw Normal View History

#!/usr/bin/ruby
2022-07-16 03:37:26 -04:00
target_directory = true
noop = false
force = false
until ARGV.empty?
case ARGV[0]
when '-n'
noop = true
when '-f'
force = true
2022-07-16 03:37:26 -04:00
when '-T'
target_directory = false
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)
2022-07-16 03:37:26 -04:00
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.try_convert(src) || [src]
2022-07-16 03:37:26 -04:00
link = proc do |s, target_dir_p = true|
s = File.path(s)
if fu_starting_path?(s)
srcdirs = fu_split_path((File.realdirpath(s) rescue File.expand_path(s)))
else
srcdirs = fu_clean_components(*fu_split_path(s))
end
destdirs = fu_split_path(File.realdirpath(dest))
2022-07-16 03:37:26 -04:00
destdirs.pop unless target_dir_p
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)
2022-07-16 03:37:26 -04:00
d = target_dir_p ? File.join(dest, File.basename(s)) : dest
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
2022-07-16 03:37:26 -04:00
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.chomp!(%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)
begin
2022-07-16 03:37:26 -04:00
ln_sr(src, dest, verbose: true, target_directory: target_directory, force: force, noop: noop)
rescue NotImplementedError, Errno::EPERM
else
exit
end
end
cp_r(src, dest)