aboutsummaryrefslogtreecommitdiff
path: root/exec.go
diff options
context:
space:
mode:
authorFumitoshi Ukai <fumitoshi.ukai@gmail.com>2015-06-30 15:31:49 +0900
committerFumitoshi Ukai <fumitoshi.ukai@gmail.com>2015-06-30 15:51:19 +0900
commita70b4eab60338c4f5e731264e3e21a3392546682 (patch)
tree1237cf7b7fa51ae1b24830c9c30d0b52abc11354 /exec.go
parent0d8e79b7753a89ac6beaf638a535ec63f1941444 (diff)
downloadkati-a70b4eab60338c4f5e731264e3e21a3392546682.tar.gz
factor out execContext from executor.
Diffstat (limited to 'exec.go')
-rw-r--r--exec.go231
1 files changed, 3 insertions, 228 deletions
diff --git a/exec.go b/exec.go
index 83b2cde..f572924 100644
--- a/exec.go
+++ b/exec.go
@@ -15,12 +15,7 @@
package kati
import (
- "bytes"
"fmt"
- "io"
- "path/filepath"
- "strings"
- "sync"
"time"
)
@@ -30,17 +25,12 @@ type Executor struct {
implicitRules []*rule
suffixRules map[string][]*rule
firstRule *rule
- shell string
- vars Vars
- varsLock sync.Mutex
// target -> Job, nil means the target is currently being processed.
done map[string]*job
wm *workerManager
- currentOutput string
- currentInputs []string
- currentStem string
+ ctx *execContext
trace []string
buildCnt int
@@ -50,117 +40,6 @@ type Executor struct {
runCommandCnt int
}
-type autoVar struct{ ex *Executor }
-
-func (v autoVar) Flavor() string { return "undefined" }
-func (v autoVar) Origin() string { return "automatic" }
-func (v autoVar) IsDefined() bool { return true }
-func (v autoVar) Append(*Evaluator, string) (Var, error) {
- return nil, fmt.Errorf("cannot append to autovar")
-}
-func (v autoVar) AppendVar(*Evaluator, Value) (Var, error) {
- return nil, fmt.Errorf("cannot append to autovar")
-}
-func (v autoVar) serialize() serializableVar {
- return serializableVar{Type: ""}
-}
-func (v autoVar) dump(d *dumpbuf) {
- d.err = fmt.Errorf("cannot dump auto var: %v", v)
-}
-
-type autoAtVar struct{ autoVar }
-
-func (v autoAtVar) Eval(w io.Writer, ev *Evaluator) error {
- fmt.Fprint(w, v.ex.currentOutput)
- return nil
-}
-func (v autoAtVar) String() string { return "$*" }
-
-type autoLessVar struct{ autoVar }
-
-func (v autoLessVar) Eval(w io.Writer, ev *Evaluator) error {
- if len(v.ex.currentInputs) > 0 {
- fmt.Fprint(w, v.ex.currentInputs[0])
- }
- return nil
-}
-func (v autoLessVar) String() string { return "$<" }
-
-type autoHatVar struct{ autoVar }
-
-func (v autoHatVar) Eval(w io.Writer, ev *Evaluator) error {
- var uniqueInputs []string
- seen := make(map[string]bool)
- for _, input := range v.ex.currentInputs {
- if !seen[input] {
- seen[input] = true
- uniqueInputs = append(uniqueInputs, input)
- }
- }
- fmt.Fprint(w, strings.Join(uniqueInputs, " "))
- return nil
-}
-func (v autoHatVar) String() string { return "$^" }
-
-type autoPlusVar struct{ autoVar }
-
-func (v autoPlusVar) Eval(w io.Writer, ev *Evaluator) error {
- fmt.Fprint(w, strings.Join(v.ex.currentInputs, " "))
- return nil
-}
-func (v autoPlusVar) String() string { return "$+" }
-
-type autoStarVar struct{ autoVar }
-
-func (v autoStarVar) Eval(w io.Writer, ev *Evaluator) error {
- // TODO: Use currentStem. See auto_stem_var.mk
- fmt.Fprint(w, stripExt(v.ex.currentOutput))
- return nil
-}
-func (v autoStarVar) String() string { return "$*" }
-
-type autoSuffixDVar struct {
- autoVar
- v Var
-}
-
-func (v autoSuffixDVar) Eval(w io.Writer, ev *Evaluator) error {
- var buf bytes.Buffer
- err := v.v.Eval(&buf, ev)
- if err != nil {
- return err
- }
- ws := newWordScanner(buf.Bytes())
- sw := ssvWriter{w: w}
- for ws.Scan() {
- sw.WriteString(filepath.Dir(string(ws.Bytes())))
- }
- return nil
-}
-
-func (v autoSuffixDVar) String() string { return v.v.String() + "D" }
-
-type autoSuffixFVar struct {
- autoVar
- v Var
-}
-
-func (v autoSuffixFVar) Eval(w io.Writer, ev *Evaluator) error {
- var buf bytes.Buffer
- err := v.v.Eval(&buf, ev)
- if err != nil {
- return err
- }
- ws := newWordScanner(buf.Bytes())
- sw := ssvWriter{w: w}
- for ws.Scan() {
- sw.WriteString(filepath.Base(string(ws.Bytes())))
- }
- return nil
-}
-
-func (v autoSuffixFVar) String() string { return v.v.String() + "F" }
-
func (ex *Executor) makeJobs(n *DepNode, neededBy *job) error {
output := n.Output
if neededBy != nil {
@@ -260,30 +139,13 @@ func NewExecutor(vars Vars, opt *ExecutorOpt) (*Executor, error) {
if err != nil {
return nil, err
}
+ ctx := newExecContext(vars, false)
ex := &Executor{
rules: make(map[string]*rule),
suffixRules: make(map[string][]*rule),
done: make(map[string]*job),
- vars: vars,
wm: wm,
- }
- // TODO: We should move this to somewhere around evalCmd so that
- // we can handle SHELL in target specific variables.
- ev := NewEvaluator(ex.vars)
- ex.shell, err = ev.EvaluateVar("SHELL")
- if err != nil {
- ex.shell = "/bin/sh"
- }
- for k, v := range map[string]Var{
- "@": autoAtVar{autoVar: autoVar{ex: ex}},
- "<": autoLessVar{autoVar: autoVar{ex: ex}},
- "^": autoHatVar{autoVar: autoVar{ex: ex}},
- "+": autoPlusVar{autoVar: autoVar{ex: ex}},
- "*": autoStarVar{autoVar: autoVar{ex: ex}},
- } {
- ex.vars[k] = v
- ex.vars[k+"D"] = autoSuffixDVar{v: v}
- ex.vars[k+"F"] = autoSuffixFVar{v: v}
+ ctx: ctx,
}
return ex, nil
}
@@ -301,90 +163,3 @@ func (ex *Executor) Exec(roots []*DepNode) error {
logStats("exec time: %q", time.Since(startTime))
return err
}
-
-func (ex *Executor) createRunners(n *DepNode, avoidIO bool) ([]runner, bool, error) {
- var runners []runner
- if len(n.Cmds) == 0 {
- return runners, false, nil
- }
-
- var restores []func()
- defer func() {
- for i := len(restores) - 1; i >= 0; i-- {
- restores[i]()
- }
- }()
-
- ex.varsLock.Lock()
- restores = append(restores, func() { ex.varsLock.Unlock() })
- // For automatic variables.
- ex.currentOutput = n.Output
- ex.currentInputs = n.ActualInputs
- for k, v := range n.TargetSpecificVars {
- restores = append(restores, ex.vars.save(k))
- ex.vars[k] = v
- logf("tsv: %s=%s", k, v)
- }
-
- ev := NewEvaluator(ex.vars)
- ev.avoidIO = avoidIO
- ev.filename = n.Filename
- ev.lineno = n.Lineno
- logf("Building: %s cmds:%q", n.Output, n.Cmds)
- r := runner{
- output: n.Output,
- echo: true,
- shell: ex.shell,
- }
- for _, cmd := range n.Cmds {
- rr, err := evalCmd(ev, r, cmd)
- if err != nil {
- return nil, false, err
- }
- for _, r := range rr {
- if len(r.cmd) != 0 {
- runners = append(runners, r)
- }
- }
- }
- return runners, ev.hasIO, nil
-}
-
-func evalCommands(nodes []*DepNode, vars Vars) error {
- ioCnt := 0
- ex, err := NewExecutor(vars, nil)
- if err != nil {
- return err
- }
- for i, n := range nodes {
- runners, hasIO, err := ex.createRunners(n, true)
- if err != nil {
- return err
- }
- if hasIO {
- ioCnt++
- if ioCnt%100 == 0 {
- logStats("%d/%d rules have IO", ioCnt, i+1)
- }
- continue
- }
-
- n.Cmds = []string{}
- n.TargetSpecificVars = make(Vars)
- for _, r := range runners {
- cmd := r.cmd
- // TODO: Do not preserve the effect of dryRunFlag.
- if r.echo {
- cmd = "@" + cmd
- }
- if r.ignoreError {
- cmd = "-" + cmd
- }
- n.Cmds = append(n.Cmds, cmd)
- }
- }
-
- err = ex.wm.Wait()
- logStats("%d/%d rules have IO", ioCnt, len(nodes))
- return err
-}