1
0
mirror of https://github.com/go-task/task.git synced 2025-03-05 15:05:42 +02:00

186 lines
4.4 KiB
Go
Raw Normal View History

2017-04-24 09:47:10 -03:00
// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information
package interp
import (
2018-09-01 11:00:49 -03:00
"context"
2018-01-03 15:12:40 -02:00
"fmt"
2017-04-24 09:47:10 -03:00
"os"
"os/exec"
"regexp"
2017-11-19 18:26:37 -02:00
"golang.org/x/crypto/ssh/terminal"
2019-09-26 19:04:09 -03:00
"mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/syntax"
2017-04-24 09:47:10 -03:00
)
// non-empty string is true, empty string is false
2018-09-01 11:00:49 -03:00
func (r *Runner) bashTest(ctx context.Context, expr syntax.TestExpr, classic bool) string {
2017-04-24 09:47:10 -03:00
switch x := expr.(type) {
case *syntax.Word:
2019-02-24 11:45:32 -03:00
return r.document(x)
2017-04-24 09:47:10 -03:00
case *syntax.ParenTest:
2018-09-01 11:00:49 -03:00
return r.bashTest(ctx, x.X, classic)
2017-04-24 09:47:10 -03:00
case *syntax.BinaryTest:
switch x.Op {
2019-09-26 19:04:09 -03:00
case syntax.TsMatchShort, syntax.TsMatch, syntax.TsNoMatch:
2018-12-15 15:44:17 -02:00
str := r.literal(x.X.(*syntax.Word))
yw := x.Y.(*syntax.Word)
2018-07-22 18:05:13 -03:00
if classic { // test, [
2018-12-15 15:44:17 -02:00
lit := r.literal(yw)
2019-09-26 19:04:09 -03:00
if (str == lit) == (x.Op != syntax.TsNoMatch) {
2018-07-22 18:05:13 -03:00
return "1"
}
} else { // [[
2018-12-15 15:44:17 -02:00
pattern := r.pattern(yw)
2019-09-26 19:04:09 -03:00
if match(pattern, str) == (x.Op != syntax.TsNoMatch) {
2018-07-22 18:05:13 -03:00
return "1"
}
}
return ""
}
2018-09-01 11:00:49 -03:00
if r.binTest(x.Op, r.bashTest(ctx, x.X, classic), r.bashTest(ctx, x.Y, classic)) {
2017-04-24 09:47:10 -03:00
return "1"
}
return ""
case *syntax.UnaryTest:
2018-09-01 11:00:49 -03:00
if r.unTest(ctx, x.Op, r.bashTest(ctx, x.X, classic)) {
2017-04-24 09:47:10 -03:00
return "1"
}
return ""
}
return ""
}
func (r *Runner) binTest(op syntax.BinTestOperator, x, y string) bool {
switch op {
case syntax.TsReMatch:
re, err := regexp.Compile(y)
if err != nil {
r.exit = 2
return false
}
return re.MatchString(x)
case syntax.TsNewer:
2018-01-03 15:12:40 -02:00
info1, err1 := r.stat(x)
info2, err2 := r.stat(y)
if err1 != nil || err2 != nil {
2017-04-24 09:47:10 -03:00
return false
}
2018-01-03 15:12:40 -02:00
return info1.ModTime().After(info2.ModTime())
2017-04-24 09:47:10 -03:00
case syntax.TsOlder:
2018-01-03 15:12:40 -02:00
info1, err1 := r.stat(x)
info2, err2 := r.stat(y)
if err1 != nil || err2 != nil {
2017-04-24 09:47:10 -03:00
return false
}
2018-01-03 15:12:40 -02:00
return info1.ModTime().Before(info2.ModTime())
2017-04-24 09:47:10 -03:00
case syntax.TsDevIno:
2018-01-03 15:12:40 -02:00
info1, err1 := r.stat(x)
info2, err2 := r.stat(y)
if err1 != nil || err2 != nil {
return false
}
return os.SameFile(info1, info2)
2017-04-24 09:47:10 -03:00
case syntax.TsEql:
return atoi(x) == atoi(y)
case syntax.TsNeq:
return atoi(x) != atoi(y)
case syntax.TsLeq:
return atoi(x) <= atoi(y)
case syntax.TsGeq:
return atoi(x) >= atoi(y)
case syntax.TsLss:
return atoi(x) < atoi(y)
case syntax.TsGtr:
return atoi(x) > atoi(y)
case syntax.AndTest:
return x != "" && y != ""
case syntax.OrTest:
return x != "" || y != ""
case syntax.TsBefore:
return x < y
default: // syntax.TsAfter
return x > y
}
}
2017-07-05 20:46:05 -03:00
func (r *Runner) statMode(name string, mode os.FileMode) bool {
2018-01-03 15:12:40 -02:00
info, err := r.stat(name)
return err == nil && info.Mode()&mode != 0
2017-04-24 09:47:10 -03:00
}
2018-09-01 11:00:49 -03:00
func (r *Runner) unTest(ctx context.Context, op syntax.UnTestOperator, x string) bool {
2017-04-24 09:47:10 -03:00
switch op {
case syntax.TsExists:
2018-01-03 15:12:40 -02:00
_, err := r.stat(x)
return err == nil
2017-04-24 09:47:10 -03:00
case syntax.TsRegFile:
2018-01-03 15:12:40 -02:00
info, err := r.stat(x)
return err == nil && info.Mode().IsRegular()
2017-04-24 09:47:10 -03:00
case syntax.TsDirect:
2017-07-05 20:46:05 -03:00
return r.statMode(x, os.ModeDir)
2017-11-19 18:26:37 -02:00
case syntax.TsCharSp:
return r.statMode(x, os.ModeCharDevice)
case syntax.TsBlckSp:
2018-01-03 15:12:40 -02:00
info, err := r.stat(x)
return err == nil && info.Mode()&os.ModeDevice != 0 &&
2017-11-19 18:26:37 -02:00
info.Mode()&os.ModeCharDevice == 0
2017-04-24 09:47:10 -03:00
case syntax.TsNmPipe:
2017-07-05 20:46:05 -03:00
return r.statMode(x, os.ModeNamedPipe)
2017-04-24 09:47:10 -03:00
case syntax.TsSocket:
2017-07-05 20:46:05 -03:00
return r.statMode(x, os.ModeSocket)
2017-04-24 09:47:10 -03:00
case syntax.TsSmbLink:
2018-01-03 15:12:40 -02:00
info, err := os.Lstat(r.relPath(x))
return err == nil && info.Mode()&os.ModeSymlink != 0
2017-04-24 09:47:10 -03:00
case syntax.TsSticky:
2017-07-05 20:46:05 -03:00
return r.statMode(x, os.ModeSticky)
2017-04-24 09:47:10 -03:00
case syntax.TsUIDSet:
2017-07-05 20:46:05 -03:00
return r.statMode(x, os.ModeSetuid)
2017-04-24 09:47:10 -03:00
case syntax.TsGIDSet:
2017-07-05 20:46:05 -03:00
return r.statMode(x, os.ModeSetgid)
2019-09-26 19:04:09 -03:00
// case syntax.TsGrpOwn:
// case syntax.TsUsrOwn:
// case syntax.TsModif:
2017-04-24 09:47:10 -03:00
case syntax.TsRead:
2018-09-01 11:00:49 -03:00
f, err := r.open(ctx, r.relPath(x), os.O_RDONLY, 0, false)
2017-04-24 09:47:10 -03:00
if err == nil {
f.Close()
}
return err == nil
case syntax.TsWrite:
2018-09-01 11:00:49 -03:00
f, err := r.open(ctx, r.relPath(x), os.O_WRONLY, 0, false)
2017-04-24 09:47:10 -03:00
if err == nil {
f.Close()
}
return err == nil
case syntax.TsExec:
2017-07-05 20:46:05 -03:00
_, err := exec.LookPath(r.relPath(x))
2017-04-24 09:47:10 -03:00
return err == nil
case syntax.TsNoEmpty:
2018-01-03 15:12:40 -02:00
info, err := r.stat(x)
return err == nil && info.Size() > 0
2017-11-19 18:26:37 -02:00
case syntax.TsFdTerm:
return terminal.IsTerminal(atoi(x))
2017-04-24 09:47:10 -03:00
case syntax.TsEmpStr:
return x == ""
case syntax.TsNempStr:
return x != ""
2017-11-19 18:26:37 -02:00
case syntax.TsOptSet:
2018-04-28 15:35:15 -03:00
if opt := r.optByName(x, false); opt != nil {
2018-01-03 15:12:40 -02:00
return *opt
2017-11-19 18:26:37 -02:00
}
2018-01-03 15:12:40 -02:00
return false
2017-05-27 11:17:49 -03:00
case syntax.TsVarSet:
2018-12-15 15:44:17 -02:00
return r.lookupVar(x).IsSet()
2017-11-19 18:26:37 -02:00
case syntax.TsRefVar:
2019-09-26 19:04:09 -03:00
return r.lookupVar(x).Kind == expand.NameRef
2017-04-24 09:47:10 -03:00
case syntax.TsNot:
return x == ""
default:
2018-01-03 15:12:40 -02:00
panic(fmt.Sprintf("unhandled unary test op: %v", op))
2017-04-24 09:47:10 -03:00
}
}