mirror of https://github.com/dirtbags/moth.git
Transpiler now runs commands with JSON output
This commit is contained in:
parent
c020fb18c2
commit
890718e8bb
|
@ -12,6 +12,10 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"strconv"
|
"strconv"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
"os/exec"
|
||||||
|
"bytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,18 +36,28 @@ func PrngOfStrings(input ...string) (*rand.Rand) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func ParsePuzzle(puzzlePath string, seed string) (*Puzzle, error) {
|
func runPuzzleGen(puzzlePath string, seed string) (*Puzzle, error) {
|
||||||
puzzleFd, err := os.Open(puzzlePath)
|
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||||
if err != nil {
|
defer cancel()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer puzzleFd.Close()
|
|
||||||
|
|
||||||
puzzle, err := ParseMoth(puzzleFd)
|
cmd := exec.CommandContext(ctx, puzzlePath)
|
||||||
|
cmd.Env = append(
|
||||||
|
os.Environ(),
|
||||||
|
fmt.Sprintf("MOTH_PUZZLE_SEED=%s", seed),
|
||||||
|
)
|
||||||
|
stdout, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jsdec := json.NewDecoder(bytes.NewReader(stdout))
|
||||||
|
jsdec.DisallowUnknownFields()
|
||||||
|
puzzle := new(Puzzle)
|
||||||
|
err = jsdec.Decode(puzzle)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return puzzle, nil
|
return puzzle, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,22 +76,43 @@ func ParseCategory(categoryPath string, seed string) ([]PuzzleEntry, error) {
|
||||||
|
|
||||||
puzzleEntries := make([]PuzzleEntry, 0, len(puzzleDirs))
|
puzzleEntries := make([]PuzzleEntry, 0, len(puzzleDirs))
|
||||||
for _, puzzleDir := range puzzleDirs {
|
for _, puzzleDir := range puzzleDirs {
|
||||||
puzzlePath := filepath.Join(categoryPath, puzzleDir, "puzzle.moth")
|
var puzzle *Puzzle
|
||||||
puzzleSeed := fmt.Sprintf("%s/%s", seed, puzzleDir)
|
|
||||||
|
|
||||||
|
puzzlePath := filepath.Join(categoryPath, puzzleDir)
|
||||||
|
|
||||||
|
// Determine point value from directory name
|
||||||
points, err := strconv.Atoi(puzzleDir)
|
points, err := strconv.Atoi(puzzleDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Skipping %s: %v", puzzlePath, err)
|
log.Printf("Skipping %s: %v", puzzlePath, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
puzzle, err := ParsePuzzle(puzzlePath, puzzleSeed)
|
// Try the .moth file first
|
||||||
if err != nil {
|
puzzleMothPath := filepath.Join(puzzlePath, "puzzle.moth")
|
||||||
log.Printf("Skipping %s: %v", puzzlePath, err)
|
puzzleFd, err := os.Open(puzzleMothPath)
|
||||||
|
if err == nil {
|
||||||
|
defer puzzleFd.Close()
|
||||||
|
puzzle, err = ParseMoth(puzzleFd)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Skipping %s: %v", puzzleMothPath, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if os.IsNotExist(err) {
|
||||||
|
var genErr error
|
||||||
|
puzzleGenPath := filepath.Join(puzzlePath, "mkpuzzle")
|
||||||
|
puzzle, genErr = runPuzzleGen(puzzleGenPath, puzzlePath)
|
||||||
|
if genErr != nil {
|
||||||
|
log.Printf("Skipping %20s: %v", puzzleMothPath, err)
|
||||||
|
log.Printf("Skipping %20s: %v", puzzleGenPath, genErr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("Skipping %s: %v", puzzleMothPath, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
prng := PrngOfStrings(puzzleSeed)
|
// Create a category entry for this
|
||||||
|
prng := PrngOfStrings(puzzlePath)
|
||||||
idBytes := make([]byte, 16)
|
idBytes := make([]byte, 16)
|
||||||
prng.Read(idBytes)
|
prng.Read(idBytes)
|
||||||
id := hex.EncodeToString(idBytes)
|
id := hex.EncodeToString(idBytes)
|
||||||
|
@ -99,6 +134,10 @@ func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
baseSeedString := os.Getenv("SEED")
|
baseSeedString := os.Getenv("SEED")
|
||||||
|
|
||||||
|
jsenc := json.NewEncoder(os.Stdout)
|
||||||
|
jsenc.SetEscapeHTML(false)
|
||||||
|
jsenc.SetIndent("", " ")
|
||||||
|
|
||||||
for _, dirname := range flag.Args() {
|
for _, dirname := range flag.Args() {
|
||||||
categoryName := filepath.Base(dirname)
|
categoryName := filepath.Base(dirname)
|
||||||
categorySeed := fmt.Sprintf("%s/%s", baseSeedString, categoryName)
|
categorySeed := fmt.Sprintf("%s/%s", baseSeedString, categoryName)
|
||||||
|
@ -108,12 +147,9 @@ func main() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
jpuzzles, err := json.MarshalIndent(puzzles, "", " ")
|
if err := jsenc.Encode(puzzles); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(string(jpuzzles))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
Summary: YAML Metadata
|
||||||
|
Author: neale
|
||||||
|
Answer: YAML
|
||||||
|
Answer: yaml
|
||||||
|
Objective: |
|
||||||
|
Understand how YAML metadata can be used in a `.moth` file
|
||||||
|
Success:
|
||||||
|
Acceptable: |
|
||||||
|
Enter the answer and move on
|
||||||
|
Mastery: |
|
||||||
|
Create a `.moth` file using YAML metadata and serve it
|
||||||
|
through the devel server.
|
||||||
|
---
|
||||||
|
|
||||||
|
You can also provide metadata in YAML format.
|
||||||
|
This puzzle's `.moth` file serves as an example.
|
|
@ -0,0 +1,24 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
cat <<EOD
|
||||||
|
{
|
||||||
|
"pre": {
|
||||||
|
"authors": ["neale"],
|
||||||
|
"body": "\
|
||||||
|
<h1>Writing Your Own Generator<h1>\
|
||||||
|
<p>\
|
||||||
|
You can output the JSON puzzle format if you want.\
|
||||||
|
See the source of this puzzle for an example!\
|
||||||
|
</p>\
|
||||||
|
"
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"log": [
|
||||||
|
"There are many fields you can specify, aside from those in this file.",
|
||||||
|
"See puzzle.moth for the full spec.",
|
||||||
|
"MOTH_PUZZLE_SEED=$MOTH_PUZZLE_SEED"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"answers": ["JSON"]
|
||||||
|
}
|
||||||
|
EOD
|
Loading…
Reference in New Issue