1
0
mirror of https://github.com/go-task/task.git synced 2025-03-17 21:08:01 +02:00
task/status.go
2023-03-07 00:30:24 +00:00

141 lines
3.3 KiB
Go

package task
import (
"context"
"fmt"
"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/status"
"github.com/go-task/task/v3/taskfile"
)
// Status returns an error if any the of given tasks is not up-to-date
func (e *Executor) Status(ctx context.Context, calls ...taskfile.Call) error {
for _, call := range calls {
t, err := e.CompiledTask(call)
if err != nil {
return err
}
isUpToDate, err := e.isTaskUpToDate(ctx, t)
if err != nil {
return err
}
if !isUpToDate {
return fmt.Errorf(`task: Task "%s" is not up-to-date`, t.Name())
}
}
return nil
}
func (e *Executor) isTaskUpToDate(ctx context.Context, t *taskfile.Task) (bool, error) {
var statusUpToDate bool
var sourcesUpToDate bool
var err error
statusIsSet := len(t.Status) != 0
sourcesIsSet := len(t.Sources) != 0
// If status is set, check if it is up-to-date
if statusIsSet {
statusUpToDate, err = e.isTaskUpToDateStatus(ctx, t)
if err != nil {
return false, err
}
}
// If sources is set, check if they are up-to-date
if sourcesIsSet {
checker, err := e.getStatusChecker(t)
if err != nil {
return false, err
}
sourcesUpToDate, err = checker.IsUpToDate()
if err != nil {
return false, err
}
}
// If both status and sources are set, the task is up-to-date if both are up-to-date
if statusIsSet && sourcesIsSet {
return statusUpToDate && sourcesUpToDate, nil
}
// If only status is set, the task is up-to-date if the status is up-to-date
if statusIsSet {
return statusUpToDate, nil
}
// If only sources is set, the task is up-to-date if the sources are up-to-date
if sourcesIsSet {
return sourcesUpToDate, nil
}
// If no status or sources are set, the task should always run
// i.e. it is never considered "up-to-date"
return false, nil
}
func (e *Executor) statusOnError(t *taskfile.Task) error {
checker, err := e.getStatusChecker(t)
if err != nil {
return err
}
return checker.OnError()
}
func (e *Executor) getStatusChecker(t *taskfile.Task) (status.Checker, error) {
method := t.Method
if method == "" {
method = e.Taskfile.Method
}
switch method {
case "timestamp":
return e.timestampChecker(t), nil
case "checksum":
return e.checksumChecker(t), nil
case "none":
return status.None{}, nil
default:
return nil, fmt.Errorf(`task: invalid method "%s"`, method)
}
}
func (e *Executor) timestampChecker(t *taskfile.Task) status.Checker {
return &status.Timestamp{
TempDir: e.TempDir,
Task: t.Name(),
Dir: t.Dir,
Sources: t.Sources,
Generates: t.Generates,
Dry: e.Dry,
}
}
func (e *Executor) checksumChecker(t *taskfile.Task) status.Checker {
return &status.Checksum{
TempDir: e.TempDir,
TaskDir: t.Dir,
Task: t.Name(),
Sources: t.Sources,
Generates: t.Generates,
Dry: e.Dry,
}
}
func (e *Executor) isTaskUpToDateStatus(ctx context.Context, t *taskfile.Task) (bool, error) {
for _, s := range t.Status {
err := execext.RunCommand(ctx, &execext.RunCommandOptions{
Command: s,
Dir: t.Dir,
Env: getEnviron(t),
})
if err != nil {
e.Logger.VerboseOutf(logger.Yellow, "task: status command %s exited non-zero: %s", s, err)
return false, nil
}
e.Logger.VerboseOutf(logger.Yellow, "task: status command %s exited zero", s)
}
return true, nil
}