#!/usr/bin/perl -w # # mirror_list.pl -- generate various Debian mirror lists # Copyright (C) 1998 James Treacy # Copyright (C) 2000-2002, 2007-2008 Josip Rodin # Copyright (C) 2005 Joey Hess # Copyright (C) 2016, 2021 Peter Palfrader use strict; use English; use HTML::Entities; use List::Util qw(max); binmode(STDOUT => ':utf8'); require 5.001; my @filter_arches=qw(); # Architectures not to list. my $officialsiteregex = q{^ftp\d?(?:\.wa)?\...\.debian\.org$}; my $encode = '<>&"\''; use Getopt::Long; my ($mirror_source, $output_type, $help); my %opthash = ( "mirror|m=s" => \$mirror_source, "type|t=s" => \$output_type, "help|h!" => \$help, ); Getopt::Long::config('no_getopt_compat', 'no_auto_abbrev'); GetOptions(%opthash) or die "error parsing options"; $output_type = 'html' if (! defined $output_type); $mirror_source = 'Mirrors.masterlist' if (! defined $mirror_source); my $last_modify = gmtime((stat($mirror_source))[9]); my (@mirror, %countries, %countries_sponsors, %longest); my ($count, $cdimagecount); my (%code_of_country, %plain_name_of_country); my %includedsites; my $globalsite; sub cmpbydomain { my $sitea = $mirror[$a]{site}; my $siteb = $mirror[$b]{site}; my @a = map(scalar reverse, split(/\./, (scalar reverse $sitea))); my @b = map(scalar reverse, split(/\./, (scalar reverse $siteb))); while (1) { if ((scalar @a == 0) || (scalar @b == 0)) { return ((scalar @a) <=> (scalar @b)); } my $ca = shift @a; my $cb = shift @b; my $cmp = $ca cmp $cb; return $cmp if ($cmp != 0); } return 0; } sub process_line { my ($lno, $line) = @_; my $field = ''; if ($line =~ /^Site:\s*(.+)\s*$/i) { my $site = $1; $globalsite = $site; $count++; $mirror[$count-1]{site} = $site; $mirror[$count-1]{_lno} = $lno; return; } elsif ($line =~ /^Alias(?:es)?:\s*(.+)\s*$/is) { push @{ $mirror[$count-1]{aliases} }, $_ foreach (split("\n", $1)); } elsif ($line =~ /^(\w+)-architecture:\s*(.+)\s*$/i && length $2) { my $key = "$1"."-architecture"; my @arches=split(' ', $2); foreach my $f (@filter_arches) { @arches=grep { ! /^$f$/ } @arches; } if (! @arches) { # Mirror only carries filtered architectures. $mirror[$count-1]{filtered}=1; } foreach my $f (@filter_arches) { @arches=grep { ! /^\!$f$/ } @arches; } if (@arches) { $mirror[$count-1]{$key}=\@arches; } } elsif ($line=~ /^((Archive|CDimage|Jigdo|Old)-(\w*)):\s*(.*)\s*$/i) { my $type = lc $1; my $value = $4; $mirror[$count-1]{method}{$type} = $value; if (!defined($longest{$type}) || length($value)+1 > $longest{$type}) { $longest{$type} = length($value)+1; } } elsif ($line =~ /^Includes:\s*(.+)\s*$/i) { push @{ $mirror[$count-1]{includes} }, $_ foreach (split(" ", $1)); } elsif ($line =~ /^Sponsor:\s*(.+)\s*$/i) { push @{ $mirror[$count-1]{sponsor} }, $1; } elsif ($line =~ /^([\w-]+):\s*(.+)\s*$/s) { $field = lc $1; my $value = $2; # Ignore X-* fields if ($field !~ /^x-/) { $mirror[$count-1]{$field} = $value; } if ($field eq 'country') { if ($value =~ /^(\w\w) (.+)$/) { $code_of_country{$value} = $1; $plain_name_of_country{$value} = $2; } else { die "strangely formatted Country field value: $value"; } } } else { die "Error: incorrect line format\n\"$line\"\n"; } } sub aptlines { foreach my $country (sort keys %countries) { print "\n$country\n"; print "-" x length($country); # underline print "\n"; foreach my $id (@{ $countries{$country} }) { my $archcomm=""; if ($mirror[$id]{'Archive-architecture'}) { $archcomm=" # ".join(" ", sort @{$mirror[$id]{'Archive-architecture'}})."\n"; } if (defined $mirror[$id]{method}{'archive-http'}) { print "deb http://$mirror[$id]{site}$mirror[$id]{method}{'archive-http'} stable main contrib non-free non-free-firmware$archcomm\n"; } } print "\n"; } } sub secondary_mirrors { # TODO make the text version not have such long lines. my $format = shift; die "must get format for secondary_mirrors()" unless $format; my $html = 1 if ($format eq 'html'); my $text = 1 if ($format eq 'text'); my $wml = 1 if ($format eq 'wml'); my $formatstring; if ($html || $text) { print "

" if $html; print "\n\n " if $text; print "List of mirrors of the Debian archive"; print "\n ---------------------------------------\n\n" if $text; print "

\n\n" if $html; if ($html) { print < Host name HTTP Architectures END } else { my $formatstring = "%-$longest{site}s %-$longest{'archive-http'}s%s\n"; printf $formatstring, "HOST NAME", "HTTP", "ARCHITECTURES"; printf $formatstring, "---------", "----", "-------------"; } } elsif ($wml) { print "\n"; } foreach my $country (sort keys %countries) { my $countryplain = $plain_name_of_country{$country}; my $countrycode = $code_of_country{$country}; my %our_mirrors; foreach my $id (@{ $countries{$country} }) { if (defined $mirror[$id]{method}{'archive-http'}) { $our_mirrors{$id} = 1; } } next unless (keys %our_mirrors); print "\n"; if ($html) { print "
\n"; print "$country\n"; } elsif ($text) { print "$country"; } print "\n"; if ($text) { print "-" x length($country); # underline print "\n"; } foreach my $id (@{ $countries{$country} }) { next unless defined $mirror[$id]{method}{'archive-http'}; my $aliaslist; if (exists $mirror[$id]{'aliases'}) { if (!exists $mirror[$id]{includes}) { # we want to display aliases in the main list for official mirrors # but for others, it's just clutter, so skip them if ($mirror[$id]{site} =~ /$officialsiteregex/) { my $truename = @{$mirror[$id]{'aliases'}}[0]; if ($truename =~ /^ftp.+\.debian\.org$/) { $truename = @{$mirror[$id]{'aliases'}}[1]; } $aliaslist .= " (" . $truename . ")"; } } } if (exists $mirror[$id]{includes}) { $aliaslist .= " ("; my @tmparray = @{$mirror[$id]{includes}}; my $notalldone = $#tmparray + 1; SUBSITE: foreach my $subsite (@{ $mirror[$id]{includes} }) { # this is basically a sanity check my $subsite_id; SUBSITEID: foreach my $mid (0 .. $#mirror) { if ($mirror[$mid]{site} eq $subsite) { $subsite_id = $mid; last SUBSITEID; } } die $subsite ." included in " . $mirror[$id]{site} . " does not exist\n" unless defined $subsite_id; # must be an error # this prints the canonical name of the included site rather than its reference - should be in sync, but might actually vary $aliaslist .= $mirror[$subsite_id]{site}; $notalldone--; $aliaslist .= ", " if ($notalldone); } $aliaslist .= ")"; } if ($html) { print "\n"; print "$mirror[$id]{site}"; print "
$aliaslist" if ($aliaslist); print "\n"; } elsif ($text) { my $formatstring = "%-$longest{site}s "; printf $formatstring, $mirror[$id]{site}; } if (defined $mirror[$id]{method}{'archive-http'}) { my $rest = $longest{'archive-http'} - length($mirror[$id]{method}{'archive-http'}); if ($html) { print <$mirror[$id]{method}{'archive-http'} END } elsif ($text) { my $formatstring = "%s%${rest}s"; printf $formatstring, $mirror[$id]{method}{'archive-http'}, ''; } elsif ($wml) { print <"}{"$mirror[$id]{site}"} }, "$mirror[$id]{method}{'archive-http'}"; EOF } } else { if ($html) { print "\n"; } elsif ($text) { my $formatstring = "%-$longest{'archive-http'}s"; printf $formatstring, " "; } elsif ($wml) { print <"}{"$mirror[$id]{site}"} }, ""; EOF } } my $archlistsorted = join(" ", sort @{$mirror[$id]{'Archive-architecture'}}); if ($html) { print "$archlistsorted\n"; } elsif ($text) { print $archlistsorted; print "\n"; } elsif ($wml) { print <"}{"$mirror[$id]{site}"} }, "$archlistsorted"; EOF } if ($aliaslist) { if ($text) { print $aliaslist . "\n"; } elsif ($wml) { print <"}{"$mirror[$id]{site}"} }, "$aliaslist"; EOF } } if ($html) { print "\n"; } } } if ($wml) { # in our WML templates there is a langcmp comparison method, # which sorts alphabetically depending on the language print <
\$country EOM } \$sawcountry{\$country} = 1; sub officialfirst { (\$b =~ /^ftp\\d?(?:\\.wa)?\\...\\.debian\\.org\$/) <=> (\$a =~ /^ftp\\d?(?:\\.wa)?\\...\\.debian\\.org\$/) || \$a cmp \$b; } foreach my \$countrysite (sort officialfirst keys \%{\$secondaries{\$country}}) { my \@elems = \@{\$secondaries{\$country}{\$countrysite}}; print < \$countrysite EOM if (\$elems[3]) { my \$extraname = \$elems[3]; \$extraname =~ s% %\ \;\ \;%; print < \$extraname EOM } print < \$elems[0] \$elems[1] EOM } }
EOF } print "\n" if ($html); } sub intro { my $format = shift; die "must get format for intro()" unless $format; my $html = 1 if ($format eq 'html'); my $text = 1 if ($format eq 'text'); print "

" if $html; print " " if $text; print "Debian worldwide mirror sites"; print "

" if $html; print "\n -----------------------------\n" if $text; print "\n"; print "

" if $html; print "Debian is distributed ("; print $html ? "mirrored" : "mirrored"; print ") on hundreds of servers on the Internet.\n"; print <" if $html; print < A primary mirror site has good bandwidth, is available 24 hours a day, and has an easy to remember name of the form ftp.<country>.debian.org.
END } else { print <.debian.org. END } print <\n" if $html; if ($html) { print < A secondary mirror site may have restrictions on what they mirror (due to END } else { print <\n" if $html; print "

" if $html; print < netselect can be used to\n"; } else { print "a primary or secondary site. The program `netselect' can be used to\n"; } print < wget or rsync for determining the site with the most throughput.\n"; } else { print "`wget' or `rsync' for determining the site with the most throughput.\n"; } print <" if $html; print "The authoritative copy of the following list can always be found at:\n"; print "" if $html; print " https://www.debian.org/mirror/list"; print ".
" if $html; print "\n"; print <" if $html; print " https://www.debian.org/mirror/submit"; print ".
" if $html; print "\n"; print <" if $html; print " https://www.debian.org/mirror/"; print ".
" if $html; print "\n"; } sub primary_mirrors { my $format = shift; die "must get format for primary_mirrors()" unless $format; my $html = 1 if ($format eq 'html'); my $text = 1 if ($format eq 'text'); my $wml = 1 if ($format eq 'wml'); my %primaries = (); if ($html) { print <Primary Debian mirror sites END } elsif ($text) { print < END } foreach my $country (sort keys %countries) { foreach my $id (@{ $countries{$country} }) { next unless ($mirror[$id]{site} =~ /$officialsiteregex/); my $countryplain = $plain_name_of_country{$country}; my $countrycode = $code_of_country{$country}; unless (exists $mirror[$id]{method}{'archive-http'}) { warn "official mirror " . $mirror[$id]{site} . " does not have archive-http?!"; next; } my $arches = join(" ", sort @{$mirror[$id]{'Archive-architecture'}}); if ($html) { $countryplain =~ s/ / /; print < END } elsif ($text) { printf " %-14s %-20s %-14s %s\n", $countryplain, $mirror[$id]{site}, $mirror[$id]{method}{'archive-http'}, $arches; } elsif ($wml) { # this creates a hash of with keys like # later this gets expanded by WML into forms like # Germany or Deutschland # the next-level key is the site name, because countries # can have more than one site print <"}{"$mirror[$id]{site}"} }, ( "$mirror[$id]{method}{'archive-http'}", "$arches", ); EOF } } } if ($wml) { # in our WML templates there is a langcmp comparison method, # which sorts alphabetically depending on the language print < EOM } } EOF } print "
Country Site Architectures
$countryplain $mirror[$id]{site}$mirror[$id]{method}{'archive-http'} $arches
\$country \$countrysite\$elems[0] \$elems[1]
\n" if ($html); } # meant to be output into a file which is then included into a .wml file # and processed by WML sub primary_mirror_sponsors { print <


END foreach my $country (sort keys %countries) { foreach my $id (@{ $countries{$country} }) { next unless ($mirror[$id]{site} =~ /$officialsiteregex/); my $countrycode = $code_of_country{$country}; print < <${countrycode}c> $mirror[$id]{site} END if (exists $mirror[$id]{includes}) { my $numsubsites = @{ $mirror[$id]{includes} }; my $snum = 0; foreach my $subsite (@{ $mirror[$id]{includes} }) { # XXX Note this is a little bit wrong; if there is more than one id # for a subsite, it just takes the first one. This problem # could occur if a subsite begins mirroring some other arch, # like amd64. my $subsite_id; foreach my $mid (0..$#mirror) { if ($mirror[$mid]{site} eq $subsite) { $subsite_id=$mid; last; } } die "can't find $subsite, wtf?!" unless defined $subsite_id; # must be an error die "can't find sponsor for $subsite, wtf?!" unless defined $mirror[$subsite_id]{sponsor}; # must be an error my $numsponsors = @{ $mirror[$subsite_id]{sponsor} }; my $num = 0; my ($sponsorname, $sponsorurl); foreach my $sponsor (@{ $mirror[$subsite_id]{sponsor} }) { if ($sponsor =~ /^(.+) (https?:.*)$/) { $sponsorname = $1; $sponsorurl = $2; } else { warn "can't find sponsor URL for sponsor $sponsor of $subsite"; $sponsorname = $sponsor; } encode_entities($sponsorname, $encode); if ($sponsorurl) { print "$sponsorname"; } else { print "$sponsorname"; } $num++; print ", " unless ($num >= $numsponsors); } $snum++; print ", " unless ($snum >= $numsubsites); } } else { die "$mirror[$id]{site} has no sponsor\n" unless exists $mirror[$id]{sponsor}; # must be an error my $numsponsors = @{ $mirror[$id]{sponsor} }; my $num = 0; my ($sponsorname, $sponsorurl); foreach my $sponsor (@{ $mirror[$id]{sponsor} }) { if ($sponsor =~ /^(.+) (http:.*)$/) { $sponsorname = $1; $sponsorurl = $2; } else { warn "can't find sponsor URL for sponsor $sponsor of $mirror[$id]{site}"; $sponsorname = $sponsor; } encode_entities($sponsorname, $encode); if ($sponsorurl) { print "$sponsorname"; } else { print "$sponsorname"; } $num++; print ", " unless ($num >= $numsponsors); } } print < END } } print "\n"; } # meant to be output into a file which is then included into a .wml file # and processed by WML sub mirror_sponsors { print <
END foreach my $country (sort keys %countries) { next unless $countries_sponsors{$country}; foreach my $id (@{ $countries_sponsors{$country} }) { # sites which have Includes don't have to have Sponsor, the included ones # have it; and those are looped over separately anyway, so no need to repeat next if (exists $mirror[$id]{includes}); my $countrycode = $code_of_country{$country}; print < ${countrycode} <${countrycode}c> $mirror[$id]{site} END if (exists $mirror[$id]{'included-in'}) { print "
("; print join (", ", @{ $mirror[$id]{'included-in'} }); print ")"; } print < END my $numsponsors = @{ $mirror[$id]{sponsor} }; my $num = 0; my ($sponsorname, $sponsorurl); foreach my $sponsor (@{ $mirror[$id]{sponsor} }) { if ($sponsor =~ /^(.+) (https?:.*)$/) { $sponsorname = $1; $sponsorurl = $2; } else { warn "can't find sponsor URL for sponsor $sponsor of $mirror[$id]{site}"; $sponsorname = $sponsor; } encode_entities($sponsorname, $encode); if ($sponsorurl) { print "$sponsorname"; } else { print "$sponsorname"; } $num++; print ",\n" unless ($num >= $numsponsors); } print "\n"; print < END } } } # meant to be output into a file which is then included into a .wml file # and processed by WML sub cdimage_mirrors($) { my $which = shift; die unless $which; print "#use wml::debian::languages\n\n\nmy \@cdmirrors = (\n"; foreach my $country (sort keys %countries) { foreach my $id (@{ $countries{$country} }) { my $countrycode = $code_of_country{$country}; if ($which eq "httpftp") { if (defined $mirror[$id]{method}{'cdimage-ftp'} || defined $mirror[$id]{method}{'cdimage-http'}) { print " '<${countrycode}c>: $mirror[$id]{site}:"; if (defined $mirror[$id]{method}{'cdimage-ftp'}) { print qq( FTP); } if (defined $mirror[$id]{method}{'cdimage-http'}) { print qq( HTTP); } print "',\n"; } } elsif ($which eq "rsync") { if (defined $mirror[$id]{method}{'cdimage-rsync'}) { print qq( '<${countrycode}c>: $mirror[$id]{site}: rsync $mirror[$id]{site}\:\:$mirror[$id]{method}{'cdimage-rsync'}',\n); END } } } } print ");\n\n"; # Write some code to sort the list alphabetically (the ordering is # language-dependent) print <<'EOM'; print "
    \n"; foreach $line (sort langcmp @cdmirrors) { print "
  • $line
  • \n"; } print "
\n";
EOM } sub header { print < Debian worldwide mirror sites END } sub trailer { print "\n\n"; } sub full_listing { # TODO: fix the html mode to output actual normal HTML, rather than
  my $format = shift;
  die "must get format for full_listing()" unless $format;
  my $html = 1 if ($format eq 'html');
  my $text = 1 if ($format eq 'text');
  my $wml = 1 if ($format eq 'wml');

  if ($html) {
    print "\n
\n"; print "

Jump directly to a country on the list:
\n"; } if ($html) { my $linelength = 0; foreach my $country (sort keys %countries) { my $countryplain = $plain_name_of_country{$country}; my $countrycode = $code_of_country{$country}; print " ["; print $countryplain; print "]"; $linelength += length($countryplain) + 3; if ($linelength >= 75) { print "
\n"; $linelength = 0; } } } elsif ($wml) { # in our WML templates there is a langcmp comparison method, # which sorts alphabetically depending on the language print <"} = $countrycode; EOF } print <' . "\$country]"; \$linelength += length(\$country) + 3; if (\$linelength >= 75) { print "
\n"; \$linelength = 0; } } :> EOF } if ($html || $wml) { print "\n


\n"; } print "
\n" if $html;
  foreach my $country (sort keys %countries) {
    my $countryplain = $plain_name_of_country{$country};
    my $countrycode = $code_of_country{$country};
    print "\n";
    if ($html) {
      print "$country\n";
    } elsif ($text) {
      print "$country\n";
    } elsif ($wml) {
      print "

<${countrycode}c>

\n"; } if ($html || $text) { print "-" x length($country); # underline } elsif ($wml) { print "\n"; } print "\n"; foreach my $id (@{ $countries{$country} }) { next unless keys %{$mirror[$id]{'method'}}; print "Site: "; print "" if $wml; print $mirror[$id]{site}; if (exists $mirror[$id]{'aliases'}) { print ", ".join(", ", @{ $mirror[$id]{'aliases'} }); } print "" if $wml; print "
" if $wml; print "\n"; foreach my $method ( sort keys %{ $mirror[$id]{method} } ) { my $display = $method; $display =~ s/archive-/Packages /; $display =~ s/cdimage-/CD Images /; $display =~ s/jigdo-/Jigdo files /; $display =~ s/old-/Old releases /; $display =~ s/ftp/over FTP/; $display =~ s/http/over HTTP/; $display =~ s/nfs/over NFS/; $display =~ s/rsync/over rsync/; if ($method =~ /http/) { print $display.": "; print "" if $wml; print "$mirror[$id]{method}{$method}\n"; print "" if $wml; } elsif ($method =~ /ftp/) { print $display.": "; print "" if $wml; print "$mirror[$id]{method}{$method}\n"; print "" if $wml; } else { print $display.": "; print "" if $wml; print $mirror[$id]{method}{$method}."\n"; print "" if $wml; } print "
" if $wml; } if (exists $mirror[$id]{'Archive-architecture'}) { print "Includes architectures: ".join(" ", sort @{$mirror[$id]{'Archive-architecture'}})."\n"; print "
" if $wml; } print "\n"; print "
" if $wml; if (exists $mirror[$id]{'comment'}) { print "Comment: "; print "" if $wml; print $mirror[$id]{comment}; print "" if $wml; print "\n"; print "
" if $wml; } print "
" if $wml; print "\n"; } } print "
\n" if $html; } sub compact_list($$) { my $whichtype = shift; die "must get type for compact_list()" unless $whichtype; my $ordering = shift; die "must get ordering for compact_list()" unless $ordering; sub printhtmlftprsync($$$$) { my ($site, $http, $ftp, $rsync) = @_; print "HTTP " if (defined $http); print "FTP " if (defined $ftp); print "rsync ". $site . "::" . $rsync if (defined $rsync); } if ($ordering eq 'countrysite') { foreach my $country (sort keys %countries) { my %our_mirrors; foreach my $id (@{ $countries{$country} }) { if ( defined($mirror[$id]{method}{$whichtype.'-ftp'}) or defined($mirror[$id]{method}{$whichtype.'-http'}) or defined($mirror[$id]{method}{$whichtype.'-rsync'}) ) { $our_mirrors{$id} = 1; } } next unless (keys %our_mirrors); my $countryplain = $plain_name_of_country{$country}; my $countrycode = $code_of_country{$country}; foreach my $id (@{ $countries{$country} }) { next unless (exists $our_mirrors{$id}); print "
  • <".$countrycode."c>: " . $mirror[$id]{site} . ": "; printhtmlftprsync($mirror[$id]{site}, $mirror[$id]{method}{$whichtype.'-http'}, $mirror[$id]{method}{$whichtype.'-ftp'}, $mirror[$id]{method}{$whichtype.'-rsync'}); print "
  • \n"; } } } elsif ($ordering eq 'sitecountry') { my %our_mirrors; foreach my $id (0..$#mirror) { if ( defined($mirror[$id]{method}{$whichtype.'-ftp'}) or defined($mirror[$id]{method}{$whichtype.'-http'}) or defined($mirror[$id]{method}{$whichtype.'-rsync'}) ) { $our_mirrors{ $mirror[$id]{site} } = $id; } } foreach my $site (sort keys %our_mirrors) { my $id = $our_mirrors{$site}; my $countryplain = exists $mirror[$id]{country} ? $plain_name_of_country{ $mirror[$id]{country} } : ''; my $countrycode = exists $mirror[$id]{country} ? $code_of_country{ $mirror[$id]{country} } : ''; print "
  • " . $mirror[$id]{site}; if ($countrycode ne ''){print " (<".$countrycode."c>)"} print ": "; printhtmlftprsync($mirror[$id]{site}, $mirror[$id]{method}{$whichtype.'-http'}, $mirror[$id]{method}{$whichtype.'-ftp'}, $mirror[$id]{method}{$whichtype.'-rsync'}); print "
  • \n"; } } } sub footer_stuff($$) { my $format = shift; die "must get format for footer_stuff()" unless $format; my $html = 1 if ($format eq 'html'); my $text = 1 if ($format eq 'text'); my $wml = 1 if ($format eq 'wml'); my $whichcount = shift; die "must get count for footer_stuff()" unless $whichcount; if ($html || $wml) { print <
    Last modified: $last_modify Number of sites listed: $whichcount
    END } elsif ($text) { print "\n"; print "-" x 79 . "\n"; # expecting $last_modify like: Mon Jan 1 00:00:00 0000 - 24 characters wide # expecting $whichcount to be less than 1k :) printf "%-14s %-24s %-11s %-23s %-3d\n", 'Last modified:', $last_modify, '', 'Number of sites listed:', $whichcount; } } ######### Begin main routine ########################### if (defined $help) { print_help(); exit; } open SRC, "<:utf8", $mirror_source or die "Error: problem opening mirror source file, $mirror_source\n" ."Use the -m option?\n"; my $current = ''; while () { chomp; if (/^$/ && $current eq '') { next; } elsif (/^$/) { process_line($INPUT_LINE_NUMBER, $current); $current = ''; next; } elsif (/^\s+(.*)$/) { # add line to current entry $current .= "\n$1"; } elsif (/^[\w-]+:\s/) { if ($current ne "") { # need to process previous line process_line($INPUT_LINE_NUMBER, $current); } $current = $_; } else { die "Error: unknown format on line $INPUT_LINE_NUMBER:\n$_\n"; } } if ($current ne "") { process_line($INPUT_LINE_NUMBER, $current); } @mirror = grep { ! $_->{'internal'} } @mirror; $longest{site} = max( map { length($_->{'site'}) + 1 } @mirror ); # Remove filtered mirrors. my @filtered; foreach my $id (0..$#mirror) { if ($mirror[$id]{filtered}) { push @filtered, $id; } } foreach my $id (reverse @filtered) { # reverse order so indexes are valid splice(@mirror, $id, 1); } # count the number of mirrors # the masterlist parser's $count included the filtered sites $count = @mirror; # Create arrays of countries, with their mirrors. foreach my $id (0..$#mirror) { if (exists $mirror[$id]{country}) { push @{ $countries{ $mirror[$id]{country} } }, $id; if (exists $mirror[$id]{sponsor} && keys %{$mirror[$id]{method}}) { push @{ $countries_sponsors{ $mirror[$id]{country} } }, $id; } } elsif ($mirror[$id]{type} =~/^(GeoDNS|RoundRobinDNS)$/i) { # TODO these are not currently displayed anywhere } else { warn "found a mirror without a country, wtf? " . $mirror[$id]{site} .", defined at line ". $mirror[$id]{_lno}; } # we'll also use this opportunity to help create a references # between sites which are connected with Includes: if (exists $mirror[$id]{includes}) { foreach my $includedsite (@{ $mirror[$id]{includes} }) { $includedsites{$includedsite} = $mirror[$id]{site}; } } } # Sort the country info arrays to first list the official sites, # then the unofficial sites, but exclude special Debian sites foreach my $country (sort keys %countries) { my (%countries_sorted_o, %countries_sorted_u); foreach my $id (@{ $countries{$country} }) { if ($mirror[$id]{site} =~ /$officialsiteregex/) { push @{ $countries_sorted_o{$country} }, $id; } else { push @{ $countries_sorted_u{$country} }, $id; } # using the opportunity to add the Included-in: back-reference if (exists $includedsites{ $mirror[$id]{site} }) { push @{ $mirror[$id]{'included-in'} }, $includedsites{ $mirror[$id]{site} }; } } # merge the reordered lists into %countries_sorted @{ $countries{$country} } = (sort cmpbydomain @{ $countries_sorted_o{$country} }, sort cmpbydomain @{ $countries_sorted_u{$country} }); } if ($output_type eq 'html') { header(); intro('html'); primary_mirrors('html'); secondary_mirrors('html'); footer_stuff('html', $count); trailer(); } elsif ($output_type eq 'text') { intro('text'); primary_mirrors('text'); secondary_mirrors('text'); footer_stuff('text', $count); } elsif ($output_type eq 'wml-primary') { primary_mirrors('wml'); } elsif ($output_type eq 'wml-secondary') { secondary_mirrors('wml'); } elsif ($output_type eq 'wml-footer') { footer_stuff('wml', $count); } elsif ($output_type eq 'apt') { header(); print "
    \n";
      aptlines();
      print "
    \n"; trailer(); } elsif ($output_type eq 'wml-full') { full_listing('wml'); footer_stuff('wml', $count); } elsif ($output_type eq 'compact-old') { compact_list('old', 'sitecountry'); } elsif ($output_type eq 'officialsponsors') { primary_mirror_sponsors(); } elsif ($output_type eq 'sponsors') { mirror_sponsors(); } elsif ($output_type eq 'cdimages-httpftp') { cdimage_mirrors("httpftp"); } elsif ($output_type eq 'cdimages-rsync') { cdimage_mirrors("rsync"); } else { die "Error: unknown output type requested, $output_type\n"; } sub print_help { print <