webis.py 4.68 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()
Martin Potthast's avatar
Martin Potthast committed
34 35
    # FIXME: Variable names should be English only; also "moduls" has been
    # renamed to "command".
Martin Potthast's avatar
Martin Potthast committed
36 37
    for directory in os.listdir(config["moduls_directory"]):
        if (os.path.isdir(config["moduls_directory"] + directory) and
Steve Goering's avatar
Steve Goering committed
38
                directory not in config["ignored_dirs"]):
Martin Potthast's avatar
Martin Potthast committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
            commands[directory] = config["moduls_directory"] + directory
    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)
62 63 64 65 66 67 68
    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
69 70 71 72 73 74 75
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
76

77

Martin Potthast's avatar
Martin Potthast committed
78 79 80 81 82 83
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)
84 85
    return_value = os.system(cmd)
    if return_value == 0:
Martin Potthast's avatar
Martin Potthast committed
86
        lInfo("Done.")
87
    else:
Martin Potthast's avatar
Martin Potthast committed
88
        lError("An error occurred while executing " + cmd)
89
    return return_value
90 91 92


def main(args):
Martin Potthast's avatar
Martin Potthast committed
93 94 95 96 97 98 99 100 101
    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
102
        # TODO: It is conceivable to introduce aliases for each command, but it
Martin Potthast's avatar
Martin Potthast committed
103 104
        # 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
105 106
        commandparser = commandparsers.add_parser(
            command, help='TODO: Help message for commands.')
Martin Potthast's avatar
Martin Potthast committed
107 108 109 110 111 112 113 114 115
        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
116
                    get_subcommand_help(subcommands[subcommand])),
Martin Potthast's avatar
Martin Potthast committed
117 118 119 120 121
                add_help=False)
            subparsers[subcommand] = subcommandparser

    if len(args) == 0:
        parser.print_help()
122 123
        return 0

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

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

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


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