update docstrings
This commit is contained in:
parent
0321b7d7b1
commit
97a4611d56
@ -13,15 +13,26 @@ from tzk.util import BuildError, fail, numerize
|
||||
|
||||
|
||||
class CliCommand(ABC):
|
||||
"""
|
||||
Base class for subcommands of tzk.
|
||||
"""
|
||||
#: The text of the subcommand to be used on the command line.
|
||||
cmd = None # type: str
|
||||
#: Help string for argparse to display for this subcommand.
|
||||
help = None # type: str
|
||||
|
||||
@abstractclassmethod
|
||||
def setup_arguments(cls, parser: argparse.ArgumentParser) -> None:
|
||||
"""
|
||||
Given the :arg:`parser`, add any arguments this subcommand wants to accept.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def execute(self, parser: argparse.Namespace) -> None:
|
||||
def execute(self, args: argparse.Namespace) -> None:
|
||||
"""
|
||||
Given the :arg:`args` passed to this subcommand, do whatever the command does.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@ -182,21 +193,27 @@ class BuildCommand(CliCommand):
|
||||
def execute(self, args: argparse.Namespace) -> None:
|
||||
self._precheck(args.product)
|
||||
|
||||
# Find the build steps for the product the user specified.
|
||||
steps = cm().products[args.product]
|
||||
print(f"tzk: Starting build of product '{args.product}'.")
|
||||
print(f"tzk: Found {len(steps)} build {numerize(len(steps), 'step')}.")
|
||||
|
||||
# For each build step...
|
||||
for idx, step in enumerate(steps, 1):
|
||||
# Explain what we're doing. Use first line of the builder's docstring
|
||||
# as a summary, if present.
|
||||
if hasattr(step, '__doc__'):
|
||||
short_description = step.__doc__.strip().split('\n')[0].rstrip('.')
|
||||
print(f"tzk: Step {idx}/{len(steps)}: {short_description}")
|
||||
else:
|
||||
print(f"tzk: Step {idx}/{len(steps)}")
|
||||
|
||||
# If the user asked to skip this builder on the command line, do so.
|
||||
if step.__name__ in args.skip_builder:
|
||||
print(f"tzk: Skipping step {idx} due to --skip-builder parameter.")
|
||||
continue
|
||||
|
||||
# Execute step and handle any errors.
|
||||
try:
|
||||
step()
|
||||
except BuildError as e:
|
||||
@ -231,10 +248,12 @@ def launch():
|
||||
|
||||
args = parser.parse_args()
|
||||
if not hasattr(args, '_cls'):
|
||||
# no subcommand was given
|
||||
parser.print_help()
|
||||
sys.exit(0)
|
||||
|
||||
# For all operations except 'init', we start in the wiki folder.
|
||||
# (For init, we're actually *creating* the wiki folder.)
|
||||
if not args._cls.cmd == "init":
|
||||
if not cm().wiki_folder:
|
||||
fail("No 'wiki_folder' option found in config. Set this option to the name "
|
||||
@ -256,4 +275,4 @@ def launch():
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
launch()
|
||||
launch()
|
||||
|
@ -1,3 +1,6 @@
|
||||
"""
|
||||
config.py - read and manage the TZK config file
|
||||
"""
|
||||
import datetime
|
||||
import functools
|
||||
import importlib
|
||||
@ -57,6 +60,14 @@ class ConfigurationManager:
|
||||
|
||||
|
||||
def cm(cache=[]):
|
||||
"""
|
||||
Call this function to retrieve the singleton ConfigurationManager object,
|
||||
reading and initializing it if necessary.
|
||||
|
||||
Since so much happens when the ConfigurationManager is initialized,
|
||||
this has to go in a function so that autodoc doesn't blow up
|
||||
when it tries to import the module.
|
||||
"""
|
||||
if not cache:
|
||||
cache.append(ConfigurationManager())
|
||||
return cache[0]
|
||||
|
14
tzk/git.py
14
tzk/git.py
@ -1,11 +1,17 @@
|
||||
import subprocess
|
||||
from typing import Sequence
|
||||
|
||||
def exec(*args: str):
|
||||
return subprocess.check_call(["git", *args])
|
||||
|
||||
def rc(*args: str):
|
||||
def exec(*args: str) -> None:
|
||||
"Execute a Git command, raising CalledProcessError if the exit code is nonzero."
|
||||
subprocess.check_call(["git", *args])
|
||||
|
||||
|
||||
def rc(*args: str) -> int:
|
||||
"Execute a Git command, returning the exit code."
|
||||
return subprocess.call(["git", *args])
|
||||
|
||||
def read(*args: str):
|
||||
|
||||
def read(*args: str) -> str:
|
||||
"Execute a Git command, returning the output as a string."
|
||||
return subprocess.check_output(["git", *args], text=True).strip()
|
||||
|
27
tzk/tw.py
27
tzk/tw.py
@ -20,6 +20,7 @@ def _tw_path() -> str:
|
||||
|
||||
@functools.lru_cache(1)
|
||||
def _whoami() -> str:
|
||||
"Try to guess the user's name."
|
||||
try:
|
||||
return subprocess.check_output(("whoami",), text=True).strip()
|
||||
except subprocess.CalledProcessError:
|
||||
@ -27,6 +28,19 @@ def _whoami() -> str:
|
||||
|
||||
|
||||
def exec(args: Sequence[Sequence[str]], base_wiki_folder: str = None) -> int:
|
||||
"""
|
||||
Execute a series of TiddlyWiki commands.
|
||||
|
||||
:param args: A list of lists of CLI commands to send to TiddlyWiki.
|
||||
The first element of each list is a TiddlyWiki CLI command,
|
||||
without the ``--``, e.g., ``savewikifolder``.
|
||||
The following elements of the list are arguments to that command.
|
||||
:param base_wiki_folder: If the wiki to execute commands against is not the one
|
||||
in the current directory, provide its path here.
|
||||
The current directory is the source wiki's root directory
|
||||
during the execution of builders,
|
||||
unless explicitly changed.
|
||||
"""
|
||||
call_args = [_tw_path()]
|
||||
if base_wiki_folder is not None:
|
||||
call_args.append(base_wiki_folder)
|
||||
@ -98,6 +112,10 @@ def _save_wikifolder_to_config(wiki_name: str) -> bool:
|
||||
|
||||
|
||||
def _add_filesystem_plugins(wiki_name: str) -> None:
|
||||
"""
|
||||
Add the "tiddlywiki/filesystem" and "tiddlywiki/tiddlyweb" plugins
|
||||
required for Node.js client-server operation to the new wiki's tiddlywiki.info.
|
||||
"""
|
||||
print("tzk: Adding filesystem plugins to tiddlywiki.info...")
|
||||
info_path = Path.cwd() / wiki_name / "tiddlywiki.info"
|
||||
with info_path.open("r") as f:
|
||||
@ -108,6 +126,9 @@ def _add_filesystem_plugins(wiki_name: str) -> None:
|
||||
|
||||
|
||||
def _init_gitignore() -> None:
|
||||
"""
|
||||
Create a basic gitignore for the new wiki.
|
||||
"""
|
||||
print("tzk: Creating gitignore...")
|
||||
GITIGNORE = dedent("""
|
||||
__pycache__/
|
||||
@ -122,6 +143,9 @@ def _init_gitignore() -> None:
|
||||
|
||||
|
||||
def _initial_commit() -> None:
|
||||
"""
|
||||
Create a new Git repo and commit everything we've done so far.
|
||||
"""
|
||||
print("tzk: Initializing new Git repository for wiki...")
|
||||
git.exec("init")
|
||||
|
||||
@ -131,6 +155,9 @@ def _initial_commit() -> None:
|
||||
|
||||
|
||||
def install(wiki_name: str, tw_version_spec: str, author: Optional[str]):
|
||||
"""
|
||||
Install TiddlyWiki on Node.js in the current directory and set up a new wiki.
|
||||
"""
|
||||
# assert: caller has checked npm and git are installed
|
||||
warnings = False
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
"""
|
||||
util.py - miscellaneous utility functions
|
||||
"""
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
import sys
|
||||
@ -9,11 +12,13 @@ class BuildError(Exception):
|
||||
|
||||
|
||||
def fail(msg: str, exit_code: int = 1) -> NoReturn:
|
||||
"Print message to stderr and quit with exit code 1."
|
||||
print(msg, file=sys.stderr)
|
||||
sys.exit(exit_code)
|
||||
|
||||
|
||||
def numerize(number: int, singular: str, plural: str = None):
|
||||
def numerize(number: int, singular: str, plural: str = None) -> str:
|
||||
"Render a string in the singular or plural as appropriate."
|
||||
if plural is None:
|
||||
plural = singular + 's'
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user