mirror of
https://github.com/go-task/task.git
synced 2025-03-05 15:05:42 +02:00
139 lines
3.0 KiB
Go
139 lines
3.0 KiB
Go
package status
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
// Timestamp checks if any source change compared with the generated files,
|
|
// using file modifications timestamps.
|
|
type Timestamp struct {
|
|
TempDir string
|
|
Task string
|
|
Dir string
|
|
Sources []string
|
|
Generates []string
|
|
Dry bool
|
|
}
|
|
|
|
// IsUpToDate implements the Checker interface
|
|
func (t *Timestamp) IsUpToDate() (bool, error) {
|
|
if len(t.Sources) == 0 {
|
|
return false, nil
|
|
}
|
|
|
|
sources, err := globs(t.Dir, t.Sources)
|
|
if err != nil {
|
|
return false, nil
|
|
}
|
|
generates, err := globs(t.Dir, t.Generates)
|
|
if err != nil {
|
|
return false, nil
|
|
}
|
|
|
|
timestampFile := t.timestampFilePath()
|
|
|
|
// if the file exists, add the file path to the generates
|
|
// if the generate file is old, the task will be executed
|
|
_, err = os.Stat(timestampFile)
|
|
if err == nil {
|
|
generates = append(generates, timestampFile)
|
|
} else {
|
|
// create the timestamp file for the next execution when the file does not exist
|
|
if !t.Dry {
|
|
_ = os.MkdirAll(filepath.Dir(timestampFile), 0o755)
|
|
_, _ = os.Create(timestampFile)
|
|
}
|
|
}
|
|
|
|
taskTime := time.Now()
|
|
|
|
// compare the time of the generates and sources. If the generates are old, the task will be executed
|
|
|
|
// get the max time of the generates
|
|
generateMaxTime, err := getMaxTime(generates...)
|
|
if err != nil || generateMaxTime.IsZero() {
|
|
return false, nil
|
|
}
|
|
|
|
// check if any of the source files is newer than the max time of the generates
|
|
shouldUpdate, err := anyFileNewerThan(sources, generateMaxTime)
|
|
if err != nil {
|
|
return false, nil
|
|
}
|
|
|
|
// modify the metadata of the file to the the current time
|
|
if !t.Dry {
|
|
_ = os.Chtimes(timestampFile, taskTime, taskTime)
|
|
}
|
|
|
|
return !shouldUpdate, nil
|
|
}
|
|
|
|
func (t *Timestamp) Kind() string {
|
|
return "timestamp"
|
|
}
|
|
|
|
// Value implements the Checker Interface
|
|
func (t *Timestamp) Value() (interface{}, error) {
|
|
sources, err := globs(t.Dir, t.Sources)
|
|
if err != nil {
|
|
return time.Now(), err
|
|
}
|
|
|
|
sourcesMaxTime, err := getMaxTime(sources...)
|
|
if err != nil {
|
|
return time.Now(), err
|
|
}
|
|
|
|
if sourcesMaxTime.IsZero() {
|
|
return time.Unix(0, 0), nil
|
|
}
|
|
|
|
return sourcesMaxTime, nil
|
|
}
|
|
|
|
func getMaxTime(files ...string) (time.Time, error) {
|
|
var t time.Time
|
|
for _, f := range files {
|
|
info, err := os.Stat(f)
|
|
if err != nil {
|
|
return time.Time{}, err
|
|
}
|
|
t = maxTime(t, info.ModTime())
|
|
}
|
|
return t, nil
|
|
}
|
|
|
|
// if the modification time of any of the files is newer than the the given time, returns true
|
|
// This function is lazy, as it stops when it finds a file newer than the given time
|
|
func anyFileNewerThan(files []string, givenTime time.Time) (bool, error) {
|
|
for _, f := range files {
|
|
info, err := os.Stat(f)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if info.ModTime().After(givenTime) {
|
|
return true, nil
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func maxTime(a, b time.Time) time.Time {
|
|
if a.After(b) {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
// OnError implements the Checker interface
|
|
func (*Timestamp) OnError() error {
|
|
return nil
|
|
}
|
|
|
|
func (t *Timestamp) timestampFilePath() string {
|
|
return filepath.Join(t.TempDir, "timestamp", NormalizeFilename(t.Task))
|
|
}
|