diff options
Diffstat (limited to 'golang/kati/evalcmd.go')
-rw-r--r-- | golang/kati/evalcmd.go | 369 |
1 files changed, 0 insertions, 369 deletions
diff --git a/golang/kati/evalcmd.go b/golang/kati/evalcmd.go deleted file mode 100644 index 37f94b8..0000000 --- a/golang/kati/evalcmd.go +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright 2015 Google Inc. All rights reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package kati - -import ( - "fmt" - "os/exec" - "strings" - "sync" - - "github.com/golang/glog" -) - -type execContext struct { - shell string - - mu sync.Mutex - ev *Evaluator - vpaths searchPaths - output string - inputs []string -} - -func newExecContext(vars Vars, vpaths searchPaths, avoidIO bool) *execContext { - ev := NewEvaluator(vars) - ev.avoidIO = avoidIO - - ctx := &execContext{ - ev: ev, - vpaths: vpaths, - } - av := autoVar{ctx: ctx} - for k, v := range map[string]Var{ - "@": autoAtVar{autoVar: av}, - "<": autoLessVar{autoVar: av}, - "^": autoHatVar{autoVar: av}, - "+": autoPlusVar{autoVar: av}, - "*": autoStarVar{autoVar: av}, - } { - ev.vars[k] = v - // $<k>D = $(patsubst %/,%,$(dir $<k>)) - ev.vars[k+"D"] = suffixDVar(k) - // $<k>F = $(notdir $<k>) - ev.vars[k+"F"] = suffixFVar(k) - } - - // TODO: We should move this to somewhere around evalCmd so that - // we can handle SHELL in target specific variables. - shell, err := ev.EvaluateVar("SHELL") - if err != nil { - shell = "/bin/sh" - } - ctx.shell = shell - return ctx -} - -func (ec *execContext) uniqueInputs() []string { - var uniqueInputs []string - seen := make(map[string]bool) - for _, input := range ec.inputs { - if !seen[input] { - seen[input] = true - uniqueInputs = append(uniqueInputs, input) - } - } - return uniqueInputs -} - -type autoVar struct{ ctx *execContext } - -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 evalWriter, ev *Evaluator) error { - fmt.Fprint(w, v.String()) - return nil -} -func (v autoAtVar) String() string { return v.ctx.output } - -type autoLessVar struct{ autoVar } - -func (v autoLessVar) Eval(w evalWriter, ev *Evaluator) error { - fmt.Fprint(w, v.String()) - return nil -} -func (v autoLessVar) String() string { - if len(v.ctx.inputs) > 0 { - return v.ctx.inputs[0] - } - return "" -} - -type autoHatVar struct{ autoVar } - -func (v autoHatVar) Eval(w evalWriter, ev *Evaluator) error { - fmt.Fprint(w, v.String()) - return nil -} -func (v autoHatVar) String() string { - return strings.Join(v.ctx.uniqueInputs(), " ") -} - -type autoPlusVar struct{ autoVar } - -func (v autoPlusVar) Eval(w evalWriter, ev *Evaluator) error { - fmt.Fprint(w, v.String()) - return nil -} -func (v autoPlusVar) String() string { return strings.Join(v.ctx.inputs, " ") } - -type autoStarVar struct{ autoVar } - -func (v autoStarVar) Eval(w evalWriter, ev *Evaluator) error { - fmt.Fprint(w, v.String()) - return nil -} - -// TODO: Use currentStem. See auto_stem_var.mk -func (v autoStarVar) String() string { return stripExt(v.ctx.output) } - -func suffixDVar(k string) Var { - return &recursiveVar{ - expr: expr{ - &funcPatsubst{ - fclosure: fclosure{ - args: []Value{ - literal("(patsubst"), - literal("%/"), - literal("%"), - &funcDir{ - fclosure: fclosure{ - args: []Value{ - literal("(dir"), - &varref{ - varname: literal(k), - }, - }, - }, - }, - }, - }, - }, - }, - origin: "automatic", - } -} - -func suffixFVar(k string) Var { - return &recursiveVar{ - expr: expr{ - &funcNotdir{ - fclosure: fclosure{ - args: []Value{ - literal("(notdir"), - &varref{varname: literal(k)}, - }, - }, - }, - }, - origin: "automatic", - } -} - -// runner is a single shell command invocation. -type runner struct { - output string - cmd string - echo bool - ignoreError bool - shell string -} - -func (r runner) String() string { - cmd := r.cmd - if !r.echo { - cmd = "@" + cmd - } - if r.ignoreError { - cmd = "-" + cmd - } - return cmd -} - -func (r runner) forCmd(s string) runner { - for { - s = trimLeftSpace(s) - if s == "" { - return runner{} - } - switch s[0] { - case '@': - if !DryRunFlag { - r.echo = false - } - s = s[1:] - continue - case '-': - r.ignoreError = true - s = s[1:] - continue - } - break - } - r.cmd = s - return r -} - -func (r runner) eval(ev *Evaluator, s string) ([]runner, error) { - r = r.forCmd(s) - if strings.IndexByte(r.cmd, '$') < 0 { - // fast path - return []runner{r}, nil - } - // TODO(ukai): parse once more earlier? - expr, _, err := parseExpr([]byte(r.cmd), nil, parseOp{}) - if err != nil { - return nil, ev.errorf("parse cmd %q: %v", r.cmd, err) - } - buf := newEbuf() - err = expr.Eval(buf, ev) - if err != nil { - return nil, err - } - cmds := buf.String() - buf.release() - glog.V(1).Infof("evalcmd: %q => %q", r.cmd, cmds) - var runners []runner - for _, cmd := range strings.Split(cmds, "\n") { - if len(runners) > 0 && strings.HasSuffix(runners[len(runners)-1].cmd, "\\") { - runners[len(runners)-1].cmd += "\n" - runners[len(runners)-1].cmd += cmd - continue - } - runners = append(runners, r.forCmd(cmd)) - } - return runners, nil -} - -func (r runner) run(output string) error { - if r.echo || DryRunFlag { - fmt.Printf("%s\n", r.cmd) - } - s := cmdline(r.cmd) - glog.Infof("sh:%q", s) - if DryRunFlag { - return nil - } - args := []string{r.shell, "-c", s} - cmd := exec.Cmd{ - Path: args[0], - Args: args, - } - out, err := cmd.CombinedOutput() - fmt.Printf("%s", out) - exit := exitStatus(err) - if r.ignoreError && exit != 0 { - fmt.Printf("[%s] Error %d (ignored)\n", output, exit) - err = nil - } - return err -} - -func createRunners(ctx *execContext, n *DepNode) ([]runner, bool, error) { - var runners []runner - if len(n.Cmds) == 0 { - return runners, false, nil - } - - ctx.mu.Lock() - defer ctx.mu.Unlock() - // For automatic variables. - ctx.output = n.Output - ctx.inputs = n.ActualInputs - for k, v := range n.TargetSpecificVars { - restore := ctx.ev.vars.save(k) - defer restore() - ctx.ev.vars[k] = v - if glog.V(1) { - glog.Infof("set tsv: %s=%s", k, v) - } - } - - ctx.ev.filename = n.Filename - ctx.ev.lineno = n.Lineno - glog.Infof("Building: %s cmds:%q", n.Output, n.Cmds) - r := runner{ - output: n.Output, - echo: true, - shell: ctx.shell, - } - for _, cmd := range n.Cmds { - rr, err := r.eval(ctx.ev, cmd) - if err != nil { - return nil, false, err - } - for _, r := range rr { - if len(r.cmd) != 0 { - runners = append(runners, r) - } - } - } - if len(ctx.ev.delayedOutputs) > 0 { - var nrunners []runner - r := runner{ - output: n.Output, - shell: ctx.shell, - } - for _, o := range ctx.ev.delayedOutputs { - nrunners = append(nrunners, r.forCmd(o)) - } - nrunners = append(nrunners, runners...) - runners = nrunners - ctx.ev.delayedOutputs = nil - } - return runners, ctx.ev.hasIO, nil -} - -func evalCommands(nodes []*DepNode, vars Vars) error { - ioCnt := 0 - ectx := newExecContext(vars, searchPaths{}, true) - for i, n := range nodes { - runners, hasIO, err := createRunners(ectx, n) - 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 { - n.Cmds = append(n.Cmds, r.String()) - } - } - logStats("%d/%d rules have IO", ioCnt, len(nodes)) - return nil -} |