#!/usr/bin/perl # # $FreeBSD: branches/pkg_install/Tools/make_index 340851 2014-01-23 19:55:14Z mat $ # # INDEX builds visit each port once and write out each port's # *-depends as a list of directories, using 'make describe'. This # script goes back in and maps the directories back to pkgnames, # fixes up the *-depends list, and writes out the new INDEX file. require 5.002; use Carp; $SIG{__DIE__} = sub { confess "$0: ERROR: @_" unless $^S }; # Helper function to map a directory to a pkgname. sub by_path { my ($name, $port) = @_; # If a direct mapping exists, then use it. return $by_path{$name} if (defined $by_path{$name}); # Make sure we have /usr/ports at the beginning. $name =~ s!^$pwd!/usr/ports!o; return $by_path{$name} if (defined $by_path{$name}); # Collapse all the '..' sequences. my @f = split('/', $name), @p = (); foreach (@f) { (/\.\./) ? pop(@p) : push(@p, $_); } $name = join('/', @p); return $by_path{$name} if (defined $by_path{$name}); print STDERR "make_index: $port: no entry for $name\n"; return undef; } # This routine replaces what used to be the time-consuming # recursive 'depends-list' and 'package-depends' targets. sub recurse { my $pkg = shift(@_); return if $pkg->{checked}; # extract-depends = extract-depends + recursive list of run-depends # for each extract-depends my @deps = (); foreach $name (@{$pkg->{edep}}) { recurse($index{$name}); push(@deps, @{$index{$name}->{rdep}}); } $pkg->{edep} = uniqify(@{$pkg->{edep}}, @deps); # same as above except for patch-depends this time @deps = (); foreach $name (@{$pkg->{pdep}}) { recurse($index{$name}); push(@deps, @{$index{$name}->{rdep}}); } $pkg->{pdep} = uniqify(@{$pkg->{pdep}}, @deps); # same as above except for fetch-depends this time @deps = (); foreach $name (@{$pkg->{fdep}}) { recurse($index{$name}); push(@deps, @{$index{$name}->{rdep}}); } $pkg->{fdep} = uniqify(@{$pkg->{fdep}}, @deps); $pkg->{checked} = 1; # same as above except for build-depends this time @deps = (); foreach $name (@{$pkg->{bdep}}) { recurse($index{$name}); push(@deps, @{$index{$name}->{rdep}}); } $pkg->{bdep} = uniqify(@{$pkg->{bdep}}, @deps); $pkg->{checked} = 1; # same as above except for run-depends this time @deps = (); foreach $name (@{$pkg->{rdep}}) { recurse($index{$name}); push(@deps, @{$index{$name}->{rdep}}); } $pkg->{rdep} = uniqify(@{$pkg->{rdep}}, @deps); $pkg->{checked} = 1; } # Given one or more lists as arguments return the set # of unique elements among them. sub uniqify { my %seen = (); my @unique = grep {! $seen{$_}++} (@_); return \@unique; } # Save where we are so that we can map all directories formed # from ${PORTSDIR} to their canonical location '/usr/ports/...'. chomp($pwd = `pwd`); # Read each line of output generated by the 'index' target. while (<>) { chomp; s/\015$//; my @f = split(/\|/); # Force to canonical form. $f[1] =~ s!^$pwd!/usr/ports!o; $f[4] =~ s!^$pwd!/usr/ports!o; # Save directory -> pkgname relationship. # Note: $f[0] gets clobbered by the splice below so we'll save # it to a new $name first. $by_path{$f[1]} = $name = $f[0]; # Create a hash table of the infomation we need about this port. my $pkg = { 'edep' => [split(/ /, $f[7])], 'pdep' => [split(/ /, $f[8])], 'fdep' => [split(/ /, $f[9])], 'bdep' => [split(/ /, $f[10])], 'rdep' => [split(/ /, $f[11])], 'rest' => join('|', splice(@f, 12)), 'text' => join('|', splice(@f, 0, 7)) }; $index{$name} = $pkg; # This is a cheap way of preserving the order of the entries. push(@names, $name); } # For each port perform the mapping between directory and pkgnames. foreach $name (keys %index) { my $pkg = $index{$name}; # first the extract dependencies if (@{$pkg->{edep}}) { my @edep = map { by_path($_, $name) } @{$pkg->{edep}}; $pkg->{edep} = \@edep; } # then the patch dependencies if (@{$pkg->{pdep}}) { my @pdep = map { by_path($_, $name) } @{$pkg->{pdep}}; $pkg->{pdep} = \@pdep; } # then the fetch dependencies if (@{$pkg->{fdep}}) { my @fdep = map { by_path($_, $name) } @{$pkg->{fdep}}; $pkg->{fdep} = \@fdep; } # then the build dependencies if (@{$pkg->{bdep}}) { my @bdep = map { by_path($_, $name) } @{$pkg->{bdep}}; $pkg->{bdep} = \@bdep; } # then the run dependencies if (@{$pkg->{rdep}}) { my @rdep = map { by_path($_, $name) } @{$pkg->{rdep}}; $pkg->{rdep} = \@rdep; } } # With all that done we're finally ready to write out the new # INDEX file one port at a time. foreach $name (@names) { my $pkg = $index{$name}; if (exists $pkg->{'PRINTED'}) { print STDERR "Warning: Duplicate INDEX entry: $name\n"; } else { recurse($pkg); print "$pkg->{text}|"; print join(' ', sort(@{$pkg->{bdep}})) if @{$pkg->{bdep}}; print "|"; print join(' ', sort(@{$pkg->{rdep}})) if @{$pkg->{rdep}}; print "|$pkg->{rest}|"; print join(' ', sort(@{$pkg->{edep}})) if @{$pkg->{edep}}; print "|"; print join(' ', sort(@{$pkg->{pdep}})) if @{$pkg->{pdep}}; print "|"; print join(' ', sort(@{$pkg->{fdep}})) if @{$pkg->{fdep}}; print "\n"; ++$pkg->{'PRINTED'}; } }