Skip to content

Commit 558f48a

Browse files
authored
Merge pull request aurutils#1224 from aurutils/perl-playground
`Depends.pm`: add `Depends::tsort`
2 parents a600dee + 7908d38 commit 558f48a

File tree

3 files changed

+87
-22
lines changed

3 files changed

+87
-22
lines changed

lib/aurweb/aur-depends

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,28 @@ my $argv0 = 'depends';
1313
sub solve {
1414
my ($targets, $types, $callback, $opt_verify, $opt_provides, $opt_installed) = @_;
1515

16-
# Retrieve AUR results (JSON -> dict -> extract depends -> repeat until none)
16+
# Retrieve AUR information
1717
my ($results, $pkgdeps, $pkgmap) = recurse($targets, $types, $callback);
1818

1919
# Verify dependency requirements
2020
my ($dag, $dag_foreign) = graph($results, $pkgdeps, $pkgmap, $opt_verify, $opt_provides);
21-
my @removals = ();
21+
22+
# Targets to be removed from the graph
23+
my @to_prune;
2224

2325
# Remove virtual dependencies from dependency graph (#1063)
24-
if ($opt_provides) {
25-
my @virtual = keys %{$pkgmap};
26+
push @to_prune, keys %{$pkgmap} if $opt_provides;
2627

27-
# XXX: assumes <pkgmap> only contains keys with provides != pkgname
28-
@removals = prune($dag, \@virtual);
29-
}
3028
# Remove transitive dependencies for installed targets (#592)
31-
# XXX: prune from $dag_foreign as well?
32-
if (scalar @{$opt_installed}) {
33-
@removals = prune($dag, $opt_installed);
34-
}
35-
# Remove packages no longer in graph from results
36-
if (scalar @removals) {
37-
map { delete $results->{$_} } @removals;
29+
push @to_prune, @{$opt_installed} if $opt_installed && @{$opt_installed};
30+
31+
if (@to_prune) {
32+
my @removed = prune($dag, \@to_prune); # mutates $dag
33+
delete @{$results}{@removed}; # drop from results
3834
}
39-
# Return $dag for subsequent application of C<prune>
40-
return $results, $dag, $dag_foreign;
35+
36+
# Possible further pruning by the caller
37+
return ($results, $dag, $dag_foreign);
4138
}
4239

4340
# tsv output for usage with aur-sync (aurutils <=10)

makepkg/aurutils.changelog

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
## 21
22

33
* `aur-build`
4-
+ move local repository sync to `build--sync`
4+
+ move local repository sync to `build--sync` (#1183)
55
- implement file-based locking (`makepkg` implementation)
66
- implement `pactrans` upgrade
7-
+ add `--pool`
7+
+ add `--pool` (#1213)
88

99
* `aur-fetch`
1010
+ support mixed url and pkgbase names (#1104)
1111
+ add trurl(1) as dependency
1212

13+
* `perl`
14+
+ add `Depends::tsort` (#1224)
15+
1316
## 20.5
1417

1518
* `aur-build`

perl/AUR/Depends.pm

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ use List::Util qw(first);
77
use Carp;
88
use Exporter qw(import);
99
use AUR::Vercmp qw(vercmp);
10-
our @EXPORT_OK = qw(recurse prune graph);
10+
11+
use constant EX_SUCCESS => 0;
12+
use constant EX_FAILURE => 1;
13+
use constant EX_OUT_OF_RANGE => 34;
14+
our @EXPORT_OK = qw(recurse prune graph tsort);
1115
our $VERSION = 'unstable';
1216

1317
# Maximum number of calling the callback
@@ -135,12 +139,12 @@ sub recurse {
135139
# Check if results are available
136140
if (scalar keys %results == 0) {
137141
say STDERR __PACKAGE__ . ": no packages found";
138-
exit(1);
142+
exit EX_FAILURE;
139143
}
140144
# Check if request limits have been exceeded
141145
if ($a == $aur_callback_max) {
142146
say STDERR __PACKAGE__ . ": total requests: $a (out of range)";
143-
exit(34);
147+
exit EX_OUT_OF_RANGE;
144148
}
145149
return \%results, \%pkgdeps, \%pkgmap;
146150
}
@@ -227,7 +231,7 @@ sub graph {
227231
}
228232
}
229233
if (not $dag_valid) {
230-
exit(1);
234+
exit EX_FAILURE;
231235
}
232236
return \%dag, \%dag_foreign;
233237
}
@@ -292,4 +296,65 @@ sub prune {
292296
return @removals;
293297
}
294298

299+
=head2 tsort()
300+
301+
Topological sorting adapted from PerlPowerTools.
302+
303+
=Performs depth-first traversal by default.
304+
305+
=over
306+
307+
=item C<$bfs> Perform breadth-first traversal.
308+
309+
=back
310+
311+
=cut
312+
313+
sub tsort {
314+
my ($bfs, $input) = @_;
315+
$bfs //= 0;
316+
317+
my %pairs; # all pairs ($l, $r)
318+
my %npred; # number of predecessors
319+
my %succ; # list of successors
320+
my @output;
321+
322+
if (scalar(@{$input}) % 2 == 1) {
323+
say STDERR __PACKAGE__ . ": odd number of tokens";
324+
exit EX_FAILURE;
325+
}
326+
327+
while (@{$input}) {
328+
my $l = shift @${input};
329+
my $r = shift @${input};
330+
331+
next if defined $pairs{$l}{$r};
332+
$pairs{$l}{$r}++;
333+
$npred{$l} += 0;
334+
335+
next if $l eq $r;
336+
++$npred{$r};
337+
push @{$succ{$l}}, $r;
338+
}
339+
340+
# create a list of nodes without predecessors
341+
my @list = grep {!$npred{$_}} keys %npred;
342+
343+
while (@list) {
344+
$_ = pop @list;
345+
push @output, $_;
346+
347+
foreach my $child (@{$succ{$_}}) {
348+
if ($bfs) { # breadth-first
349+
unshift @list, $child unless --$npred{$child};
350+
} else { # depth-first (default)
351+
push @list, $child unless --$npred{$child};
352+
}
353+
354+
}
355+
}
356+
warn "$Program: cycle detected\n" if grep {$npred{$_}} keys %npred;
357+
358+
return @output;
359+
}
295360
# vim: set et sw=4 sts=4 ft=perl:

0 commit comments

Comments
 (0)