refactor: refactor cli module

This commit is contained in:
2026-09-14 14:27:09 +08:00
parent 5aaad2f3b4
commit 312e323d1d
2 changed files with 162 additions and 51 deletions
+20 -10
View File
@@ -2,22 +2,32 @@ import logging
import sys
from . import pofile, render
from .cli import create_argparser
from .cli import parse, RcOpts, RcPotOpts, RcRenderOpts
def main() -> None:
logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")
parser = create_argparser()
args = parser.parse_args()
opts = parse()
try:
if args.command == "rc":
if args.rc_command == "pot":
pofile.generate(args.manifest, args.output)
elif args.rc_command == "render":
render.render(args.manifest, args.po, args.template, args.output)
except (ValueError, RuntimeError) as exc:
logging.fatal("%s", exc)
match opts.opts:
case RcOpts() as rc_opts:
match rc_opts.opts:
case RcPotOpts() as rc_pot_opts:
pofile.generate(rc_pot_opts.in_manifest, rc_pot_opts.out_pot)
case RcRenderOpts() as rc_rdr_opts:
render.render(
rc_rdr_opts.in_manifest,
rc_rdr_opts.in_po,
rc_rdr_opts.in_template,
rc_rdr_opts.out_rc,
)
case _:
raise RuntimeError(f"unhandled rc options: {rc_opts.opts!r}")
case _:
raise RuntimeError(f"unhandled options: {opts.opts!r}")
except Exception as e:
logging.fatal("Runtime error: %s", e, exc_info=True)
sys.exit(1)
+142 -41
View File
@@ -1,68 +1,109 @@
import enum
from argparse import ArgumentParser
from dataclasses import dataclass
from pathlib import Path
# region: Options and Commands
def create_argparser() -> ArgumentParser:
"""
Create MetaGlot argument parser.
:return: The built argument parser.
"""
parser = ArgumentParser(
prog="metaglot",
description="A command-line tool that unifies localization metadata for applications shipped on multiple platforms.",
)
commands = parser.add_subparsers(dest="command", required=True)
@dataclass(frozen=True)
class RcPotOpts:
in_manifest: Path
"""The path to input manifest file including translation strings."""
out_pot: Path
"""The path to output POT file."""
rc = commands.add_parser(
"rc",
help="Commands for Windows RC resource files.",
)
rc_commands = rc.add_subparsers(dest="rc_command", required=True)
rc_pot = rc_commands.add_parser(
"pot",
help="Generate a POT template from a string manifest.",
)
rc_pot.add_argument(
@dataclass(frozen=True)
class RcRenderOpts:
in_manifest: Path
"""The path to input manifest file including translation strings."""
in_po: list[Path]
"""The path to input PO files to read, each may be a glob pattern."""
in_template: Path
"""The path to the input user-provided Liquid for rendering."""
out_rc: Path
"""The path to the output rendered Windows RC file."""
@dataclass(frozen=True)
class RcOpts:
opts: RcPotOpts | RcRenderOpts
"""The option of one of subcommand."""
class RcCommand(enum.StrEnum):
Pot = "pot"
Render = "render"
@dataclass(frozen=True)
class Opts:
"""The root options."""
opts: RcOpts
"""The option of one of subcommand."""
class Command(enum.StrEnum):
Rc = "rc"
# endregion
# region: Parameter Register
_SUBCMD_DEST = "command"
_RC_SUBCMD_DEST = "rc_command"
_RC_POT_MANIFEST_DEST = "manifest"
_RC_POT_OUTPUT_DEST = "output"
_RC_RDR_MANIFEST_DEST = "manifest"
_RC_RDR_PO_DEST = "po"
_RC_RDR_TEMPLATE_DEST = "template"
_RC_RDR_OUTPUT_DEST = "output"
def _register_rc_pot_param(parser: ArgumentParser) -> None:
parser.add_argument(
"-m",
"--manifest",
dest="manifest",
dest=_RC_POT_MANIFEST_DEST,
action="store",
type=Path,
required=True,
help="The path to the string manifest file.",
help="The path to input manifest file including translation strings.",
metavar="FILE",
)
rc_pot.add_argument(
parser.add_argument(
"-o",
"--output",
dest="output",
dest=_RC_POT_OUTPUT_DEST,
action="store",
type=Path,
required=True,
help="The path of the POT file to write.",
help="The path to output POT file.",
metavar="FILE",
)
rc_render = rc_commands.add_parser(
"render",
help="Render a user-provided template with manifest data and PO translations.",
)
rc_render.add_argument(
def _register_rc_render_param(parser: ArgumentParser) -> None:
parser.add_argument(
"-m",
"--manifest",
dest="manifest",
dest=_RC_RDR_MANIFEST_DEST,
action="store",
type=Path,
required=True,
help="The path to the string manifest file.",
help="The path to input manifest file including translation strings.",
metavar="FILE",
)
rc_render.add_argument(
parser.add_argument(
"-p",
"--po",
dest="po",
dest=_RC_RDR_PO_DEST,
action="extend",
nargs="+",
type=Path,
@@ -70,25 +111,85 @@ def create_argparser() -> ArgumentParser:
help="The PO files to read, each may be a glob pattern.",
metavar="GLOB",
)
rc_render.add_argument(
parser.add_argument(
"-t",
"--template",
dest="template",
dest=_RC_RDR_TEMPLATE_DEST,
action="store",
type=Path,
required=True,
help="The path to the user-provided Liquid template.",
help="The path to the input user-provided Liquid for rendering.",
metavar="FILE",
)
rc_render.add_argument(
parser.add_argument(
"-o",
"--output",
dest="output",
dest=_RC_RDR_OUTPUT_DEST,
action="store",
type=Path,
required=True,
help="The path of the rendered file to write.",
help="The path to the output rendered Windows RC file.",
metavar="FILE",
)
return parser
def _register_rc_param(parser: ArgumentParser) -> None:
cmds = parser.add_subparsers(dest=_RC_SUBCMD_DEST, required=True)
pot_subcmd = cmds.add_parser(
RcCommand.Pot.value, help="Generate a POT template from given manifest."
)
_register_rc_pot_param(pot_subcmd)
render_subcmd = cmds.add_parser(
RcCommand.Render.value,
help="Render a user-provided template with manifest data and PO translations.",
)
_register_rc_render_param(render_subcmd)
def _register_param(parser: ArgumentParser) -> None:
cmds = parser.add_subparsers(dest=_SUBCMD_DEST, required=True)
rc_subcmd = cmds.add_parser(
Command.Rc.value, help="Commands for Windows RC resource files."
)
_register_rc_param(rc_subcmd)
# endregion
def parse() -> Opts:
"""
Parse MetaGlot command line options.
:return: The parsed command line options.
"""
parser = ArgumentParser(
prog="metaglot",
description="A command-line tool that unifies localization metadata for applications shipped on multiple platforms.",
)
_register_param(parser)
args = vars(parser.parse_args())
match Command(args[_SUBCMD_DEST]):
case Command.Rc:
match RcCommand(args[_RC_SUBCMD_DEST]):
case RcCommand.Pot:
rc_pot_opts = RcPotOpts(
args[_RC_POT_MANIFEST_DEST], args[_RC_POT_OUTPUT_DEST]
)
rc_opts = RcOpts(rc_pot_opts)
case RcCommand.Render:
rc_rdr_opts = RcRenderOpts(
args[_RC_RDR_MANIFEST_DEST],
args[_RC_RDR_PO_DEST],
args[_RC_RDR_TEMPLATE_DEST],
args[_RC_RDR_OUTPUT_DEST],
)
rc_opts = RcOpts(rc_rdr_opts)
case _:
raise ValueError(f"unhandled rc command: {args[_RC_SUBCMD_DEST]}")
opts = Opts(rc_opts)
case _:
raise ValueError(f"unhandled command: {args[_SUBCMD_DEST]}")
return opts