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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
|
#!/usr/bin/perl -w
use strict;
use warnings;
# debtags-get - Keep debtags source data up to date
#
# Copyright (C) 2006 Enrico Zini <enrico@debian.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
our $CONFIG='/etc/debtags/sources.list';
our $OUTPUTDIR='/var/lib/debtags';
sub readConfig ($);
sub fetcher_apt ($$);
sub fetcher_wget ($$);
sub fetcher_copy ($$);
my $VERBOSE=undef;
my $LOCAL=undef;
sub error (@)
{
print STDERR @_, "\n";
exit 1;
}
sub verbose (@)
{
print STDOUT @_, "\n" if $VERBOSE;
}
if (@ARGV and $ARGV[0] eq '--verbose')
{
$VERBOSE=1;
shift @ARGV;
}
if (@ARGV and $ARGV[0] eq '--local')
{
$LOCAL=1;
shift @ARGV;
}
# TODO: allow to use more than one config file
# TODO: allow to override $OUTPUTDIR with parameters read from commandline
if (@ARGV and $ARGV[0] eq 'islocal')
{
my $res = 0;
# Read all the configuration first, so we can warn of syntax errors
for my $task (readConfig($CONFIG))
{
my ($islocal, $func, $arg1, $arg2) = @$task;
$res = 1 if not $islocal;
}
exit $res;
} else {
if (not -w $OUTPUTDIR)
{
if (not -e $OUTPUTDIR)
{
error "Output directory $OUTPUTDIR does not exist";
} else {
error "I do not have permission to write to $OUTPUTDIR";
}
}
# Read all the configuration first, so we can warn of syntax errors
my @sources = readConfig($CONFIG);
# Delete old sources (this will also get rid of sources removed from
# sources.list)
system "rm -f '$OUTPUTDIR/debtags-fetch-'*";
for my $task (@sources)
{
my ($islocal, $func, $arg1, $arg2) = @$task;
# Skip nonlocal sources if so instructed
next if $LOCAL and not $islocal;
&$func($arg1, $arg2);
}
}
exit 0;
sub readConfig ($)
{
my $config = shift;
my @res;
open IN, $config or error "Cannot open $config: $!";
while (<IN>)
{
# Skip empty lines and comments
next if /^\s*(#|$)/;
# We are only interested in 'tags' lines
next if not /^\s*tags\s+(.+?)\s*$/;
my $line = $1;
if ($line eq 'apt://')
{
push @res, [ 1, \&fetcher_apt, undef, "$OUTPUTDIR/debtags-fetch-apt" ];
}
elsif ($line =~ /^(?:http|ftp):\/\//)
{
my $mangle = $line;
$mangle =~ s/[^A-Za-z0-9._-]/-/g;
push @res, [ undef, \&fetcher_wget, $line, "$OUTPUTDIR/debtags-fetch-$mangle" ];
}
elsif ($line =~ /^file:(.+)/)
{
my $name = $1;
my $mangle = $name;
$mangle =~ s/[^A-Za-z0-9._-]/-/g;
# Delete extra leading slashes
$name =~ s/^\/*(\/.+)/$1/;
push @res, [ 1, \&fetcher_copy, $name, "$OUTPUTDIR/debtags-fetch-$mangle" ];
}
}
close IN;
return @res;
}
sub checked_copy ($$)
{
my ($src, $dst) = @_;
system("cp", $src, $dst) and error "Cannot copy $src to $dst";
}
sub finalize_file ($)
{
my ($file) = @_;
rename "$file.tmp", "$file" or error "Cannot rename $file.tmp to $file: $!";
}
sub fetcher_apt ($$)
{
my ($dummy, $target) = @_;
verbose("Fetching data from apt...");
open IN, "apt-cache dumpavail |" or error "Cannot run apt-cache dumpavail: $!";
open OUT, '>', "$target.tag.tmp" or error "Cannot write to $target: $!";
my $pkg;
while (<IN>)
{
if (/^Package:\s*(\S+)/)
{
$pkg = $1;
}
elsif (/^Tag:\s*(.+?)\s*$/)
{
if (not defined $pkg)
{
error "Error in apt-cache dumpavail output, line $.: a Tag: line appeared before any Package: line";
}
# Split and join the tags, to normalize the spaces inbetween
my @tags = split(/,\s+/, $1);
print OUT "$pkg: ", join(', ', @tags), "\n";
}
}
close IN;
close OUT;
checked_copy("/usr/share/debtags/vocabulary", "$target.voc.tmp");
finalize_file "$target.tag";
finalize_file "$target.voc";
}
sub fetcher_wget ($$)
{
my ($uri, $target) = @_;
verbose("Fetching data from $uri via wget...");
system "wget", "-O", "$target.voc.gz.tmp", "$uri/vocabulary.gz" and error "Failed downloading $uri/vocabulary.gz";
system "wget", "-O", "$target.tag.gz.tmp", "$uri/tags-current.gz" and error "Failed downloading $uri/tags-current.gz";
finalize_file "$target.tag.gz";
finalize_file "$target.voc.gz";
}
sub fetcher_copy ($$)
{
my ($base, $target) = @_;
verbose("Fetching data from directory $base...");
my $voc;
if (-r "$base/vocabulary.gz")
{
$voc = "$target.voc.gz";
checked_copy("$base/vocabulary.gz", "$voc.tmp");
} elsif (-r "$base/vocabulary") {
$voc = "$target.voc";
checked_copy("$base/vocabulary", "$voc.tmp");
} else {
error "Cannot find $base/vocabulary.gz or $base/vocabulary";
}
my $tag;
if (-r "$base/tags-current.gz")
{
$tag = "$target.tag.gz";
checked_copy("$base/tags-current.gz", "$tag.tmp");
} elsif (-r "$base/tags-current") {
$tag = "$target.tag";
checked_copy("$base/tags-current", "$tag.tmp");
} else {
error "Cannot find $base/tags-current.gz or $base/tags-current";
}
finalize_file "$tag";
finalize_file "$voc";
}
# vim:set ts=4 sw=4:
|