9 DECOMPRESS_BUF_SIZE = 4*1024*1024
11 BLOCK_MAGIC =
"\x00\x00\xFF\xFF"
17 assert body[0:2] ==
"\x1f\x8b"
18 method, flags, mtime = struct.unpack(
"<BBIxx", body[2:10])
28 size, = struct.unpack(
"<H", body[i:i+2])
31 def skip_until_zero(ix):
32 while body[ix] !=
'\x00': ix += 1
35 if flags & FNAME: i = skip_until_zero(i)
36 if flags & FCOMMENT: i = skip_until_zero(i)
37 if flags & FHCRC: i += 2
44 self.
f = open(fname,
"rb")
50 if hasattr(self,
'zstream'):
53 self.
zstream = zlib.decompressobj(-zlib.MAX_WBITS)
55 def decode(self, bytes, if_start=False):
64 x = bytes.find(BLOCK_MAGIC)
66 bytes = bytes[x + len(BLOCK_MAGIC):]
73 text = self.zstream.decompress(bytes)
75 if len(self.zstream.unused_data) == 8:
84 sys.stdout.write(line)
92 start =
max(0, end - DECOMPRESS_BUF_SIZE)
95 body = f.read(end - start)
96 text = self.
decode(body, start == 0)
105 lines = text.rsplit(ENDLINE_MAGIC, n_lines + 1)
106 if len(lines) > n_lines:
116 size = os.fstat(self.f.fileno()).st_size
119 sys.stderr.write(
"%s: file truncated\n" % sys.argv[0])
120 sys.stderr.write(
"%s: waiting for the next write\n" % sys.argv[0])
126 self.
zstream = zlib.decompressobj(-zlib.MAX_WBITS)
142 if __name__ ==
"__main__":
144 parser = argparse.ArgumentParser(description=
'tail, but for gzip files (with Z_FULL_SYNC)')
145 parser.add_argument(
'-f', action=
"store_true", help=
'watch the file for changes')
146 parser.add_argument(
'-n', type=int, help=
'output the last K lines', metavar=
'K', default=10)
147 parser.add_argument(
'file', help=
"file name to watch")
149 args = parser.parse_args()