# HG changeset patch # User Matti Hamalainen # Date 1208863904 -10800 # Node ID d72d5d73b93ad13db37a9324ff4e6820b2a38d37 Added Autopoop and mkchangelog. diff -r 000000000000 -r d72d5d73b93a autopoop --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/autopoop Tue Apr 22 14:31:44 2008 +0300 @@ -0,0 +1,257 @@ +#!/usr/bin/perl -w +# autopoop v0.57 (C) 2008 Matti 'ccr' Hamalainen +# +# Tries to generate extra.mk.in from known configure.ac and other +# autoconf m4-macros, scanning against Makefiles. Also checks for +# missing / unsubstituted symbols, etc. +# +# Requirements: +# - Recent enough GNU Autoconf (and requirements for that) +# - Perl 5 +# +# TODO: +# - see fixmes +# - document this +# - find bugs +# - ??? +# - profit +# +use strict; +use Cwd qw(getcwd realpath); + +# List of subdirectories to check for additional Autoconf m4 macros +my @m4testdirs = ("m4", "unix"); + +# Misc. settings +my $makefile = "Makefile"; +my $extrasys = "extra.mk"; +my $buildsys = "buildsys.mk"; +my $tmpfile = "autopoop.tmp"; +my $autom4te = "autom4te"; + +# Things that may be set by user +my %bsdefines = ( + "DESTDIR" => 1, +); + +# Special substitutions +my %confdefines = ( +# "VPATH" => "srcdir", +# "SET_MAKE" => "", +); + + +### Function prototypes +sub shortpath($); +sub scanfile($$$$$$$$); + + +### Argument handling +my $pcwd = getcwd(); +my $argc = ($#ARGV + 1); +print "Autopoop v0.57 (C) 2008 Matti 'ccr' Hamalainen\n"; +die("Usage: autopoop [autom4te options]\n". +"Example: autopoop configure.ac extra.mk.in\n\n". +"NOTICE! Assumes following files are used:\n". +"$buildsys\[.in\], $extrasys, $makefile\n\n") unless ($argc >= 2); +my $configure = shift; +my $outfile = shift; + + +### Execute Autoconf 'autom4te' ... +my @args = (@ARGV); +foreach my $dir (@m4testdirs) { + if (-d $dir) { push(@args, ("-I", $dir)); } +} + +push(@args, ( + "--force", "--no-cache", "--melt", "--language=autoconf", + "--trace=AC_SUBST", "-o", $tmpfile, $configure)); + +print "- Running $autom4te ".join(" ", @args)." ...\n"; +system($autom4te, @args) == 0 or die("Failed to execute $autom4te: $?\n"); + + +### Paf files +$buildsys = realpath($buildsys); +$extrasys = realpath($extrasys); +$outfile = realpath($outfile); + + +### Process results +open(INFILE,"<".$tmpfile) or die("Could not open '$tmpfile'!\n"); +while () { + chop; + my @entries = split(/:/); + my $key = $entries[3]; + unless ($key =~ /_(FALSE|TRUE)$/) { $confdefines{$key} = $key; } +} +close INFILE; +unlink($tmpfile); + + +### Scan Makefiles and depencies +my %makesubsts = (); +my %confsubsts = (); +my %makedefines = (); +my %scanned = ($outfile => 1, $extrasys => 1); +scanfile(".", $makefile, \%scanned, \%makesubsts, \%confsubsts, \%makedefines, 1, 1); +scanfile("", $buildsys, \%scanned, \%makesubsts, \%confsubsts, \%makedefines, 1, 0); + + +### Scan buildsys.mk.in +my %bssubsts = (); +scanfile("", $buildsys.".in", \%scanned, \%bssubsts, \%bssubsts, \%bsdefines, 0, 0); + + +my %globdefs = (); +foreach my $file (keys %makedefines) { + foreach my $s (keys %{$makedefines{$file}}) { + $globdefs{$s} = 1; + } +} + + +### Compare results +print "- Checking for used, but possibly undefined Make variables:\n"; +foreach my $file (keys %makesubsts) { + foreach my $s (sort { $a cmp $b } keys %{$makesubsts{$file}}) { + if (!defined($confdefines{$s}) && !defined($makedefines{$file}{$s}) && !defined($bsdefines{$s})) { + my $err = 0; + if (!defined($globdefs{$s})) { + $err = 1; + } elsif ($file ne $buildsys && $file ne $outfile) { + $err = 2; + } + if ($err) { + printf " %-20s", "'$s'"; + print " in ".shortpath($file).":".$makesubsts{$file}{$s}." ($err)\n"; + } + } + } +} +print qq|Legend: + (1) = Not defined anywhere (or misdetected). + (2) = Defined 'somewhere', but unsure if symbol is propagated. + +|; + + +print "- Checking for used, but possibly undefined substitutions:\n"; +foreach my $file (keys %confsubsts) { + foreach my $s (keys %{$confsubsts{$file}}) { + if (!defined($confdefines{$s})) { + printf " %-20s", "'$s'"; + print " in ".shortpath($file).":".$confsubsts{$file}{$s}."\n"; + } + } +} +print "\n"; + + +### Output stuff +print "- Outputting '$outfile'\n"; +open(OUTFILE, ">", $outfile) or die("Could not open '$outfile'!\n"); +foreach my $s (keys %confdefines) { + if ($confdefines{$s} ne "") { + print OUTFILE "$s ?= \@".$confdefines{$s}."\@\n"; + } else { + print OUTFILE "\@".$s."\@\n"; + } +} +close OUTFILE; + +print "- Done.\n"; + + +### +### Functions +### +sub shortpath($) { + if (index($_[0], $pcwd) == 0) { + return substr($_[0], length($pcwd) + 1); + } else { + return $_[0]; + } +} + +sub addhash($$$$$) +{ +# if ($usenames) { $substs->{$filename}{$1} = $line; } else { $substs->{$1} = $line; } + if ($_[0]) { + $_[1]->{$_[2]}{$_[3]} = $_[4]; + } else { + $_[1]->{$_[3]} = $_[4]; + } +} + +sub scanfile($$$$$$$$) { + my $mypath = $_[0]; + my $myfile = $_[1]; + + my $scanned = $_[2]; + my $substs = $_[3]; + my $confsubsts = $_[4]; + my $defines = $_[5]; + + my $usenames = $_[6]; + my $recurse = $_[7]; + + # Form real path and check if we have already scanned the file + my $filename = realpath($mypath."/".$myfile); + if (defined($filename)) { + if (defined($scanned->{$filename})) { + $scanned->{$filename}++; + return; + } + $scanned->{$filename} = 1; + } else { + $filename = $mypath."/".$myfile; + } + +#print "ASDF: $filename\n"; + + # Scan file, if found + if (open(my $SCANFILE, "<", $filename)) { + print "- Scanning ".shortpath($filename)." ...\n"; + my $line = 0; + while (<$SCANFILE>) { + $line++; + chop; + if (/^#/) { + # ignore comment lines + } else { + + while (/[^\$]\$\{([A-Za-z0-9_]+)\}/g) { + addhash($usenames, $substs, $filename, $1, $line); + } + while (/[^\$]\$\(([A-Za-z0-9_]+)\)/g) { + addhash($usenames, $substs, $filename, $1, $line); + } + while (/\@([A-Za-z0-9_]+)\@/g) { + addhash($usenames, $confsubsts, $filename, $1, $line); + } + + if (/^ifdef\s+([A-Za-z0-9_]+)/g) { + addhash($usenames, $substs, $filename, $1, $line); + } elsif (/^([A-Za-z][A-Za-z0-9_]+)\s*[\+]?=/) { + addhash($usenames, $defines, $filename, $1, $line); + } + elsif (/^include (\S+)/) { + scanfile($mypath, "$1", $scanned, $substs, $confsubsts, $defines, $usenames, $recurse); + } + } + } + close $SCANFILE; + } + + # Recurse into subdirectories + if ($recurse) { + opendir(DIR, $mypath) || return; + my @dirs = grep { /^[^\.]/ && -d "$mypath/$_" } readdir(DIR); + closedir(DIR); + foreach my $dir (@dirs) { + scanfile($mypath."/".$dir, $myfile, $scanned, $substs, $confsubsts, $defines, $usenames, $recurse); + } + } +} diff -r 000000000000 -r d72d5d73b93a mkchangelog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mkchangelog Tue Apr 22 14:31:44 2008 +0300 @@ -0,0 +1,120 @@ +#!/usr/bin/perl -w +use strict; +my $HG = "hg"; + +my $argc = ($#ARGV + 1); +print STDERR "mkchangelog v0.1 (C) 2008 Matti 'ccr' Hamalainen\n"; +die("Usage: mkchangelog [revision]\n". +"Assumes latest tagged revision if no revision given." +) unless ($argc <= 1); +my $startrev = ""; +if ($argc >= 1) { $startrev = shift; } + + +### Parse tag information +my $hgcmd = "$HG tags"; +open(PIIPPU, '-|', $hgcmd) or die("Cannot execute $hgcmd\n"); +my %tags = (); +my $gottags = 0; +while () { + chop; + if (/^(\S+)\s+(\d+):(.+)$/) { + $tags{$2} = $1; + $gottags = 1; + } +} +close PIIPPU; + +die("No Mercurial tags data found, quitting.\n") unless ($gottags); + +### Do shit +if ($startrev eq "") { + foreach my $i (sort { $a <=> $b } keys %tags) { + if ($tags{$i} ne "tip") { $startrev = $i; } + } +} + +my $revcmd; +my $therevs = "tip:$startrev"; +if ($startrev ne "") { + $revcmd = "-r $therevs"; + print STDERR "Getting log for revisions $therevs ...\n"; +} else { + $revcmd = ""; + $therevs = "ALL"; + print STDERR "Getting log for all revisions ...\n"; +} + +### Parse log +$hgcmd = "$HG log -M -v -f $revcmd --template '\@\$REV:#rev#:#node|short#:#files#\$\@\n#desc#\n\@\$END\$\@\n'"; +open(PIIPPU, '-|', $hgcmd) or die("Cannot execute $hgcmd\n"); +my %log = (); +my %loghash = (); +my %revhash = (); +my %filehash = (); +my %rmref = (); +my $isdesc = 0; +my $rev = -1; +my $hash = ""; +my $text = ""; +my $gotrevs = 0; +my $files = ""; +while () { + chop; + if (/^\@\$REV:(\d+):([0-9a-f]{12}):(.*)\$\@$/) { + $rev = $1; + $hash = $2; + $files = $3; + $text = ""; + $isdesc = 1; + $gotrevs = 1; + } elsif (/^\@\$END\$\@$/) { + die("lol\n") unless ($isdesc); + $isdesc = 0; + $filehash{$rev} = $files; + $log{$rev} = $text; + $loghash{$hash} = $rev; + $revhash{$rev} = $hash; + } elsif ($isdesc) { + $text .= $_." "; + } else { + print STDERR "? $_\n"; + } +} +close PIIPPU; + +die("No Mercurial revision data found? How odd... quitting.\n") unless ($gotrevs); + +### +my %hide = (); +foreach my $i (sort { $a <=> $b } keys %log) { + if ($log{$i} =~ /Backed out changeset ([0-9a-f]{12})/) { + my $href = $1; + if (defined($loghash{$href})) { + $hide{$i} = 1; + $rmref{$href} = $revhash{$i}; + } + } +} + +my $s = "ChangeLog between revisions $therevs"; +print "$s\n"; +print "=" x length($s) . "\n\n"; + +foreach my $i (sort { $a <=> $b } keys %log) { + my $href = $revhash{$i}; + if (!defined($rmref{$href}) && !defined($hide{$i})) { + my @foo = split(/\s+/,$filehash{$i}); + my $n = $#foo + 1; + if ($n > 3) { $n = 3; } + + print "- $log{$i} [".($#foo + 1).": "; + for (my $k = 0; $k < $n; $k++) { + print $foo[$k]; + print " " unless ($k+1 == $n); + } + print " ..." unless ($#foo <= $n); + print "]\n"; + } +} +