110dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen#!/usr/bin/env python
210dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
310dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen"""
410dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny ChenGreps and returns the first svn log entry containing a line matching the regular
510dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chenexpression pattern passed as the only arg.
610dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
710dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny ChenExample:
810dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
910dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chensvn log -v | grep-svn-log.py '^   D.+why_are_you_missing.h$'
1010dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen"""
1110dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
1210dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chenimport fileinput, re, sys, StringIO
1310dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
1410dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen# Separator string for "svn log -v" output.
1510dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chenseparator = '-' * 72
1610dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
1710dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chenusage = """Usage: grep-svn-log.py line-pattern
1810dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny ChenExample:
1910dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    svn log -v | grep-svn-log.py '^   D.+why_are_you_missing.h'"""
2010dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
2110dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chenclass Log(StringIO.StringIO):
2210dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    """Simple facade to keep track of the log content."""
2310dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    def __init__(self):
2410dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        self.reset()
2510dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    def add_line(self, a_line):
2610dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        """Add a line to the content, if there is a previous line, commit it."""
2710dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        global separator
2810dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        if self.prev_line != None:
2910dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            print >> self, self.prev_line
3010dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        self.prev_line = a_line
3110dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        self.separator_added = (a_line == separator)
3210dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    def del_line(self):
3310dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        """Forget about the previous line, do not commit it."""
3410dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        self.prev_line = None
3510dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    def reset(self):
3610dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        """Forget about the previous lines entered."""
3710dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        StringIO.StringIO.__init__(self)
3810dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        self.prev_line = None
3910dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    def finish(self):
4010dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        """Call this when you're finished with populating content."""
4110dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        if self.prev_line != None:
4210dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            print >> self, self.prev_line
4310dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        self.prev_line = None
4410dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
4510dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chendef grep(regexp):
4610dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    # The log content to be written out once a match is found.
4710dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    log = Log()
4810dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
4910dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    LOOKING_FOR_MATCH = 0
5010dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    FOUND_LINE_MATCH = 1
5110dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    state = LOOKING_FOR_MATCH
5210dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
5310dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    while 1:
5410dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        line = sys.stdin.readline()
5510dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        if not line:
5610dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            return
5710dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        line = line.splitlines()[0]
5810dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        if state == FOUND_LINE_MATCH:
5910dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            # At this state, we keep on accumulating lines until the separator
6010dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            # is encountered.  At which point, we can return the log content.
6110dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            if line == separator:
62aa142bcacd9768bbd4fa83deed12b1accb6fd080Johnny Chen                log.finish()
6310dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen                print log.getvalue()
6410dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen                return
6510dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            log.add_line(line)
6610dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
6710dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        elif state == LOOKING_FOR_MATCH:
6810dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            if line == separator:
6910dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen                log.reset()
7010dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            log.add_line(line)
7110dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            # Update next state if necessary.
7210dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen            if regexp.search(line):
7310dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen                state = FOUND_LINE_MATCH
7410dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
7510dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chendef main():
7610dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    if len(sys.argv) != 2:
7710dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        print usage
7810dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen        sys.exit(0)
7910dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
8010dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    regexp = re.compile(sys.argv[1])
8110dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    grep(regexp)
82aa142bcacd9768bbd4fa83deed12b1accb6fd080Johnny Chen    sys.stdin.close()
8310dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen
8410dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chenif __name__ == '__main__':
8510dd7a4a70fe639b806e004bc0a0d6fb791279a3Johnny Chen    main()
86