1#!/usr/bin/env perl
2#
3#
4# INDEX builds visit each port once and write out each port's
5# *-depends as a list of directories, using 'make describe'.  This
6# script goes back in and maps the directories back to pkgnames,
7# fixes up the *-depends list, and writes out the new INDEX file.
8
9require 5.002;
10
11# Helper function to map a directory to a pkgname.
12sub by_path {
13    my ($name, $port) = @_;
14
15  # If a direct mapping exists, then use it.
16    return $by_path{$name} if (defined $by_path{$name});
17
18  # Make sure we have /usr/mports at the beginning.
19    $name =~ s!^$pwd!/usr/mports!o;
20    return $by_path{$name} if (defined $by_path{$name});
21
22  # Collapse all the '..' sequences.
23    my @f = split('/', $name), @p = ();
24    foreach (@f) { (/\.\./) ? pop(@p) : push(@p, $_); }
25    $name = join('/', @p);
26    return $by_path{$name} if (defined $by_path{$name});
27
28    print STDERR "make_index: $port: no entry for $name\n";
29    return undef;
30}
31
32# This routine replaces what used to be the time-consuming
33# recursive 'depends-list' and 'package-depends' targets.
34sub recurse {
35    my $pkg = shift(@_);
36    return if $pkg->{checked};
37
38  # extract-depends = extract-depends + recursive list of run-depends
39  #     for each extract-depends
40    my @deps = ();
41    foreach $name (@{$pkg->{edep}}) {
42        recurse($index{$name});
43	push(@deps, @{$index{$name}->{rdep}});
44    }
45    $pkg->{edep} = uniqify(@{$pkg->{edep}}, @deps);
46
47  # same as above except for patch-depends this time
48    @deps = ();
49    foreach $name (@{$pkg->{pdep}}) {
50	recurse($index{$name});
51	push(@deps, @{$index{$name}->{rdep}});
52    }
53    $pkg->{pdep} = uniqify(@{$pkg->{pdep}}, @deps);
54
55  # same as above except for fetch-depends this time
56    @deps = ();
57    foreach $name (@{$pkg->{fdep}}) {
58	recurse($index{$name});
59	push(@deps, @{$index{$name}->{rdep}});
60    }
61    $pkg->{fdep} = uniqify(@{$pkg->{fdep}}, @deps);
62    $pkg->{checked} = 1;
63
64  # same as above except for build-depends this time
65    @deps = ();
66    foreach $name (@{$pkg->{bdep}}) {
67	recurse($index{$name});
68	push(@deps, @{$index{$name}->{rdep}});
69    }
70    $pkg->{bdep} = uniqify(@{$pkg->{bdep}}, @deps);
71    $pkg->{checked} = 1;
72
73  # same as above except for run-depends this time
74    @deps = ();
75    foreach $name (@{$pkg->{rdep}}) {
76	recurse($index{$name});
77	push(@deps, @{$index{$name}->{rdep}});
78    }
79    $pkg->{rdep} = uniqify(@{$pkg->{rdep}}, @deps);
80    $pkg->{checked} = 1;
81
82}
83
84# Given one or more lists as arguments return the set
85# of unique elements among them.
86sub uniqify {
87    my %seen = ();
88    my @unique = grep {! $seen{$_}++} (@_);
89    return \@unique;
90}
91
92# Save where we are so that we can map all directories formed
93# from ${PORTSDIR} to their canonical location '/usr/mports/...'.
94chomp($pwd = `pwd`);
95
96# Read each line of output generated by the 'index' target.
97while (<>) {
98    chomp;
99    s/\015$//;
100
101    my @f = split(/\|/);
102
103  # Force to canonical form.
104    $f[1] =~ s!^$pwd!/usr/mports!o;
105    $f[4] =~ s!^$pwd!/usr/mports!o;
106
107  # Save directory -> pkgname relationship.
108  # Note: $f[0] gets clobbered by the splice below so we'll save
109  # it to a new $name first.
110    $by_path{$f[1]} = $name = $f[0];
111
112  # Create a hash table of the infomation we need about this port.
113    my $pkg = {
114	'edep'		=> [split(/ /, $f[7])],
115	'pdep'		=> [split(/ /, $f[8])],
116	'fdep'		=> [split(/ /, $f[9])],
117	'bdep'		=> [split(/ /, $f[10])],
118	'rdep'		=> [split(/ /, $f[11])],
119	'rest'		=> join('|', splice(@f, 12)),
120	'text'		=> join('|', splice(@f, 0, 7))
121    };
122    $index{$name} = $pkg;
123
124  # This is a cheap way of preserving the order of the entries.
125    push(@names, $name);
126}
127
128# For each port perform the mapping between directory and pkgnames.
129foreach $name (keys %index) {
130    my $pkg = $index{$name};
131  # first the extract dependencies
132    if (@{$pkg->{edep}}) {
133	my @edep = map { by_path($_, $name) } @{$pkg->{edep}};
134	$pkg->{edep} = \@edep;
135    }
136  # then the patch dependencies
137    if (@{$pkg->{pdep}}) {
138	my @pdep = map { by_path($_, $name) } @{$pkg->{pdep}};
139	$pkg->{pdep} = \@pdep;
140    }
141  # then the fetch dependencies
142    if (@{$pkg->{fdep}}) {
143	my @fdep = map { by_path($_, $name) } @{$pkg->{fdep}};
144	$pkg->{fdep} = \@fdep;
145    }
146  # then the build dependencies
147    if (@{$pkg->{bdep}}) {
148	my @bdep = map { by_path($_, $name) } @{$pkg->{bdep}};
149	$pkg->{bdep} = \@bdep;
150    }
151  # then the run dependencies
152    if (@{$pkg->{rdep}}) {
153	my @rdep = map { by_path($_, $name) } @{$pkg->{rdep}};
154	$pkg->{rdep} = \@rdep;
155    }
156}
157
158# With all that done we're finally ready to write out the new
159# INDEX file one port at a time.
160foreach $name (@names) {
161    my $pkg = $index{$name};
162    if (exists $pkg->{'PRINTED'}) {
163        print STDERR "Warning: Duplicate INDEX entry: $name\n";
164    } else {
165	recurse($pkg);
166	print "$pkg->{text}|";
167	print join(' ', sort(@{$pkg->{bdep}})) if @{$pkg->{bdep}};
168	print "|";
169	print join(' ', sort(@{$pkg->{rdep}})) if @{$pkg->{rdep}};
170	print "|$pkg->{rest}|";
171	print join(' ', sort(@{$pkg->{edep}})) if @{$pkg->{edep}};
172	print "|";
173	print join(' ', sort(@{$pkg->{pdep}})) if @{$pkg->{pdep}};
174	print "|";
175	print join(' ', sort(@{$pkg->{fdep}})) if @{$pkg->{fdep}};
176	print "\n";
177	++$pkg->{'PRINTED'};
178    }
179}
180