Exemplo n.º 1
0
def _command_prep(**args):
    """Prepares the environment for selected problems.

    This command is idempotent irrespective of the "--force" switch.
    """
    conf_all = args['conf_all']
    dir_working = expanduser(conf_all['workdir'])

    # 1) Working directory has to exist.
    if not isdir(dir_working):
        error('Directory "' + dir_working + '" does not exist!')
        return ExitStatus.ERROR

    # 2) Establish contest directory.
    contest_obj = args['contest_obj']
    if conf_all['subdir_depth'] == 2:
        dir_contest = join(dir_working, contest_obj.id)
        safe_mkdir(dir_contest, force=conf_all['force'])
    else:
        dir_contest = dir_working

    # Proceed if there exists directory hierachy until this point
    if (isdir(dir_contest)):

        # 3) Establish problems directories.
        problems_objs = args['problems_objs']
        if conf_all['subdir_depth'] >= 1:
            problems_dirs = {}
            for prob in problems_objs:
                problems_dirs[prob] = join(dir_contest, prob.id)
                safe_mkdir(problems_dirs[prob], force=conf_all['force'])
        else:
            problems_dirs = {prob: dir_contest for prob in problems_objs}

        plugin_langs = args['plugin_langs']
        selected_langs = conf_all['lang']
        sep_langs = hac.SETTINGS_CONST['plugin_temp_sep'][DataType.LANG]

        plugin_runners = args['plugin_runners']
        selected_runners = conf_all['runner']
        sep_runners = hac.SETTINGS_CONST['plugin_temp_sep'][DataType.RUNNER]

        # 4) Create language and runner templates.
        # For each problem ...
        for prob in problems_objs:
            if isdir(problems_dirs[prob]):
                problem_path = join(problems_dirs[prob], prob.id)

                # ... create language for all selected languages.
                for lang in selected_langs:
                    assert sep_langs in lang
                    assert lang in plugin_langs

                    lang_ext = lang.split(sep_langs)[0]

                    lang_file = problem_path + os.extsep + lang_ext
                    safe_fwrite(lang_file, plugin_langs[lang],
                                force=conf_all['force'])

                # ... create runner for every combiantion of runner/language.
                for runn in selected_runners:
                    for lang in selected_langs:
                        assert sep_runners in runn
                        assert runn in plugin_runners

                        runn_ext = runn.split(sep_runners)[0]
                        lang_ext = lang.split(sep_langs)[0]

                        if lang_ext in plugin_runners[runn]:
                            runner_file = problem_path + os.extsep + \
                                          lang_ext + os.extsep + runn_ext
                            safe_fwrite(runner_file,
                                        plugin_runners[runn][lang_ext],
                                        force=conf_all['force'],
                                        executable=True)
                        else:
                            warn("Runner for [{0}/{1}] combo can't be created!"
                                  .format(runn, lang_ext))

                # 5) Dump inputs and outputs.
                if conf_all['tests'] >= 1:
                    for i, inp in enumerate(prob.inputs):
                        in_file = join(problems_dirs[prob],
                                       prob.id + os.extsep + str(i+1) +
                                       os.extsep + 'in')
                        safe_fwrite(in_file, inp, force=conf_all['force'])

                    for i, out in enumerate(prob.outputs):
                        out_file = join(problems_dirs[prob],
                                       prob.id + os.extsep + str(i+1) +
                                       os.extsep + 'out')
                        safe_fwrite(out_file, out, force=conf_all['force'])

    return ExitStatus.OK
Exemplo n.º 2
0
def main(args=sys.argv[1:]):
    """Execution flow of the application:

        1) discover and load plugins (languages, runners and sites)
            1a] read application global defaults
            1b] override with user's custom plugins
        2) handle configuration (hacrc files and CLI arguments)
            2a] read hacrc from application global defaults
            2b] override with user's hacrc
            2c] override with command-line arguments
        3) handle special command-line switches
        4) fetch data from site
        5) execute command (prep, show)
    """

    # -- PLUGIN-SYSTEM -------------------------------------------------------
    config_global_path = os.path.join(hac.SETTINGS_CONST["hac_root_path"],
                                      hac.SETTINGS_CONST["config_dir"])
    config_user_path = hac.SETTINGS_CONST["config_user_path"]
    # User configs override global configs
    config_paths = [config_user_path, config_global_path]

    #TODO NOW separate/refactor templating from plugin collection
    # Discover plug-ins (sites) and templates (runners, languages).
    plugin_langs = plugin_collect(config_paths, DataType.LANG)
    plugin_runners = plugin_collect(config_paths, DataType.RUNNER)
    plugin_sites = plugin_collect(config_paths, DataType.SITE)

    # Generating auxiliary data.
    #
    # For example:
    #   available_langs == ['cpp.0', 'cpp.1', 'py.15'], then
    #   choice_langs    == ['cpp', 'cpp.0', 'cpp.1', 'py', 'py.15']
    available_langs = plugin_langs.keys()
    sep_langs = hac.SETTINGS_CONST['plugin_temp_sep'][DataType.LANG]
    choice_langs = choice_generate(available_langs, sep_langs)

    available_runners = plugin_runners.keys()
    sep_runners = hac.SETTINGS_CONST['plugin_temp_sep'][DataType.RUNNER]
    choice_runners = choice_generate(available_runners, sep_runners)


    # -- READ CONFIG FILES ---------------------------------------------------
    # Construct and use parsers (utilize data from plug-ins).

    # Get parser arguments.
    pargs_pack_common = get_pargs_pack_common(
            choice_langs = choice_langs,
            choice_runners = choice_runners,
    )
    pargs_pack_cli = get_pargs_pack_cli()

    # Add arguments to parsers.
    parser_config = get_bare_config_parser()
    parser_cli = get_bare_cli_parser()

    pargs_packed_add(parser_config, pargs_pack_common)
    pargs_packed_add(parser_cli, pargs_pack_common)
    pargs_packed_add(parser_cli, pargs_pack_cli)

    # Get default application configuration (from files).
    config_global_file = os.path.join(hac.SETTINGS_CONST["hac_root_path"],
                                      hac.SETTINGS_CONST["config_dir"],
                                      hac.SETTINGS_CONST["config_filename"])
    assert os.path.exists(config_global_file)
    env_global = parser_config.parse_args(['@' + config_global_file])
    conf_global = vars(env_global)

    # Get user specific configuration (from files).
    config_user_file = os.path.join(hac.SETTINGS_CONST["config_user_path"],
                                    hac.SETTINGS_CONST["config_filename"])

    if os.path.exists(config_user_file):
        env_user = parser_config.parse_args(['@' + config_user_file])
        # Resolve configuration read from files
        conf_user = dict_override(conf_global, vars(env_user))
    else:
        conf_user = conf_global


    # -- READ CLI ------------------------------------------------------------
    # Special handling of CLI arguments.

    # Print help message and exit if:
    #
    #   - no arguments given OR
    #   - "-h" or "--help" is given as optional argument
    #
    if (len(args) == 0) or any([o in args for o in ("-h", "--help")]):
         parser_cli.print_help()
         sys.exit(ExitStatus.OK)

    # Print application version and exit if:
    #
    #   - "--version" is given as optional argument
    #
    if "--version" in args:
        print(
        "hac v{0}, License {1}, Copyright (C) 2014-2015 {2}".format(
                                    hac.__version__,
                                    hac.__license__,
                                    hac.__author__))
        sys.exit(ExitStatus.OK)

    # Copy global configuration to user's local directory if:
    #
    #   - "--copy-config" is given as optional argument
    #
    if "--copy-config" in args:
        safe_cpdir(os.path.join(hac.SETTINGS_CONST["hac_root_path"],
                                hac.SETTINGS_CONST["config_dir"]),
                   hac.SETTINGS_CONST["config_user_path"])

        sys.exit(ExitStatus.OK)

    # Use default command (from configuration files) if:
    #
    #   - no command given
    #
    margs_ind = mainargs_index(args)
    if (margs_ind == len(args)) or (args[margs_ind] not in app_commands):
        args.insert(margs_ind, conf_user["command"])

    # Notify user and exit if:
    #
    #   - no location (legal CONTEST / PROBLEM) given
    #
    if (len(args) == margs_ind + 1) and (args[margs_ind] in app_commands):
        error("No CONTEST / PROBLEM given!")
        sys.exit(ExitStatus.ERROR)


    # Regular handling of CLI arguments. Parse CLI arguments and resolve with
    # respect to configuration files.
    env_cli = parser_cli.parse_args(args=args)
    if env_cli:
        conf_all = dict_override(conf_user, vars(env_cli))
    else:
        conf_all = conf_user

    # -- PROCESS CONFIG / CLI ------------------------------------------------
    # Normalize aggregated configuration.

    # Reduce lang, runner lists and extract problems.
    conf_all["lang"] = list_reduce(conf_all["lang"])
    conf_all["runner"] = list_reduce(conf_all["runner"])
    conf_all["problems"] = conf_all["problems"][0]

    # Normalize lang and runner lists.
    # If available_langs == ['cpp.0', 'cpp.1', 'py.15'], then
    # conf_all["runner"] == ['cpp.0', 'cpp.1', 'py'] is normalized to
    # ['cpp.0', 'py.15']
    conf_all["lang"] = choice_normal(conf_all["lang"], available_langs)
    conf_all["runner"] = choice_normal(conf_all["runner"], available_runners)

    # Normalize location member (should be URL).
    if not conf_all['location'].startswith('http://') and \
       not conf_all['location'].startswith('https://'):
        conf_all['location'] = 'http://' + conf_all['location']


    # -- FETCH / PROCESS / PREPARE DATA --------------------------------------
    # NOTE: Matching done in two steps for testability.

    # Get site processor:
    #     1) Match site-processor, gets url of matched processor.
    site_url = plugin_match_site(plugin_sites, conf_all)
    #     2) Extract site-processor.
    site_matched = [site for site in plugin_sites if site_url == site.url]
    assert site_matched
    site_obj = site_matched[0]

    # Print the site specific info.
    if site_obj._info:
        print(site_obj._info)

    # Get contest data (utilize web-site processor).
    contest_url = site_obj.match_contest(conf_all)
    contest_obj = site_obj.get_contest(contest_url)

    # Get problems data (utilize web-site processor).
    problems_urls = site_obj.match_problems(conf_all)
    problems_objs = site_obj.get_problems(problems_urls)


    # -- EXECUTE -------------------------------------------------------------
    assert conf_all["command"] in app_commands

    # Execute selected command with all relevant information
    return app_commands[conf_all["command"]](
        conf_global = conf_global,
        conf_user = conf_user,
        conf_all = conf_all,
        plugin_langs = plugin_langs,
        plugin_runners = plugin_runners,
        plugin_sites = plugin_sites,
        site_obj = site_obj,
        contest_obj = contest_obj,
        problems_objs = problems_objs)