-
-
Save ecnerwala/ffc9b8c3f61e87ca043393a135d7794d to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3 | |
"""Download and setup problems from Competitive Companion | |
Usage: | |
download_prob.py --echo | |
download_prob.py [<name>... | -n <number> | -b <batches> | --timeout <timeout>] [--dryrun] | |
Options: | |
-h --help Show this screen. | |
--echo Just echo received responses and exit. | |
--dryrun Don't actually create any problems | |
Download limit options: | |
-n COUNT, --number COUNT Number of problems. | |
-b COUNT, --batches COUNT Number of batches. (Default 1 batch) | |
-t TIME, --timeout TIME Timeout for listening to problems. in seconds | |
""" | |
from docopt import docopt | |
import sys | |
import http.server | |
import json | |
from pathlib import Path | |
import subprocess | |
import re | |
# Returns unmarshalled or None | |
def listen_once(*, timeout=None): | |
json_data = None | |
class CompetitiveCompanionHandler(http.server.BaseHTTPRequestHandler): | |
def do_POST(self): | |
nonlocal json_data | |
json_data = json.load(self.rfile) | |
with http.server.HTTPServer(('127.0.0.1', 10046), CompetitiveCompanionHandler) as server: | |
server.timeout = timeout | |
server.handle_request() | |
if json_data is not None: | |
print(f"Got data {json.dumps(json_data)}") | |
else: | |
print("Got no data") | |
return json_data | |
def listen_many(*, num_items=None, num_batches=None, timeout=None): | |
if num_items is not None: | |
res = [] | |
for _ in range(num_items): | |
cur = listen_once(timeout=None) | |
res.append(cur) | |
return res | |
if num_batches is not None: | |
res = [] | |
batches = {} | |
while len(batches) < num_batches or any(need for need, tot in batches.values()): | |
print(f"Waiting for {num_batches} batches:", batches) | |
cur = listen_once(timeout=None) | |
res.append(cur) | |
cur_batch = cur['batch'] | |
batch_id = cur_batch['id'] | |
batch_cnt = cur_batch['size'] | |
if batch_id not in batches: | |
batches[batch_id] = [batch_cnt, batch_cnt] | |
assert batches[batch_id][0] > 0 | |
batches[batch_id][0] -= 1 | |
return res | |
res = [listen_once(timeout=None)] | |
while True: | |
cnd = listen_once(timeout=timeout) | |
if cnd is None: | |
break | |
res.append(cnd) | |
return res | |
NAME_PATTERN = re.compile(r'^(?:Problem )?([A-Z][0-9]*)\b') | |
def get_prob_name(data): | |
if 'USACO' in data['group']: | |
if 'fileName' in data['input']: | |
names = [data['input']['fileName'].rstrip('.in'), data['output']['fileName'].rstrip('.out')] | |
if len(set(names)) == 1: | |
return names[0] | |
if 'url' in data and data['url'].startswith('https://www.codechef.com'): | |
return data['url'].rstrip('/').rsplit('/')[-1] | |
patternMatch = NAME_PATTERN.search(data['name']) | |
if patternMatch is not None: | |
return patternMatch.group(1) | |
print(f"For data: {json.dumps(data, indent=2)}") | |
return input("What name to give? ") | |
def save_samples(data, prob_dir): | |
with open(prob_dir / 'problem.json', 'w') as f: | |
json.dump(data, f) | |
for i, t in enumerate(data['tests'], start=1): | |
with open(prob_dir / f'sample{i}.in', 'w') as f: | |
f.write(t['input']) | |
with open(prob_dir / f'sample{i}.out', 'w') as f: | |
f.write(t['output']) | |
# Providing name = '.' | |
def make_prob(data, name=None): | |
if name is None: | |
name = get_prob_name(data) | |
prob_dir = Path('.')/name | |
if name == '.': | |
print("Using current directory...") | |
pass | |
elif prob_dir.exists() and prob_dir.is_dir(): | |
# Skip making it | |
print(f"Already created problem {name}...") | |
else: | |
print(f"Creating problem {name}...") | |
MAKE_PROB = Path(sys.path[0]) / 'make_prob.sh' | |
try: | |
subprocess.check_call([MAKE_PROB, name], stdout=sys.stdout, stderr=sys.stderr) | |
except subprocess.CalledProcessError as e: | |
print(f"Got error {e}") | |
return | |
print("Saving samples...") | |
save_samples(data, prob_dir) | |
print() | |
def main(): | |
arguments = docopt(__doc__) | |
if arguments['--echo']: | |
while True: | |
print(listen_once()) | |
else: | |
dryrun = arguments['--dryrun'] | |
def run_make_prob(*args, **kwargs): | |
nonlocal dryrun | |
if dryrun: | |
print(f"make_prob(*args={args}, **kwargs={kwargs})") | |
return | |
make_prob(*args, **kwargs) | |
if names := arguments['<name>']: | |
datas = listen_many(num_items=len(names)) | |
for data, name in zip(datas, names): | |
run_make_prob(data, name) | |
elif cnt := arguments['--number']: | |
cnt = int(cnt) | |
datas = listen_many(num_items=cnt) | |
for data in datas: | |
run_make_prob(data) | |
elif batches := arguments['--batches']: | |
batches = int(batches) | |
datas = listen_many(num_batches=batches) | |
for data in datas: | |
run_make_prob(data) | |
elif timeout := arguments['--timeout']: | |
timeout = float(timeout) | |
datas = listen_many(timeout=timeout) | |
for data in datas: | |
run_make_prob(data) | |
else: | |
datas = listen_many(num_batches=1) | |
for data in datas: | |
run_make_prob(data) | |
if __name__ == '__main__': | |
main() |
#!/usr/bin/env bash | |
DIR=$(dirname $0) | |
search_up () | |
( | |
while [[ $PWD != "/" ]]; do | |
if [[ -e "$1" ]]; then | |
pwd | |
if [[ ! -e "$1/$2" ]]; then | |
break | |
fi | |
fi | |
cd .. | |
done | |
) | |
TEMPLATE_DIR='.template' | |
PARENT_FILE='$PARENT' | |
IFS=$'\n' | |
TEMPLATE_DIRS=($(search_up "$TEMPLATE_DIR" "$PARENT_FILE" | tac)) | |
unset IFS | |
TEMPLATE_DIRS=(${TEMPLATE_DIRS[@]/%/\/"$TEMPLATE_DIR"}) | |
if hash rename.ul 2>/dev/null; then | |
RENAME=rename.ul | |
else | |
RENAME=rename | |
fi | |
for filepath in "$@"; do | |
PROBLEM_NAME=$(basename "$filepath") | |
if [[ -e "$filepath" ]]; then | |
echo "$filepath already exists. Remove it and retry." | |
continue | |
fi | |
# Copy files in | |
mkdir -p "$filepath" | |
for CURRENT_TEMPLATE_DIR in "${TEMPLATE_DIRS[@]}"; do | |
cp -r -T "$CURRENT_TEMPLATE_DIR" "$filepath/" | |
done | |
rm -f "$filepath/$PARENT_FILE" | |
# Rename PROBLEM_NAME in file names | |
find $filepath -type f -print0 | xargs -0 ${RENAME} "\$PROBLEM_NAME" "$PROBLEM_NAME" | |
# Envsubst PROBLEM_NAME in files | |
export PROBLEM_NAME | |
REPLACE_STRING='${PROBLEM_NAME}' | |
find $filepath -type f -print0 | xargs -0 -I{} bash -c\ | |
'TEMP=$(mktemp) && cat "$1" > "$TEMP" && envsubst '"'$REPLACE_STRING'"' < "$TEMP" > "$1" && rm "$TEMP"'\ | |
-- {} | |
pushd $filepath > /dev/null | |
if [[ -e "setup" ]]; then | |
echo "Running setup" | |
./setup | |
fi | |
popd > /dev/null | |
done |
Hi there, I'm confused by $PARENT since it's empty in mac. What exact meaning it is? Is it the folder name like "Codeforces 746"?
Very weird, someone else reported something like that too. I verified that it's the same code as on my computer, so I'm not sure what the difference is. Maybe there's something with docopt versions or something? (By the way, the right usage is ./download_prob.py A B C
to download 3 problems named A B C)
Excuse me, docopt version to install? I tried it on a Mac but it gives me the same error, I think my docopt version is wrong.
It's just the newest one (0.6.2 I think).
For anyone with the same issue, add a new line after Usage ends. Here is the link where I found the solution:
https://stackoverflow.com/questions/31901138/docopt-on-python-3-only-prints-help-screen-and-does-not-execute-the-function
For anyone with the same issue, add a new line after Usage ends. Here is the link where I found the solution: https://stackoverflow.com/questions/31901138/docopt-on-python-3-only-prints-help-screen-and-does-not-execute-the-function
Huh, isn't there already a newline? Strange
For anyone with the same issue, add a new line after Usage ends. Here is the link where I found the solution: https://stackoverflow.com/questions/31901138/docopt-on-python-3-only-prints-help-screen-and-does-not-execute-the-function
Huh, isn't there already a newline? Strange
That is really strange. For some reason when I copied the contents of download_prob.py the newline after Usage was gone ...
Hm, that happens to me if I copy from this page (with syntax highlighting), but not if I copy from the Raw version. I guess there's some funny HTML/CSS going on. I guess that explains it then.
#ecnerwala can you share your setup file and the whole process how to setup nvim
Nevermind
I made it work by using
cat
,echo
andsed
commands instead of the lines46-54
in make_prob.shI'm adding my make_prob.sh here, in case anyone finds it useful