1# Copyright 2024 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4""" An AbstractContextManager to wait the modifications to finish during exit. 5""" 6 7import os 8import time 9from contextlib import AbstractContextManager 10 11 12class ModificationWaiter(AbstractContextManager): 13 """ Exits if there is no modifications for a certain time period, or the 14 timeout has been reached. """ 15 16 def __init__(self, path: str) -> None: 17 self._path = path 18 # Waits at most 60 seconds. 19 self._timeout = 60 20 # Exits early if no modification happened during last 5 seconds. 21 self._quiet_time = 5 22 23 def __enter__(self) -> None: 24 # Do nothing, the logic happens in __exit__ 25 return 26 27 def __exit__(self, exc_type, exc_value, traceback) -> bool: 28 # Always consider the last modification happening now to avoid an 29 # unexpected early return. 30 last_mod_time = time.time() 31 start_time = last_mod_time 32 while True: 33 cur_time = time.time() 34 if cur_time - start_time >= self._timeout: 35 break 36 cur_mod_time = os.path.getmtime(self._path) 37 if cur_mod_time > last_mod_time: 38 last_mod_time = cur_mod_time 39 elif cur_time - last_mod_time >= self._quiet_time: 40 break 41 time.sleep(1) 42 43 # Do not suppress exceptions. 44 return False 45