shell builder: subscriptions and clean target
This commit is contained in:
parent
5951b38551
commit
5d4a3164de
53
builders.py
53
builders.py
@ -4,12 +4,13 @@ import os
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Dict, List, Set, Tuple
|
from typing import Dict, List, Set, Sequence, Tuple
|
||||||
|
|
||||||
import git
|
import git
|
||||||
import tw
|
import tw
|
||||||
from util import BuildError
|
from util import BuildError, pushd
|
||||||
|
|
||||||
|
|
||||||
def _lazy_evaluable(func):
|
def _lazy_evaluable(func):
|
||||||
@ -153,8 +154,8 @@ def save_attachments_externally(attachment_filter: str = "[is[image]]",
|
|||||||
@tzk_builder
|
@tzk_builder
|
||||||
def compile_html_file(
|
def compile_html_file(
|
||||||
wiki_name: str = "index.html",
|
wiki_name: str = "index.html",
|
||||||
output_folder: str = "public_site/",
|
output_folder: str = "output/public_site/",
|
||||||
remove_output: bool = False,
|
overwrite: bool = True,
|
||||||
externalize_attachments: bool = False,
|
externalize_attachments: bool = False,
|
||||||
attachment_filter: str = "[is[image]]",
|
attachment_filter: str = "[is[image]]",
|
||||||
canonical_uri_template: str = "$:/core/templates/canonical-uri-external-image",
|
canonical_uri_template: str = "$:/core/templates/canonical-uri-external-image",
|
||||||
@ -172,17 +173,15 @@ def compile_html_file(
|
|||||||
commands.append(("render", "$:/core/save/all", wiki_name, "text/plain"))
|
commands.append(("render", "$:/core/save/all", wiki_name, "text/plain"))
|
||||||
|
|
||||||
tw.exec(commands, base_wiki_folder=build_state['public_wiki_folder'])
|
tw.exec(commands, base_wiki_folder=build_state['public_wiki_folder'])
|
||||||
if os.path.exists(output_folder) and not remove_output:
|
if os.path.exists(output_folder) and not overwrite:
|
||||||
stop(f"The output folder '{os.path.abspath(output_folder)}' already exists. "
|
stop(f"The output folder '{os.path.abspath(output_folder)}' already exists. "
|
||||||
f"(To delete the output folder if it exists, set remove_output = True "
|
f"(To overwrite any files existing in the output folder, "
|
||||||
f"for this builder.)")
|
f"set overwrite = True for this builder.)")
|
||||||
elif os.path.exists(output_folder) and remove_output:
|
|
||||||
info(f"Removing existing output folder {os.path.abspath(output_folder)}.")
|
|
||||||
shutil.rmtree(output_folder)
|
|
||||||
|
|
||||||
shutil.copytree(
|
shutil.copytree(
|
||||||
Path(build_state['public_wiki_folder']) / "output",
|
Path(build_state['public_wiki_folder']) / "output",
|
||||||
Path(output_folder)
|
Path(output_folder),
|
||||||
|
dirs_exist_ok=True
|
||||||
)
|
)
|
||||||
info(f"Successfully copied built output to {os.path.abspath(output_folder)}.")
|
info(f"Successfully copied built output to {os.path.abspath(output_folder)}.")
|
||||||
|
|
||||||
@ -282,15 +281,41 @@ def publish_wiki_to_github(
|
|||||||
output_folder: str = "output/public_site/",
|
output_folder: str = "output/public_site/",
|
||||||
commit_message: str = "publish checkpoint",
|
commit_message: str = "publish checkpoint",
|
||||||
remote: str = "origin",
|
remote: str = "origin",
|
||||||
refspec: str = "master") -> None:
|
refspec: str = "master",
|
||||||
|
push = True) -> None:
|
||||||
"Publish the wiki to GitHub"
|
"Publish the wiki to GitHub"
|
||||||
|
|
||||||
os.chdir(output_folder)
|
with pushd(output_folder):
|
||||||
if not os.path.isdir(".git"):
|
if not os.path.isdir(".git"):
|
||||||
info(f"The output folder {output_folder} doesn't appear to be a Git repository. "
|
info(f"The output folder {output_folder} doesn't appear to be a Git repository. "
|
||||||
f"I'll try to make it one.")
|
f"I'll try to make it one.")
|
||||||
git.exec("init")
|
git.exec("init")
|
||||||
|
|
||||||
git.exec("add", "-A")
|
git.exec("add", "-A")
|
||||||
git.exec("commit", "-m", commit_message)
|
rc = git.rc("commit", "-m", commit_message)
|
||||||
|
if rc == 0:
|
||||||
|
if push:
|
||||||
git.exec("push", remote, refspec)
|
git.exec("push", remote, refspec)
|
||||||
|
elif rc == 1:
|
||||||
|
info("No changes to commit or publish. "
|
||||||
|
"You probably rebuilt without changing the wiki in between.")
|
||||||
|
else:
|
||||||
|
stop(f"'git commit' returned unknown return code {rc}.")
|
||||||
|
|
||||||
|
|
||||||
|
@tzk_builder
|
||||||
|
def shell(shell_command: str) -> None:
|
||||||
|
"Run an arbitrary shell command"
|
||||||
|
info("$ " + shell_command)
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(shell_command, shell=True, text=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
if e.output.strip():
|
||||||
|
stop(f"Command exited with return code {e.returncode}:\n{e.output}")
|
||||||
|
else:
|
||||||
|
stop(f"Command exited with return code {e.returncode} (no output).")
|
||||||
|
else:
|
||||||
|
if output.strip():
|
||||||
|
info(f"Command exited with return code 0:\n{output}")
|
||||||
|
else:
|
||||||
|
info(f"Command exited with return code 0 (no output).")
|
||||||
|
17
tw.py
17
tw.py
@ -1,4 +1,3 @@
|
|||||||
from contextlib import contextmanager
|
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
@ -9,25 +8,13 @@ from typing import Optional, Sequence
|
|||||||
|
|
||||||
import config
|
import config
|
||||||
import git
|
import git
|
||||||
|
from util import pushd
|
||||||
|
|
||||||
|
|
||||||
@functools.lru_cache(1)
|
@functools.lru_cache(1)
|
||||||
def _npm_bin() -> str:
|
def _npm_bin() -> str:
|
||||||
return subprocess.check_output(("npm", "bin"), text=True).strip()
|
return subprocess.check_output(("npm", "bin"), text=True).strip()
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def _pushd(directory: str):
|
|
||||||
"""
|
|
||||||
Change directory into the directory /directory/ until the end of the with-block,
|
|
||||||
then return to previous directory.
|
|
||||||
"""
|
|
||||||
old_directory = os.getcwd()
|
|
||||||
try:
|
|
||||||
os.chdir(directory)
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
os.chdir(old_directory)
|
|
||||||
|
|
||||||
def _tw_path() -> str:
|
def _tw_path() -> str:
|
||||||
return _npm_bin() + "/tiddlywiki"
|
return _npm_bin() + "/tiddlywiki"
|
||||||
|
|
||||||
@ -86,7 +73,7 @@ def _init_tw(wiki_name: str) -> None:
|
|||||||
os.mkdir(wiki_name)
|
os.mkdir(wiki_name)
|
||||||
except FileExistsError:
|
except FileExistsError:
|
||||||
pass
|
pass
|
||||||
with _pushd(wiki_name):
|
with pushd(wiki_name):
|
||||||
subprocess.check_call((_tw_path(), "--init"))
|
subprocess.check_call((_tw_path(), "--init"))
|
||||||
|
|
||||||
|
|
||||||
|
5
tzk.py
5
tzk.py
@ -9,7 +9,7 @@ from typing import Optional
|
|||||||
from config import cm
|
from config import cm
|
||||||
import git
|
import git
|
||||||
import tw
|
import tw
|
||||||
from util import BuildError, fail
|
from util import BuildError, fail, numerize
|
||||||
|
|
||||||
|
|
||||||
class CliCommand(ABC):
|
class CliCommand(ABC):
|
||||||
@ -166,6 +166,7 @@ class BuildCommand(CliCommand):
|
|||||||
help="Function name of a builder to skip even if part of the PRODUCT. "
|
help="Function name of a builder to skip even if part of the PRODUCT. "
|
||||||
"This option can be specified multiple times.",
|
"This option can be specified multiple times.",
|
||||||
action="append",
|
action="append",
|
||||||
|
default=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
def _precheck(self, product: str) -> None:
|
def _precheck(self, product: str) -> None:
|
||||||
@ -183,7 +184,7 @@ class BuildCommand(CliCommand):
|
|||||||
|
|
||||||
steps = cm.products[args.product]
|
steps = cm.products[args.product]
|
||||||
print(f"tzk: Starting build of product '{args.product}'.")
|
print(f"tzk: Starting build of product '{args.product}'.")
|
||||||
print(f"tzk: Found {len(steps)} build steps.")
|
print(f"tzk: Found {len(steps)} build {numerize(len(steps), 'step')}.")
|
||||||
|
|
||||||
for idx, step in enumerate(steps, 1):
|
for idx, step in enumerate(steps, 1):
|
||||||
if hasattr(step, '__doc__'):
|
if hasattr(step, '__doc__'):
|
||||||
|
26
util.py
26
util.py
@ -1,3 +1,5 @@
|
|||||||
|
from contextlib import contextmanager
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
|
|
||||||
@ -9,3 +11,27 @@ class BuildError(Exception):
|
|||||||
def fail(msg: str, exit_code: int = 1) -> NoReturn:
|
def fail(msg: str, exit_code: int = 1) -> NoReturn:
|
||||||
print(msg, file=sys.stderr)
|
print(msg, file=sys.stderr)
|
||||||
sys.exit(exit_code)
|
sys.exit(exit_code)
|
||||||
|
|
||||||
|
|
||||||
|
def numerize(number: int, singular: str, plural: str = None):
|
||||||
|
if plural is None:
|
||||||
|
plural = singular + 's'
|
||||||
|
|
||||||
|
if number == 1:
|
||||||
|
return singular
|
||||||
|
else:
|
||||||
|
return plural
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def pushd(directory: str):
|
||||||
|
"""
|
||||||
|
Change directory into the directory /directory/ until the end of the with-block,
|
||||||
|
then return to previous directory.
|
||||||
|
"""
|
||||||
|
old_directory = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.chdir(directory)
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
os.chdir(old_directory)
|
||||||
|
Loading…
Reference in New Issue
Block a user