From 70db99ebf6f74cbffebf824a731ef64b27432d15 Mon Sep 17 00:00:00 2001 From: slackish Date: Tue, 18 Oct 2016 09:36:24 -0600 Subject: [PATCH 1/9] starting zip capability --- package-puzzles | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100755 package-puzzles diff --git a/package-puzzles b/package-puzzles new file mode 100755 index 0000000..0304ca4 --- /dev/null +++ b/package-puzzles @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 + +import argparse +import base64 +import glob +import hashlib +import hmac +import io +import json +import os +import markdown +import random +import uuid +import zipfile + +messageChars = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + +def djb2hash(buf): + h = 5381 + for c in buf: + h = ((h * 33) + c) & 0xffffffff + return h + +def write_kv_pairs(ziphandle, filename, kv): + filehandle = io.StringIO() + for key in sorted(kv.keys()): + if type(kv[key]) == type([]): + for val in kv[key]: + filehandle.write("%s: %s%s" % (key, val, os.linesep)) + else: + filehandle.write("%s: %s%s" % (key, kv[key], os.linesep)) + filehandle.seek(0) + ziphandle.writestr(filename, filehandle.read()) + +class Puzzle: + def __init__(self, stream): + self.message = bytes(random.choice(messageChars) for i in range(20)) + self.fields = {} + self.answers = [] + self.hashes = [] + + body = [] + header = True + for line in stream: + if header: + line = line.strip() + if not line.strip(): + header = False + continue + key, val = line.split(':', 1) + key = key.lower() + val = val.strip() + self._add_field(key, val) + else: + body.append(line) + self.body = ''.join(body) + + def _add_field(self, key, val): + if key == 'answer': + h = djb2hash(val.encode('utf8')) + self.answers.append(val) + self.hashes.append(h) + else: + self.fields[key] = val + + def publish(self): + obj = { + 'author': self.fields['author'], + 'hashes': self.hashes, + 'body': markdown.markdown(self.body), + } + return obj + + def secrets(self): + obj = { + 'answers': self.answers, + 'summary': self.fields['summary'], + } + return obj + + +parser = argparse.ArgumentParser(description='Build a puzzle category') +parser.add_argument('seed', help='contest seed') +parser.add_argument('puzzledir', nargs='+', help='Directory of puzzle source') +parser.add_argument('outdir', help='Output directory') +args = parser.parse_args() + + +for puzzledir in args.puzzledir: + puzzles = {} + secrets = {} + + + categoryname = os.path.basename(puzzledir.strip(os.sep)) + + # build puzzle seed + puzzle_seed = hashlib.new('sha1') + puzzle_seed.update(categoryname.encode('utf-8')) + puzzle_seed.update(args.seed.encode('utf-8')) + puzzle_seed = puzzle_seed.hexdigest() + + # create zipfile + zipfilename = os.path.join(args.outdir, "%s.zip" % categoryname) + if os.path.exists(zipfilename): +# assume blank state for now + pass +# # open and gather some state +# zf = zipfile.ZipFile(zipfilename, 'a') + else: + # create and read in state + zf = zipfile.ZipFile(zipfilename, 'w') + + # read in puzzle details (will be pflarr in future) + for puzzlePath in glob.glob(os.path.join(puzzledir, "*.moth")): + filename = os.path.basename(puzzlePath) + points, ext = os.path.splitext(filename) + points = int(points) + puzzle = Puzzle(open(puzzlePath)) + puzzles[points] = puzzle + + # build mapping, answers, and summary + mapping = {} + answers = {} + summary = {} + for points in sorted(puzzles): + puzzle = puzzles[points] + + mapping[points] = str(uuid.uuid4()) # random uuid + answers[points] = puzzle.answers + summary[points] = puzzle.fields['summary'] + + # write mapping, answers, and summary + write_kv_pairs(zf, os.path.join(categoryname, 'mapping.txt'), mapping) + write_kv_pairs(zf, os.path.join(categoryname, 'answers.txt'), answers) + write_kv_pairs(zf, os.path.join(categoryname, 'summary.txt'), summary) + print(mapping) + print(answers) + print(summary) + + # write out puzzles + for points in sorted(puzzles): + puzzle = puzzles[points] + + +#vim:py From f865f3d0a3750a551823458c2a393e548a7843d0 Mon Sep 17 00:00:00 2001 From: slackish Date: Tue, 18 Oct 2016 09:36:24 -0600 Subject: [PATCH 2/9] starting zip capability --- package-puzzles | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100755 package-puzzles diff --git a/package-puzzles b/package-puzzles new file mode 100755 index 0000000..0304ca4 --- /dev/null +++ b/package-puzzles @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 + +import argparse +import base64 +import glob +import hashlib +import hmac +import io +import json +import os +import markdown +import random +import uuid +import zipfile + +messageChars = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + +def djb2hash(buf): + h = 5381 + for c in buf: + h = ((h * 33) + c) & 0xffffffff + return h + +def write_kv_pairs(ziphandle, filename, kv): + filehandle = io.StringIO() + for key in sorted(kv.keys()): + if type(kv[key]) == type([]): + for val in kv[key]: + filehandle.write("%s: %s%s" % (key, val, os.linesep)) + else: + filehandle.write("%s: %s%s" % (key, kv[key], os.linesep)) + filehandle.seek(0) + ziphandle.writestr(filename, filehandle.read()) + +class Puzzle: + def __init__(self, stream): + self.message = bytes(random.choice(messageChars) for i in range(20)) + self.fields = {} + self.answers = [] + self.hashes = [] + + body = [] + header = True + for line in stream: + if header: + line = line.strip() + if not line.strip(): + header = False + continue + key, val = line.split(':', 1) + key = key.lower() + val = val.strip() + self._add_field(key, val) + else: + body.append(line) + self.body = ''.join(body) + + def _add_field(self, key, val): + if key == 'answer': + h = djb2hash(val.encode('utf8')) + self.answers.append(val) + self.hashes.append(h) + else: + self.fields[key] = val + + def publish(self): + obj = { + 'author': self.fields['author'], + 'hashes': self.hashes, + 'body': markdown.markdown(self.body), + } + return obj + + def secrets(self): + obj = { + 'answers': self.answers, + 'summary': self.fields['summary'], + } + return obj + + +parser = argparse.ArgumentParser(description='Build a puzzle category') +parser.add_argument('seed', help='contest seed') +parser.add_argument('puzzledir', nargs='+', help='Directory of puzzle source') +parser.add_argument('outdir', help='Output directory') +args = parser.parse_args() + + +for puzzledir in args.puzzledir: + puzzles = {} + secrets = {} + + + categoryname = os.path.basename(puzzledir.strip(os.sep)) + + # build puzzle seed + puzzle_seed = hashlib.new('sha1') + puzzle_seed.update(categoryname.encode('utf-8')) + puzzle_seed.update(args.seed.encode('utf-8')) + puzzle_seed = puzzle_seed.hexdigest() + + # create zipfile + zipfilename = os.path.join(args.outdir, "%s.zip" % categoryname) + if os.path.exists(zipfilename): +# assume blank state for now + pass +# # open and gather some state +# zf = zipfile.ZipFile(zipfilename, 'a') + else: + # create and read in state + zf = zipfile.ZipFile(zipfilename, 'w') + + # read in puzzle details (will be pflarr in future) + for puzzlePath in glob.glob(os.path.join(puzzledir, "*.moth")): + filename = os.path.basename(puzzlePath) + points, ext = os.path.splitext(filename) + points = int(points) + puzzle = Puzzle(open(puzzlePath)) + puzzles[points] = puzzle + + # build mapping, answers, and summary + mapping = {} + answers = {} + summary = {} + for points in sorted(puzzles): + puzzle = puzzles[points] + + mapping[points] = str(uuid.uuid4()) # random uuid + answers[points] = puzzle.answers + summary[points] = puzzle.fields['summary'] + + # write mapping, answers, and summary + write_kv_pairs(zf, os.path.join(categoryname, 'mapping.txt'), mapping) + write_kv_pairs(zf, os.path.join(categoryname, 'answers.txt'), answers) + write_kv_pairs(zf, os.path.join(categoryname, 'summary.txt'), summary) + print(mapping) + print(answers) + print(summary) + + # write out puzzles + for points in sorted(puzzles): + puzzle = puzzles[points] + + +#vim:py From 1ba99db98f23c0a8899120285406428bf4d5e1c4 Mon Sep 17 00:00:00 2001 From: slackish Date: Tue, 18 Oct 2016 10:46:54 -0600 Subject: [PATCH 3/9] puzzle directories are writing --- package-puzzles | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/package-puzzles b/package-puzzles index 0304ca4..8b6f39f 100755 --- a/package-puzzles +++ b/package-puzzles @@ -10,7 +10,6 @@ import json import os import markdown import random -import uuid import zipfile messageChars = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' @@ -124,22 +123,30 @@ for puzzledir in args.puzzledir: summary = {} for points in sorted(puzzles): puzzle = puzzles[points] + print(args.seed) + print(categoryname) + print(points) - mapping[points] = str(uuid.uuid4()) # random uuid + hashmap = hashlib.sha1(args.seed.encode('utf-8')) + hashmap.update(categoryname.encode('utf-8')) + hashmap.update(str(points).encode('utf-8')) + mapping[points] = hashmap.hexdigest() answers[points] = puzzle.answers summary[points] = puzzle.fields['summary'] # write mapping, answers, and summary - write_kv_pairs(zf, os.path.join(categoryname, 'mapping.txt'), mapping) + write_kv_pairs(zf, os.path.join(categoryname, 'map.txt'), mapping) write_kv_pairs(zf, os.path.join(categoryname, 'answers.txt'), answers) write_kv_pairs(zf, os.path.join(categoryname, 'summary.txt'), summary) - print(mapping) - print(answers) - print(summary) # write out puzzles for points in sorted(puzzles): puzzle = puzzles[points] + puzzledir = os.path.join(categoryname, "content", mapping[points]) + # test write + write_kv_pairs(zf, os.path.join(puzzledir, 'summary.txt'), summary) + # build json + #vim:py From 36c93973ccab4ee7cb78889347cf44c23a8d0813 Mon Sep 17 00:00:00 2001 From: slackish Date: Tue, 18 Oct 2016 15:42:42 -0600 Subject: [PATCH 4/9] some updates to package-puzzles --- package-puzzles | 180 +++++++++++++++++------------------------------- 1 file changed, 65 insertions(+), 115 deletions(-) diff --git a/package-puzzles b/package-puzzles index 8b6f39f..5ea2b0b 100755 --- a/package-puzzles +++ b/package-puzzles @@ -12,15 +12,15 @@ import markdown import random import zipfile -messageChars = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' - -def djb2hash(buf): - h = 5381 - for c in buf: - h = ((h * 33) + c) & 0xffffffff - return h +import puzzles def write_kv_pairs(ziphandle, filename, kv): + """ Write out a sorted map to file + :param ziphandle: a zipfile object + :param filename: The filename to write within the zipfile object + :param kv: the map to write out + :return: + """ filehandle = io.StringIO() for key in sorted(kv.keys()): if type(kv[key]) == type([]): @@ -30,123 +30,73 @@ def write_kv_pairs(ziphandle, filename, kv): filehandle.write("%s: %s%s" % (key, kv[key], os.linesep)) filehandle.seek(0) ziphandle.writestr(filename, filehandle.read()) + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Build a puzzle category') + parser.add_argument('seed', help='contest seed') + parser.add_argument('puzzledir', nargs='+', help='Directory of puzzle source') + parser.add_argument('outdir', help='Output directory') + args = parser.parse_args() -class Puzzle: - def __init__(self, stream): - self.message = bytes(random.choice(messageChars) for i in range(20)) - self.fields = {} - self.answers = [] - self.hashes = [] - body = [] - header = True - for line in stream: - if header: - line = line.strip() - if not line.strip(): - header = False - continue - key, val = line.split(':', 1) - key = key.lower() - val = val.strip() - self._add_field(key, val) - else: - body.append(line) - self.body = ''.join(body) + for puzzledir in args.puzzledir: + puzzles = {} + secrets = {} - def _add_field(self, key, val): - if key == 'answer': - h = djb2hash(val.encode('utf8')) - self.answers.append(val) - self.hashes.append(h) - else: - self.fields[key] = val - def publish(self): - obj = { - 'author': self.fields['author'], - 'hashes': self.hashes, - 'body': markdown.markdown(self.body), - } - return obj - - def secrets(self): - obj = { - 'answers': self.answers, - 'summary': self.fields['summary'], - } - return obj - + categoryname = os.path.basename(puzzledir.strip(os.sep)) -parser = argparse.ArgumentParser(description='Build a puzzle category') -parser.add_argument('seed', help='contest seed') -parser.add_argument('puzzledir', nargs='+', help='Directory of puzzle source') -parser.add_argument('outdir', help='Output directory') -args = parser.parse_args() + # build puzzle seed + puzzle_seed = hashlib.new('sha1') + puzzle_seed.update(categoryname.encode('utf-8')) + puzzle_seed.update(args.seed.encode('utf-8')) + puzzle_seed = puzzle_seed.hexdigest() + # create zipfile + zipfilename = os.path.join(args.outdir, "%s.zip" % categoryname) + if os.path.exists(zipfilename): + # assume blank state for now + pass + # # open and gather some state + # zf = zipfile.ZipFile(zipfilename, 'a') + else: + # create and read in state + zf = zipfile.ZipFile(zipfilename, 'w') -for puzzledir in args.puzzledir: - puzzles = {} - secrets = {} + # read in puzzle details (will be pflarr in future) + for puzzlePath in glob.glob(os.path.join(puzzledir, "*.moth")): + filename = os.path.basename(puzzlePath) + points, ext = os.path.splitext(filename) + points = int(points) + puzzle = puzzles.Puzzle(open(puzzlePath)) + puzzles[points] = puzzle + # build mapping, answers, and summary + mapping = {} + answers = {} + summary = {} + for points in sorted(puzzles): + puzzle = puzzles[points] + hashmap = hashlib.sha1(args.seed.encode('utf-8')) + hashmap.update(categoryname.encode('utf-8')) + hashmap.update(str(points).encode('utf-8')) + mapping[points] = hashmap.hexdigest() + answers[points] = puzzle.answers + summary[points] = puzzle.fields['summary'] - categoryname = os.path.basename(puzzledir.strip(os.sep)) - - # build puzzle seed - puzzle_seed = hashlib.new('sha1') - puzzle_seed.update(categoryname.encode('utf-8')) - puzzle_seed.update(args.seed.encode('utf-8')) - puzzle_seed = puzzle_seed.hexdigest() - - # create zipfile - zipfilename = os.path.join(args.outdir, "%s.zip" % categoryname) - if os.path.exists(zipfilename): -# assume blank state for now - pass -# # open and gather some state -# zf = zipfile.ZipFile(zipfilename, 'a') - else: - # create and read in state - zf = zipfile.ZipFile(zipfilename, 'w') - - # read in puzzle details (will be pflarr in future) - for puzzlePath in glob.glob(os.path.join(puzzledir, "*.moth")): - filename = os.path.basename(puzzlePath) - points, ext = os.path.splitext(filename) - points = int(points) - puzzle = Puzzle(open(puzzlePath)) - puzzles[points] = puzzle - - # build mapping, answers, and summary - mapping = {} - answers = {} - summary = {} - for points in sorted(puzzles): - puzzle = puzzles[points] - print(args.seed) - print(categoryname) - print(points) - - hashmap = hashlib.sha1(args.seed.encode('utf-8')) - hashmap.update(categoryname.encode('utf-8')) - hashmap.update(str(points).encode('utf-8')) - mapping[points] = hashmap.hexdigest() - answers[points] = puzzle.answers - summary[points] = puzzle.fields['summary'] - - # write mapping, answers, and summary - write_kv_pairs(zf, os.path.join(categoryname, 'map.txt'), mapping) - write_kv_pairs(zf, os.path.join(categoryname, 'answers.txt'), answers) - write_kv_pairs(zf, os.path.join(categoryname, 'summary.txt'), summary) - - # write out puzzles - for points in sorted(puzzles): - puzzle = puzzles[points] - puzzledir = os.path.join(categoryname, "content", mapping[points]) - # test write - write_kv_pairs(zf, os.path.join(puzzledir, 'summary.txt'), summary) - # build json - + # write mapping, answers, and summary + write_kv_pairs(zf, os.path.join(categoryname, 'map.txt'), mapping) + write_kv_pairs(zf, os.path.join(categoryname, 'answers.txt'), answers) + write_kv_pairs(zf, os.path.join(categoryname, 'summary.txt'), summary) + # write out puzzles + for points in sorted(puzzles): + puzzle = puzzles[points] + puzzledir = os.path.join(categoryname, 'content', mapping[points]) + # build/write json + ziphandle.writestr(filename, filehandle.read()) + zf.writestr(os.path.join(puzzledir, 'puzzle.json'), \ + json.dumps(puzzle.publish())) + # write associated files #vim:py From 4ba361e2768fa9d12ef924667daaf53db8c7d397 Mon Sep 17 00:00:00 2001 From: slackish Date: Tue, 18 Oct 2016 15:43:14 -0600 Subject: [PATCH 5/9] some changes to package puzzles, still gluing --- package-puzzles | 52 +++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/package-puzzles b/package-puzzles index 5ea2b0b..979feba 100755 --- a/package-puzzles +++ b/package-puzzles @@ -10,6 +10,7 @@ import json import os import markdown import random +import sys import zipfile import puzzles @@ -32,25 +33,23 @@ def write_kv_pairs(ziphandle, filename, kv): ziphandle.writestr(filename, filehandle.read()) if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Build a puzzle category') + parser = argparse.ArgumentParser(description='Build a category package') parser.add_argument('seed', help='contest seed') - parser.add_argument('puzzledir', nargs='+', help='Directory of puzzle source') + parser.add_argument('categorydirs', nargs='+', help='Directory of category source') parser.add_argument('outdir', help='Output directory') args = parser.parse_args() - - for puzzledir in args.puzzledir: - puzzles = {} + for categorydir in args.categorydirs: + puzzles_dict = {} secrets = {} - - categoryname = os.path.basename(puzzledir.strip(os.sep)) + categoryname = os.path.basename(categorydir.strip(os.sep)) - # build puzzle seed - puzzle_seed = hashlib.new('sha1') - puzzle_seed.update(categoryname.encode('utf-8')) - puzzle_seed.update(args.seed.encode('utf-8')) - puzzle_seed = puzzle_seed.hexdigest() + # build category seed + category_seed = hashlib.new('sha1') + category_seed.update(categoryname.encode('utf-8')) + category_seed.update(args.seed.encode('utf-8')) + category_seed = category_seed.hexdigest() # create zipfile zipfilename = os.path.join(args.outdir, "%s.zip" % categoryname) @@ -63,20 +62,24 @@ if __name__ == '__main__': # create and read in state zf = zipfile.ZipFile(zipfilename, 'w') - # read in puzzle details (will be pflarr in future) - for puzzlePath in glob.glob(os.path.join(puzzledir, "*.moth")): - filename = os.path.basename(puzzlePath) - points, ext = os.path.splitext(filename) - points = int(points) - puzzle = puzzles.Puzzle(open(puzzlePath)) - puzzles[points] = puzzle + # read in category details (will be pflarr in future) + for categorypath in glob.glob(os.path.join(categorydir, "*", "puzzle.moth")): + points = categorypath.split(os.sep)[-2] # directory before '/puzzle.moth' + categorypath = os.path.dirname(categorypath) + try: + points = int(points) + except: + print("Failed to identify points on: %s" % categorypath, file=sys.stderr) + continue + puzzle = puzzles.Puzzle(open(categorypath), category_seed) + puzzles_dict[points] = puzzle # build mapping, answers, and summary mapping = {} answers = {} summary = {} - for points in sorted(puzzles): - puzzle = puzzles[points] + for points in sorted(puzzles_dict): + puzzle = puzzles_dict[points] hashmap = hashlib.sha1(args.seed.encode('utf-8')) hashmap.update(categoryname.encode('utf-8')) hashmap.update(str(points).encode('utf-8')) @@ -90,13 +93,16 @@ if __name__ == '__main__': write_kv_pairs(zf, os.path.join(categoryname, 'summary.txt'), summary) # write out puzzles - for points in sorted(puzzles): - puzzle = puzzles[points] + for points in sorted(puzzles_dict): + puzzle = puzzles_dict[points] puzzledir = os.path.join(categoryname, 'content', mapping[points]) # build/write json ziphandle.writestr(filename, filehandle.read()) zf.writestr(os.path.join(puzzledir, 'puzzle.json'), \ json.dumps(puzzle.publish())) # write associated files + for fobj in puzzle['files']: + zf.writestr(os.path.join(puzzledir, fobj.name), \ + fobj.handle.read()) #vim:py From ff2c0bc9997f77a300f7bb12644caac77b545ae8 Mon Sep 17 00:00:00 2001 From: slackish Date: Tue, 18 Oct 2016 16:06:11 -0600 Subject: [PATCH 6/9] checking in what i have --- package-puzzles | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package-puzzles b/package-puzzles index 979feba..18bad55 100755 --- a/package-puzzles +++ b/package-puzzles @@ -66,12 +66,13 @@ if __name__ == '__main__': for categorypath in glob.glob(os.path.join(categorydir, "*", "puzzle.moth")): points = categorypath.split(os.sep)[-2] # directory before '/puzzle.moth' categorypath = os.path.dirname(categorypath) + print(categorypath) try: points = int(points) except: print("Failed to identify points on: %s" % categorypath, file=sys.stderr) continue - puzzle = puzzles.Puzzle(open(categorypath), category_seed) + puzzle = puzzles.Puzzle(category_seed, categorypath) puzzles_dict[points] = puzzle # build mapping, answers, and summary From c388d271a2c0111467f1cb7f014b57972dd19a80 Mon Sep 17 00:00:00 2001 From: slackish Date: Tue, 18 Oct 2016 17:03:42 -0600 Subject: [PATCH 7/9] added a debug message to puzzles.py, got some resemblence of files working on package-puzzles --- package-puzzles | 26 +++++++++++++++++++++----- puzzles.py | 2 +- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/package-puzzles b/package-puzzles index 6bc6539..1d9c7da 100755 --- a/package-puzzles +++ b/package-puzzles @@ -85,8 +85,9 @@ if __name__ == '__main__': hashmap.update(categoryname.encode('utf-8')) hashmap.update(str(points).encode('utf-8')) mapping[points] = hashmap.hexdigest() - answers[points] = puzzle.answers - summary[points] = puzzle.fields['summary'] + answers[points] = puzzle['answer'] + if len(puzzle['summary']) > 0: + summary[points] = puzzle['summary'] # write mapping, answers, and summary write_kv_pairs(zf, os.path.join(categoryname, 'map.txt'), mapping) @@ -96,13 +97,28 @@ if __name__ == '__main__': # write out puzzles for points in sorted(puzzles_dict): puzzle = puzzles_dict[points] + puzzlebody = [json.dumps(puzzle.publish())] puzzledir = os.path.join(categoryname, 'content', mapping[points]) # build/write json - ziphandle.writestr(filename, filehandle.read()) - zf.writestr(os.path.join(puzzledir, 'puzzle.json'), \ - json.dumps(puzzle.publish())) + # write associated files + assoc_files = [] for fobj in puzzle['files']: + if fobj.visible == True: + assoc_files.append(fobj.name) zf.writestr(os.path.join(puzzledir, fobj.name), \ fobj.handle.read()) + + + if len(assoc_files) > 0: + puzzlebody.append("") + puzzlebody.append("## Associated Files:") + for f in assoc_files: + puzzlebody.append(f) + + puzzlebody = os.linesep.join(puzzlebody) + + # non-optimal writing of file-like objects, but it works + zf.writestr(os.path.join(puzzledir, 'puzzle.json'), \ + json.dumps(puzzle.publish())) #vim:py diff --git a/puzzles.py b/puzzles.py index 3923f89..b7b3a53 100644 --- a/puzzles.py +++ b/puzzles.py @@ -171,7 +171,7 @@ class Puzzle: # Make sure it actually exists. if not os.path.exists(path): - raise ValueError("Included file {} does not exist.") + raise ValueError("Included file {} does not exist.".format(path)) file = open(path, 'rb') From 2b29ffcf3d9e03242473d64a6721d66da3adbbfe Mon Sep 17 00:00:00 2001 From: slackish Date: Thu, 20 Oct 2016 12:48:48 -0600 Subject: [PATCH 8/9] Associated files now included in puzzle.json --- package-puzzles | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/package-puzzles b/package-puzzles index 1d9c7da..3141fb8 100755 --- a/package-puzzles +++ b/package-puzzles @@ -97,9 +97,8 @@ if __name__ == '__main__': # write out puzzles for points in sorted(puzzles_dict): puzzle = puzzles_dict[points] - puzzlebody = [json.dumps(puzzle.publish())] puzzledir = os.path.join(categoryname, 'content', mapping[points]) - # build/write json + puzzlejson = puzzle.publish() # write associated files assoc_files = [] @@ -109,14 +108,8 @@ if __name__ == '__main__': zf.writestr(os.path.join(puzzledir, fobj.name), \ fobj.handle.read()) - if len(assoc_files) > 0: - puzzlebody.append("") - puzzlebody.append("## Associated Files:") - for f in assoc_files: - puzzlebody.append(f) - - puzzlebody = os.linesep.join(puzzlebody) + puzzlejson["associated_files"] = assoc_files # non-optimal writing of file-like objects, but it works zf.writestr(os.path.join(puzzledir, 'puzzle.json'), \ From 962fa791f65648417431f9910a7f655062a609f8 Mon Sep 17 00:00:00 2001 From: slackish Date: Thu, 20 Oct 2016 13:27:34 -0600 Subject: [PATCH 9/9] category_seed now getting read or generated --- package-puzzles | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/package-puzzles b/package-puzzles index 3141fb8..344d85a 100755 --- a/package-puzzles +++ b/package-puzzles @@ -1,20 +1,20 @@ #!/usr/bin/env python3 import argparse -import base64 +import binascii import glob import hashlib -import hmac import io import json import os -import markdown -import random +import shutil import sys import zipfile import puzzles +TMPFILE = "%s.tmp" + def write_kv_pairs(ziphandle, filename, kv): """ Write out a sorted map to file :param ziphandle: a zipfile object @@ -34,7 +34,6 @@ def write_kv_pairs(ziphandle, filename, kv): if __name__ == '__main__': parser = argparse.ArgumentParser(description='Build a category package') - parser.add_argument('seed', help='contest seed') parser.add_argument('categorydirs', nargs='+', help='Directory of category source') parser.add_argument('outdir', help='Output directory') args = parser.parse_args() @@ -45,22 +44,20 @@ if __name__ == '__main__': categoryname = os.path.basename(categorydir.strip(os.sep)) - # build category seed - category_seed = hashlib.new('sha1') - category_seed.update(categoryname.encode('utf-8')) - category_seed.update(args.seed.encode('utf-8')) - category_seed = category_seed.hexdigest() - # create zipfile zipfilename = os.path.join(args.outdir, "%s.zip" % categoryname) if os.path.exists(zipfilename): - # assume blank state for now - pass - # # open and gather some state - # zf = zipfile.ZipFile(zipfilename, 'a') - else: - # create and read in state - zf = zipfile.ZipFile(zipfilename, 'w') + # open and gather some state + zf = zipfile.ZipFile(zipfilename, 'r') + try: + category_seed = zf.open(os.path.join(categoryname, "category_seed.txt")).read().strip() + except: + pass + zf.close() + + zf = zipfile.ZipFile(TMPFILE % zipfilename, 'w') + if 'category_seed' not in locals(): + category_seed = binascii.b2a_hex(os.urandom(20)) # read in category details (will be pflarr in future) for categorypath in glob.glob(os.path.join(categorydir, "*", "puzzle.moth")): @@ -81,18 +78,18 @@ if __name__ == '__main__': summary = {} for points in sorted(puzzles_dict): puzzle = puzzles_dict[points] - hashmap = hashlib.sha1(args.seed.encode('utf-8')) - hashmap.update(categoryname.encode('utf-8')) + hashmap = hashlib.sha1(category_seed) hashmap.update(str(points).encode('utf-8')) mapping[points] = hashmap.hexdigest() answers[points] = puzzle['answer'] if len(puzzle['summary']) > 0: summary[points] = puzzle['summary'] - # write mapping, answers, and summary + # write mapping, answers, summary, category_seed write_kv_pairs(zf, os.path.join(categoryname, 'map.txt'), mapping) write_kv_pairs(zf, os.path.join(categoryname, 'answers.txt'), answers) write_kv_pairs(zf, os.path.join(categoryname, 'summary.txt'), summary) + zf.writestr(os.path.join(categoryname, "category_seed.txt"), category_seed) # write out puzzles for points in sorted(puzzles_dict): @@ -114,4 +111,8 @@ if __name__ == '__main__': # non-optimal writing of file-like objects, but it works zf.writestr(os.path.join(puzzledir, 'puzzle.json'), \ json.dumps(puzzle.publish())) + + # clean up + zf.close() + shutil.move(TMPFILE % zipfilename, zipfilename) #vim:py