#!/usr/bin/env python
"""
ch10_bookmark_tailgrep.py
Stateful tail, remembers where it left off reading.
"""
import sys, os, re, shelve
def main():
"""
Run the bookmark_tailgrep function as a command.
Usage: ch10_bookmark_tailgrep.py []
"""
filename = sys.argv[1]
if len(sys.argv) > 2:
pattern = re.compile(sys.argv[2])
pattern_filter = lambda x: ( pattern.match(x) is not None )
new_lines = bookmark_tailgrep(filename, pattern_filter)
else:
new_lines = bookmark_tailgrep(filename)
sys.stdout.write("".join(new_lines))
class BookmarkInvalidException(Exception): pass
def bookmark_tailgrep(tail_fn, line_filter=lambda x: True,
state_fn="tail_bookmarks", max_initial_lines=50):
"""
Stateful file tail reader which keeps a line number bookmark of
where it last left off for a given filename.
"""
fin = open(tail_fn, 'r')
state = shelve.open(state_fn)
last_num = state.get(tail_fn, 0)
try:
# Fast foward through file to bookmark.
for idx in range(last_num):
# If EOF hit before bookmark, it's become invalid.
if fin.readline() == '':
raise BookmarkInvalidException
except BookmarkInvalidException:
# In case of invalid bookmark, rewind to start of file.
last_num = 0
fin.seek(0)
# Grab the rest of the lines in the file as new.
new_lines = fin.readlines()
# Advance the bookmark index.
state[tail_fn] = last_num + len(new_lines)
# If rewound to beginning of file, limit to the tail-end.
if last_num == 0:
new_lines = new_lines[-max_initial_lines:]
# Pass the new lines through the given line filter
return [ x for x in new_lines if line_filter(x) ]
if __name__ == '__main__': main()