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.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)
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)
|