add 'tzk convert' to switch between Node & single-file

This commit is contained in:
Soren I. Bjornstad 2021-09-20 14:16:32 -05:00
parent cf69aa54dd
commit 91b27c6e40
3 changed files with 113 additions and 8 deletions

View File

@ -1,14 +1,16 @@
from abc import ABC, abstractmethod, abstractclassmethod
import argparse
import os
from pathlib import Path
import shutil
import sys
import traceback
from typing import Optional
from tzk.config import cm
from tzk.config import cm, DEFAULT_INIT_OPTS
from tzk import git
from tzk import tw
from tzk.util import BuildError, fail, numerize, require_dependencies
from tzk.util import BuildError, fail, numerize, require_dependencies, pushd
class CliCommand(ABC):
@ -127,19 +129,19 @@ class InitCommand(CliCommand):
"-n", "--wiki-name",
metavar="NAME",
help="The wiki will be installed in a subfolder of the current directory, called NAME.",
default="wiki",
default=DEFAULT_INIT_OPTS['wiki_name'],
)
parser.add_argument(
"-v", "--tiddlywiki-version-spec",
metavar="SPEC",
help="NPM version spec for the version of TiddlyWiki to start your package.json at.",
default="^5.1.23",
default=DEFAULT_INIT_OPTS['tw_version_spec'],
)
parser.add_argument(
"-a", "--author",
metavar="AUTHOR_NAME",
help="The author to be credited in the package.json, if not your current username.",
default=None,
default=DEFAULT_INIT_OPTS['author'],
)
def _precheck(self):
@ -257,6 +259,93 @@ class BuildCommand(CliCommand):
print(f"tzk: Build of product '{args.product}' completed successfully.")
class ConvertCommand(CliCommand):
cmd = "convert"
help = "Convert a tzk repository to a single-file wiki or vice versa."
@classmethod
def setup_arguments(cls, parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"source",
metavar="SOURCE",
help="Wiki to convert. "
"Either a folder containing a tzk_config.py file or an HTML file.",
)
parser.add_argument(
"destination",
metavar="DEST",
help="Output location for the converted wiki. "
"Either a folder (existing or not) or the name of an HTML file."
)
parser.add_argument(
"-f", "--force",
action="store_true",
help="Overwrite the destination location if it already exists.",
)
def _precheck(self, args: argparse.Namespace) -> None:
if not os.path.exists(args.source):
fail(f"The source location '{args.source}' does not exist.")
if os.path.exists(args.destination) and not args.force:
fail(f"The destination location '{args.source}' already exists. "
f"(Use --force to overwrite it.)")
def execute(self, args: argparse.Namespace) -> None:
require_dependencies()
self._precheck(args)
source = Path(args.source).absolute()
destination = Path(args.destination)
source_type = 'file' if source.is_file() else 'folder'
dest_type = 'file' if destination.name.endswith(".html") else 'folder'
# If types are the same, there's nothing to convert...
if source_type == dest_type:
fail("The source or the destination may not be of the same type. "
"One must be a folder and the other an HTML file.")
# Conversion from folder to file using --render.
if source_type == 'folder':
if not Path(source / "tzk_config.py").exists():
fail("The source folder '{source}' does not contain "
"a tzk_config.py file.")
with pushd(str(source)):
source_wiki_folder = cm().wiki_folder
tw.exec(
(
("output", str(destination.parent)),
("render", "$:/core/save/all", destination.name, "text/plain"),
),
base_wiki_folder=source_wiki_folder
)
# Conversion from file to folder using --savewikifolder.
elif source_type == 'file':
if destination.exists() and args.force:
doing_what = "Overwriting existing"
shutil.rmtree(destination)
else:
doing_what = "Creating new"
print(f"tzk: {doing_what} tzk repository in destination '{destination}'...")
os.mkdir(destination)
def installer(wiki_name):
tw.exec(
(
("load", str(source)),
("savewikifolder", wiki_name),
),
)
with pushd(str(destination)):
tw.install(_tw_func=installer, **DEFAULT_INIT_OPTS) # type: ignore
else:
raise AssertionError(f"Invalid source type {source_type}.")
def chdir_to_wiki():
"""
For most operations, we want the current directory to be the wiki folder.

View File

@ -12,6 +12,13 @@ from typing import Any
from tzk.util import fail
DEFAULT_INIT_OPTS = {
'wiki_name': 'wiki',
'tw_version_spec': '^5.1.23',
'author': None,
}
class ConfigurationManager:
def __init__(self):
self.initialize_cm()

View File

@ -5,7 +5,7 @@ import os
from pathlib import Path
import subprocess
from textwrap import dedent
from typing import Optional, Sequence
from typing import Callable, Optional, Sequence
from tzk import config
from tzk import git
@ -159,9 +159,13 @@ def _initial_commit() -> None:
print('\n'.join(output.split('\n')[0:2]))
def install(wiki_name: str, tw_version_spec: str, author: Optional[str]):
def install(wiki_name: str, tw_version_spec: str, author: Optional[str],
_tw_func: Optional[Callable[[str], None]] = None):
"""
Install TiddlyWiki on Node.js in the current directory and set up a new wiki.
If _tw_func is provided, call it to create the TiddlyWiki in the new tzk repository
rather than the default routine. It receives one argument, the name of the new wiki.
"""
# assert: caller has checked npm and git are installed
@ -170,7 +174,12 @@ def install(wiki_name: str, tw_version_spec: str, author: Optional[str]):
_init_tzk_config()
_init_npm(wiki_name, tw_version_spec, author)
_init_tw(wiki_name)
if _tw_func is not None:
_tw_func(wiki_name)
else:
_init_tw(wiki_name)
_add_filesystem_plugins(wiki_name)
_init_gitignore()
_initial_commit()