Преглед изворни кода

Command "watch" mit watchdog.Observer umgesetzt

gc-server3 пре 1 недеља
родитељ
комит
23c81c9a56
5 измењених фајлова са 142 додато и 5 уклоњено
  1. 30 4
      main.py
  2. 15 0
      move_files.py
  3. 1 0
      pyproject.toml
  4. 26 1
      uv.lock
  5. 70 0
      watch.py

+ 30 - 4
main.py

@@ -6,8 +6,9 @@ import typer
 from archive_logs import run as run_archive_logs
 from clients import run
 from files import run as run_files
-from move_files import default_desktop, move_files
+from move_files import default_desktop, refresh_and_move
 from summary import run as run_summary
+from watch import run as run_watch
 
 app = typer.Typer(help="PC-Visit Filetracker")
 DATA_DIRECTORY = Path("data")
@@ -75,9 +76,12 @@ def move_files_command(
     """Verschiebt gefundene Dateien in Desktop/PC-Visit/Kunde."""
     directory = directory or default_session_history()
     try:
-        run_files(directory, files_csv, ignore_timestamp=ignore_timestamp)
-        moved_count, skipped_count, missing_client_count = move_files(
-            files_csv, clients_csv, desktop or default_desktop()
+        _, _, moved_count, skipped_count, missing_client_count = refresh_and_move(
+            directory,
+            files_csv,
+            clients_csv,
+            desktop or default_desktop(),
+            ignore_timestamp,
         )
     except ValueError as error:
         raise typer.BadParameter(str(error)) from error
@@ -113,5 +117,27 @@ def summary_command(
     typer.echo(f"{xml_count} XML-Dateien geprüft, {customer_count} Kunden nach {output} geschrieben.")
 
 
+@app.command("watch")
+def watch_command(
+    directory: Path | None = typer.Argument(None, help="Verzeichnis mit XML-Dateien"),
+    files_csv: Path = typer.Option(
+        DATA_DIRECTORY / "files.csv", "--files-csv", help="CSV-Datei mit den gefundenen Dateien"
+    ),
+    clients_csv: Path = typer.Option(DATA_DIRECTORY / "clients.csv", "--clients-csv", help="CSV-Datei mit den Kunden"),
+    desktop: Path | None = typer.Option(None, "--desktop", help="Desktop-Verzeichnis als Zielbasis"),
+    ignore_timestamp: bool = typer.Option(
+        False,
+        "--ignore-timestamp",
+        help="Ignoriert den Abgleich des Erstellungsdatums mit der Session.",
+    ),
+) -> None:
+    """Überwacht XML-Dateien und führt bei Änderungen move-files aus."""
+    directory = directory or default_session_history()
+    try:
+        run_watch(directory, files_csv, clients_csv, desktop or default_desktop(), ignore_timestamp)
+    except ValueError as error:
+        raise typer.BadParameter(str(error), param_hint="directory") from error
+
+
 if __name__ == "__main__":
     app()

+ 15 - 0
move_files.py

@@ -51,6 +51,21 @@ def move_files(
             skipped_count += 1
             continue
         shutil.move(str(source), str(target))
+        print(f"Datei verschoben: {source} -> {target}")
         moved_count += 1
 
     return moved_count, skipped_count, missing_client_count
+
+
+def refresh_and_move(
+    directory: Path,
+    files_csv: Path,
+    clients_csv: Path,
+    desktop_directory: Path | None = None,
+    ignore_timestamp: bool = False,
+) -> tuple[int, int, int, int, int]:
+    from files import run as run_files
+
+    xml_count, file_count = run_files(directory, files_csv, ignore_timestamp=ignore_timestamp)
+    moved_count, skipped_count, missing_client_count = move_files(files_csv, clients_csv, desktop_directory)
+    return xml_count, file_count, moved_count, skipped_count, missing_client_count

+ 1 - 0
pyproject.toml

@@ -6,4 +6,5 @@ readme = "README.md"
 requires-python = ">=3.13"
 dependencies = [
     "typer>=0.27.1",
+    "watchdog>=6.0.0",
 ]

+ 26 - 1
uv.lock

@@ -47,10 +47,14 @@ version = "0.1.0"
 source = { virtual = "." }
 dependencies = [
     { name = "typer" },
+    { name = "watchdog" },
 ]
 
 [package.metadata]
-requires-dist = [{ name = "typer", specifier = ">=0.27.1" }]
+requires-dist = [
+    { name = "typer", specifier = ">=0.27.1" },
+    { name = "watchdog", specifier = ">=6.0.0" },
+]
 
 [[package]]
 name = "pygments"
@@ -97,3 +101,24 @@ sdist = { url = "https://files.pythonhosted.org/packages/ae/40/4a3db7990d1f62a53
 wheels = [
     { url = "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl", hash = "sha256:53150287edd11baeb4e4722c8e394fcdf8181c0ae89485cba8d25c778d5edd56", size = 122874, upload-time = "2026-08-03T14:41:04.391Z" },
 ]
+
+[[package]]
+name = "watchdog"
+version = "6.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" },
+    { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" },
+    { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" },
+    { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
+    { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
+    { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },
+    { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" },
+    { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" },
+    { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" },
+    { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" },
+    { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" },
+    { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" },
+    { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" },
+]

+ 70 - 0
watch.py

@@ -0,0 +1,70 @@
+from pathlib import Path
+
+from watchdog.events import FileSystemEvent, FileSystemEventHandler
+from watchdog.observers import Observer
+
+from move_files import refresh_and_move
+
+
+class XmlChangeHandler(FileSystemEventHandler):
+    def __init__(
+        self,
+        directory: Path,
+        files_csv: Path,
+        clients_csv: Path,
+        desktop_directory: Path,
+        ignore_timestamp: bool,
+    ) -> None:
+        self.directory = directory
+        self.files_csv = files_csv
+        self.clients_csv = clients_csv
+        self.desktop_directory = desktop_directory
+        self.ignore_timestamp = ignore_timestamp
+
+    def on_created(self, event: FileSystemEvent) -> None:
+        self.process_xml(event)
+
+    def on_modified(self, event: FileSystemEvent) -> None:
+        self.process_xml(event)
+
+    def on_moved(self, event: FileSystemEvent) -> None:
+        self.process_xml(event)
+
+    def process_xml(self, event: FileSystemEvent) -> None:
+        if event.is_directory or not Path(event.src_path).suffix.lower() == ".xml":
+            return
+        refresh_and_move(
+            self.directory,
+            self.files_csv,
+            self.clients_csv,
+            self.desktop_directory,
+            self.ignore_timestamp,
+        )
+
+
+def run(
+    directory: Path,
+    files_csv: Path,
+    clients_csv: Path,
+    desktop_directory: Path,
+    ignore_timestamp: bool = False,
+) -> None:
+    if not directory.is_dir():
+        raise ValueError(f"Das Verzeichnis existiert nicht: {directory}")
+
+    observer = Observer()
+    observer.schedule(
+        XmlChangeHandler(directory, files_csv, clients_csv, desktop_directory, ignore_timestamp),
+        str(directory),
+        recursive=True,
+    )
+    print(f"Überwachung des XML-Verzeichnisses gestartet: {directory}")
+    print("Mit Strg+C kann die Überwachung beendet werden.")
+    observer.start()
+    try:
+        while observer.is_alive():
+            observer.join(1)
+    except KeyboardInterrupt:
+        observer.stop()
+        print("Überwachung wurde manuell mit Strg+C beendet.")
+    observer.join()