Skip to content

Commit b205953

Browse files
mzuennimpsijm
authored andcommitted
make legacy export an explicit command
1 parent 8efc27e commit b205953

File tree

4 files changed

+114
-105
lines changed

4 files changed

+114
-105
lines changed

bin/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@
120120
grep -Ev '^(h|jobs|time|verbose)$' | sed "s/^/'/;s/$/',/" | tr '\n' ' ' | sed 's/^/ARGS_LIST: Final[Sequence[str]] = [/;s/, $/]\n/'
121121
"""
122122
# fmt: off
123-
ARGS_LIST: Final[Sequence[str]] = ['1', 'add', 'all', 'answer', 'api', 'author', 'check_deterministic', 'clean', 'colors', 'contest', 'contest_id', 'contestname', 'cp', 'default_solution', 'depth', 'directory', 'error', 'force', 'force_build', 'generic', 'input', 'interaction', 'interactive', 'invalid', 'kattis', 'language', 'memory', 'more', 'move_to', 'no_bar', 'no_generate', 'no_solution', 'no_solutions', 'no_testcase_sanity_checks', 'no_time_limit', 'no_validators', 'no_visualizer', 'open', 'order', 'order_from_ccs', 'overview', 'password', 'post_freeze', 'problem', 'problemname', 'remove', 'reorder', 'samples', 'sanitizer', 'skel', 'skip', 'sort', 'submissions', 'table', 'testcases', 'time_limit', 'timeout', 'token', 'tree', 'type', 'username', 'valid_output', 'watch', 'web', 'write']
123+
ARGS_LIST: Final[Sequence[str]] = ['1', 'add', 'all', 'answer', 'api', 'author', 'check_deterministic', 'clean', 'colors', 'contest', 'contest_id', 'contestname', 'cp', 'default_solution', 'depth', 'directory', 'error', 'force', 'force_build', 'generic', 'input', 'interaction', 'interactive', 'invalid', 'kattis', 'language', 'legacy', 'memory', 'more', 'move_to', 'no_bar', 'no_generate', 'no_solution', 'no_solutions', 'no_testcase_sanity_checks', 'no_time_limit', 'no_validators', 'no_visualizer', 'open', 'order', 'order_from_ccs', 'overview', 'password', 'post_freeze', 'problem', 'problemname', 'remove', 'reorder', 'samples', 'sanitizer', 'skel', 'skip', 'sort', 'submissions', 'table', 'testcases', 'time_limit', 'timeout', 'token', 'tree', 'type', 'username', 'valid_output', 'watch', 'web', 'write']
124124
# fmt: on
125125

126126

bin/export.py

Lines changed: 108 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -180,88 +180,16 @@ def add_testcase(in_file: Path):
180180
else:
181181
util.warn(f"No answer file found for {f}, skipping.")
182182

183-
# DOMjudge and Kattis do not support 2023-07-draft yet.
184-
# TODO: Remove once they do.
185-
from ruamel.yaml.comments import CommentedMap
186-
187-
yaml_path = export_dir / "problem.yaml"
188-
yaml_data = read_yaml(yaml_path)
189-
# drop format version -> legacy
190-
if "problem_format_version" in yaml_data:
191-
ryaml_filter(yaml_data, "problem_format_version")
192-
# type -> validation
193-
if "type" in yaml_data:
194-
ryaml_filter(yaml_data, "type")
195-
validation = []
196-
if problem.custom_output:
197-
validation.append("custom")
198-
if problem.interactive:
199-
validation.append("interactive")
200-
if problem.multi_pass:
201-
validation.append("multi-pass")
202-
else:
203-
validation.append("default")
204-
yaml_data["validation"] = " ".join(validation)
205-
# credits -> author
206-
if "credits" in yaml_data:
207-
ryaml_filter(yaml_data, "credits")
208-
if problem.settings.credits.authors:
209-
yaml_data["author"] = ", ".join(p.name for p in problem.settings.credits.authors)
210-
# change source:
211-
if problem.settings.source:
212-
if len(problem.settings.source) > 1:
213-
util.warn(f"Found multiple sources, using '{problem.settings.source[0].name}'.")
214-
yaml_data["source"] = problem.settings.source[0].name
215-
yaml_data["source_url"] = problem.settings.source[0].url
216-
# limits.time_multipliers -> time_multiplier / time_safety_margin
217-
if "limits" not in yaml_data or not yaml_data["limits"]:
218-
yaml_data["limits"] = CommentedMap()
219-
limits = yaml_data["limits"]
220-
if "time_multipliers" in limits:
221-
ryaml_filter(limits, "time_multipliers")
222-
limits["time_multiplier"] = problem.limits.ac_to_time_limit
223-
limits["time_safety_margin"] = problem.limits.time_limit_to_tle
224-
# drop explicit timelimit for kattis:
225-
if "time_limit" in limits:
226-
# keep this for kattis even when "time_limit" is supported
227-
ryaml_filter(limits, "time_limit")
228-
# validator_flags
229-
validator_flags = " ".join(
230-
problem.get_testdata_yaml(
231-
problem.path / "data",
232-
"output_validator_args",
233-
PrintBar("Getting validator_flags for legacy export"),
234-
)
235-
)
236-
if validator_flags:
237-
yaml_data["validator_flags"] = validator_flags
238-
# write legacy style yaml
239-
yaml_path.unlink()
240-
write_yaml(yaml_data, yaml_path)
241-
242-
# DOMjudge does not support 'limits.time_limit' in problem.yaml yet.
243-
# TODO: Remove this once it does.
244-
if not config.args.kattis:
245-
(export_dir / ".timelimit").write_text(str(problem.limits.time_limit))
246-
247-
# Replace \problemname{...} by the value of `name:` in problems.yaml in all .tex files.
248-
# This is needed because Kattis is currently still running the legacy version of the problem spec,
249-
# rather than 2023-07-draft.
250-
for f in (export_dir / "statement").iterdir():
251-
if f.is_file() and f.suffix == ".tex" and len(f.suffixes) >= 2:
252-
lang = f.suffixes[-2][1:]
253-
t = f.read_text()
254-
match = re.search(r"\\problemname\{\s*(\\problemyamlname)?\s*\}", t)
255-
if match:
256-
if lang in problem.settings.name:
257-
t = t.replace(match[0], r"\problemname{" + problem.settings.name[lang] + "}")
258-
f.unlink()
259-
f.write_text(t)
260-
else:
261-
util.error(f"{f}: no name set for language {lang}.")
262-
263-
# DOMjudge does not support constants.
264-
# TODO: Remove this if it ever does.
183+
# drop explicit timelimit for kattis
184+
if config.args.kattis:
185+
yaml_path = export_dir / "problem.yaml"
186+
yaml_data = read_yaml(yaml_path)
187+
if "limits" in yaml_data and "time_limit" in yaml_data["limits"]:
188+
ryaml_filter(yaml_data["limits"], "time_limit")
189+
yaml_path.unlink()
190+
write_yaml(yaml_data, yaml_path)
191+
192+
# substitute constants.
265193
if problem.settings.constants:
266194
constants_supported = [
267195
"data/**/testdata.yaml",
@@ -283,29 +211,106 @@ def add_testcase(in_file: Path):
283211
f.unlink()
284212
f.write_text(text)
285213

286-
# TODO: Remove this if we know others use the output_validator dir
287-
if (export_dir / "output_validator").exists():
288-
(export_dir / "output_validators").mkdir(parents=True)
289-
(export_dir / "output_validator").rename(
290-
export_dir / "output_validators" / "output_validator"
214+
# downgrade some parts of the problem to be more legacy like
215+
if config.args.legacy:
216+
from ruamel.yaml.comments import CommentedMap
217+
218+
# handle problem.yaml
219+
yaml_path = export_dir / "problem.yaml"
220+
yaml_data = read_yaml(yaml_path)
221+
# drop format version -> legacy
222+
if "problem_format_version" in yaml_data:
223+
ryaml_filter(yaml_data, "problem_format_version")
224+
# type -> validation
225+
if "type" in yaml_data:
226+
ryaml_filter(yaml_data, "type")
227+
validation = []
228+
if problem.custom_output:
229+
validation.append("custom")
230+
if problem.interactive:
231+
validation.append("interactive")
232+
if problem.multi_pass:
233+
validation.append("multi-pass")
234+
else:
235+
validation.append("default")
236+
yaml_data["validation"] = " ".join(validation)
237+
# credits -> author
238+
if "credits" in yaml_data:
239+
ryaml_filter(yaml_data, "credits")
240+
if problem.settings.credits.authors:
241+
yaml_data["author"] = ", ".join(p.name for p in problem.settings.credits.authors)
242+
# change source:
243+
if problem.settings.source:
244+
if len(problem.settings.source) > 1:
245+
util.warn(f"Found multiple sources, using '{problem.settings.source[0].name}'.")
246+
yaml_data["source"] = problem.settings.source[0].name
247+
yaml_data["source_url"] = problem.settings.source[0].url
248+
# limits.time_multipliers -> time_multiplier / time_safety_margin
249+
if "limits" not in yaml_data or not yaml_data["limits"]:
250+
yaml_data["limits"] = CommentedMap()
251+
limits = yaml_data["limits"]
252+
if "time_multipliers" in limits:
253+
ryaml_filter(limits, "time_multipliers")
254+
limits["time_multiplier"] = problem.limits.ac_to_time_limit
255+
limits["time_safety_margin"] = problem.limits.time_limit_to_tle
256+
# drop explicit timelimit
257+
if "time_limit" in limits:
258+
ryaml_filter(limits, "time_limit")
259+
# validator_flags
260+
validator_flags = " ".join(
261+
problem.get_testdata_yaml(
262+
problem.path / "data",
263+
"output_validator_args",
264+
PrintBar("Getting validator_flags for legacy export"),
265+
)
291266
)
267+
if validator_flags:
268+
yaml_data["validator_flags"] = validator_flags
269+
# write legacy style yaml
270+
yaml_path.unlink()
271+
write_yaml(yaml_data, yaml_path)
272+
273+
# handle time limit
274+
if not config.args.kattis:
275+
(export_dir / ".timelimit").write_text(str(problem.limits.time_limit))
276+
277+
# Replace \problemname{...} by the value of `name:` in problems.yaml in all .tex files.
278+
for f in (export_dir / "statement").iterdir():
279+
if f.is_file() and f.suffix == ".tex" and len(f.suffixes) >= 2:
280+
lang = f.suffixes[-2][1:]
281+
t = f.read_text()
282+
match = re.search(r"\\problemname\{\s*(\\problemyamlname)?\s*\}", t)
283+
if match:
284+
if lang in problem.settings.name:
285+
t = t.replace(match[0], rf"\problemname{{{problem.settings.name[lang]}}}")
286+
f.unlink()
287+
f.write_text(t)
288+
else:
289+
util.error(f"{f}: no name set for language {lang}.")
292290

293-
# TODO: Remove this if we know others import the statement folder
294-
if (export_dir / "statement").exists():
295-
(export_dir / "statement").rename(export_dir / "problem_statement")
296-
for d in ["solution", "problem_slide"]:
297-
for f in list(util.glob(problem.path, f"{d}/*")):
298-
if f.is_file():
299-
out = Path("problem_statement") / f.relative_to(problem.path / d)
300-
if out.exists():
301-
message(
302-
f"Can not export {f.relative_to(problem.path)} as {out}",
303-
"Zip",
304-
output,
305-
color_type=MessageType.WARN,
306-
)
307-
else:
308-
add_file(out, f)
291+
# rename output_validator dir
292+
if (export_dir / "output_validator").exists():
293+
(export_dir / "output_validators").mkdir(parents=True)
294+
(export_dir / "output_validator").rename(
295+
export_dir / "output_validators" / "output_validator"
296+
)
297+
298+
# rename statement dirs
299+
if (export_dir / "statement").exists():
300+
(export_dir / "statement").rename(export_dir / "problem_statement")
301+
for d in ["solution", "problem_slide"]:
302+
for f in list(util.glob(problem.path, f"{d}/*")):
303+
if f.is_file():
304+
out = Path("problem_statement") / f.relative_to(problem.path / d)
305+
if out.exists():
306+
message(
307+
f"Can not export {f.relative_to(problem.path)} as {out}",
308+
"Zip",
309+
output,
310+
color_type=MessageType.WARN,
311+
)
312+
else:
313+
add_file(out, f)
309314

310315
# Build .ZIP file.
311316
message("writing zip file", "Zip", output, color_type=MessageType.LOG)

bin/tools.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,11 @@ def build_parser():
808808
action="store_true",
809809
help="Make a zip more following the kattis problemarchive.com format.",
810810
)
811+
zipparser.add_argument(
812+
"--legacy",
813+
action="store_true",
814+
help="Make a zip more following the legacy format.",
815+
)
811816
zipparser.add_argument("--no-solutions", action="store_true", help="Do not compile solutions")
812817

813818
# Build a zip with all samples.

bin/upgrade.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,6 @@ def _upgrade(problem_path: Path, bar: ProgressBar) -> None:
369369
upgrade_generators_yaml(problem_path, bar)
370370
upgrade_statement(problem_path, bar)
371371
upgrade_output_validators(problem_path, bar)
372-
# update .in.statement?
373372
upgrade_problem_yaml(problem_path, bar)
374373

375374
bar.done()

0 commit comments

Comments
 (0)