tzk/tw.py
2021-08-26 14:11:56 -05:00

165 lines
4.9 KiB
Python

from contextlib import contextmanager
import functools
import json
import os
from pathlib import Path
import subprocess
from textwrap import dedent
from typing import Optional, Sequence
import config
import git
@functools.lru_cache(1)
def _npm_bin() -> str:
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:
return _npm_bin() + "/tiddlywiki"
@functools.lru_cache(1)
def _whoami() -> str:
try:
return subprocess.check_output(("whoami",), text=True).strip()
except subprocess.CalledProcessError:
return "user"
def exec(args: Sequence[Sequence[str]], base_wiki_folder: str = None) -> int:
call_args = [_tw_path()]
if base_wiki_folder is not None:
call_args.append(base_wiki_folder)
for tw_arg in args:
call_args.append(f"--{tw_arg[0]}")
for inner_arg in tw_arg[1:]:
call_args.append(inner_arg)
return subprocess.call(call_args)
def _init_npm(wiki_name: str, tw_version_spec: str, author: str) -> None:
"""
Create a package.json file for this repository, requiring TiddlyWiki
at the specified version, and install the npm dependencies.
"""
print("tzk: Creating package.json...")
PACKAGE_JSON = dedent("""
{
"name": "%(wiki_name)s",
"version": "1.0.0",
"description": "My nice notes",
"dependencies": {
"tiddlywiki": "%(tw_version_spec)s"
},
"author": "%(author)s",
"license": "See copyright notice in wiki"
}
""").strip() % ({'tw_version_spec': tw_version_spec, 'author': author,
'wiki_name': wiki_name})
with open("package.json", "w") as f:
f.write(PACKAGE_JSON)
print("tzk: Installing npm packages from package.json...")
subprocess.check_call(("npm", "install"))
def _init_tw(wiki_name: str) -> None:
"""
Create a new TiddlyWiki in the subfolder named 'wiki_name'
using 'tiddlywiki --init'.
"""
print("tzk: Creating new TiddlyWiki...")
try:
os.mkdir(wiki_name)
except FileExistsError:
pass
with _pushd(wiki_name):
subprocess.check_call((_tw_path(), "--init"))
def _save_wikifolder_to_config(wiki_name: str) -> bool:
"""
Set the wiki_folder config option to the wiki_name we initialized with,
if it's not already set in the config.
Return True if the option ended set to wiki_name, False otherwise.
"""
print("tzk: Writing new wiki folder to config file...")
if not config.cm.write_attr("wiki_folder", wiki_name):
if config.cm.wiki_folder == wiki_name:
print("tzk: (Looks like it was already there.)")
else:
print(f"tzk: WARNING: The wiki_folder option in your config appears "
f"to be set to '{config.cm.wiki_folder}', rather than the wiki folder "
f"you're initializing, {wiki_name}. Please check your config file "
"and update this option if necessary.")
return False
return True
def _add_filesystem_plugins(wiki_name: str) -> None:
print("tzk: Adding filesystem plugins to tiddlywiki.info...")
info_path = Path.cwd() / wiki_name / "tiddlywiki.info"
with info_path.open("r") as f:
info_data = json.load(f)
info_data['plugins'] = ["tiddlywiki/filesystem", "tiddlywiki/tiddlyweb"]
with info_path.open("w") as f:
json.dump(info_data, f)
def _init_gitignore() -> None:
print("tzk: Creating gitignore...")
GITIGNORE = dedent("""
__pycache__/
node_modules/
.peru/
output/
\$__StoryList.tid
""").strip()
with open(".gitignore", "w") as f:
f.write(GITIGNORE)
def _initial_commit() -> None:
print("tzk: Initializing new Git repository for wiki...")
git.exec("init")
print("tzk: Committing changes to repository...")
git.exec("add", "-A")
git.exec("commit", "-m", "Initial commit")
def install(wiki_name: str, tw_version_spec: str, author: Optional[str]):
# assert: caller has checked npm and git are installed
warnings = False
if author is None:
author = _whoami()
_init_npm(wiki_name, tw_version_spec, author)
_init_tw(wiki_name)
warnings |= not _save_wikifolder_to_config(wiki_name)
_add_filesystem_plugins(wiki_name)
_init_gitignore()
_initial_commit()
if warnings:
print("tzk: Initialization completed with warnings. Read the output and "
"make any changes required, then run 'tzk listen' to start the server.")
else:
print("tzk: Initialized successfully. Run 'tzk listen' to start the server.")