def add_reference_solution(api: ApiClient, exercise_id, note, runtime_environment, files): solution = api.create_reference_solution(exercise_id, { "note": note, "runtimeEnvironmentId": runtime_environment, "files": [api.upload_file(file, open(file, "r")) for file in files] }) click.echo(solution["id"])
def run_import(config_dir: Path, api: ApiClient, exercise_folder, group_id, exercise_id=None, hwgroup_id=None): logging.basicConfig(level=logging.INFO) config = Config.load(config_dir / "codex_import.yml") logging.info("*** Importing from %s", exercise_folder) content_soup = load_content(exercise_folder) logging.info("content.xml loaded") # If no exercise ID was given, create a new, empty exercise if exercise_id is None: creation_payload = api.create_exercise(group_id) exercise_id = creation_payload["id"] logging.info("Exercise created with id %s", exercise_id) else: logging.info("Reusing exercise with id %s", exercise_id) # Upload additional files (attachments) and associate them with the exercise text_id, text = load_active_text(content_soup) attachment_ids = set() logging.info("Uploading attachments") for path in load_additional_files(exercise_folder, text_id): attachment_ids.add(upload_file(api, path)["id"]) if attachment_ids: api.add_exercise_attachments(exercise_id, list(attachment_ids)) logging.info("Uploaded attachments associated with the exercise") # Prepare the exercise text attachments = api.get_exercise_attachments(exercise_id) url_map = {item["name"]: "{}/v1/uploaded-files/{}/download".format(api.api_url, item["id"]) for item in attachments} text = replace_file_references(text, url_map) # Set the details of the new exercise details = load_details(content_soup) details["localizedTexts"] = [{ "locale": config.locale, "name": details["name"] or "", "description": details["description"] or "", "text": text or "" }] del details["name"] del details["description"] api.update_exercise(exercise_id, details) logging.info("Exercise details updated") # Upload exercise files and associate them with the exercise exercise_file_data = {} logging.info("Uploading supplementary exercise files") for name, path in load_exercise_files(exercise_folder): exercise_file_data[name] = upload_file(api, path, name) api.add_exercise_files(exercise_id, [data["id"] for data in exercise_file_data.values()]) logging.info("Uploaded exercise files associated with the exercise") # Configure environments extensions = list(load_allowed_extensions(content_soup)) environments = [config.extension_to_runtime[ext] for ext in extensions] env_data = {item["id"]: item for item in api.get_runtime_environments()} env_configs = [ { "runtimeEnvironmentId": env_id, "variablesTable": env_data[env_id]["defaultVariables"] } for env_id in environments ] api.update_environment_configs(exercise_id, env_configs) logging.info("Added environments %s", ", ".join(environments)) # Configure tests tests = load_codex_test_config(Path(exercise_folder) / "testdata" / "config") api.set_exercise_tests(exercise_id, [{"name": test.name} for test in tests]) test_id_map = {test["name"]: test["id"] for test in api.get_exercise_tests(exercise_id)} logging.info("Exercise tests configured") # Upload custom judges custom_judges = set(get_custom_judges(tests)) custom_judge_files = {} if custom_judges: logging.info("Uploading custom judges") for judge in custom_judges: judge_path = Path(exercise_folder).joinpath("testdata").joinpath(judge) custom_judge_files[judge] = upload_file(api, judge_path, judge_path.name) api.add_exercise_files(exercise_id, [data["id"] for data in custom_judge_files.values()]) logging.info("Uploaded judge files associated with the exercise") exercise_config = make_exercise_config( config, content_soup, [item["name"] for item in api.get_exercise_files(exercise_id)], api.get_pipelines(), tests, test_id_map ) api.update_exercise_config(exercise_id, exercise_config) logging.info("Exercise config updated") # Configure test limits if hwgroup_id is None: hwgroup_id = api.get_hwgroups()[0]['id'] for extension, environment_id in zip(extensions, environments): limits_config = {} for test in tests: key = extension if extension in test.limits.keys() else "default" limits_config[test_id_map[test.name]] = { "wall-time": test.limits[key].time_limit, "memory": test.limits[key].mem_limit } api.update_limits(exercise_id, environment_id, hwgroup_id, limits_config) logging.info("Limits set for environment %s", environment_id) # Upload reference solutions for solution_id, solution in load_reference_solution_details(content_soup, config.extension_to_runtime): path = load_reference_solution_file(solution_id, content_soup, exercise_folder) solution["files"] = [upload_file(api, path)["id"]] payload = api.create_reference_solution(exercise_id, solution) logging.info("New reference solution created, with id %s", payload["referenceSolution"]["id"])