summaryrefslogtreecommitdiff
path: root/Tools/make_index
blob: 7bb9b5af8bfa944da65026c78df4cdd1d4006e59 (plain) (blame)
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
#!/usr/bin/perl
#
# $FreeBSD$
#
# 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;

# 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'};
    }
}