don't panic
return error on api boundary.
diff --git a/eval.go b/eval.go
index 9c8427d..2d1de66 100644
--- a/eval.go
+++ b/eval.go
@@ -2,6 +2,7 @@
import (
"bytes"
+ "fmt"
"os/exec"
"path/filepath"
"regexp"
@@ -157,8 +158,13 @@
ast.eval(ev)
}
-func Eval(mk Makefile) *EvalResult {
+func Eval(mk Makefile) (er *EvalResult, err error) {
ev := newEvaluator()
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("panic: %v", r)
+ }
+ }()
for _, stmt := range mk.stmts {
ev.eval(stmt)
}
@@ -166,5 +172,5 @@
vars: ev.outVars,
rules: ev.outRules,
refs: ev.refs,
- }
+ }, nil
}
diff --git a/exec.go b/exec.go
index 158eefb..27bb27c 100644
--- a/exec.go
+++ b/exec.go
@@ -1,6 +1,7 @@
package main
import (
+ "errors"
"fmt"
"os"
"os/exec"
@@ -26,7 +27,7 @@
return st.ModTime().Unix()
}
-func (ex *Executor) runCommands(cmds []string) {
+func (ex *Executor) runCommands(cmds []string) error {
for _, cmd := range cmds {
fmt.Printf("%s\n", cmd)
@@ -37,7 +38,7 @@
}
out, err := cmd.CombinedOutput()
if err != nil {
- panic(err)
+ return err
}
success := false
if cmd.ProcessState != nil {
@@ -46,60 +47,68 @@
fmt.Printf("%s", out)
if !success {
- panic("Command failed")
+ return fmt.Errorf("command failed: %q", cmd)
}
}
+ return nil
}
-func (ex *Executor) build(output string) int64 {
+func (ex *Executor) build(output string) (int64, error) {
Log("Building: %s", output)
outputTs := getTimestamp(output)
rule, present := ex.rules[output]
if !present {
if outputTs >= 0 {
- return outputTs
+ return outputTs, nil
}
- Error("No rule to make target %q", output)
+ return outputTs, fmt.Errorf("no rule to make target %q", output)
}
latest := int64(-1)
for _, input := range rule.inputs {
- ts := ex.build(input)
+ ts, err := ex.build(input)
+ if err != nil {
+ return outputTs, err
+ }
if latest < ts {
latest = ts
}
}
if outputTs >= latest {
- return outputTs
+ return outputTs, nil
}
- ex.runCommands(rule.cmds)
+ err := ex.runCommands(rule.cmds)
+ if err != nil {
+ return outputTs, err
+ }
outputTs = getTimestamp(output)
if outputTs < 0 {
outputTs = time.Now().Unix()
}
- return outputTs
+ return outputTs, nil
}
-func (ex *Executor) exec(er *EvalResult) {
+func (ex *Executor) exec(er *EvalResult) error {
if len(er.rules) == 0 {
- panic("No targets.")
+ return errors.New("no targets.")
}
for _, rule := range er.rules {
if _, present := ex.rules[rule.output]; present {
- Warn("overiding recipie for target '%s'", rule.output)
+ Warn("overiding recipie for target %q", rule.output)
}
ex.rules[rule.output] = rule
}
- ex.build(er.rules[0].output)
+ _, err := ex.build(er.rules[0].output)
+ return err
}
-func Exec(er *EvalResult) {
+func Exec(er *EvalResult) error {
ex := newExecutor()
- ex.exec(er)
+ return ex.exec(er)
}
diff --git a/main.go b/main.go
index 9f82548..658ac9a 100644
--- a/main.go
+++ b/main.go
@@ -10,6 +10,9 @@
stmt.show()
}
- er := Eval(mk)
+ er, err := Eval(mk)
+ if err != nil {
+ panic(err)
+ }
Exec(er)
}
diff --git a/parser.go b/parser.go
index 6a0aeb9..43666f8 100644
--- a/parser.go
+++ b/parser.go
@@ -4,6 +4,7 @@
"bufio"
"bytes"
"errors"
+ "fmt"
"io"
"os"
)
@@ -115,7 +116,12 @@
return ast
}
-func (p *parser) parse() (Makefile, error) {
+func (p *parser) parse() (mk Makefile, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("panic: %v", r)
+ }
+ }()
for !p.done {
line := p.readLine()