warning-parser.py
author Benjamin Smedberg <benjamin@smedbergs.us>
Fri, 05 Dec 2008 13:51:27 -0500
changeset 1 95655dd58126
parent 0 d2e1e16d03b6
child 2 ef65f2093ed3
permissions -rw-r--r--
* Print out total warning count to tinderbox. * loosen and fix regular expressions for hyphens and for missing line numbers, e.g. <command-line> * getCVSBlame was wrong in lots of little ways * the CVS blame database was taken from the wrong CVS tag. I need to recreate it (haven't done that yet)

#!/usr/bin/env python

"""
Reads a build log on stdin. Parse warning messages (from GCC and elsewhere)
and store them in a sqlite database for later consumption.

Uses gmake "Entering directory" and "Leaving directory" messages to
keep track of the working directory. Resolves relative file paths against
these working directories, and also follows symlinks back into the
source tree.
"""

import sys, os, sqlite3, re, mercurial.hg, mercurial.ui, mercurial.revlog, mercurial.node

(srcdir, blamedb, dbname, logfile) = sys.argv[1:]

srcdir = os.path.realpath(srcdir) + '/'

blamedb = sqlite3.connect(blamedb)
blamecur = blamedb.cursor()

repo = mercurial.hg.repository(mercurial.ui.ui(), srcdir)
ctx = repo.changectx('.')

def getCVSBlame(file, line):
    blamecur.execute('''SELECT blame.who, blame.rev
                        FROM blame, files
                        WHERE
                          files.file = ? AND
                          files.id = blame.fileid AND
                          blame.minline <= ? AND blame.maxline >= ?''', (file, line, line))
    r = blamecur.fetchone()
    if r is None:
        print "Couldn't find CVS blame for %s:%i" % (file, line)
        return (None, None)

    who, rev = r
    return (who.replace('%', '@'), 'cvs:%s:%s' % (rev, file))

def getBlame(file, line):
    try:
        fctx = ctx[file]
    except mercurial.revlog.LookupError:
        return (None, None)

    (blamectx, linenumber), line = fctx.annotate(follow=True, linenumber=True)[line - 1]
    if blamectx.rev() == 1:
        # Walk backwards into CVS history
        return getCVSBlame(blamectx.path(), linenumber)

    return (blamectx.user(), "hg:%s:%s" % (mercurial.node.hex(blamectx.node()), blamectx.path()))

if os.path.exists(dbname):
    os.unlink(dbname)

db = sqlite3.connect(dbname)
dbcur = db.cursor()
dbcur.execute('''CREATE TABLE wdata
                 (
                    id INTEGER NOT NULL,
                    ord INTEGER NOT NULL,
                    file TEXT NOT NULL,
                    line INTEGER,
                    blame TEXT,
                    blamerev TEXT,
                    msg TEXT NOT NULL,
                    CONSTRAINT pkey PRIMARY KEY (id, ord)
                 )''')

cwdre = re.compile(r'g?make(\[\d+\])?: (Entering|Leaving) directory `(.*)\'$')
warningre = re.compile(r'(?P<file>[-/\.\w<>]+):((?P<line>\d+):)?(\d+:)? warning: (?P<msg>[^ ].*)$')
continuere = re.compile(r'(?P<file>[-/\.\w<>]+):((?P<line>\d+):)?(\d+:)?( warning:)?   (?P<msg>.*)$')

cwdstack = [os.getcwd()]

curid = -1
curord = -1

for line in open(logfile):
    line = line.strip()

    m = cwdre.match(line)
    if m is not None:
        e, wd = m.group(2, 3)
        if e == "Entering":
            cwdstack.append(wd)
        else:
            cwdstack.pop()
        continue

    m = warningre.match(line)
    if m is not None:
        curid += 1
        curord = 0
    else:
        m = continuere.match(line)
        if m is None:
            if line.find('warning') != -1:
                print "Found unexpected 'warning': %s" % line

            curord = -1
            continue

        if curord == -1:
            raise Exception("Found warning continuation before warning!: %s" % line)

    file, line, msg = m.group('file', 'line', 'msg')
    file = os.path.join(cwdstack[-1], file)
    file = os.path.realpath(file)

    if line is not None:
        line = int(line)

    blame = None

    if file.startswith(srcdir):
        file = file[len(srcdir):]
        blame, blamerev = getBlame(file, line)

    dbcur.execute('''INSERT INTO wdata (id, ord, file, line, blame, blamerev, msg) VALUES (?, ?, ?, ?, ?, ?, ?)''', (curid, curord, file, line, blame, blamerev, msg))

    curord += 1

dbcur.close()
db.commit()
db.close()

print "TinderboxPrint:warn:%i" % (curid + 1)