engine: resources: Add an ifequals option to block cmd

If the ifcmd returns true and this option is set, it will match that
output against this field, and if they match, then we skip cmd.

Much cleaner than needing to invoke bash to compare two strings.
This commit is contained in:
James Shubin
2025-09-29 21:24:40 -04:00
parent bbd4f1dea1
commit 154f900d2a

View File

@@ -138,6 +138,13 @@ type ExecRes struct {
// IfShell is the Shell for the IfCmd. See the docs for Shell.
IfShell string `lang:"ifshell" yaml:"ifshell"`
// IfEquals specifies that if the ifcmd returns zero, and that the
// output matches this string, then it will guard against the Cmd
// running. This can be the empty string. Remember to take into account
// if the output includes a trailing newline or not. (Hint: it usually
// does!)
IfEquals *string `lang:"ifequals" yaml:"ifequals"`
// Creates is the absolute file path to check for before running the
// main cmd. If this path exists, then the cmd will not run. More
// precisely we attempt to `stat` the file, so it must succeed for a
@@ -515,12 +522,17 @@ func (obj *ExecRes) CheckApply(ctx context.Context, apply bool) (bool, error) {
}
return true, nil // don't run
}
if s := out.String(); s == "" {
s := out.String()
if s == "" {
obj.init.Logf("ifcmd out empty!")
} else {
obj.init.Logf("ifcmd out:")
obj.init.Logf("%s", s)
}
if obj.IfEquals != nil && *obj.IfEquals == s {
obj.init.Logf("ifequals matched")
return true, nil // don't run
}
}
if obj.Creates != "" { // gate the extra syscall
@@ -895,6 +907,9 @@ func (obj *ExecRes) Cmp(r engine.Res) error {
if obj.IfShell != res.IfShell {
return fmt.Errorf("the IfShell differs")
}
if err := engineUtil.StrPtrCmp(obj.IfEquals, res.IfEquals); err != nil {
return errwrap.Wrapf(err, "the IfEquals differs")
}
if obj.Creates != res.Creates {
return fmt.Errorf("the Creates differs")