3
# Author: Petter Reinholdtsen <pere@hungry.com>
6
# Generate the control file used by the Debian Edu task package.
14
use vars qw(%opts %available %excluded %included @wanted %missing
16
my @arch = qw(alpha arm i386 ia64 m68k mips mipsel powerpc s390 sparc hppa);
22
my $aptsources = "./sources.list.testing";
24
getopts("cdaemis:", \%opts);
26
$aptsources = $opts{'s'} if ($opts{'s'});
28
$debug = 1 if ($opts{'d'});
30
load_available_packages();
38
print_excluded_packages();
39
} elsif ($opts{'a'}) {
42
print_available_packages();
45
print_missing_packages() if ($opts{'m'});
50
my $aptdir = "./tmp/apt";
51
my @aptopts = ("Dir::Etc::sourcelist=$aptsources",
52
"Dir::State=$aptdir/state",
53
"Dir::Cache=$aptdir/cache",
54
"Dir::State::Status=/dev/null",
55
"Debug::NoLocking=true");
57
# Stupid apt-get and apt-cache do not understand the same arguments!
58
# I have to map them to different formats to get both working.
60
if ("update" eq $op) {
61
mkpath "$aptdir/state/lists/partial";
62
mkpath "$aptdir/cache/archives/partial";
64
my $aptget = "apt-get --assume-yes -o " . join(" -o ", @aptopts);
66
print STDERR "aptget: $aptget\n" if $debug;
67
system("$aptget update 1>&2");
68
} elsif ("apt-cache" eq "$op") {
69
my $aptcache = "apt-cache -o=" . join(" -o=", @aptopts);
70
print STDERR "aptcache: $aptcache\n" if $debug;
77
for $task (sort keys %taskinfo) {
78
print "Package: $task\n";
80
for $header (qw(Section Architecture Priority)) {
81
print "$header: $taskinfo{$task}{$header}\n"
82
if (defined $taskinfo{$task}{$header});
85
for $header (qw(Depends Suggests Recommends)) {
86
print "$header: ", join(", ", sort @{$taskinfo{$task}{$header}}),"\n"
87
if (defined $taskinfo{$task}{$header});
90
# Description Description-long
91
print "Description: $taskinfo{$task}{Description}\n";
92
print "$taskinfo{$task}{'Description-long'}"; # Already contain newline
99
# Check the APT cache, and find the packages currently available.
101
sub load_available_packages
104
my $aptcache = apt("apt-cache");
105
open(APT, "$aptcache dump |") || die "Unable to start apt-cache";
109
if (/^Package: (.+)$/) {
111
print STDERR "Found pkg '$pkg'\n" if $debug;
113
if (/^\s+Version:\s+(.+)/) {
114
print STDERR " pkg $pkg = ver $1\n" if $debug;
115
# print "C: $pkg $available{$pkg} lt $1\n" if ( exists $available{$pkg});
116
$available{$pkg} = $1 if ( ! exists $available{$pkg} ||
117
$available{$pkg} lt $1 );
128
# First document their existence, so they can depend on each other.
129
for $taskfile (<tasks/*>) {
130
next if ("tasks/CVS" eq $taskfile);
131
next if ($taskfile =~ m/~$/);
133
my $curpkg = $taskfile;
134
$curpkg =~ s%tasks/%education-%;
135
$available{$curpkg} = "n/a";
137
push(@tasks, "$taskfile:$curpkg");
140
# Next, load their content.
143
my ($taskfile, $curpkg) = $foo =~ m/^(.+):(.+)$/;
144
next if ("tasks/CVS" eq $taskfile);
146
load_task($taskfile, $curpkg);
150
sub process_pkglist {
151
my $pkgstring = shift;
153
my @missinglist = ();
155
for $packages (split(/\s*,\s*/, $pkgstring)) {
156
print "E: double comma?: $_\n" if ($packages =~ /^\s*$/ && $debug);
158
my @alternates=split(/\s*\|\s*/, $packages);
159
my $alternatecount=0;
160
for $package (@alternates) {
161
print STDERR "Loading pkg '$package'\n" if $debug;
162
if ($package =~ /^-(.+)$/) {
164
} elsif ( !exists $available{$package} ) {
165
if ( !exists $missing{$package}) {
166
$missing{$package} = 1;
168
push(@missinglist, $package);
170
if ($alternatecount == 0) {
171
push(@pkglist, $package);
174
$pkglist[-1].=" | $package";
178
if ( ! $included{$package} ) {
179
push(@wanted, $package);
180
$included{$package} = 1;
185
return (\@pkglist, \@missinglist);
189
my ($taskfile, $curpkg) = @_;
190
open(TASKFILE, "<$taskfile") || die "Unable to open $taskfile";
193
$taskinfo{$curpkg} = ();
195
print STDERR "Loading task $curpkg\n" if $debug;
199
next if (m/^\#/); # Skip comments
203
while ($line =~ /\\$/) {
209
# Remove trailing space
213
$taskinfo{$curpkg}{'Section'} = $1 if (m/^Section:\s+(.+)$/);
214
$taskinfo{$curpkg}{'Architecture'} = $1 if (m/^Architecture:\s+(.+)$/);
216
$taskinfo{$curpkg}{'Priority'} = $1 if (m/^Priority:\s+(.+)$/);
218
if (m/^Description:\s+(.+)$/) {
219
$taskinfo{$curpkg}{'Description'} = $1;
220
$taskinfo{$curpkg}{'Description-long'} = "";
222
# End of description, pass next line to pattern matching
223
last if (m/^\S+/ || m/^\s*$/);
225
$taskinfo{$curpkg}{'Description-long'} .= $_;
229
next unless defined $_;
232
for $header (qw(Depends Suggests Recommends)) {
233
if (m/^$header:\s+(.+)$/ && $1 !~ /^\s*$/) {
234
$taskinfo{$curpkg}{$header} = ()
235
if (! exists $taskinfo{$curpkg}{$header});
236
my ($pkglist, $missinglist) = process_pkglist($1);
237
push(@{$taskinfo{$curpkg}{$header}}, @{$pkglist});
239
# Avoid missing packages in Depends lists, allow them
240
# in the two others. Insert missing depends in
242
if (@{$missinglist}) {
243
if ("Depends" eq $header) {
244
push(@{$taskinfo{$curpkg}{'Suggests'}}, @{$missinglist});
246
push(@{$taskinfo{$curpkg}{$header}}, @{$missinglist});
252
if (/^Avoid:\s+(.+)$/) {
253
my @pkgs = split(/\s*,\s*/, $1);
255
for $packages (@pkgs) {
257
for $package (split(/\s*\|\s*/, $packages)) {
258
$excluded{$package} = 1;
263
if (/^Ignore:\s+(.+)$/) {
264
my @pkgs = split(/\s*,\s*/, $1);
266
for $packages (@pkgs) {
268
for $package (split(/\s*\|\s*/, $packages)) {
269
# Remove explanations, ie the paranteses at the end.
270
$package =~ s/\s*\([^\)]*\)\s*$//;
271
$missing{$package} = 1;
279
sub print_excluded_packages {
280
print join("\n", sort keys %excluded),"\n";
283
sub print_available_packages {
284
print join("\n", @wanted),"\n";
287
sub print_all_packages {
288
print STDERR "Printing all packages\n" if $debug;
289
print join("\n", @wanted, keys %missing),"\n";
292
sub print_missing_packages {
294
print STDERR "Missing or avoided packages:\n";
296
for $package (sort keys %missing) {
297
if (exists $available{$package}) {
298
print STDERR " $package (v$available{$package} available)\n";
300
print STDERR " $package\n";
303
exit 1 unless $opts{'i'};