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

Add --watch flag to build #46

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
78 changes: 78 additions & 0 deletions pico8/build/build.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import os
import time

from .. import util
from ..game import game
from ..lua import lua
from ..lua import parser
from ..lua import lexer

try:
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
HAVE_WATCHDOG=True
except ImportError:
HAVE_WATCHDOG=False
# Build stubs to keep things happy
class Observer:
pass
class PatternMatchingEventHandler:
pass

# The default Lua load path if neither PICO8_LUA_PATH nor --lua-path are set.
DEFAULT_LUA_PATH = '?;?.lua'
Expand Down Expand Up @@ -107,6 +119,39 @@ def _walk_FunctionCall(self, node):

yield (require_path, use_game_loop, self._tokens[node.start_pos])

class DirWatcher:
def __init__(self, watchdir, callback, args):
# Watch has done its job, strip it
args.watch = None
handler = BuildEventHandler(callback, args,
patterns=args.watch_glob.split(','),
ignore_patterns=['*/' + args.filename]
)

self.observer = Observer()
self.observer.schedule(handler, watchdir, recursive=True)
self.observer.start()

util.write('Watching for changes in "{}"...\n'.format(watchdir))

def stop(self):
self.observer.stop()

def join(self):
self.observer.join()


class BuildEventHandler(PatternMatchingEventHandler):
def __init__(self, callback, args, **kwargs):
# Function to call on change
self.callback = callback
# Args to pass through to the callback
self.args = args
super().__init__(**kwargs)

def on_any_event(self, evt):
util.write('Change detected to {}, building...\n'.format(evt.src_path))
self.callback(self.args)

def _evaluate_require(ast, file_path, package_lua, lua_path=None):
"""Evaluate require() statements in a Lua AST.
Expand Down Expand Up @@ -212,6 +257,9 @@ def do_build(args):
Args:
args: The argparse.Namespace arguments object.
"""
if args.watch is not None:
return do_watch(args)

if (not args.filename.endswith('.p8') and
not args.filename.endswith('.p8.png')):
util.error('Output filename must end with .p8 or .p8.png.')
Expand Down Expand Up @@ -285,3 +333,33 @@ def do_build(args):
lua_writer_args=lua_writer_args)

return 0

def do_watch(args):
if not HAVE_WATCHDOG:
util.error('optional python library "watchdog" not installed\n'
'to use --watch, install watchdog however you see fit\n'
'using pip, that would be "pip install watchdog"\n')
return 1

# Check for valid directory
if args.watch:
if not os.path.exists(args.watch):
util.error('watch directory doesn\'t exist!\n')
return 1
if not os.path.isdir(args.watch):
util.error('watch directory isn\'t a directory!\n')
return 1
watchdir = args.filename
else:
util.write('no directory specified, defaulting to current directory\n')
watchdir = '.'

watcher = DirWatcher(watchdir, do_build, args)
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
watcher.stop()
watcher.join()

return 0
6 changes: 6 additions & 0 deletions pico8/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,12 @@ def _get_argparser():
sp_build.add_argument(
'--empty-music', action='store_true',
help='use an empty music region (overrides default)')
sp_build.add_argument(
'--watch', type=str, nargs='?', const='',
help='specify a directory to watch and automatically build on changes')
sp_build.add_argument(
'--watch-glob', type=str, default='*.p8,*.png,*.lua',
help='comma-separated list of globs to watch for')
sp_build.add_argument(
'filename', type=str,
help='filename of the output cart; if the file exists, '
Expand Down