2019-04-03 04:27:37 +00:00
|
|
|
__package__ = 'archivebox.cli'
|
2020-07-02 07:53:39 +00:00
|
|
|
__command__ = 'archivebox'
|
2019-04-03 04:27:37 +00:00
|
|
|
|
|
|
|
import os
|
2020-07-02 08:00:51 +00:00
|
|
|
import sys
|
2020-07-02 07:53:39 +00:00
|
|
|
import argparse
|
|
|
|
|
|
|
|
from typing import Optional, Dict, List, IO
|
|
|
|
|
|
|
|
from ..config import OUTPUT_DIR
|
2019-04-19 01:09:54 +00:00
|
|
|
|
2019-04-03 04:27:37 +00:00
|
|
|
from importlib import import_module
|
|
|
|
|
|
|
|
CLI_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
2019-04-19 01:09:54 +00:00
|
|
|
# these common commands will appear sorted before any others for ease-of-use
|
2019-04-27 21:26:24 +00:00
|
|
|
meta_cmds = ('help', 'version')
|
|
|
|
main_cmds = ('init', 'info', 'config')
|
|
|
|
archive_cmds = ('add', 'remove', 'update', 'list')
|
|
|
|
|
|
|
|
display_first = (*meta_cmds, *main_cmds, *archive_cmds)
|
2019-04-03 04:27:37 +00:00
|
|
|
|
2019-04-19 01:09:54 +00:00
|
|
|
# every imported command module must have these properties in order to be valid
|
|
|
|
required_attrs = ('__package__', '__command__', 'main')
|
2019-04-03 04:27:37 +00:00
|
|
|
|
2019-04-19 01:09:54 +00:00
|
|
|
# basic checks to make sure imported files are valid subcommands
|
|
|
|
is_cli_module = lambda fname: fname.startswith('archivebox_') and fname.endswith('.py')
|
|
|
|
is_valid_cli_module = lambda module, subcommand: (
|
|
|
|
all(hasattr(module, attr) for attr in required_attrs)
|
|
|
|
and module.__command__.split(' ')[-1] == subcommand
|
|
|
|
)
|
2019-04-11 10:59:14 +00:00
|
|
|
|
2020-07-02 07:53:39 +00:00
|
|
|
|
2019-04-19 01:09:54 +00:00
|
|
|
def list_subcommands() -> Dict[str, str]:
|
|
|
|
"""find and import all valid archivebox_<subcommand>.py files in CLI_DIR"""
|
2019-04-11 10:59:14 +00:00
|
|
|
|
|
|
|
COMMANDS = []
|
2019-04-03 04:27:37 +00:00
|
|
|
for filename in os.listdir(CLI_DIR):
|
2019-04-19 01:09:54 +00:00
|
|
|
if is_cli_module(filename):
|
2019-04-03 04:27:37 +00:00
|
|
|
subcommand = filename.replace('archivebox_', '').replace('.py', '')
|
|
|
|
module = import_module('.archivebox_{}'.format(subcommand), __package__)
|
2019-04-19 01:09:54 +00:00
|
|
|
assert is_valid_cli_module(module, subcommand)
|
2019-05-01 03:10:48 +00:00
|
|
|
COMMANDS.append((subcommand, module.main.__doc__))
|
2019-04-19 01:09:54 +00:00
|
|
|
globals()[subcommand] = module.main
|
|
|
|
|
|
|
|
display_order = lambda cmd: (
|
|
|
|
display_first.index(cmd[0])
|
|
|
|
if cmd[0] in display_first else
|
|
|
|
100 + len(cmd[0])
|
|
|
|
)
|
2019-04-03 04:27:37 +00:00
|
|
|
|
2019-04-19 01:09:54 +00:00
|
|
|
return dict(sorted(COMMANDS, key=display_order))
|
2019-04-03 04:27:37 +00:00
|
|
|
|
|
|
|
|
2019-04-27 21:26:24 +00:00
|
|
|
def run_subcommand(subcommand: str,
|
|
|
|
subcommand_args: List[str]=None,
|
|
|
|
stdin: Optional[IO]=None,
|
|
|
|
pwd: Optional[str]=None) -> None:
|
2019-05-01 03:10:48 +00:00
|
|
|
"""Run a given ArchiveBox subcommand with the given list of args"""
|
2019-04-03 04:27:37 +00:00
|
|
|
|
|
|
|
module = import_module('.archivebox_{}'.format(subcommand), __package__)
|
2019-04-27 21:26:24 +00:00
|
|
|
module.main(args=subcommand_args, stdin=stdin, pwd=pwd) # type: ignore
|
2019-04-19 01:09:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
SUBCOMMANDS = list_subcommands()
|
|
|
|
|
2020-07-02 17:31:05 +00:00
|
|
|
class NotProvided:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def main(args: Optional[List[str]]=NotProvided, stdin: Optional[IO]=NotProvided, pwd: Optional[str]=None) -> None:
|
|
|
|
args = sys.argv[1:] if args is NotProvided else args
|
|
|
|
stdin = sys.stdin if stdin is NotProvided else stdin
|
2020-07-02 07:53:39 +00:00
|
|
|
|
|
|
|
subcommands = list_subcommands()
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
prog=__command__,
|
|
|
|
description='ArchiveBox: The self-hosted internet archive',
|
|
|
|
add_help=False,
|
|
|
|
)
|
|
|
|
group = parser.add_mutually_exclusive_group()
|
|
|
|
group.add_argument(
|
|
|
|
'--help', '-h',
|
|
|
|
action='store_true',
|
|
|
|
help=subcommands['help'],
|
|
|
|
)
|
|
|
|
group.add_argument(
|
|
|
|
'--version',
|
|
|
|
action='store_true',
|
|
|
|
help=subcommands['version'],
|
|
|
|
)
|
|
|
|
group.add_argument(
|
|
|
|
"subcommand",
|
|
|
|
type=str,
|
|
|
|
help= "The name of the subcommand to run",
|
|
|
|
nargs='?',
|
|
|
|
choices=subcommands.keys(),
|
|
|
|
default=None,
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"subcommand_args",
|
|
|
|
help="Arguments for the subcommand",
|
|
|
|
nargs=argparse.REMAINDER,
|
|
|
|
)
|
|
|
|
command = parser.parse_args(args or ())
|
|
|
|
|
|
|
|
if command.help or command.subcommand is None:
|
|
|
|
command.subcommand = 'help'
|
|
|
|
if command.version:
|
|
|
|
command.subcommand = 'version'
|
|
|
|
|
|
|
|
run_subcommand(
|
|
|
|
subcommand=command.subcommand,
|
|
|
|
subcommand_args=command.subcommand_args,
|
|
|
|
stdin=stdin,
|
|
|
|
pwd=pwd or OUTPUT_DIR,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2019-04-19 01:09:54 +00:00
|
|
|
__all__ = (
|
|
|
|
'SUBCOMMANDS',
|
|
|
|
'list_subcommands',
|
|
|
|
'run_subcommand',
|
|
|
|
*SUBCOMMANDS.keys(),
|
|
|
|
)
|