Update Golang runner
This commit is contained in:
parent
7b4e3d4cf8
commit
6502ef4ff4
4 changed files with 152 additions and 121 deletions
141
runtime/runners/golangRunner.go
Normal file
141
runtime/runners/golangRunner.go
Normal file
|
@ -0,0 +1,141 @@
|
|||
package runners
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
au "github.com/logrusorgru/aurora"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
const (
|
||||
golangInstallation = "go"
|
||||
golangWrapperFilename = "runtime-wrapper.go"
|
||||
golangWrapperExecutableFilename = "runtime-wrapper"
|
||||
)
|
||||
|
||||
type golangRunner struct {
|
||||
dir string
|
||||
cmd *exec.Cmd
|
||||
wrapperFilepath string
|
||||
executableFilepath string
|
||||
stdin io.WriteCloser
|
||||
}
|
||||
|
||||
func newGolangRunner(dir string) Runner {
|
||||
return &golangRunner{
|
||||
dir: dir,
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed interface/go.go
|
||||
var golangInterface []byte
|
||||
|
||||
func (g *golangRunner) Start() error {
|
||||
g.wrapperFilepath = filepath.Join(g.dir, golangWrapperFilename)
|
||||
g.executableFilepath = filepath.Join(g.dir, golangWrapperExecutableFilename)
|
||||
|
||||
// determine package import path
|
||||
buildPath := fmt.Sprintf("github.com/codemicro/adventOfCode/challenges/%s/%s", filepath.Base(filepath.Dir(g.dir)), filepath.Base(g.dir))
|
||||
importPath := buildPath + "/go"
|
||||
|
||||
// generate code
|
||||
var wrapperContent []byte
|
||||
{
|
||||
tpl := template.Must(template.New("").Parse(string(golangInterface)))
|
||||
b := new(bytes.Buffer)
|
||||
err := tpl.Execute(b, struct {
|
||||
ImportPath string
|
||||
}{importPath})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wrapperContent = b.Bytes()
|
||||
}
|
||||
|
||||
// save interaction code
|
||||
if err := ioutil.WriteFile(g.wrapperFilepath, wrapperContent, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// compile executable
|
||||
stderrBuffer := new(bytes.Buffer)
|
||||
|
||||
cmd := exec.Command(golangInstallation, "build", "-tags", "runtime", "-o", g.executableFilepath, buildPath)
|
||||
cmd.Stderr = stderrBuffer
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("compilation failed: %s: %s", err, stderrBuffer.String())
|
||||
}
|
||||
|
||||
if !cmd.ProcessState.Success() {
|
||||
return errors.New("compilation failed, hence cannot continue")
|
||||
}
|
||||
|
||||
// now we run!
|
||||
absExecPath, err := filepath.Abs(g.executableFilepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// run executable
|
||||
g.cmd = exec.Command(absExecPath)
|
||||
cmd.Dir = g.dir
|
||||
|
||||
if stdin, err := setupBuffers(g.cmd); err != nil {
|
||||
return err
|
||||
} else {
|
||||
g.stdin = stdin
|
||||
}
|
||||
|
||||
return g.cmd.Start()
|
||||
}
|
||||
|
||||
func (g *golangRunner) Stop() error {
|
||||
if g.cmd == nil || g.cmd.Process == nil {
|
||||
return nil
|
||||
}
|
||||
return g.cmd.Process.Kill()
|
||||
}
|
||||
|
||||
func (g *golangRunner) Cleanup() error {
|
||||
if g.wrapperFilepath != "" {
|
||||
_ = os.Remove(g.wrapperFilepath)
|
||||
}
|
||||
if g.executableFilepath != "" {
|
||||
_ = os.Remove(g.executableFilepath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *golangRunner) Run(task *Task) (*Result, error) {
|
||||
taskJSON, err := json.Marshal(task)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, _ = g.stdin.Write(append(taskJSON, '\n'))
|
||||
|
||||
res := new(Result)
|
||||
for {
|
||||
inp, err := checkWait(g.cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(inp, res)
|
||||
if err != nil {
|
||||
// echo anything that won't parse to stdout (this lets us add debug print statements)
|
||||
fmt.Printf("[%s] %v\n", au.BrightRed("DBG"), strings.TrimSpace(string(inp)))
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
package runners
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
const golangInstallation = "go"
|
||||
|
||||
type golangRunner struct {
|
||||
dir string
|
||||
tasks []*Task
|
||||
}
|
||||
|
||||
func newGolangRunner(dir string) Runner {
|
||||
return &golangRunner{
|
||||
dir: dir,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *golangRunner) Queue(task *Task) {
|
||||
g.tasks = append(g.tasks, task)
|
||||
}
|
||||
|
||||
//go:embed interface/go.go
|
||||
var golangInterface []byte
|
||||
|
||||
func (g *golangRunner) Run() (chan ResultOrError, func()) {
|
||||
|
||||
wrapperFilename := "runtime-wrapper.go"
|
||||
wrapperExecutable := "runtime-wrapper"
|
||||
|
||||
wrapperFilepath := filepath.Join(g.dir, wrapperFilename)
|
||||
wrapperExecutableFilepath := filepath.Join(g.dir, wrapperExecutable)
|
||||
|
||||
// generate interaction data
|
||||
taskJSON, err := json.Marshal(g.tasks)
|
||||
if err != nil {
|
||||
return makeErrorChan(err), nil
|
||||
}
|
||||
|
||||
// determine package import path
|
||||
buildPath := fmt.Sprintf("github.com/codemicro/adventOfCode/challenges/%s/%s", filepath.Base(filepath.Dir(g.dir)), filepath.Base(g.dir))
|
||||
importPath := buildPath + "/go"
|
||||
|
||||
// generate code
|
||||
var wrapperContent []byte
|
||||
{
|
||||
tpl := template.Must(template.New("").Parse(string(golangInterface)))
|
||||
b := new(bytes.Buffer)
|
||||
err := tpl.Execute(b, struct {
|
||||
ImportPath string
|
||||
}{importPath})
|
||||
if err != nil {
|
||||
return makeErrorChan(err), nil
|
||||
}
|
||||
wrapperContent = b.Bytes()
|
||||
}
|
||||
|
||||
// save interaction code
|
||||
err = ioutil.WriteFile(wrapperFilepath, wrapperContent, 0644)
|
||||
if err != nil {
|
||||
return makeErrorChan(err), nil
|
||||
}
|
||||
|
||||
fmt.Print("Compiling...\r")
|
||||
defer fmt.Print("\n\n")
|
||||
|
||||
// compile executable
|
||||
stderrBuffer := new(bytes.Buffer)
|
||||
|
||||
cmd := exec.Command(golangInstallation, "build", "-tags", "runtime", "-o", wrapperExecutableFilepath, buildPath)
|
||||
cmd.Stderr = stderrBuffer
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return makeErrorChan(fmt.Errorf("compilation failed: %s: %s", err, stderrBuffer.String())), nil
|
||||
}
|
||||
|
||||
if !cmd.ProcessState.Success() {
|
||||
return makeErrorChan(errors.New("compilation failed, hence cannot continue")), nil
|
||||
}
|
||||
|
||||
absExecPath, err := filepath.Abs(wrapperExecutableFilepath)
|
||||
if err != nil {
|
||||
return makeErrorChan(err), nil
|
||||
}
|
||||
|
||||
fmt.Print("Running... ")
|
||||
|
||||
// run executable
|
||||
cmd = exec.Command(absExecPath)
|
||||
cmd.Dir = g.dir
|
||||
|
||||
cmd.Stdin = bytes.NewReader(append(taskJSON, '\n'))
|
||||
|
||||
return readResultsFromCommand(cmd), func() {
|
||||
// remove leftover files
|
||||
_ = os.Remove(wrapperFilepath)
|
||||
_ = os.Remove(wrapperExecutableFilepath)
|
||||
}
|
||||
}
|
|
@ -28,17 +28,16 @@ func sendResult(taskID string, ok bool, output string, duration float64) {
|
|||
|
||||
func run() error {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
tasksBytes, err := reader.ReadBytes('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
task := new(runners.Task)
|
||||
taskBytes, err := reader.ReadBytes('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(taskBytes, task); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var tasks []*runners.Task
|
||||
if err := json.Unmarshal(tasksBytes, &tasks); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, task := range tasks {
|
||||
var run func() (interface{}, error)
|
||||
|
||||
switch task.Part {
|
||||
|
|
|
@ -24,12 +24,12 @@ type RunnerCreator func(dir string) Runner
|
|||
|
||||
var Available = map[string]RunnerCreator{
|
||||
"py": newPythonRunner,
|
||||
//"go": newGolangRunner,
|
||||
"go": newGolangRunner,
|
||||
//"nim": newNimRunner,
|
||||
}
|
||||
|
||||
var RunnerNames = map[string]string{
|
||||
"py": "Python",
|
||||
//"go": "Golang",
|
||||
"go": "Golang",
|
||||
//"nim": "Nim",
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue