Compare commits
5 Commits
759722629c
...
master
Author | SHA1 | Date | |
---|---|---|---|
e155fc4611 | |||
da008ba847 | |||
6880f826e8 | |||
aa8fff37ea | |||
8b6288aefe |
@@ -2,6 +2,7 @@ import threading
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from watchdog.events import PatternMatchingEventHandler
|
from watchdog.events import PatternMatchingEventHandler
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from config import *
|
from config import *
|
||||||
from helpers import export_single_zone
|
from helpers import export_single_zone
|
||||||
@@ -29,11 +30,52 @@ def schedule_export(trigger_path):
|
|||||||
debounce_timer.start()
|
debounce_timer.start()
|
||||||
logging.debug("Debounce timer started/reset (%.1fs)", DEBOUNCE_SECONDS)
|
logging.debug("Debounce timer started/reset (%.1fs)", DEBOUNCE_SECONDS)
|
||||||
|
|
||||||
|
def _most_recent_file_under(path: Path, max_depth: int = 2) -> Path | None:
|
||||||
|
if not path.exists():
|
||||||
|
return None
|
||||||
|
best = None # (mtime, filepath)
|
||||||
|
base_depth = len(path.parts)
|
||||||
|
for root, dirs, files in os.walk(path):
|
||||||
|
depth = len(Path(root).parts) - base_depth
|
||||||
|
if depth > max_depth:
|
||||||
|
# prune deeper traversal
|
||||||
|
dirs[:] = []
|
||||||
|
continue
|
||||||
|
for fn in files:
|
||||||
|
p = Path(root) / fn
|
||||||
|
try:
|
||||||
|
m = p.stat().st_mtime
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
if best is None or m > best[0]:
|
||||||
|
best = (m, p)
|
||||||
|
return best[1] if best else None
|
||||||
|
|
||||||
class DebouncedHandler(PatternMatchingEventHandler):
|
class DebouncedHandler(PatternMatchingEventHandler):
|
||||||
def __init__(self, patterns=None, ignore_patterns=None, ignore_directories=False, case_sensitive=True):
|
def __init__(self, patterns=None, ignore_patterns=None, ignore_directories=False, case_sensitive=True):
|
||||||
super().__init__(patterns=patterns or ["*"], ignore_patterns=ignore_patterns or [], ignore_directories=ignore_directories, case_sensitive=case_sensitive)
|
super().__init__(patterns=patterns or ["*"], ignore_patterns=ignore_patterns or [], ignore_directories=ignore_directories, case_sensitive=case_sensitive)
|
||||||
|
|
||||||
def on_any_event(self, event):
|
def on_any_event(self, event):
|
||||||
# When any matching event occurs, start/reset debounce timer
|
try:
|
||||||
logging.debug(f"Filesystem event: {event.event_type} on {event.src_path}")
|
src = getattr(event, "src_path", None)
|
||||||
schedule_export(event.src_path)
|
dest = getattr(event, "dest_path", None)
|
||||||
|
|
||||||
|
if dest:
|
||||||
|
trigger = dest
|
||||||
|
elif src:
|
||||||
|
p = Path(src)
|
||||||
|
if p.is_file():
|
||||||
|
trigger = str(p)
|
||||||
|
else:
|
||||||
|
candidate = _most_recent_file_under(p)
|
||||||
|
if candidate:
|
||||||
|
trigger = str(candidate)
|
||||||
|
else:
|
||||||
|
trigger = str(src)
|
||||||
|
else:
|
||||||
|
trigger = WATCH_DIR
|
||||||
|
logging.debug(f"Filesystem event: {event.event_type} on {trigger}")
|
||||||
|
schedule_export(trigger)
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception(f"Error handling filesystem event; scheduling export for watch dir as fallback: {e}")
|
||||||
|
schedule_export(WATCH_DIR)
|
@@ -6,10 +6,10 @@ from pathlib import Path
|
|||||||
|
|
||||||
from config import *
|
from config import *
|
||||||
|
|
||||||
def run_git_cmd(args, check=True, capture_output=False):
|
def run_git_cmd(args, check=True, capture_output=False, env = None):
|
||||||
cmd = ["git", "-C", GIT_REPO_DIR] + args
|
cmd = ["git", "-C", GIT_REPO_DIR] + args
|
||||||
logging.debug(f"Running git: {' '.join(cmd)}")
|
logging.debug(f"Running git: {' '.join(cmd)}")
|
||||||
return subprocess.run(cmd, check=check, capture_output=capture_output, text=True)
|
return subprocess.run(cmd, check=check, capture_output=capture_output, text=True, env=env)
|
||||||
|
|
||||||
|
|
||||||
def ensure_git_repo():
|
def ensure_git_repo():
|
||||||
|
@@ -20,6 +20,13 @@ def write_zone_export(zone_name, content) -> Path:
|
|||||||
return out_path
|
return out_path
|
||||||
|
|
||||||
def commit_and_push(changed_files, trigger_path):
|
def commit_and_push(changed_files, trigger_path):
|
||||||
|
# Pull from remote, rebasing
|
||||||
|
try:
|
||||||
|
run_git_cmd(["pull", "--rebase", "--autostash", "origin", "master"])
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
logging.exception(f"git pull --rebase failed: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
# Stage files
|
# Stage files
|
||||||
try:
|
try:
|
||||||
# Add only the exports folder (keeps repo tidy)
|
# Add only the exports folder (keeps repo tidy)
|
||||||
@@ -31,7 +38,7 @@ def commit_and_push(changed_files, trigger_path):
|
|||||||
# Check if there is anything to commit
|
# Check if there is anything to commit
|
||||||
try:
|
try:
|
||||||
# git diff --cached --quiet will exit 0 if no changes staged
|
# git diff --cached --quiet will exit 0 if no changes staged
|
||||||
subprocess.run(["git", "-C", GIT_REPO_DIR, "diff", "--cached", "--quiet"], check=True)
|
run_git_cmd(["diff", "--cached", "--quiet"], check=True)
|
||||||
logging.info("No changes to commit (nothing staged).")
|
logging.info("No changes to commit (nothing staged).")
|
||||||
return
|
return
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
@@ -45,7 +52,7 @@ def commit_and_push(changed_files, trigger_path):
|
|||||||
env["GIT_AUTHOR_NAME"] = GIT_AUTHOR_NAME
|
env["GIT_AUTHOR_NAME"] = GIT_AUTHOR_NAME
|
||||||
env["GIT_AUTHOR_EMAIL"] = GIT_AUTHOR_EMAIL
|
env["GIT_AUTHOR_EMAIL"] = GIT_AUTHOR_EMAIL
|
||||||
try:
|
try:
|
||||||
run_git_cmd(["commit", "-m", commit_msg], check=True)
|
run_git_cmd(["commit", "-m", commit_msg], check=True, env=env)
|
||||||
logging.info("Committed changes to git.")
|
logging.info("Committed changes to git.")
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
logging.exception(f"git commit failed: {e}")
|
logging.exception(f"git commit failed: {e}")
|
||||||
|
2
src/requirements.txt
Normal file
2
src/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
requests
|
||||||
|
dnspython
|
Reference in New Issue
Block a user