2 # usage: tb-list [<patch-spec>]
3 # lists all patches matching <patch-spec> and other criteria
11 #----- option parsing -----
13 Getopt::Long::Configure(qw(bundling));
22 GetOptions("d|deleted!" => \$deleted, # including deleted patches
23 "deleted-only!" => \$deleted_only, # only deleted patches
24 "r|related=s" => sub { # only patches related to that
25 $relatedto = parse_patch_spec($_[1]);
27 "c|related-current" => sub { # only patches related to current
28 my $current_branch = current_branch();
29 die "-c only permitted when on a topbloke branch\n"
30 unless $current_branch->{Kind} =~ m/^(?:tip|base)$/;
31 $relatedto = $current_branch;
33 "l|last|leaf|leaves" => \$leaves, # only leaf patches
35 ) or die "bad options\n";
40 $spec = parse_patch_spec($ARGV[0]);
43 die "too many arguments\n";
46 our @sort = grep { /./ } split m/,/, $sort;
47 push @sort, 'topo' if !$spec;
48 push @sort, 'created';
50 foreach $sort (@sort) {
51 die "bad sort $sort\n" unless grep { $_ eq $sort }
52 qw(fullname created nick topo);
53 $toposort=1 if $sort eq $toposort;
56 #----- list patches -----
62 foreach_patch($relatedto || $leaves || !$spec ? { } : $spec,
63 $deleted || $deleted_only,
64 [qw(B_deps +included)],
66 my ($patch,$parsedname,$meta) = @_;
68 print Dumper($parsedname);
69 $patches{$patch}{Meta} = $meta;
70 $patches{$patch}{ParsedName} = $parsedname;
71 $patches{$patch}{Deps} =
72 grep { m/^[^-]/ } split /\n/, $meta->{'B_deps'};
73 $patches{$patch}{Included} = { };
74 $patches{$patch}{Included}{$_} = 1
75 foreach split /\n/, $meta->{'+included'};
78 #----- selection -----
82 foreach my $p (keys %patches) {
85 next if defined $v->{Meta}{'deleted'};
86 foreach my $dep (@{ $v->{Deps} }) {
87 debug("leaves $p $dep");
88 next unless exists $patches{$dep};
89 $patches{$dep}{NotLeaf} = 1;
95 foreach my $p (keys %patches) {
97 # mark Related=1 if any patch matching $relatedto includes us
98 foreach my $dep (keys %{ $v->{Included} }) {
99 next unless exists $patches{$dep};
100 my $depv = $patches{$dep};
101 next unless patch_matches_spec($depv->{ParsedName}, $relatedto);
105 if (patch_matches_spec($v->{ParsedName}, $relatedto)) {
106 # if we match $relatedto, mark all our inclusions as Related=1
107 foreach my $dep (keys %{ $v->{Included} }) {
108 next unless exists $patches{$dep};
109 $patches{$dep}{Related} = 1;
111 # oh, and mark ourselves as Related=1 too!
119 foreach my $p (keys %patches) {
120 my $v = $patches{$p};
121 next if !$deleted && defined $v->{Meta}{'deleted'};
122 next if $deleted_only && !defined $v->{Meta}{'deleted'};
123 next if $leaves && $v->{NotLeaf};
124 next if $relatedto && !$v->{Related};
125 next if $spec && !patch_matches_spec($v->{ParsedName}, $spec);
132 my $txt = "sub sort_cmp {\n my \$r;\n";
136 foreach my $ab (qw(a b)) {
137 $txt .= " my \$v$ab = \$patches{\$$ab};\n";
142 $txt .= " \$r = $_[0];\n return \$r if \$r;\n";
144 my $by_parsed = sub {
146 $by_r->("\$va->{ParsedName}{$_[0]} cmp \$vb->{ParsedName}{$_[0]}");
149 foreach my $sort (@sort) {
150 next if $done{$sort}++;
151 if ($sort eq 'fullname') {
152 $by_r->('$a cmp $b');
153 } elsif ($sort eq 'created') {
154 $by_parsed->('Date');
155 } elsif ($sort eq 'nick') {
156 $by_parsed->('Nick');
157 } elsif ($sort eq 'topo') {
159 foreach my $ix (qw(0 1)) {
160 my $ab = (qw(a b))[$ix];
161 my $ba = (qw(b a))[$ix];
162 my $r = (qw(1 -1))[$ix];
163 $txt .= " return $r if \$v${ab}->{Included}{\$$ba};\n";
169 $txt .= " return 0;\n}\n";
170 debug("sortsub | $_") foreach split /\n/, $txt;
173 eval sortsub()." 1;" or die "$@ ?";
175 @output = sort sort_cmp @output;
177 #----- printing -----
179 my $current_branch = current_branch();
180 my $current_patch = '';
182 if ($current_branch->{Kind} eq 'tip') {
183 $current_patch = $current_branch->{Fullname};
185 } elsif ($current_branch->{Kind} eq 'base') {
186 $current_patch = $current_branch->{Fullname};
190 foreach my $p (@output) {
191 my $v = $patches{$p};
192 my $pa = $v->{ParsedName};
193 my ($msgkind, $msg) = git_get_object("$pa->{Ref}:.topbloke/msg");
194 if ($msgkind ne 'blob') {
195 warn "$p $msgkind ?";
199 $msg =~ m/^Subject:\s*(?:\[[^][]*\]\s*)?(.*\S)\s*$/mi
200 ? $1 : "[no subject]";
201 printf("%1s%1s %s\@%s/%s/%-20s %s\n",
202 $p eq $current_patch ? $ifcurrent : '',
203 defined $v->{Meta}{'deleted'} ? 'D' : '',
204 $pa->{Email}, $pa->{Domain}, $pa->{Date}, $pa->{Nick},