diff options
author | Fumitoshi Ukai <fumitoshi.ukai@gmail.com> | 2015-06-30 15:31:49 +0900 |
---|---|---|
committer | Fumitoshi Ukai <fumitoshi.ukai@gmail.com> | 2015-06-30 15:51:19 +0900 |
commit | a70b4eab60338c4f5e731264e3e21a3392546682 (patch) | |
tree | 1237cf7b7fa51ae1b24830c9c30d0b52abc11354 /exec.go | |
parent | 0d8e79b7753a89ac6beaf638a535ec63f1941444 (diff) | |
download | kati-a70b4eab60338c4f5e731264e3e21a3392546682.tar.gz |
factor out execContext from executor.
Diffstat (limited to 'exec.go')
-rw-r--r-- | exec.go | 231 |
1 files changed, 3 insertions, 228 deletions
@@ -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 -} |