-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Tomas Walch
committed
Dec 10, 2015
0 parents
commit 1541f25
Showing
18 changed files
with
1,971 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
.DS_Store | ||
|
||
test.* | ||
*.swp | ||
*~ | ||
*.py[co] | ||
|
||
*.egg | ||
*.egg-info | ||
dist | ||
eggs | ||
sdist | ||
develop-eggs | ||
.installed.cfg | ||
|
||
build | ||
|
||
pip-log.txt | ||
|
||
.idea | ||
.coverage | ||
.tox | ||
.env/ | ||
|
||
docs/_build | ||
example/style.css | ||
tests/tmp | ||
cover/ | ||
*.orig | ||
|
||
/README.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
language: python | ||
python: | ||
- '2.7' | ||
- '3.4' | ||
script: nosetests | ||
deploy: | ||
provider: pypi | ||
user: Tomas.Walch | ||
password: | ||
secure: tS5xcmgEv5tf55PTSGZKRt0kRU0QjcVmQOZ3yN3+80tAM/0AC3YrUBs5AFUjRMzhx/yd9jaTZxYoMO1NYpEDcOeUXGDazTXsd7nb6A7sc6yWzWUCWmHhc1HSf/7GdRoiTHrpthCkMcDZ9cQemuuN8yHpAZteT/XSjBebJOWG0URJe8y7vsVzn9bDP+NRHQyrqaYD2lFKjLIx8i0UiWWdjnB7huAN+LCVTnjoeu85GA1Q97kCt5YuZel/W/PhL4vvDWLNV37DYMrxnjDSYfEvafcYiXSqw9CV1cJF2jnNKP+d+0wzSMK66MA85axR0ZInBuqsygGEN+apojBVp+erOHQ4SE0ODaEpNRyCEIgmSEVSarJKGq3JMc3xkGnq0cle2DdUs7M93Ay4Prk+vMjqNuVWpDLAtCmfTl4Nt29XK6uUiZ0a4zW3GO24qRHzg0vl+8pUJ7LAqChfr4C1TnbF5VuB//2EMzP6R7PcIzt9f4dEhPLlj+U8zBWrcrLqQ+ul9+Qs5fTwFROwEeti+19v45nW4IeumPgck5L/89jOzkJo/xqkqlN7vOO6RVIg0UF8QHHkAXEycGDB4s405ocSkHnSBGJZMlcZy5+jcxE+2MxfzDDQJ3l6v8B/eP+unaQAvyhKa/849CFA0V/E8Kl1nrgqEnZuw0tOsfgqB+WRDBs= | ||
on: | ||
branch: master | ||
tags: true | ||
repo: tjwalch/django-livereload-server |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Changelog | ||
========= | ||
|
||
Version 0.1 | ||
------------ | ||
First release |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
Copyright (c) 2015, Tomas Walch | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions | ||
are met: | ||
|
||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above | ||
copyright notice, this list of conditions and the following | ||
disclaimer in the documentation and/or other materials provided | ||
with the distribution. | ||
* Neither the name of the author nor the names of its contributors | ||
may be used to endorse or promote products derived from this | ||
software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
include livereload/vendors/livereload.js | ||
include LICENSE | ||
include README.rst |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
======================== | ||
django-livereload-server | ||
======================== | ||
|
||
This django app adds a management command that starts a livereload server watching all your static files and templates as well | ||
as a custom ``runserver`` command that issues livereload requests when the development server is ready after a restart. | ||
|
||
Installation | ||
------------ | ||
|
||
Install package: :: | ||
|
||
$ pip install django-livereload-server | ||
|
||
Add ``'livereload'`` to the ``INSTALLED_APPS``, before ``'django.contrib.staticfiles'`` if this is used:: | ||
|
||
INSTALLED_APPS = ( | ||
... | ||
'livereload', | ||
... | ||
) | ||
|
||
Add ``'livereload.middleware.LiveReloadScript'`` to the | ||
``MIDDLEWARE_CLASSES`` (probably at the end):: | ||
|
||
MIDDLEWARE_CLASSES = ( | ||
... | ||
'livereload.middleware.LiveReloadScript', | ||
) | ||
|
||
Configuration | ||
------------- | ||
If you need the livereload server to use a different port than the default 35729, | ||
specify it by setting ``LIVERELOAD_PORT`` in ``settings.py``. | ||
|
||
Usage | ||
----- | ||
Start the livereload server with: :: | ||
|
||
$ ./manage.py livereload | ||
|
||
Extra files and/or paths to watch for changes can be added as positional arguments. | ||
|
||
Start the development server as usual with ``./manage.py runserver``. The command now accepts two additional | ||
options: | ||
|
||
* ``--nolivereload`` to disable livereload functionality | ||
* ``--livereload-port`` to override both default and settings file specified port | ||
|
||
Background | ||
---------- | ||
This project is based on a merge of `python-livereload <https://github.com/lepture/python-livereload>`_ and | ||
`django-livereload <https://github.com/Fantomas42/django-livereload>`_, excellent projects both and even better for | ||
smooth django development when combined. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
"""django-livereload""" | ||
__version__ = '0.1' | ||
__license__ = 'BSD License' | ||
|
||
__author__ = 'Tomas Walch' | ||
__email__ = '[email protected]' | ||
|
||
__url__ = 'https://github.com/tjwalch/django-livereload-server' | ||
|
||
|
||
def livereload_port(): | ||
from django.conf import settings | ||
return int(getattr(settings, 'LIVERELOAD_PORT', 35729)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
livereload.handlers | ||
~~~~~~~~~~~~~~~~~~~ | ||
HTTP and WebSocket handlers for livereload. | ||
:copyright: (c) 2013 - 2015 by Hsiaoming Yang | ||
:license: BSD, see LICENSE for more details. | ||
""" | ||
|
||
import os | ||
import time | ||
import logging | ||
from pkg_resources import resource_string | ||
from tornado import web | ||
from tornado import ioloop | ||
from tornado import escape | ||
from tornado.websocket import WebSocketHandler | ||
from tornado.util import ObjectDict | ||
|
||
logger = logging.getLogger('livereload') | ||
|
||
|
||
class LiveReloadHandler(WebSocketHandler): | ||
waiters = set() | ||
watcher = None | ||
_last_reload_time = None | ||
|
||
def allow_draft76(self): | ||
return True | ||
|
||
def check_origin(self, origin): | ||
return True | ||
|
||
def on_close(self): | ||
if self in LiveReloadHandler.waiters: | ||
LiveReloadHandler.waiters.remove(self) | ||
|
||
def send_message(self, message): | ||
if isinstance(message, dict): | ||
message = escape.json_encode(message) | ||
|
||
try: | ||
self.write_message(message) | ||
except: | ||
logger.error('Error sending message', exc_info=True) | ||
|
||
@classmethod | ||
def start_tasks(cls): | ||
if cls._last_reload_time: | ||
return | ||
|
||
if not cls.watcher._tasks: | ||
logger.info('Watch current working directory') | ||
cls.watcher.watch(os.getcwd()) | ||
|
||
cls._last_reload_time = time.time() | ||
logger.info('Start watching changes') | ||
if not cls.watcher.start(cls.poll_tasks): | ||
logger.info('Start detecting changes') | ||
ioloop.PeriodicCallback(cls.poll_tasks, 800).start() | ||
|
||
@classmethod | ||
def poll_tasks(cls): | ||
filepath, delay = cls.watcher.examine() | ||
if not filepath or delay == 'forever' or not cls.waiters: | ||
return | ||
reload_time = 3 | ||
|
||
if delay: | ||
reload_time = max(3 - delay, 1) | ||
if filepath == '__livereload__': | ||
reload_time = 0 | ||
|
||
if time.time() - cls._last_reload_time < reload_time: | ||
# if you changed lot of files in one time | ||
# it will refresh too many times | ||
logger.info('Ignore: %s', filepath) | ||
return | ||
if delay: | ||
loop = ioloop.IOLoop.current() | ||
loop.call_later(delay, cls.reload_waiters) | ||
else: | ||
cls.reload_waiters() | ||
|
||
@classmethod | ||
def reload_waiters(cls, path=None): | ||
logger.info( | ||
'Reload %s waiters: %s', | ||
len(cls.waiters), | ||
cls.watcher.filepath, | ||
) | ||
|
||
if path is None: | ||
path = cls.watcher.filepath or '*' | ||
|
||
msg = { | ||
'command': 'reload', | ||
'path': path, | ||
'liveCSS': True, | ||
'liveImg': True, | ||
} | ||
|
||
cls._last_reload_time = time.time() | ||
for waiter in cls.waiters: | ||
try: | ||
waiter.write_message(msg) | ||
except: | ||
logger.error('Error sending message', exc_info=True) | ||
cls.waiters.remove(waiter) | ||
|
||
def on_message(self, message): | ||
"""Handshake with livereload.js | ||
1. client send 'hello' | ||
2. server reply 'hello' | ||
3. client send 'info' | ||
""" | ||
message = ObjectDict(escape.json_decode(message)) | ||
if message.command == 'hello': | ||
handshake = { | ||
'command': 'hello', | ||
'protocols': [ | ||
'http://livereload.com/protocols/official-7', | ||
], | ||
'serverName': 'livereload-tornado', | ||
} | ||
self.send_message(handshake) | ||
|
||
if message.command == 'info' and 'url' in message: | ||
logger.info('Browser Connected: %s' % message.url) | ||
LiveReloadHandler.waiters.add(self) | ||
|
||
|
||
class LiveReloadJSHandler(web.RequestHandler): | ||
|
||
def get(self): | ||
self.set_header('Content-Type', 'application/javascript') | ||
self.write(resource_string(__name__, 'vendors/livereload.js')) | ||
|
||
|
||
class ForceReloadHandler(web.RequestHandler): | ||
def get(self): | ||
path = self.get_argument('path', default=None) or '*' | ||
LiveReloadHandler.reload_waiters(path) | ||
self.write('ok') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Management for django-livereload-server""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Management commands for django-livereload""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import os | ||
from django.conf import settings | ||
from django.apps import apps | ||
from django.core.management.base import BaseCommand | ||
import itertools | ||
from livereload.server import Server | ||
from livereload import livereload_port | ||
|
||
|
||
class Command(BaseCommand): | ||
help = 'Runs a livereload server watching static files and templates.' | ||
|
||
def add_arguments(self, parser): | ||
super(Command, self).add_arguments(parser) | ||
parser.add_argument( | ||
'extra', | ||
nargs='*', | ||
action='store', | ||
help='Extra files or directories to watch', | ||
) | ||
|
||
def handle(self, *args, **options): | ||
server = Server() | ||
|
||
for dir in itertools.chain( | ||
settings.STATICFILES_DIRS, | ||
getattr(settings, 'TEMPLATE_DIRS', []), | ||
options.get('extra', []), | ||
args): | ||
server.watch(dir) | ||
for template in getattr(settings, 'TEMPLATES', []): | ||
for dir in template['DIRS']: | ||
server.watch(dir) | ||
for app_config in apps.get_app_configs(): | ||
server.watch(os.path.join(app_config.path, 'static')) | ||
server.watch(os.path.join(app_config.path, 'templates')) | ||
|
||
server.serve( | ||
host='127.0.0.1', | ||
liveport=livereload_port(), | ||
) |
Oops, something went wrong.