Skip to content

Commit 12871eb

Browse files
committed
fix watchdog; add logging
bump version to 1.0.16
1 parent 3553172 commit 12871eb

File tree

2 files changed

+77
-3
lines changed

2 files changed

+77
-3
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "htmlcmp"
3-
version = "1.0.15"
3+
version = "1.0.16"
44
description = "Compare HTML files by rendered output"
55
classifiers = []
66
authors = [

src/htmlcmp/compare_output_server.py

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
33

4+
import io
45
import sys
56
import argparse
7+
import logging
68
import threading
7-
import io
89
from pathlib import Path
910
from concurrent.futures import ThreadPoolExecutor
1011

@@ -36,19 +37,32 @@ def dispatch(self, event):
3637
event_type = event.event_type
3738
src_path = Path(event.src_path)
3839

39-
if event_type in ["opened"]:
40+
logging.verbose(f"Watchdog event: {event_type} {src_path}")
41+
42+
if event_type not in ["moved", "deleted", "created", "modified"]:
4043
return
4144

4245
if src_path.is_file():
46+
logging.debug(
47+
f"Submit watchdog file change: {event_type} {src_path}"
48+
)
4349
Config.comparator.submit(src_path.relative_to(self._path))
50+
51+
logging.info("Create watchdog for paths:")
52+
logging.info(f" A: {Config.path_a}")
53+
logging.info(f" B: {Config.path_b}")
54+
4455
self._observer = watchdog.observers.Observer()
4556
self._observer.schedule(Handler(Config.path_a), Config.path_a, recursive=True)
4657
self._observer.schedule(Handler(Config.path_b), Config.path_b, recursive=True)
4758

4859
def start(self):
60+
logging.info("Starting watchdog observer")
4961
self._observer.start()
5062

5163
def init_compare(a: Path, b: Path):
64+
logging.verbose(f"Initial compare: {a} vs {b}")
65+
5266
if not isinstance(a, Path) or not isinstance(b, Path):
5367
raise TypeError("Paths must be of type Path")
5468
if not a.is_dir() or not b.is_dir():
@@ -63,16 +77,23 @@ def init_compare(a: Path, b: Path):
6377

6478
for name in common:
6579
if (a / name).is_file() and comparable_file(a / name):
80+
logging.debug(
81+
f"Submit initial file comparison: {common_path / name}"
82+
)
6683
Config.comparator.submit(common_path / name)
6784
elif (a / name).is_dir():
6885
init_compare(a / name, b / name)
6986

87+
logging.info("Kick off initial comparison of all files")
7088
init_compare(Config.path_a, Config.path_b)
89+
logging.info("Initial comparison submitted")
7190

7291
def stop(self):
92+
logging.info("Stopping watchdog observer")
7393
self._observer.stop()
7494

7595
def join(self):
96+
logging.info("Joining watchdog observer")
7697
self._observer.join()
7798

7899

@@ -84,13 +105,17 @@ def initializer():
84105
browser = get_browser(driver=Config.driver)
85106
Config.thread_local.browser = browser
86107

108+
logging.info(f"Creating comparator with {max_workers} workers")
109+
87110
self._executor = ThreadPoolExecutor(
88111
max_workers=max_workers, initializer=initializer
89112
)
90113
self._result = {}
91114
self._future = {}
92115

93116
def submit(self, path: Path):
117+
logging.debug(f"Submitting comparison for path: {path}")
118+
94119
if not isinstance(path, Path):
95120
raise TypeError("Path must be of type Path")
96121

@@ -106,6 +131,8 @@ def submit(self, path: Path):
106131
self._future[path] = self._executor.submit(self.compare, path)
107132

108133
def compare(self, path: Path):
134+
logging.debug(f"Comparing files for path: {path}")
135+
109136
if not isinstance(path, Path):
110137
raise TypeError("Path must be of type Path")
111138
if path not in self._future:
@@ -121,6 +148,8 @@ def compare(self, path: Path):
121148
self._future.pop(path)
122149

123150
def result(self, path: Path):
151+
logging.debug(f"Getting comparison result for path: {path}")
152+
124153
if not isinstance(path, Path):
125154
raise TypeError("Path must be of type Path")
126155

@@ -129,6 +158,8 @@ def result(self, path: Path):
129158
return "unknown"
130159

131160
def result_symbol(self, path: Path):
161+
logging.debug(f"Getting comparison result symbol for path: {path}")
162+
132163
if not isinstance(path, Path):
133164
raise TypeError("Path must be of type Path")
134165

@@ -142,6 +173,8 @@ def result_symbol(self, path: Path):
142173
return "⛔"
143174

144175
def result_css(self, path: Path):
176+
logging.debug(f"Getting comparison result CSS for path: {path}")
177+
145178
if not isinstance(path, Path):
146179
raise TypeError("Path must be of type Path")
147180

@@ -160,6 +193,8 @@ def result_css(self, path: Path):
160193

161194
@app.route("/")
162195
def root():
196+
logging.debug("Generating root directory listing")
197+
163198
def print_tree(a: Path, b: Path):
164199
if not isinstance(a, Path) or not isinstance(b, Path):
165200
raise TypeError("Paths must be of type Path")
@@ -239,6 +274,8 @@ def print_tree(a: Path, b: Path):
239274

240275
@app.route("/compare/<path:path>")
241276
def compare(path: str):
277+
logging.debug(f"Generating comparison page for path: {path}")
278+
242279
if not isinstance(path, str):
243280
raise TypeError("Path must be a string")
244281

@@ -279,6 +316,8 @@ def compare(path: str):
279316

280317
@app.route("/image_diff/<path:path>")
281318
def image_diff(path: str):
319+
logging.debug(f"Generating image diff for path: {path}")
320+
282321
if not isinstance(path, str):
283322
raise TypeError("Path must be a string")
284323

@@ -295,6 +334,8 @@ def image_diff(path: str):
295334

296335
@app.route("/file/<variant>/<path:path>")
297336
def file(variant: str, path: str):
337+
logging.debug(f"Serving file for variant: {variant}, path: {path}")
338+
298339
if not isinstance(variant, str) or not isinstance(path, str):
299340
raise TypeError("Variant and path must be strings")
300341
if variant not in ["a", "b"]:
@@ -304,6 +345,30 @@ def file(variant: str, path: str):
304345
return send_from_directory(variant_root, path)
305346

306347

348+
def setup_logging(verbosity: int):
349+
if verbosity >= 3:
350+
level = logging.VERBOSE
351+
elif verbosity == 2:
352+
level = logging.DEBUG
353+
elif verbosity == 1:
354+
level = logging.INFO
355+
else:
356+
level = logging.WARNING
357+
358+
logger = logging.getLogger()
359+
logger.setLevel(level)
360+
logger.handlers.clear()
361+
362+
formatter = logging.Formatter(
363+
fmt="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
364+
datefmt="%Y-%m-%d %H:%M:%S",
365+
)
366+
367+
console_handler = logging.StreamHandler(sys.stderr)
368+
console_handler.setFormatter(formatter)
369+
logger.addHandler(console_handler)
370+
371+
307372
def main():
308373
parser = argparse.ArgumentParser()
309374
parser.add_argument("a", type=Path, help="Path to the first directory")
@@ -314,8 +379,17 @@ def main():
314379
parser.add_argument("--max-workers", type=int, default=1)
315380
parser.add_argument("--compare", action="store_true")
316381
parser.add_argument("--port", type=int, default=5000)
382+
parser.add_argument(
383+
"-v",
384+
"--verbose",
385+
action="count",
386+
default=0,
387+
help="Increase verbosity (-v, -vv, -vvv)",
388+
)
317389
args = parser.parse_args()
318390

391+
setup_logging(args.verbose)
392+
319393
Config.path_a = args.a
320394
Config.path_b = args.b
321395
Config.driver = args.driver

0 commit comments

Comments
 (0)