webis.py 4.58 KB
Newer Older
1
#!/usr/bin/env python3
Martin Potthast's avatar
Martin Potthast committed
2
"""The main webis command.
Steve Goering's avatar
Steve Goering committed
3

Martin Potthast's avatar
Martin Potthast committed
4 5
Copyright webis.de 2015-today
Authors: Steve Göring, Martin Potthast
Steve Goering's avatar
Steve Goering committed
6
"""
Martin Potthast's avatar
Martin Potthast committed
7

8
import argparse
Martin Potthast's avatar
Martin Potthast committed
9
import collections
10
import json
Martin Potthast's avatar
Martin Potthast committed
11 12
import os
import sys
13

Steve Goering's avatar
Steve Goering committed
14 15
import loader

16
from lib import *
Martin Potthast's avatar
Martin Potthast committed
17
from log import *
18 19 20
from system import *


Martin Potthast's avatar
Martin Potthast committed
21 22 23 24 25 26 27 28
def load_config():
    """Returns the configuration, based on the JSON configuration file."""
    try:
        return json.loads(read_file(os.path.dirname(
            os.path.realpath(__file__)) + "/config.json"))
    except Exception as e:
        lError("The file config.json is invalid.")
        sys.exit(1)
29

Steve Goering's avatar
Steve Goering committed
30

Martin Potthast's avatar
Martin Potthast committed
31 32 33
def get_commands(config):
    """Returns commands mapped to directories containing their subcommands."""
    commands = collections.OrderedDict()
34 35
    for directory in os.listdir(config["commands_directory"]):
        if (os.path.isdir(config["commands_directory"] + directory) and
Steve Goering's avatar
Steve Goering committed
36
                directory not in config["ignored_dirs"]):
37
            commands[directory] = config["commands_directory"] + directory
Martin Potthast's avatar
Martin Potthast committed
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
    return commands


def get_subcommands(config, commandpath):
    """Returns subcommands of a given command mapped to their script files."""
    subcommands = collections.OrderedDict()
    for script in os.listdir(commandpath):
        subcommandpath = commandpath + "/" + script
        if os.path.isfile(subcommandpath):
            allowed_scripts = config["allowed_scripts"]
            if check_subcommand_shebang(subcommandpath, allowed_scripts):
                subcommand = script.rsplit(".", 1)[0]
                subcommands[subcommand] = subcommandpath
    return subcommands


def get_subcommand_help(subcommandpath):
    """Returns the help message expected at the beginning of a command."""
    if not os.path.isfile(subcommandpath):
        return os.path.basename(subcommandpath)

    f = open(subcommandpath)
60 61 62 63 64 65 66
    lines = f.readlines()
    f.close()
    if len(lines) < 1 or lines[1][0] != "#":
        return ""
    return lines[1][1:].replace("\n", "").strip()


Martin Potthast's avatar
Martin Potthast committed
67 68 69 70 71 72 73
def check_subcommand_shebang(subcommandpath, allowed_scripts):
    """Checks if the shebang of a given script is among the allowed shebangs."""
    shebang = get_shebang(subcommandpath)
    for interpreter in allowed_scripts:
        if interpreter in shebang:
            return True
    return False
Steve Goering's avatar
Steve Goering committed
74

75

Martin Potthast's avatar
Martin Potthast committed
76 77 78 79 80 81
def run_subcommand(subcommand, subcommandpath, params=[]):
    """Runs subcommand passing params and returns its exit code."""
    lDbg("Running " + subcommand + " at " + subcommandpath)
    # FIXME: When the script is installed at /usr/lib, this won't work, anymore:
    os.system("chmod +x {}".format(subcommandpath))
    cmd = " ".join([subcommandpath] + params)
82 83
    return_value = os.system(cmd)
    if return_value == 0:
Martin Potthast's avatar
Martin Potthast committed
84
        lInfo("Done.")
85
    else:
Martin Potthast's avatar
Martin Potthast committed
86
        lError("An error occurred while executing " + cmd)
87
    return return_value
88 89 90


def main(args):
Martin Potthast's avatar
Martin Potthast committed
91 92 93 94 95 96 97 98 99
    config = load_config()
    commands = get_commands(config)
    parser = argparse.ArgumentParser()
    subparsers = {}
    allcommands = {}
    commandparsers = parser.add_subparsers(
        metavar='<command>', dest='<command>', help='Available commands:')
    for command in commands:
        # TODO: It is unclear where to obtain the help messages for commands.
Martin Potthast's avatar
Martin Potthast committed
100
        # TODO: It is conceivable to introduce aliases for each command, but it
Martin Potthast's avatar
Martin Potthast committed
101 102
        # is unclear where to obtain them. Simply using a prefix does not
        # work for betamng and betaweb, since they share a long prefix.
Steve Goering's avatar
Steve Goering committed
103 104
        commandparser = commandparsers.add_parser(
            command, help='TODO: Help message for commands.')
Martin Potthast's avatar
Martin Potthast committed
105 106 107 108 109 110 111 112 113
        subparsers[command] = commandparser
        subcommandparsers = commandparser.add_subparsers(
            metavar='<subcommand>', dest='<subcommand>',
            help='Available subcommands:')
        subcommands = get_subcommands(config, commands[command])
        allcommands[command] = subcommands
        for subcommand in subcommands:
            subcommandparser = subcommandparsers.add_parser(
                subcommand, help=str(
Steve Goering's avatar
Steve Goering committed
114
                    get_subcommand_help(subcommands[subcommand])),
Martin Potthast's avatar
Martin Potthast committed
115 116 117 118 119
                add_help=False)
            subparsers[subcommand] = subcommandparser

    if len(args) == 0:
        parser.print_help()
120 121
        return 0

Martin Potthast's avatar
Martin Potthast committed
122 123 124
    parseresults = parser.parse_known_args(args)
    argsdict = vars(parseresults[0])
    parameter = parseresults[1]
Steve Goering's avatar
Steve Goering committed
125 126

    if len(argsdict) == 2 and argsdict['<subcommand>'] is None:
Martin Potthast's avatar
Martin Potthast committed
127 128
        subparsers[argsdict['<command>']].print_help()
        return 0
129

Steve Goering's avatar
Steve Goering committed
130 131 132 133
    return run_subcommand(
        argsdict['<subcommand>'],
        allcommands[argsdict['<command>']][argsdict['<subcommand>']],
        parameter)
134 135 136 137


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))