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
|
#!/usr/bin/env ruby
# 2013, 2016, 2018 Luke Shumaker
require 'json'
require 'net/http'
require 'optparse'
require 'set'
devnull = open("/dev/null")
requires = Set.new()
begin
OptionParser.new do |parser|
parser.on("--require=DIR", "Optional directory that the mirror needs ('archive', 'iso', 'other', or 'sources')") do |dir|
requires.add(dir)
end
parser.on("-h", "--help", "Display this help") do
puts parser
exit
end
end.parse!
rescue OptionParser::ParseError => e
STDERR.puts "#{$0}: #{e}"
STDERR.puts "Try '#{$0} --help' for more information."
exit 2
end
unless ARGV.empty?
STDERR.puts "#{$0}: extra argument '#{ARGV[0]}'"
STDERR.puts "Try '#{$0} --help' for more information."
exit 2
end
data = JSON::parse(Net::HTTP.get(URI("https://www.archlinux.org/mirrors/status/tier/1/json/")))
if data["version"] != 3
print "Data format version != 3"
exit 1
end
# Filter out URLs with incomplete information
urls = data["urls"].select{|a| a.none?{|k,v|v.nil?}}
# Filter based on our criteria
rsync_urls = urls.select{|a| a["protocol"]=="rsync"}
if requires.include?("iso")
rsync_urls = rsync_urls.select{|a| a["isos"]==true}
requires.delete("iso")
end
unless requires.empty?
listing_procs = {}
rsync_urls.each do |a|
# trailing slash is important; ensure we have one
listing_procs[a["url"]] ||= IO.popen(["rsync", "--no-motd", "--list-only", "--", a["url"]+"/"], :err => devnull)
end
listings = {}
listing_procs.map.each do |url,listing_proc|
listings[url] = listing_proc.read.lines.map{|line|line.chomp.sub(/.*\s/,'')}
listing_proc.close
end
rsync_urls = rsync_urls.select{|a|requires.all?{|dir|listings[a["url"]].include?(dir)}}
end
puts JSON.dump(rsync_urls)
|