3 # Used to download, extract and patch extension libraries (extlibs)
4 # for Ruby. See common.mk for Ruby's usage.
7 require_relative 'downloader'
8 require_relative 'lib/colorize'
12 /\$\((#{Regexp.union(keys)})\)/
19 str.gsub(pattern) {self[$1]}
26 @colorize = Colorize.new
29 def cache_file(url, cache_dir)
30 Downloader.cache_file(url, nil, cache_dir).to_path
33 def do_download(url, cache_dir)
34 Downloader.download(url, nil, nil, nil, :cache_dir => cache_dir)
37 def do_checksum(cache, chksums)
39 name, sum = sum.split(/:/)
41 $stdout.print "checking #{name} of #{cache} ..."
44 hd = Digest(name.upcase).file(cache).hexdigest
47 $stdout.puts hd == sum ? @colorize.pass("OK") : @colorize.fail("NG")
51 raise "checksum mismatch: #{cache}, #{name}:#{hd}, expected #{sum}"
56 def do_extract(cache, dir)
58 $stdout.puts "extracting #{cache} into #{dir}"
61 ext = File.extname(cache)
64 f = IO.popen(["gzip", "-dc", cache])
65 cache = cache.chomp('.gz')
67 f = IO.popen(["bzip2", "-dc", cache])
68 cache = cache.chomp('.bz2')
70 f = IO.popen(["xz", "-dc", cache])
71 cache = cache.chomp('.xz')
76 ext = File.extname(cache)
78 when '.tar', /\A\.t[gbx]z\z/
79 pid = Process.spawn("tar", "xpf", "-", in: inp, chdir: dir)
81 pid = Process.spawn("unzip", inp, "-d", dir)
85 $?.success? or raise "failed to extract #{cache}"
88 def do_patch(dest, patch, args)
90 $stdout.puts "applying #{patch} under #{dest}"
93 Process.wait(Process.spawn(ENV.fetch("PATCH", "patch"), "-d", dest, "-i", patch, *args))
94 $?.success? or raise "failed to patch #{patch}"
97 def do_link(file, src, dest)
98 file = File.join(dest, file)
99 if (target = src).start_with?("/")
100 target = File.join([".."] * file.count("/"), src)
102 return unless File.exist?(File.expand_path(target, File.dirname(file)))
103 File.unlink(file) rescue nil
105 File.symlink(target, file)
109 $stdout.puts "linked #{target} to #{file}"
115 src = src.sub(/\A\//, '')
116 File.copy_stream(src, file)
119 $stdout.puts "failed to link #{src} to #{file}: #{$!.message}"
123 $stdout.puts "copied #{src} to #{file}"
128 def do_exec(command, dir, dest)
129 dir = dir ? File.join(dest, dir) : dest
131 $stdout.puts "running #{command.dump} under #{dir}"
134 system(command, chdir: dir) or raise "failed #{command.dump}"
137 def do_command(mode, dest, url, cache_dir, chksums)
139 base = /.*(?=\.tar(?:\.\w+)?\z)/
143 cache = do_download(url, cache_dir)
144 do_checksum(cache, chksums)
146 cache = cache_file(url, cache_dir)
147 target = File.join(dest, File.basename(cache)[base])
148 unless File.directory?(target)
149 do_checksum(cache, chksums)
150 extracted = do_extract(cache, dest)
153 cache = do_download(url, cache_dir)
154 target = File.join(dest, File.basename(cache)[base])
155 unless File.directory?(target)
156 do_checksum(cache, chksums)
157 extracted = do_extract(cache, dest)
185 warn "unknown option: #{argv[0]}"
195 Dir.glob("#{dir}/**/extlibs") do |list|
197 $stdout.puts "downloading for #{list}"
202 dest = File.dirname(list)
204 IO.foreach(list) do |line|
205 line.sub!(/\s*#.*/, '')
206 if /^(\w+)\s*=\s*(.*)/ =~ line
207 vars[$1] = vars.expand($2)
211 chksums.concat(line.split)
213 if extracted and (mode == :all or mode == :patch)
214 patch, *args = line.split.map {|s| vars.expand(s)}
215 do_patch(dest, patch, args)
218 elsif /^!\s*(?:chdir:\s*([^|\s]+)\|\s*)?(.*)/ =~ line
219 if extracted and (mode == :all or mode == :patch)
220 command = vars.expand($2.strip)
221 chdir = $1 and chdir = vars.expand(chdir)
222 do_exec(command, chdir, dest)
226 if extracted and (mode == :all or mode == :patch)
227 link, file = $`.strip, $'.strip
228 do_link(vars.expand(link), vars.expand(file), dest)
232 url, *chksums = line.split(' ')
234 if chksums.last == '\\'
242 url = vars.expand(url)
244 extracted = do_command(mode, dest, url, cache_dir, chksums)
262 exit ExtLibs.run(ARGV)