lexipython/lexipython.py

192 lines
5.7 KiB
Python
Executable File

#!/usr/bin/env python3
import sys
if sys.version_info[0] < 3:
raise Exception("Lexipython requires Python 3")
import argparse
import os
import re
import json
from src.article import LexiconArticle
from src import build
from src import utils
def is_lexicon(name):
"""
Checks whether the given folder is a Lexicon game.
Inputs:
name The Lexicon name to check. Assumed to be an existing folder.
Output:
Returns a tuple (result, msg, status), where result is True if the
given name is a Lexicon game and False otherwise, msg is the Lexicon's
status or an error message, and status is the status dictionary of the
Lexicon or None.
"""
if not os.path.isfile(os.path.join("lexicon", name, "lexicon.cfg")):
return (False, "'{}' is not a Lexicon game, or its config file may be missing.".format(name), None)
if not os.path.isfile(os.path.join("lexicon", name, "status")):
return (True, "status missing", None)
with open(os.path.join("lexicon", name, "status")) as statusfile:
raw = statusfile.read()
if len(raw) == 0:
return (True, "unbuilt", {})
try:
status = json.loads(raw)
except:
return (True, "status corrupted", None)
return (True, "ye", status) # TODO
return (False, "Error checking Lexicon status", None)
def overview_all():
"""
Prints the names and statuses of all extant Lexicons,
or a short help message if none have been created yet.
"""
# Scan the directory
lexicon_names = []
with os.scandir("lexicon") as lexicons:
for entry in lexicons:
if entry.is_dir():
result, msg, status = is_lexicon(entry.name)
if result:
lexicon_names.append((entry.name, msg))
# Print the results
if len(lexicon_names) > 0:
l = max([len(name) for name, msg in lexicon_names]) + 4
print("Lexicons:")
for name, msg in sorted(lexicon_names):
print(" {}{}{}".format(name, " " * (l - len(name)), msg))
else:
print("There are no Lexicons yet. Create one with:\n\n"\
" lexipython.py [name] init\n")
def overview_one(name):
"""
Prints the status and summary information for the Lexicon with the
given name.
"""
# Verify the name
if not os.path.isdir(os.path.join("lexicon", name)):
print("Error: There is no Lexicon named '{}'.".format(name))
return
result, msg, status = is_lexicon(name)
if not result:
print("Error: " + msg)
return
# Print status and summary
print(msg)
print(status)
# TODO
def run_command(name, command):
"""
Runs a command on a Lexicon.
"""
if command == "init":
# Check that the folder isn't already there
if os.path.exists(os.path.join("lexicon", name)):
print("Error: Can't create '{}', it already exists.".format(name))
return
# Create the Lexicon
command_init(name)
return
elif command == "build":
if not os.path.exists(os.path.join("lexicon", name)):
print("Error: There is no Lexicon named '{}'.".format(name))
return
result, msg, status = is_lexicon(name)
if not result:
print("Error: " + msg)
return
# Build the Lexicon
command_build(name)
return
elif command == "run":
if not os.path.exists(os.path.join("lexicon", name)):
print("Error: There is no Lexicon named '{}'.".format(name))
return
result, msg, status = is_lexicon(name)
if not result:
print("Error: " + msg)
return
# Run a server managing the Lexicon
command_run(name)
return
else:
print("Error: '{}' is not a valid command.".format(command))
return
def command_init(name):
"""
Sets up a Lexicon game with the given name.
"""
# Create the folder structure
lex_path = os.path.join("lexicon", name)
os.mkdir(lex_path)
os.mkdir(os.path.join(lex_path, "src"))
os.mkdir(os.path.join(lex_path, "article"))
os.mkdir(os.path.join(lex_path, "contents"))
os.mkdir(os.path.join(lex_path, "formatting"))
os.mkdir(os.path.join(lex_path, "rules"))
os.mkdir(os.path.join(lex_path, "session"))
os.mkdir(os.path.join(lex_path, "statistics"))
# Open the default config file
config = utils.load_resource("lexicon.cfg")
# Edit the name field
config = re.sub("Lexicon Title", "Lexicon {}".format(name), config)
# Create the Lexicon's config file
with open(os.path.join(lex_path, "lexicon.cfg"), "w") as config_file:
config_file.write(config)
# Copy the CSS file
with open(os.path.join(lex_path, "lexicon.css"), "w") as css_file:
css_file.write(utils.load_resource("lexicon.css"))
# Create an example page
with open(os.path.join(lex_path, "src", "example-page.txt"), "w") as destfile:
destfile.write(utils.load_resource("example-page.txt"))
# Create an empty status file
open(os.path.join(lex_path, "status"), "w").close()
print("Created Lexicon {}".format(name))
# Done initializing
return
def command_build(name):
"""
Rebuilds the browsable pages of a Lexicon.
"""
build.build_all("lexicon", name)
def command_run(name):
"""
Runs as a server managing a Lexicon.
"""
print("Not implemented")
def main():
parser = argparse.ArgumentParser(
description="Lexipython is a Python application for playing the Lexicon RPG.",
epilog="Run lexipython.py without arguments to list the extant Lexicons.\n\n"\
"Available commands:\n\n"\
" init Create a Lexicon with the provided name\n"\
" build Build the Lexicon, then exit\n"\
" run Launch a persistent server managing the Lexicon\n",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("name", help="The name of the Lexicon to operate on",
nargs="?", default=None)
parser.add_argument("command", help="The operation to perform on the Lexicon",
nargs="?", default=None)
args = parser.parse_args()
# If no Lexicon as specified
if args.name is None:
overview_all()
# If no command was specified
elif args.command is None:
overview_one(args.name)
# A command was specified
else:
run_command(args.name, args.command)
if __name__ == "__main__":
main()