1#!/usr/bin/perl 2 3# How to use: 4# 5# Step 1: run release-notes diff old-jsapi.h new-jsapi.h > diff.txt 6# 7# Step 2: edit diff.txt 8# - when a function has been renamed, get the - and + lines adjacent and mark the - line with [renamed] at the end 9# - when a function has been replaced, do the same (replacements behave differently) 10# - for anything that isn't a simple addition, deletion, rename, or replace, tag with [other] 11# (things tagged [other] will be put in a separate section for manual fixup) 12# 13# Step 3: run release-notes < diff.txt > changes.txt 14# - this will group changes into sections and annotate them with bug numbers 15# - the bugs chosen are just the bug that last touched each line, and are unlikely to be entirely accurate 16# 17# Step 4: run release-notes mdn < changes.txt > final.txt 18# - this will add an MDN link to every list item, first checking whether such a link is valid 19# 20# Step 5: paste into the MDN page, eg https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Releases/45 21 22# Upcoming: basing everything off of jsapi.h is probably not going to work for 23# much longer, given that more stuff is moving into js/public. Scan 24# js/public/*.h too and record where everything comes from (to automate header 25# changes in the notes)? 26# 27# This is only looking at C style APIs. Dump out all methods too? 28# 29# The enbuggification should be split out into a separate phase because it is 30# wrong a fair amount of the time (whitespace changes, parameter changes, 31# etc.), and should have a way of running repeatedly so you can incrementally 32# fix stuff up. 33# 34# It would be very nice to have an example program that links against mozjs, 35# tested in CI, so we can diff that for release notes. 36 37use strict; 38use warnings; 39 40if (@ARGV && $ARGV[0] eq 'diff') { 41 my ($orig_file, $new_file) = @ARGV[1..2]; 42 my $orig_api = grab_api($orig_file); 43 my $new_api = grab_api($new_file); 44 diff_apis($orig_api, $new_api); 45 exit 0; 46} 47 48my $path = "/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_Reference"; 49my $url_prefix = "https://developer.mozilla.org$path"; 50 51if (@ARGV && $ARGV[0] eq 'mdn') { 52 shift(@ARGV); 53 while(<>) { 54 if (/<li>([\w:]+)/) { 55 print STDERR "Checking $1...\n"; 56 system("wget", "-q", "$url_prefix/$1"); 57 if ($? == 0) { 58 s!<li>([\w:]+)!<li><a href="$path/$1">$1</a>!; 59 } 60 } 61 print; 62 } 63 exit 0; 64} 65 66sub grab_api { 67 my ($file) = @_; 68 open(my $fh, "<", $file) or die "open $file: $!"; 69 my $grabbing; 70 my @api; 71 while(<$fh>) { 72 if ($grabbing && /^(\w+)/) { 73 push @api, $1; 74 } 75 $grabbing = /JS_PUBLIC_API/; 76 } 77 return \@api; 78} 79 80sub diff_apis { 81 my ($old, $new) = @_; 82 my %old; 83 @old{@$old} = (); 84 my %new; 85 @new{@$new} = (); 86 87 open(my $ofh, ">", "/tmp/r-c.diff.1"); 88 print $ofh "$_\n" foreach (@$old); 89 close $ofh; 90 open(my $nfh, ">", "/tmp/r-c.diff.2"); 91 print $nfh "$_\n" foreach (@$new); 92 close $nfh; 93 open(my $diff, "diff -u /tmp/r-c.diff.1 /tmp/r-c.diff.2 |"); 94 while(<$diff>) { 95 if (/^-(\w+)/) { 96 next if exists $new{$1}; # Still exists, so skip it 97 } elsif (/^\+(\w+)/) { 98 next if exists $old{$1}; # It was already there, skip it 99 } 100 print; 101 } 102} 103 104my @added; 105my @renamed; 106my @replaced; 107my @deleted; 108my @other; 109 110my %N; 111 112my $renaming; 113my $replacing; 114while (<>) { 115 my $name; 116 if (/^[ +-](\w+)/) { 117 $name = $1; 118 $N{$name} = $name =~ /^JS_/ ? $name : "JS::$name"; 119 } 120 121 if (/^-/) { 122 die if ! $name; 123 if (/\[rename\]/) { 124 $renaming = $name; 125 } elsif (/\[replace\]/) { 126 $replacing = $name; 127 } elsif (/\[other\]/) { 128 push @other, $name; 129 } else { 130 push @deleted, $name; 131 } 132 } elsif (/^\+/) { 133 die if ! $name; 134 if ($renaming) { 135 push @renamed, [ $renaming, $name ]; 136 undef $renaming; 137 } elsif ($replacing) { 138 push @replaced, [ $replacing, $name ]; 139 undef $replacing; 140 } elsif (/\[other\]/) { 141 push @other, $name; 142 } else { 143 push @added, $name; 144 } 145 } 146} 147 148open(my $fh, "<", "jsapi.blame") or die "open jsapi.blame: $!"; 149my $grabbing; 150my %changerev; 151my %revs; 152while(<$fh>) { 153 if ($grabbing && /^\s*(\d+): (\w+)/ ) { 154 $changerev{$2} = $1; 155 $revs{$1} = 1; 156 } 157 $grabbing = /JS_PUBLIC_API/; 158} 159 160my %bug; 161for my $rev (keys %revs) { 162 open(my $fh, "hg log -r $rev -T '{desc}' |"); 163 while(<$fh>) { 164 if (/[bB]ug (\d+)/) { 165 $bug{$rev} = $1; 166 } 167 } 168} 169 170sub get_bug_suffix { 171 my ($api) = @_; 172 $DB::single = 1 if ! $changerev{$api}; 173 my $bug = $bug{$changerev{$api}}; 174 return $bug ? " {{{bug($bug)}}}" : ""; 175} 176 177print "(new apis)\n"; 178print "<ul>\n"; 179print " <li>$N{$_}" . get_bug_suffix($_) . "</li>\n" foreach @added; 180print " <li>$N{$_->[0]} renamed to $N{$_->[1]}" . get_bug_suffix($_->[1]) . "</li>\n" foreach @renamed; 181print " <li>$N{$_->[0]} replaced with $N{$_->[1]}" . get_bug_suffix($_->[1]) . "</li>\n" foreach @replaced; 182print "</ul>\n"; 183print "\n"; 184 185print qq(<h2 id="Deleted_APIs">Deleted APIs</h2>\n); 186print "<ul>\n"; 187print " <li>$N{$_}</li>\n" foreach @deleted; 188print "</ul>\n"; 189print "\n"; 190 191print qq(<h2 id="Changed_APIs">Changed APIs</h2>\n); 192print "<ul>\n"; 193print " <li>$N{$_}" . get_bug_suffix($_) . "</li>\n" foreach @other; 194print "</ul>\n"; 195print "\n"; 196