#!/usr/bin/perl -w use strict; use Text::Wrap; my $kernel_auth = "Upstream Kernel Changes"; my (%map, @reverts); my $pstate = 1; my $no_kern_log = 0; my $print_shas = 0; my $first_print = 1; while (@ARGV) { my $opt = $ARGV[0]; shift; if ($opt eq "--no-kern-log") { $no_kern_log = 1; } elsif ($opt eq "--print-shas") { $print_shas = 1; } else { print STDERR "Unknown options: $opt\n"; exit(1); } } sub check_reverts($) { my ($entry) = @_; my ($check); foreach $check (reverse @reverts) { my $desc = "Revert \"" . $entry->{'desc'} . "\""; if ($check->{'desc'} eq $desc) { @reverts = grep($_->{'desc'} ne $desc, @reverts); return 1; } } return 0; } sub add_entry($) { my ($entry) = @_; my $key = $entry->{'author'}; # store description in array, in email->{desc list} map if (exists $map{$key}) { # grab ref my $obj = $map{$key}; # add desc to array push(@$obj, $entry); } else { # create new array, containing 1 item my @arr = ($entry); # store ref to array $map{$key} = \@arr; } } sub shortlog_entry($$$$$) { my ($name, $desc, $bug, $cve, $commit) = @_; my $entry; $desc =~ s#/pub/scm/linux/kernel/git/#/.../#g; $desc =~ s#\[PATCH\] ##g; $desc =~ s#^\s*##g; $desc =~ s# *UBUNTU: ##g; $entry->{'desc'} = $desc; if ($bug ne '') { $entry->{'bugno'} = $bug; } $entry->{'cve'} = $cve; $entry->{'commit'} = $commit; $entry->{'author'} = $name; if ($desc =~ /^Revert "/) { push(@reverts, $entry); return; } return if check_reverts($entry); add_entry($entry); } # sort comparison function sub by_name($$) { my ($a, $b) = @_; uc($a) cmp uc($b); } sub shortlog_output { my ($obj, $key, $entry); foreach $key (sort by_name keys %map) { next if $key eq $kernel_auth and $no_kern_log; print "\n" unless $first_print; $first_print = 0; # output author printf " [ %s ]\n\n", $key; # output author's 1-line summaries $obj = $map{$key}; foreach $entry (reverse @$obj) { print wrap(" * ", " ", $entry->{'desc'}) . "\n"; # For non upstream changes, add other info. if ($key ne $kernel_auth) { if ($print_shas) { print " - GIT-SHA " . $entry->{'commit'} . "\n"; } } if (defined($entry->{'bugno'})) { print " - LP: #" . $entry->{'bugno'} . "\n"; } if (defined($entry->{'cve'})) { print " - " . $entry->{'cve'} . "\n"; } } } } sub changelog_input { my ($author, $desc, $commit, $entry, $cve); while () { # get commit if ($pstate == 1) { next unless /^commit (.*)/; $commit = $1; $pstate++; } # get author and email elsif ($pstate == 2) { my ($email); next unless /^[Aa]uthor:?\s*(.*?)\s*<(.*)>/; $author = $1; $email = $2; $desc = undef; $cve = undef; # cset author fixups if (!$author) { $author = $email; } $pstate++; } # skip to blank line elsif ($pstate == 3) { next unless /^\s*$/; $pstate++; } # skip to non-blank line elsif ($pstate == 4) { next unless /^\s*?(.*)/; my $ignore = 0; my $do_ignore = 0; my $bug = undef; my %bugz = (); my $k; # skip lines that are obviously not # a 1-line cset description next if /^\s*From: /; chomp; $desc = $1; if ($desc =~ /^ *(Revert "|)UBUNTU:/) { $do_ignore = 1; } else { $do_ignore = 0; $author = $kernel_auth; $ignore = 1 if $desc =~ /Merge /; } while () { $ignore = 1 if ($do_ignore && /^ *Ignore: yes/i); if (/^ *Bug: *(#|)([0-9#,\s]*)\s*$/i) { foreach $k (split('(,|\s)\s*(#|)', $2)) { $bugz{$k} = 1 if (($k ne '') and ($k =~ /[0-9]+/)); } } elsif (/^ *BugLink: *http.*:\/\/.*\/([0-9]+)/i) { $bugz{$1} = 1; } elsif (/^ *(CVE-.*)/) { $cve = $1 } last if /^commit /; } $bug = join(", #", sort keys(%bugz)); if (!$ignore) { &shortlog_entry($author, $desc, $bug, $cve, $commit, 0); } $pstate = 1; if ($_ && /^commit (.*)/) { $commit = $1; $pstate++; } } else { die "invalid parse state $pstate"; } } foreach $entry (@reverts) { add_entry($entry); } } &changelog_input; &shortlog_output; exit(0);