Skip to content

Instantly share code, notes, and snippets.

@ddrscott
Last active November 15, 2024 15:23
Show Gist options
  • Save ddrscott/7e5e2ffb39b391462421baf0d280f87e to your computer and use it in GitHub Desktop.
Save ddrscott/7e5e2ffb39b391462421baf0d280f87e to your computer and use it in GitHub Desktop.
Checks files in the specified directory and determines if changes have occurred within the given age limit
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import os
import glob
from textwrap import dedent
from datetime import datetime, timedelta
def check_files(directory, max_age_minutes, last_state_file):
"""
Checks files in the specified directory and determines if changes have occurred within the given age limit.
Hidden files ignored by default.
Args:
directory (str): The path to the directory containing the files.
max_age_minutes (float): The maximum age in minutes for a file to be considered as having changes detected.
last_state_file (str): The path to the file that stores the last done time.
Usage:
python script.py <directory> <max_age_minutes> [last_state_file]
<directory>: The path to the directory containing the files.
<max_age_minutes>: The maximum age in minutes for a file to be considered as having changes detected.
[last_state_file]: Optional. The path to the file that stores the last done time (default is '.last_state').
Returns:
bool: True if all files are older than the max age and the last done time is updated, otherwise False.
"""
# List all files in the directory and sort them by modification time
# print(f"Checking files in directory: {glob.glob(os.path.join(directory, '*.*')) }")
files = [
(f, os.path.getmtime(f))
for f in glob.glob(os.path.join(directory, '*.*'))
if os.path.isfile(f)
]
if not files:
print("No files found in the specified directory.")
return
# Read the last state time if it exists
last_done_time = read_last_state(last_state_file)
newest_file_time = max(files, key=lambda x: x[1])[1]
all_files_old = True
for file, mod_time in files:
mod_time_datetime = datetime.fromtimestamp(mod_time)
age_minutes = (datetime.now() - mod_time_datetime).total_seconds() / 60
if age_minutes < max_age_minutes:
all_files_old = False
break
if all_files_old:
if last_done_time is None or (newest_file_time > last_done_time.timestamp()):
print("all done")
update_last_state(last_state_file)
return True
else:
print("waiting for next batch...")
else:
print(f"changes detected: {all_files_old=}, {file=}, {age_minutes:.2f} minutes old")
return False
def read_last_state(last_state_file):
"""
Reads the last state time from the specified file.
Args:
last_state_file (str): The path to the file that stores the last done time.
Returns:
datetime: The last done time if it exists and is valid, otherwise None.
"""
if os.path.exists(last_state_file):
try:
with open(last_state_file, 'r') as f:
return datetime.fromisoformat(f.read().strip())
except ValueError:
pass # Ignore invalid date format
return None
def update_last_state(last_state_file):
"""
Updates the last state time in the specified file to the current time.
Args:
last_state_file (str): The path to the file that stores the last done time.
"""
with open(last_state_file, 'w') as f:
f.write(datetime.now().isoformat())
def remove_last_state(last_state_file):
"""
Removes the specified last state file if it exists.
Args:
last_state_file (str): The path to the file that stores the last done time.
"""
if os.path.exists(last_state_file):
os.remove(last_state_file)
# Example usage
if __name__ == "__main__":
import sys
if len(sys.argv) < 3 or len(sys.argv) > 4:
print(dedent(check_files.__doc__))
sys.exit(1)
directory = sys.argv[1]
max_age_minutes = float(sys.argv[2])
last_state_file = os.path.join(directory,'.last_state') if len(sys.argv) == 3 else sys.argv[3]
check_files(directory, max_age_minutes, last_state_file)
@ddrscott
Copy link
Author

@chordol @graham-allen-partners Enjoy!

Example Use:

watch -n 1 python watch_directory.py tmp 0.1

Watch tmp for any changing files. Swap "all done" message with a function call or anything else.

@ddrscott
Copy link
Author

check_files will return True when changes have been detected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment