Files
task/taskfile/ast/fingerprint.go
2026-07-13 17:58:27 -03:00

135 lines
3.4 KiB
Go

package ast
import (
"reflect"
"strings"
)
// ReferencesFingerprintVar reports whether the task references the variable
// produced by the given fingerprint method in fields compiled after it.
func (t *Task) ReferencesFingerprintVar(kind string) bool {
name := strings.ToUpper(kind)
if t == nil || name == "" {
return false
}
for _, status := range t.Status {
if stringReferencesFingerprintVar(status, name) {
return true
}
}
for _, cmd := range t.Cmds {
if cmdReferencesFingerprintVar(cmd, name) {
return true
}
}
for _, dep := range t.Deps {
if depReferencesFingerprintVar(dep, name) {
return true
}
}
for _, precondition := range t.Preconditions {
if preconditionReferencesFingerprintVar(precondition, name) {
return true
}
}
return false
}
func cmdReferencesFingerprintVar(cmd *Cmd, name string) bool {
if cmd == nil {
return false
}
return stringReferencesFingerprintVar(cmd.Cmd, name) ||
stringReferencesFingerprintVar(cmd.Task, name) ||
stringReferencesFingerprintVar(cmd.If, name) ||
forReferencesFingerprintVar(cmd.For, name) ||
varsReferenceFingerprintVar(cmd.Vars, name)
}
func depReferencesFingerprintVar(dep *Dep, name string) bool {
if dep == nil {
return false
}
return stringReferencesFingerprintVar(dep.Task, name) ||
forReferencesFingerprintVar(dep.For, name) ||
varsReferenceFingerprintVar(dep.Vars, name)
}
func preconditionReferencesFingerprintVar(precondition *Precondition, name string) bool {
if precondition == nil {
return false
}
return stringReferencesFingerprintVar(precondition.Sh, name) ||
stringReferencesFingerprintVar(precondition.Msg, name)
}
func forReferencesFingerprintVar(f *For, name string) bool {
if f == nil {
return false
}
if valueReferencesFingerprintVar(f.List, name) {
return true
}
for _, row := range f.Matrix.All() {
if row != nil && (stringReferencesFingerprintVar(row.Ref, name) ||
valueReferencesFingerprintVar(row.Value, name)) {
return true
}
}
return false
}
func varsReferenceFingerprintVar(vars *Vars, name string) bool {
for _, v := range vars.All() {
if valueReferencesFingerprintVar(v.Value, name) ||
valueReferencesFingerprintVar(v.Live, name) ||
stringPointerReferencesFingerprintVar(v.Sh, name) ||
stringReferencesFingerprintVar(v.Ref, name) ||
stringReferencesFingerprintVar(v.Dir, name) {
return true
}
}
return false
}
func valueReferencesFingerprintVar(value any, name string) bool {
if value == nil {
return false
}
if s, ok := value.(string); ok {
return stringReferencesFingerprintVar(s, name)
}
rv := reflect.ValueOf(value)
switch rv.Kind() {
case reflect.Pointer, reflect.Interface:
if rv.IsNil() {
return false
}
return valueReferencesFingerprintVar(rv.Elem().Interface(), name)
case reflect.Array, reflect.Slice:
for i := 0; i < rv.Len(); i++ {
if valueReferencesFingerprintVar(rv.Index(i).Interface(), name) {
return true
}
}
case reflect.Map:
for _, key := range rv.MapKeys() {
if valueReferencesFingerprintVar(key.Interface(), name) ||
valueReferencesFingerprintVar(rv.MapIndex(key).Interface(), name) {
return true
}
}
}
return false
}
func stringPointerReferencesFingerprintVar(s *string, name string) bool {
return s != nil && stringReferencesFingerprintVar(*s, name)
}
func stringReferencesFingerprintVar(s string, name string) bool {
return strings.Contains(s, name)
}