Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature event delay #75

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,11 @@ pip-log.txt
# Translations
*.mo

# VirtualEnv
/env

# IDE
/.idea

# Sphinx
docs/_build
95 changes: 80 additions & 15 deletions sphinx_autobuild/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@
Automatic builder for Sphinx based documentation sets.

MIT License. See LICENSE for more details.
Copyright (c) 2013, Jonathan Stoppani
Copyright (c) 2013, Jonathan Stoppani, Fork by Carrot & Company
"""


import argparse
import fnmatch
import os
import re
import subprocess
import sys
import port_for
from threading import Thread, Lock
from collections import deque
import time

try:
import pty
Expand All @@ -25,30 +27,74 @@
from watchdog.observers.polling import PollingObserver
from watchdog.events import FileSystemEventHandler


__version__ = '0.7.1'
__url__ = 'https://github.com/GaretJax/sphinx-autobuild'

__url__ = 'https://github.com/carrotandcompany/sphinx-autobuild'

DEFAULT_IGNORE_REGEX = [
r'__pycache__/.*\.py',
r'.*\.pyc',
r'.*\.kate-swp',
]

DEFAULT_EVENT_DELAY_TIME = 5


class EventActionData(object):
def __init__(self):
self.lock = Lock()
self.queue = deque()


class EventActionThread(Thread):
"""
This Thread runs an endless loop which checks every defined interval time
if the the FileSystemEvent Queue has entries.
If the queue has entries it empties the queue and invokes an action

"""

def __init__(self, event_action_data, action, watcher,
check_interval=DEFAULT_EVENT_DELAY_TIME):
super().__init__()
self.action = action
self.event_action_data = event_action_data
self.watcher = watcher
self.check_interval = check_interval
self._kill_received = False

def run(self):
print('EventActionThread is running.')
while not self._kill_received:
with self.event_action_data.lock:
if len(self.event_action_data.queue) > 0:
print('{} files changed. Building...'.format(
len(self.event_action_data.queue)))
# clear queue and remember the last_event
last_event = self.event_action_data.queue.popleft()
self.event_action_data.queue.clear()
# call the action
self.action(self.watcher,
getattr(last_event, 'dest_path',
last_event.src_path))
time.sleep(self.check_interval)

def kill(self):
self._kill_received = True


class _WatchdogHandler(FileSystemEventHandler):

def __init__(self, watcher, action):
def __init__(self, watcher, action, event_action_data):
super(_WatchdogHandler, self).__init__()
self._watcher = watcher
self._action = action
self.event_action_data = event_action_data

def on_any_event(self, event):
if event.is_directory:
return
self._action(self._watcher,
getattr(event, 'dest_path', event.src_path))
with self.event_action_data.lock:
self.event_action_data.queue.append(event)


def _set_changed(w, _):
Expand All @@ -59,7 +105,8 @@ class LivereloadWatchdogWatcher(object):
"""
File system watch dog.
"""
def __init__(self, use_polling=False):

def __init__(self, event_queue, use_polling=False):
super(LivereloadWatchdogWatcher, self).__init__()
self._changed = False
# TODO: Hack.
Expand All @@ -70,7 +117,7 @@ def __init__(self, use_polling=False):
if use_polling:
self._observer = PollingObserver()
else:
self._observer = Observer()
self._observer = Observer(timeout=1000)
self._observer.start()

# Compatibility with livereload's builtin watcher
Expand All @@ -87,6 +134,8 @@ def __init__(self, use_polling=False):
# LiveReloadHandler's poll_tasks method.
self._changes = []

self.event_queue = event_queue

def set_changed(self):
self._changed = True

Expand All @@ -112,7 +161,7 @@ def watch(self, path, action, *args, **kwargs):
"""
if action is None:
action = _set_changed
event_handler = _WatchdogHandler(self, action)
event_handler = _WatchdogHandler(self, action, self.event_queue)
self._observer.schedule(event_handler, path=path, recursive=True)

def start(self, callback):
Expand All @@ -129,6 +178,7 @@ class SphinxBuilder(object):
"""
Helper class to run sphinx-build command.
"""

def __init__(self, outdir, args, ignored=None, regex_ignored=None):
self._outdir = outdir
self._args = args
Expand All @@ -149,6 +199,7 @@ def is_ignored(self, src_path):
return True

def __call__(self, watcher, src_path):

path = self.get_relative_path(src_path)

if self.is_ignored(src_path):
Expand All @@ -167,7 +218,6 @@ def build(self, path=None):
sys.stdout.write(pre)
sys.stdout.write('-' * (81 - len(pre)))
sys.stdout.write('\n')

args = ['sphinx-build'] + self._args
if pty:
master, slave = pty.openpty()
Expand Down Expand Up @@ -228,6 +278,8 @@ def get_parser():
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--port', type=int, default=8000)
parser.add_argument('-H', '--host', type=str, default='127.0.0.1')
parser.add_argument('-ed', '--event-delay', type=int,
default=DEFAULT_EVENT_DELAY_TIME)
parser.add_argument('-r', '--re-ignore', action='append', default=[])
parser.add_argument('-i', '--ignore', action='append', default=[])
parser.add_argument('--poll', dest='use_polling',
Expand Down Expand Up @@ -297,10 +349,17 @@ def main():
else:
portn = port_for.select_random()

event_action_data = EventActionData()

builder = SphinxBuilder(outdir, build_args, ignored, re_ignore)
server = Server(
watcher=LivereloadWatchdogWatcher(use_polling=args.use_polling),
)
watcher = LivereloadWatchdogWatcher(event_action_data,
use_polling=args.use_polling)
action_thread = EventActionThread(
event_action_data, action=builder, watcher=watcher,
check_interval=args.event_delay)

server = Server(watcher=watcher)
action_thread.start()

server.watch(srcdir, builder)
for dirpath in args.additional_watched_dirs:
Expand All @@ -316,3 +375,9 @@ def main():
root=outdir, open_url_delay=args.delay)
else:
server.serve(port=portn, host=args.host, root=outdir)

try:
action_thread.kill()
action_thread.join()
except KeyboardInterrupt:
pass