Flesh out runtime

This commit is contained in:
akp 2021-10-20 21:04:27 +01:00
parent 61fede23ab
commit ce41860c5c
No known key found for this signature in database
GPG key ID: AA5726202C8879B7
8 changed files with 152 additions and 45 deletions

6
go.mod
View file

@ -2,11 +2,13 @@ module github.com/codemicro/adventOfCode
go 1.17
require github.com/AlecAivazis/survey/v2 v2.3.2
require (
github.com/AlecAivazis/survey/v2 v2.3.2 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/mattn/go-colorable v0.1.2 // indirect
github.com/mattn/go-isatty v0.0.8 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect

12
go.sum
View file

@ -1,18 +1,27 @@
github.com/AlecAivazis/survey/v2 v2.3.2 h1:TqTB+aDDCLYhf9/bD2TwSO8u8jDSmMUd2SUVO4gCnU8=
github.com/AlecAivazis/survey/v2 v2.3.2/go.mod h1:TH2kPCDU3Kqq7pLbnCWwZXDBjnhZtmsCle5EiYDJ2fg=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -20,6 +29,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=

View file

@ -5,32 +5,31 @@ import (
"io/ioutil"
)
type ChallengeInfo struct {
type Info struct {
InputFile string `json:"inputFile"`
TestCases struct {
One []struct {
Input string `json:"input"`
Expected int64 `json:"expected"`
} `json:"one"`
Two []struct {
Input string `json:"input"`
Expected int `json:"expected"`
} `json:"two"`
One []*TestCase `json:"one"`
Two []*TestCase `json:"two"`
} `json:"testCases"`
}
func LoadChallengeInfo(fname string) (*ChallengeInfo, error) {
type TestCase struct {
Input string `json:"input"`
Expected interface{} `json:"expected"`
}
func LoadChallengeInfo(fname string) (*Info, error) {
fcont, err := ioutil.ReadFile(fname)
if err != nil {
return nil, err
}
c := new(ChallengeInfo)
c := new(Info)
err = json.Unmarshal(fcont, c)
if err != nil {
return nil, err
}
return c, nil
}
}

View file

@ -96,16 +96,19 @@ func run() error {
challengeInputString := string(challengeInput)
runner := runners.Available[selectedImplementation](selectedChallenge.Dir)
runner.Queue(&runners.Task{
Part: 1,
Input: challengeInputString,
})
lookupTable := make(taskLookupTable)
setupTestTasks(challengeInfo, runner, &lookupTable)
setupMainTasks(challengeInputString, runner, &lookupTable)
fmt.Println("\nRunning...\n")
for roe := range runner.Run() {
if roe.Error != nil {
return roe.Error
}
fmt.Println(*roe.Result)
// fmt.Println(*roe.Result)
lookupTable[roe.Result.TaskID](roe.Result)
}
return nil

View file

@ -11,13 +11,14 @@ import (
)
type Task struct {
TaskID string `json:"task_id"`
Part Part `json:"part"`
Input string `json:"input"`
OutputDir string `json:"output_dir,omitempty"`
}
type Result struct {
TaskNumber int `json:"task_n"`
TaskID string `json:"task_id"`
Ok bool `json:"ok"`
Output string `json:"output"`
Duration float32 `json:"duration"`
@ -30,8 +31,6 @@ func makeErrorChan(err error) chan ResultOrError {
return c
}
// custom writer type
type customWriter struct {
pending []byte
entries [][]byte

View file

@ -3,19 +3,20 @@ from py import Challenge
import time
import json
TASKS_STR = """{{ .TasksJSON }}"""
TASKS_STR = input()
TASKS = json.loads(TASKS_STR)
def send_result(task_number, ok, output, duration):
def send_result(task_id, ok, output, duration):
print(json.dumps({
"task_n": task_number,
"task_id": task_id,
"ok": ok,
"output": str(output) if output is not None else "",
"duration": float(duration),
}), flush=True)
for task_number, task in enumerate(TASKS):
for task in TASKS:
taskPart = task["part"]
task_id = task["task_id"]
run = None
@ -26,7 +27,7 @@ for task_number, task in enumerate(TASKS):
elif taskPart == 3:
run = lambda: Challenge().vis(task["input"], task["output_dir"])
else:
send_result(task_number, False, "unknown task part", 0)
send_result(task_id, False, "unknown task part", 0)
continue
start_time = time.time()
@ -41,6 +42,6 @@ for task_number, task in enumerate(TASKS):
running_time = end_time-start_time
if err is not None:
send_result(task_number, False, err, running_time)
send_result(task_id, False, err, running_time)
else:
send_result(task_number, True, res, running_time)
send_result(task_id, True, res, running_time)

View file

@ -8,7 +8,6 @@ import (
"os"
"os/exec"
"path/filepath"
"text/template"
)
const python3Installation = "python3"
@ -29,32 +28,21 @@ func (p *pythonRunner) Queue(task *Task) {
}
//go:embed interface/python.py
var pythonInterface string
var pythonInterface []byte
func (p *pythonRunner) Run() chan ResultOrError {
wrapperFilename := "runtime-wrapper.py"
wrapperFilepath := filepath.Join(p.dir, wrapperFilename)
// Generate interaction code
// Generate interaction data
taskJSON, err := json.Marshal(p.tasks)
if err != nil {
return makeErrorChan(err)
}
interactionCodeBuffer := new(bytes.Buffer)
{
templ := template.Must(template.New("").Parse(pythonInterface))
err := templ.Execute(interactionCodeBuffer, struct{
TasksJSON string
}{string(taskJSON)})
if err != nil {
return makeErrorChan(err)
}
}
// Save interaction code
err = ioutil.WriteFile(wrapperFilepath, interactionCodeBuffer.Bytes(), 0644)
err = ioutil.WriteFile(wrapperFilepath, pythonInterface, 0644)
if err != nil {
return makeErrorChan(err)
}
@ -63,6 +51,8 @@ func (p *pythonRunner) Run() chan ResultOrError {
cmd := exec.Command(python3Installation, "-B", wrapperFilename) // -B prevents .pyc files from being written
cmd.Dir = p.dir
cmd.Stdin = bytes.NewReader(append(taskJSON, '\n'))
return readResultsFromCommand(cmd, func() {
// Remove leftover files
_ = os.Remove(wrapperFilepath)

103
runtime/tasks.go Normal file
View file

@ -0,0 +1,103 @@
package main
import (
"fmt"
"github.com/codemicro/adventOfCode/runtime/challenge"
"github.com/codemicro/adventOfCode/runtime/runners"
au "github.com/logrusorgru/aurora"
)
type taskLookupTable map[string]func(*runners.Result)
var (
passLabel = au.BrightGreen("pass").String()
failLabel = au.BrightRed("fail").String()
incompleteLabel = au.BgBrightRed("did not complete").String()
)
func setupTestTasks(info *challenge.Info, runner runners.Runner, table *taskLookupTable) {
st := func(part runners.Part, testCases []*challenge.TestCase, runner runners.Runner, table *taskLookupTable) {
for i, testCase := range testCases {
// loop variables change, remember? :P
i := i
testCase := testCase
id := fmt.Sprintf("test.%d.%d", part, i)
runner.Queue(&runners.Task{
TaskID: id,
Part: part,
Input: testCase.Input,
})
(*table)[id] = func(r *runners.Result) {
expected := fmt.Sprintf("%v", testCase.Expected)
passed := r.Output == expected
fmt.Print(au.Bold(fmt.Sprintf("Test %s: ",
au.BrightBlue(fmt.Sprintf("%d.%d", part, i)),
)))
var status string
var followUpText string
if !r.Ok {
status = incompleteLabel
followUpText = "saying \"" + r.Output + "\""
} else if passed {
status = passLabel
} else {
status = failLabel
}
if followUpText == "" {
followUpText = fmt.Sprintf("in %.4f seconds", r.Duration)
}
fmt.Print(status)
fmt.Println(au.Gray(10, " " + followUpText))
if !passed && r.Ok {
fmt.Printf(" └ Expected %s, got %s\n", au.BrightBlue(expected), au.BrightBlue(r.Output))
}
}
}
}
st(runners.PartOne, info.TestCases.One, runner, table)
st(runners.PartTwo, info.TestCases.Two, runner, table)
}
func setupMainTasks(input string, runner runners.Runner, table *taskLookupTable) {
for part := runners.PartOne; part <= runners.PartTwo; part += 1 {
part := part // loop variables need to be copied be used elsewhere to be used in function below, otherwise they
// become rather wrong
id := fmt.Sprintf("main.%d", part)
runner.Queue(&runners.Task{
TaskID: id,
Part: part,
Input: input,
})
(*table)[id] = func(r *runners.Result) {
fmt.Print(au.Bold(fmt.Sprintf("Part %d: ", au.Yellow(part))))
if !r.Ok {
fmt.Print(incompleteLabel)
fmt.Println(au.Gray(10, " saying \"" + r.Output + "\""))
} else {
fmt.Print(au.BrightBlue(r.Output))
fmt.Println(au.Gray(10, fmt.Sprintf(" in %.4f seconds", r.Duration)))
}
}
}
}