tail_until_writer_finished: Refactor as cxtmanager
Per akeshet@'s comments in CL:359000, refactored
tail_until_writer_finished to use a contextmanager for the inotifywait
process.
BUG=chromium:621745
TEST=unittests still pass.
Change-Id: Ic786b3b1fbfc98d74a40fbb548745c987b8a558e
Reviewed-on: https://chromium-review.googlesource.com/359319
Commit-Ready: Paul Hobbs <phobbs@google.com>
Tested-by: Paul Hobbs <phobbs@google.com>
Reviewed-by: Aviv Keshet <akeshet@chromium.org>
diff --git a/tail_until_writer_finished.py b/tail_until_writer_finished.py
index 394f6cf..d7e275a 100755
--- a/tail_until_writer_finished.py
+++ b/tail_until_writer_finished.py
@@ -13,6 +13,26 @@
import subprocess
import sys
import time
+import contextlib
+
+
+@contextlib.contextmanager
+def WriterClosedFile(path):
+ """Context manager to watch whether a file is closed by a writer."""
+ inotify_process = subprocess.Popen(
+ ['inotifywait', '-qe', 'close_write', path],
+ stdout=subprocess.PIPE)
+
+ # stdout.read is blocking, so use select.select to detect if input is
+ # available.
+ def IsClosed():
+ read_list, _, _ = select.select([inotify_process.stdout], [], [], 0)
+ return bool(read_list)
+
+ try:
+ yield IsClosed
+ finally:
+ inotify_process.kill()
def TailFile(path, sleep_interval, chunk_size,
@@ -28,35 +48,25 @@
seek_to_end: Whether to start at the end of the file at |path| when reading.
"""
- writer_closed = subprocess.Popen(['inotifywait', '-qe', 'close_write', path],
- stdout=subprocess.PIPE)
-
- # stdout.read is blocking, so use select.select to detect if input is
- # available.
- def WriterClosedFile():
- read_list, _, _ = select.select([writer_closed.stdout], [], [], 0)
- return bool(read_list)
-
def ReadChunks(fh):
for chunk in iter(lambda: fh.read(chunk_size), b''):
print(chunk, end='', file=outfile)
- with open(path) as fh:
- if seek_to_end == True:
- fh.seek(0, 2)
- while True:
- ReadChunks(fh)
- if WriterClosedFile():
- # We need to read the chunks again to avoid a race condition where the
- # writer finishes writing some output in between the ReadChunks() and
- # the WriterClosedFile() call.
+ with WriterClosedFile(path) as IsClosed:
+ with open(path) as fh:
+ if seek_to_end == True:
+ fh.seek(0, 2)
+ while True:
ReadChunks(fh)
- break
+ if IsClosed():
+ # We need to read the chunks again to avoid a race condition where the
+ # writer finishes writing some output in between the ReadChunks() and
+ # the IsClosed() call.
+ ReadChunks(fh)
+ break
- # Sleep a bit to limit the number of wasted reads.
- time.sleep(sleep_interval)
-
- writer_closed.kill()
+ # Sleep a bit to limit the number of wasted reads.
+ time.sleep(sleep_interval)
def main():