mirror of https://github.com/patacrep/patacrep.git
Engine for LaTeX songbooks
http://www.patacrep.com
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
5.4 KiB
172 lines
5.4 KiB
"""Command line tool to compile songbooks using the songbook library."""
|
|
|
|
import argparse
|
|
import locale
|
|
import logging
|
|
import sys
|
|
import textwrap
|
|
|
|
from patacrep import __version__
|
|
from patacrep import errors
|
|
from patacrep.songbook import open_songbook
|
|
from patacrep.build import SongbookBuilder, DEFAULT_STEPS
|
|
from patacrep.utils import yesno
|
|
|
|
# Logging configuration
|
|
logging.basicConfig(level=logging.INFO)
|
|
LOGGER = logging.getLogger()
|
|
|
|
# pylint: disable=too-few-public-methods
|
|
class ParseStepsAction(argparse.Action):
|
|
"""Argparse action to split a string into a list."""
|
|
def __call__(self, __parser, namespace, values, __option_string=None):
|
|
if not getattr(namespace, self.dest):
|
|
setattr(namespace, self.dest, [])
|
|
setattr(
|
|
namespace,
|
|
self.dest,
|
|
(
|
|
getattr(namespace, self.dest)
|
|
+ [value.strip() for value in values[0].split(',')]
|
|
),
|
|
)
|
|
|
|
class VerboseAction(argparse.Action):
|
|
"""Set verbosity level with option --verbose."""
|
|
def __call__(self, *_args, **_kwargs):
|
|
LOGGER.setLevel(logging.DEBUG)
|
|
|
|
def yesno_type(string):
|
|
"""Interpret argument as a "yes" or a "no".
|
|
|
|
Raise `argparse.ArgumentTypeError` if string cannot be analysed.
|
|
"""
|
|
try:
|
|
return yesno(string)
|
|
except ValueError as error:
|
|
raise argparse.ArgumentTypeError(str(error))
|
|
|
|
def argument_parser(args):
|
|
"""Parse arguments"""
|
|
parser = argparse.ArgumentParser(
|
|
prog="songbook",
|
|
description="A song book compiler",
|
|
formatter_class=argparse.RawTextHelpFormatter,
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--version', help='Show version', action='version',
|
|
version='%(prog)s ' + __version__,
|
|
)
|
|
|
|
parser.add_argument(
|
|
'book', nargs=1, help=textwrap.dedent("Book to compile.")
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--datadir', '-d', nargs='+', type=str, action='append',
|
|
help=textwrap.dedent("""\
|
|
Data location. Expected (not necessarily required) subdirectories are 'songs', 'img', 'latex', 'templates'.
|
|
"""),
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--verbose', '-v', nargs=0, action=VerboseAction,
|
|
help=textwrap.dedent("""\
|
|
Show details about the compilation process.
|
|
""")
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--cache', '-c', nargs=1,
|
|
help=textwrap.dedent("""\
|
|
Enable song cache.
|
|
"""),
|
|
type=yesno_type,
|
|
default=[True],
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--error', '-e', nargs=1,
|
|
help=textwrap.dedent("""\
|
|
By default, this program tries hard to fix or ignore song and book errors. This option changes this behaviour:
|
|
- failonsong: stop as soon as a song contains (at least) one error;
|
|
- failonbook: stop when all the songs have been parsed and rendered, if any error was met;
|
|
- fix: tries to fix (or ignore) errors.
|
|
|
|
Note that compilation *may* fail even with `--error=fix`.
|
|
"""),
|
|
type=str,
|
|
choices=[
|
|
"failonsong",
|
|
"failonbook",
|
|
"fix",
|
|
],
|
|
default=["fix"],
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--steps', '-s', nargs=1, type=str,
|
|
action=ParseStepsAction,
|
|
help=textwrap.dedent("""\
|
|
Steps to run. Default is "{steps}". Available steps are:
|
|
- "tex" produce .tex file from templates;
|
|
- "pdf" compile .tex file;
|
|
- "sbx" compile index files;
|
|
- "clean" remove temporary files;
|
|
- any string beginning with '#' (in this case, it will be run in a shell).
|
|
Several steps (excepted the custom shell command) can be combinend in one --steps argument, as a comma separated string.
|
|
|
|
Substring {{basename}} is replaced by the basename of the song book, and substrings {{aux}}, {{log}}, {{out}}, {{pdf}}, {{sxc}}, {{tex}} are replaced by "<BASENAME>.aux", "<BASENAME>.log", and so on.
|
|
""".format(steps=','.join(DEFAULT_STEPS))),
|
|
default=None,
|
|
)
|
|
|
|
options = parser.parse_args(args)
|
|
|
|
return options
|
|
|
|
|
|
def main(args=None):
|
|
"""Main function:"""
|
|
if args is None:
|
|
args = sys.argv
|
|
|
|
# set script locale to match user's
|
|
try:
|
|
locale.setlocale(locale.LC_ALL, '')
|
|
except locale.Error as error:
|
|
# Locale is not installed on user's system, or wrongly configured.
|
|
LOGGER.error("Locale error: {}\n".format(str(error)))
|
|
|
|
options = argument_parser(args[1:])
|
|
|
|
try:
|
|
songbook = open_songbook(options.book[-1])
|
|
|
|
# Command line options
|
|
if options.datadir:
|
|
for datadir in reversed(options.datadir):
|
|
songbook['datadir'].insert(0, datadir)
|
|
songbook['_cache'] = options.cache[0]
|
|
songbook['_error'] = options.error[0]
|
|
|
|
sb_builder = SongbookBuilder(songbook)
|
|
sb_builder.unsafe = True
|
|
|
|
sb_builder.build_steps(options.steps)
|
|
except errors.SongbookError as error:
|
|
LOGGER.error(error)
|
|
if LOGGER.level >= logging.INFO:
|
|
LOGGER.error(
|
|
"Running again with option '-v' may give more information."
|
|
)
|
|
sys.exit(1)
|
|
except KeyboardInterrupt:
|
|
LOGGER.warning("Aborted by user.")
|
|
sys.exit(1)
|
|
|
|
sys.exit(0)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|