Skip to content

Commit

Permalink
fix js/css reload, enable delete/clean, tag for release
Browse files Browse the repository at this point in the history
  • Loading branch information
fastily committed Dec 14, 2021
1 parent 0cf9598 commit 89f8945
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 30 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ optional arguments:
-p port serve website on this port
-i input_dir The input directory (contianing jinja templates) to use. Defaults to the current working directory.
-o output_dir The output directory to write website output files to. Defaults to ./out
-t template_dir Shared templates directory (this must be a subfolder of the input directory). Defaults to ./templates
-t template_dir Shared templates directory (relative path only, this must be a subfolder of the input directory). Defaults to templates
--blacklist ignored_dir [ignored_dir ...]
directories to ignore
```
Expand All @@ -51,7 +51,7 @@ jinja2html -d
jinja2html -d --blacklist Foo/ Bar/

# run in dev mode, on port 8080 and ignore folder hello/world/
jinja2html -p 8080 --blacklist hello/world/
jinja2html -d -p 8080 --blacklist hello/world/
```

## Scope
Expand Down
29 changes: 17 additions & 12 deletions jinja2html/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from rich.logging import RichHandler
from watchgod import awatch, Change

from .core import Context, JinjaWatcher, WebsiteManager
from .core import Context, is_css_js, JinjaWatcher, WebsiteManager


_SESSIONS = defaultdict(list)
Expand Down Expand Up @@ -77,21 +77,28 @@ async def changed_files_handler(wm: WebsiteManager) -> None:
wm (WebsiteManager): The WebsiteManager to associate with this asyncio loop
"""
async for changes in awatch(wm.context.input_dir, watcher_cls=JinjaWatcher, watcher_kwargs={"context": wm.context}):
rebuild: set[Path] = set()
l: set[Path] = set()
build_all = notify_all = False

for change, p in changes:
p = Path(p)
if wm.context.is_template(p) or wm.context.is_config_json(p):
rebuild = wm.find_acceptable_files()
l = wm.find_acceptable_files()
build_all = True
break
elif change in (Change.added, Change.modified):
rebuild.add(Path(p))
l.add(p)
if is_css_js(p):
notify_all = True
else:
# (wm.context.output_dir / wm.context.stub_of(p)).unlink(True)
pass
(wm.context.output_dir / wm.context.stub_of(p)).unlink(True)

wm.build_files(rebuild)
wm.build_files(l)

for p in rebuild:
if notify_all and not build_all:
l = wm.find_acceptable_files()

for p in l:
stub = str(wm.context.stub_of(p))
message = f'{{"command": "reload", "path": "{stub}", "liveCSS": false}}'

Expand Down Expand Up @@ -133,14 +140,12 @@ def _main() -> None:
cli_parser.add_argument("-p", type=int, metavar="port", default=8000, help="serve website on this port")
cli_parser.add_argument("-i", type=Path, metavar="input_dir", default=Path("."), help="The input directory (contianing jinja templates) to use. Defaults to the current working directory.")
cli_parser.add_argument("-o", type=Path, metavar="output_dir", default=Path("out"), help="The output directory to write website output files to. Defaults to ./out")
cli_parser.add_argument("-t", type=Path, metavar="template_dir", default=Path("templates"), help="Shared templates directory (this must be a subfolder of the input directory). Defaults to ./templates")
cli_parser.add_argument("-t", type=str, metavar="template_dir", default="templates", help="Shared templates directory (relative path only, this must be a subfolder of the input directory). Defaults to templates")
cli_parser.add_argument("--blacklist", nargs="+", type=Path, metavar="ignored_dir", default=set(), help="directories to ignore")

args = cli_parser.parse_args()

c = Context(args.i, args.o, args.t, args.blacklist, args.d)
# c.clean()

(c := Context(args.i, args.o, args.t, args.blacklist, args.d)).clean()
(wm := WebsiteManager(c)).build_files(auto_find=True)

if not c.dev_mode:
Expand Down
45 changes: 35 additions & 10 deletions jinja2html/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@ class Context:

_NOT_DIR_PATTERN = re.compile(r"(\.|venv_|__pycache)")

def __init__(self, input_dir: Path = Path("."), output_dir: Path = Path("out"), template_dir: Path = Path("./templates"), ignore_list: set[Path] = set(), dev_mode: bool = False) -> None:
def __init__(self, input_dir: Path = Path("."), output_dir: Path = Path("out"), template_dir: str = "templates", ignore_list: set[Path] = set(), dev_mode: bool = False) -> None:
"""Initializer, creates a new `Context`. For best results, all `Path` type arguments should be absolute (this is automatically done in the initializer, but if you want to change the properties after initializing, make sure you do this).
Args:
input_dir (Path, optional): The directory to watch for changes. Defaults to Path(".").
output_dir (Path, optional): The directory to save generated files. Defaults to Path("out").
template_dir (Path, optional): The directory containing jinja2 mixin-type templates. Defaults to Path("./templates").
template_dir (str, optional): The directory containing jinja2 mixin-type templates. If it exists, this is the name of a folder under `input_dir`. Defaults to "templates".
ignore_list (set[Path], optional): The set of directories to ignore (will not be watched, even if `input_dir` is a parent folder). Defaults to set().
dev_mode (bool, optional): Flag which turns on development mode (i.e. livereload server). Defaults to False.
"""
self.input_dir: Path = input_dir.resolve()
self.output_dir: Path = output_dir.resolve()
self.template_dir: Path = template_dir.resolve()
self.template_dir: Path = self.input_dir / template_dir
self.dev_mode: bool = dev_mode

self.ignore_list: set[Path] = {p.resolve() for p in ignore_list} if ignore_list else ignore_list
Expand Down Expand Up @@ -75,7 +75,7 @@ def is_template(self, f: Path) -> bool:
Returns:
bool: `True` if `f` is a template in the `self.template_dir` directory.
"""
return self.template_dir in f.parents and _is_html(f)
return self.template_dir in f.parents and is_html(f)

def is_config_json(self, f: Path) -> bool:
"""Convienience method, determines whether `f` is the `config.json` file.
Expand Down Expand Up @@ -160,9 +160,9 @@ def build_files(self, files: Iterable[Path] = (), auto_find: bool = False) -> No
for f in files:
(output_path := self.context.output_dir / (stub := self.context.stub_of(f))).parent.mkdir(parents=True, exist_ok=True) # create dir structure if it doesn't exist

if f.suffix.lower() in (".js", ".css"):
if is_css_js(f):
shutil.copy(f, output_path)
elif _is_html(f):
elif is_html(f):
log.debug("building html for %s", f)

try:
Expand Down Expand Up @@ -226,13 +226,38 @@ def should_watch_dir(self, entry: DirEntry) -> bool:
return self.context.should_watch_dir(entry)


def _is_html(f: Path) -> bool:
"""Convenience method, determines whether `f` represents an HTML file.
def _is_ext(f: Path, ext: tuple[str]) -> bool:
"""Determines whether a file has one of the specified extension(s).
Args:
f (Path): The file to check.
ext (tuple[str]): The extension(s) to check for. These should be lower case.
Returns:
bool: `True` if `f` is an html file.
bool: `True` if `f` has an extension in `ext`.
"""
return f.suffix.lower() in (".html", ".htm", ".jinja")
return f.suffix.lower() in ext


def is_css_js(f: Path) -> bool:
"""Convenience method, determines whether `f` represents a css/js file.
Args:
f (Path): The file to check.
Returns:
bool: `True` if `f` is a css/js file.
"""
return _is_ext(f, (".css", ".js"))


def is_html(f: Path) -> bool:
"""Convenience method, determines whether `f` represents an jinja file.
Args:
f (Path): The file to check.
Returns:
bool: `True` if `f` is a jinja file.
"""
return _is_ext(f, (".html", ".htm", ".jinja"))
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
beautifulsoup4==4.10.0
Jinja2==3.0.3
lxml==4.6.4
rich==10.15.2
lxml==4.7.1
rich==10.16.0
watchgod==0.7
websockets==10.1
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="jinja2html",
version="0.3.0",
version="0.4.0",
author="Fastily",
author_email="[email protected]",
description="user-friendly generation of websites with jinja2 templates",
Expand Down
6 changes: 3 additions & 3 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ class TestCore(TestCase):
def test_find_acceptable_files(self):
expected = {_SAMPLE_PROJECT / s for s in ("config.json", "content1.html", "content2.html", "index.html", "shared.css", "shared.js")}
with TemporaryDirectory() as tempdir:
self.assertSetEqual(expected, WebsiteManager(Context(_SAMPLE_PROJECT, Path(tempdir), _SAMPLE_TEMPLATES)).find_acceptable_files())
self.assertSetEqual(expected, WebsiteManager(Context(_SAMPLE_PROJECT, Path(tempdir))).find_acceptable_files())

def test_process_files(self):
with TemporaryDirectory() as tempdir:
WebsiteManager(Context(_SAMPLE_PROJECT, Path(tempdir), _SAMPLE_TEMPLATES)).build_files(auto_find=True)
WebsiteManager(Context(_SAMPLE_PROJECT, Path(tempdir))).build_files(auto_find=True)

self.assertFalse(dircmp(_RES_DIR / "expected_output", tempdir).diff_files)

def test_sanity(self):
with TemporaryDirectory() as tempdir:
c = Context(_SAMPLE_PROJECT, Path(tempdir), _SAMPLE_TEMPLATES)
c = Context(_SAMPLE_PROJECT, Path(tempdir))

self.assertEqual(Path("index.html"), c.stub_of(_SAMPLE_PROJECT / "index.html"))
self.assertEqual(Path("shared.js"), c.stub_of(_SAMPLE_PROJECT / "shared.js"))
Expand Down

0 comments on commit 89f8945

Please sign in to comment.