diff --git a/.gitignore b/.gitignore index 360f4ed..7ea83a5 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ __pycache__/ *ipynb_checkpoints* hello_looper-master* +venv/ \ No newline at end of file diff --git a/markmeld/_version.py b/markmeld/_version.py index 0dddc48..0f8d969 100644 --- a/markmeld/_version.py +++ b/markmeld/_version.py @@ -1 +1,2 @@ -__version__ = "0.2.1-dev" +__version__ = "0.3.0-dev" + diff --git a/markmeld/cli.py b/markmeld/cli.py index 5ea56cf..eb39772 100644 --- a/markmeld/cli.py +++ b/markmeld/cli.py @@ -8,6 +8,7 @@ from .exceptions import * from .melder import MarkdownMelder +from .watcher import MarkmeldWatchDog from .utilities import load_config_file, get_file_open_cmd from ._version import __version__ @@ -64,6 +65,14 @@ def build_argparser(): # position 1 parser.add_argument(dest="target", metavar="T", help="Target", nargs="?") + parser.add_argument( + "-w", + "--watch", + dest="watch", + help="Watch file for changes and autocompile", + action="store_true", + ) + parser.add_argument( "-l", "--list", @@ -168,6 +177,22 @@ def main(test_args=None): _LOGGER.error(f" {k}: {v}") sys.exit(0) + # meld it and watch + if args.watch: + watcher = MarkmeldWatchDog( + ".", cfg, args.target, print_only=args.print, vardump=args.dump + ) + watcher.start() + try: + while watcher.is_alive(): + watcher.join(1) + except KeyboardInterrupt: + _LOGGER.info("Stopping...") + finally: + watcher.stop() + watcher.join() + return + _LOGGER.debug("Melding...") # Meld it! mm = MarkdownMelder(cfg) diff --git a/markmeld/watcher.py b/markmeld/watcher.py new file mode 100644 index 0000000..38abd55 --- /dev/null +++ b/markmeld/watcher.py @@ -0,0 +1,61 @@ +import logging +from pathlib import Path +from typing import Union +from watchdog.observers import Observer +from watchdog.events import LoggingEventHandler, DirModifiedEvent, FileModifiedEvent + +from .melder import Target +from .melder import MarkdownMelder + +_LOGGER = logging.getLogger(__name__) + + +class MarkmeldWatchDog(Observer): + """ + Watchdog observer to watch for file changes. + """ + + def __init__( + self, + path: str, + cfg: dict, + target: str, + print_only: bool = False, + vardump: bool = False, + ): + super().__init__() + _LOGGER.info(f"Watching {path} for changes...") + self._mm = MarkdownMelder(cfg) + self.target = Target(cfg, target) + self.path = path + self.print_only = print_only + self.vardump = vardump + + # init the ignore files list (just the output files) + if "output_file" in self.target.root_cfg["targets"][target]: + ignore_file_name = Path( + self.target.root_cfg["targets"][target]["output_file"] + ).name + self.ignore_files = [ignore_file_name] + else: + self.ignore_files = [] + + self.event_handler = LoggingEventHandler() + self.event_handler.on_modified = self.on_modified + self.schedule(self.event_handler, path, recursive=True) + + def on_modified(self, event: Union[DirModifiedEvent, FileModifiedEvent]): + """ + Check for file or directory modification and then rerun the melder. + """ + p = Path(event.src_path) + + # dont rebuild if the modified file or directory is the output file + # otherwise this causes an infinite loop + if p.name in self.ignore_files: + return + + _LOGGER.info(f"File modified: {event.src_path}") + self._mm.build_target( + self.target.target_name, print_only=self.print_only, vardump=self.vardump + ) diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index 823574c..b070e98 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -4,3 +4,4 @@ logmuse pyyaml requests ubiquerg +watchdog \ No newline at end of file