From ccd9cea29da8e0ea87bfb59df80e5f30e326f09d Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Mon, 14 Sep 2020 18:23:56 -0600 Subject: [PATCH] Standardize cat/puzzle command args --- example-puzzles/example/3/mkpuzzle | 37 +++++++++------- pkg/transpile/category.go | 33 ++++++-------- pkg/transpile/inventory.go | 4 ++ pkg/transpile/puzzle.go | 11 ++--- pkg/transpile/testdata/generated/mkcategory | 6 +-- pkg/transpile/testdata/static/3/mkpuzzle | 48 +++++++++------------ theme/puzzle.js | 6 --- 7 files changed, 69 insertions(+), 76 deletions(-) diff --git a/example-puzzles/example/3/mkpuzzle b/example-puzzles/example/3/mkpuzzle index 92df1da..5863e13 100755 --- a/example-puzzles/example/3/mkpuzzle +++ b/example-puzzles/example/3/mkpuzzle @@ -7,26 +7,12 @@ import random import shutil import sys -parser = argparse.ArgumentParser("Generate a puzzle") -parser.add_argument("--file", dest="file", help="File to provide, instead of puzzle") -parser.add_argument("--answer", dest="answer", help="Answer to check, instead of providing puzzle") -args = parser.parse_args() - -seed = hash(os.getenv("SEED")) -random.seed(seed) +random.seed(os.getenv("SEED", "")) words = ["apple", "pear", "peach", "tangerine", "orange", "potato", "carrot", "pea"] answer = ' '.join(random.sample(words, 4)) -if args.file: - f = open(args.file, "rb") - shutil.copyfileobj(f, sys.stdout.buffer) -elif args.answer: - if args.answer == answer: - print("correct") - else: - print("incorrect") -else: +def puzzle(): number = random.randint(20, 500) obj = { "Pre": { @@ -53,3 +39,22 @@ else: } } json.dump(obj, sys.stdout) + +def open_file(filename): + f = open(filename, "rb") + shutil.copyfileobj(f, sys.stdout.buffer) + +def check_answer(check): + if answer == check: + print("correct") + else: + print("incorrect") + +if len(sys.argv) == 1: + puzzle() +elif sys.argv[1] == "file": + open_file(sys.argv[2]) +elif sys.argv[1] == "answer": + check_answer(sys.argv[2]) +else: + raise RuntimeError("Unknown command: %s" % sys.argv[1]) diff --git a/pkg/transpile/category.go b/pkg/transpile/category.go index fb67339..110876c 100644 --- a/pkg/transpile/category.go +++ b/pkg/transpile/category.go @@ -6,6 +6,7 @@ import ( "encoding/json" "log" "os/exec" + "path" "strconv" "strings" "time" @@ -120,13 +121,19 @@ type FsCommandCategory struct { timeout time.Duration } -// Inventory returns a list of point values for this category. -func (c FsCommandCategory) Inventory() ([]int, error) { +func (c FsCommandCategory) run(command string, args ...string) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), c.timeout) defer cancel() - cmd := exec.CommandContext(ctx, c.command, "inventory") - stdout, err := cmd.Output() + cmdargs := append([]string{command}, args...) + cmd := exec.CommandContext(ctx, "./"+path.Base(c.command), cmdargs...) + cmd.Dir = path.Dir(c.command) + return cmd.Output() +} + +// Inventory returns a list of point values for this category. +func (c FsCommandCategory) Inventory() ([]int, error) { + stdout, err := c.run("inventory") if err != nil { return nil, err } @@ -143,11 +150,7 @@ func (c FsCommandCategory) Inventory() ([]int, error) { func (c FsCommandCategory) Puzzle(points int) (Puzzle, error) { var p Puzzle - ctx, cancel := context.WithTimeout(context.Background(), c.timeout) - defer cancel() - - cmd := exec.CommandContext(ctx, c.command, "puzzle", strconv.Itoa(points)) - stdout, err := cmd.Output() + stdout, err := c.run("puzzle", strconv.Itoa(points)) if err != nil { return p, err } @@ -163,21 +166,13 @@ func (c FsCommandCategory) Puzzle(points int) (Puzzle, error) { // Open returns an io.ReadCloser for the given filename. func (c FsCommandCategory) Open(points int, filename string) (ReadSeekCloser, error) { - ctx, cancel := context.WithTimeout(context.Background(), c.timeout) - defer cancel() - - cmd := exec.CommandContext(ctx, c.command, "file", strconv.Itoa(points), filename) - stdout, err := cmd.Output() + stdout, err := c.run("file", strconv.Itoa(points), filename) return nopCloser{bytes.NewReader(stdout)}, err } // Answer checks whether an answer is correct. func (c FsCommandCategory) Answer(points int, answer string) bool { - ctx, cancel := context.WithTimeout(context.Background(), c.timeout) - defer cancel() - - cmd := exec.CommandContext(ctx, c.command, "answer", strconv.Itoa(points), answer) - stdout, err := cmd.Output() + stdout, err := c.run("answer", strconv.Itoa(points), answer) if err != nil { log.Printf("ERROR: Answering %d points: %s", points, err) return false diff --git a/pkg/transpile/inventory.go b/pkg/transpile/inventory.go index 8c6f750..0acb11d 100644 --- a/pkg/transpile/inventory.go +++ b/pkg/transpile/inventory.go @@ -3,6 +3,7 @@ package transpile import ( "log" "sort" + "strings" "github.com/spf13/afero" ) @@ -20,6 +21,9 @@ func FsInventory(fs afero.Fs) (Inventory, error) { inv := make(Inventory) for _, ent := range dirEnts { + if strings.HasPrefix(ent.Name(), ".") { + continue + } if ent.IsDir() { name := ent.Name() c := NewFsCategory(fs, name) diff --git a/pkg/transpile/puzzle.go b/pkg/transpile/puzzle.go index 11f6b9c..ed5d433 100644 --- a/pkg/transpile/puzzle.go +++ b/pkg/transpile/puzzle.go @@ -338,18 +338,19 @@ type FsCommandPuzzle struct { timeout time.Duration } -func (fp FsCommandPuzzle) run(args ...string) ([]byte, error) { +func (fp FsCommandPuzzle) run(command string, args ...string) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), fp.timeout) defer cancel() - cmd := exec.CommandContext(ctx, "./"+path.Base(fp.command), args...) + cmdargs := append([]string{command}, args...) + cmd := exec.CommandContext(ctx, "./"+path.Base(fp.command), cmdargs...) cmd.Dir = path.Dir(fp.command) return cmd.Output() } // Puzzle returns a Puzzle struct for the current puzzle. func (fp FsCommandPuzzle) Puzzle() (Puzzle, error) { - stdout, err := fp.run() + stdout, err := fp.run("puzzle") if exiterr, ok := err.(*exec.ExitError); ok { return Puzzle{}, errors.New(string(exiterr.Stderr)) } else if err != nil { @@ -379,7 +380,7 @@ func (c nopCloser) Close() error { // Open returns a newly-opened file. // BUG(neale): FsCommandPuzzle.Open() reads everything into memory, and will suck for large files. func (fp FsCommandPuzzle) Open(filename string) (ReadSeekCloser, error) { - stdout, err := fp.run("--file", filename) + stdout, err := fp.run("file", filename) buf := nopCloser{bytes.NewReader(stdout)} if err != nil { return buf, err @@ -390,7 +391,7 @@ func (fp FsCommandPuzzle) Open(filename string) (ReadSeekCloser, error) { // Answer checks whether the given answer is correct. func (fp FsCommandPuzzle) Answer(answer string) bool { - stdout, err := fp.run("--answer", answer) + stdout, err := fp.run("answer", answer) if err != nil { log.Printf("ERROR: checking answer: %s", err) return false diff --git a/pkg/transpile/testdata/generated/mkcategory b/pkg/transpile/testdata/generated/mkcategory index cfa4892..67d96f9 100755 --- a/pkg/transpile/testdata/generated/mkcategory +++ b/pkg/transpile/testdata/generated/mkcategory @@ -20,9 +20,9 @@ case $1:$2:$3 in } } EOT - ;; - puzzle:*:) - fail "No such puzzle" + ;; + puzzle:*) + fail "No such puzzle: $2" ;; file:1:moo.txt) echo "Moo." diff --git a/pkg/transpile/testdata/static/3/mkpuzzle b/pkg/transpile/testdata/static/3/mkpuzzle index df19db0..8c28a89 100755 --- a/pkg/transpile/testdata/static/3/mkpuzzle +++ b/pkg/transpile/testdata/static/3/mkpuzzle @@ -1,7 +1,12 @@ #! /bin/sh -case $1 in - "") +fail () { + echo "ERROR: $*" 1>&2 + exit 1 +} + +case $1:$2 in + puzzle:) cat <<'EOT' { "Answers": ["answer"], @@ -12,34 +17,23 @@ case $1 in } EOT ;; - -file|--file) - case $2 in - moo.txt) - echo "Moo." - ;; - *) - echo "ERROR: no such file: $1" 1>&2 - exit 1 - ;; - esac + file:moo.txt) + echo "Moo." ;; - -answer|--answer) - case $2 in - moo) - echo "correct" - ;; - error) - echo "error" 1>&2 - exit 1 - ;; - *) - echo "incorrect" - ;; - esac + file:*) + fail "no such file: $1" + ;; + answer:moo) + echo "correct" + ;; + answer:error) + fail "you requested an error" + ;; + answer:*) + echo "incorrect" ;; *) - echo "ERROR: don't know what to do with $1" 1>&2 - exit 1 + fail "What is $1" ;; esac \ No newline at end of file diff --git a/theme/puzzle.js b/theme/puzzle.js index 49f03ce..9c8e42a 100644 --- a/theme/puzzle.js +++ b/theme/puzzle.js @@ -88,11 +88,6 @@ function submit(e) { e.preventDefault() let data = new FormData(e.target) - // Kludge for patterned answers - let xAnswer = data.get("xAnswer") - if (xAnswer) { - data.set("answer", xAnswer) - } window.data = data fetch("answer", { method: "POST", @@ -193,7 +188,6 @@ function answerCheck(e) { checkAnswer(answer) .then (correct => { - document.querySelector("[name=xAnswer").value = correct || answer if (correct) { ok.textContent = "⭕" ok.title = "Possibly correct"