Transpiler now runs commands with JSON output

This commit is contained in:
Neale Pickett 2019-08-25 17:30:32 -06:00
parent c020fb18c2
commit 890718e8bb
3 changed files with 96 additions and 19 deletions

View File

@ -12,6 +12,10 @@ import (
"encoding/hex" "encoding/hex"
"strconv" "strconv"
"math/rand" "math/rand"
"context"
"time"
"os/exec"
"bytes"
) )
@ -32,14 +36,24 @@ 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)
defer cancel()
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
} }
defer puzzleFd.Close()
puzzle, err := ParseMoth(puzzleFd) jsdec := json.NewDecoder(bytes.NewReader(stdout))
jsdec.DisallowUnknownFields()
puzzle := new(Puzzle)
err = jsdec.Decode(puzzle)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -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
puzzleMothPath := filepath.Join(puzzlePath, "puzzle.moth")
puzzleFd, err := os.Open(puzzleMothPath)
if err == nil {
defer puzzleFd.Close()
puzzle, err = ParseMoth(puzzleFd)
if err != nil { if err != nil {
log.Printf("Skipping %s: %v", puzzlePath, err) 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))
} }
} }

View File

@ -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.

View File

@ -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