# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
""" An AbstractContextManager to wait the modifications to finish during exit.
"""
import os
import time
from contextlib import AbstractContextManager
class ModificationWaiter(AbstractContextManager):
""" Exits if there is no modifications for a certain time period, or the
timeout has been reached. """
def __init__(self, path: str) -> None:
self._path = path
# Waits at most 60 seconds.
self._timeout = 60
# Exits early if no modification happened during last 5 seconds.
self._quiet_time = 5
def __enter__(self) -> None:
# Do nothing, the logic happens in __exit__
return
def __exit__(self, exc_type, exc_value, traceback) -> bool:
# The default log.dir is /tmp and it's not a good idea to monitor it.
if not self._path:
return False
# Always consider the last modification happening now to avoid an
# unexpected early return.
last_mod_time = time.time()
start_time = last_mod_time
while True:
cur_time = time.time()
if cur_time - start_time >= self._timeout:
break
cur_mod_time = os.path.getmtime(self._path)
if cur_mod_time > last_mod_time:
last_mod_time = cur_mod_time
elif cur_time - last_mod_time >= self._quiet_time:
break
time.sleep(1)
# Do not suppress exceptions.
return False