1
0
mirror of https://github.com/go-task/task.git synced 2024-12-12 10:45:49 +02:00
task/internal/fingerprint/sources_checksum.go

121 lines
2.6 KiB
Go
Raw Normal View History

package fingerprint
import (
"crypto/md5"
"fmt"
"io"
"os"
"path/filepath"
2017-09-30 19:40:11 +02:00
"regexp"
"strings"
"github.com/go-task/task/v3/internal/filepathext"
"github.com/go-task/task/v3/taskfile"
)
// ChecksumChecker validates if a task is up to date by calculating its source
// files checksum
type ChecksumChecker struct {
tempDir string
dry bool
}
func NewChecksumChecker(tempDir string, dry bool) *ChecksumChecker {
return &ChecksumChecker{
tempDir: tempDir,
dry: dry,
}
}
func (checker *ChecksumChecker) IsUpToDate(t *taskfile.Task) (bool, error) {
if len(t.Sources) == 0 {
return false, nil
}
checksumFile := checker.checksumFilePath(t)
data, _ := os.ReadFile(checksumFile)
oldMd5 := strings.TrimSpace(string(data))
newMd5, err := checker.checksum(t)
if err != nil {
return false, nil
}
if !checker.dry && oldMd5 != newMd5 {
_ = os.MkdirAll(filepathext.SmartJoin(checker.tempDir, "checksum"), 0o755)
2022-08-17 19:37:58 +02:00
if err = os.WriteFile(checksumFile, []byte(newMd5+"\n"), 0o644); err != nil {
return false, err
}
}
if len(t.Generates) > 0 {
2019-08-25 21:29:32 +02:00
// For each specified 'generates' field, check whether the files actually exist
for _, g := range t.Generates {
generates, err := Glob(t.Dir, g)
2019-08-25 21:29:32 +02:00
if os.IsNotExist(err) {
return false, nil
}
2019-08-25 21:29:32 +02:00
if err != nil {
return false, err
}
if len(generates) == 0 {
return false, nil
}
}
}
return oldMd5 == newMd5, nil
}
func (checker *ChecksumChecker) Value(t *taskfile.Task) (any, error) {
return checker.checksum(t)
}
func (checker *ChecksumChecker) OnError(t *taskfile.Task) error {
if len(t.Sources) == 0 {
return nil
}
return os.Remove(checker.checksumFilePath(t))
}
func (*ChecksumChecker) Kind() string {
return "checksum"
}
func (c *ChecksumChecker) checksum(t *taskfile.Task) (string, error) {
2023-06-15 17:04:03 +02:00
sources, err := Globs(t.Dir, t.Sources)
if err != nil {
return "", err
}
h := md5.New()
for _, f := range sources {
2019-08-21 06:34:58 +02:00
// also sum the filename, so checksum changes for renaming a file
if _, err := io.Copy(h, strings.NewReader(filepath.Base(f))); err != nil {
return "", err
}
2019-08-21 06:34:58 +02:00
f, err := os.Open(f)
2017-09-19 19:03:24 +02:00
if err != nil {
return "", err
}
if _, err = io.Copy(h, f); err != nil {
return "", err
}
f.Close()
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
}
func (checker *ChecksumChecker) checksumFilePath(t *taskfile.Task) string {
return filepath.Join(checker.tempDir, "checksum", normalizeFilename(t.Name()))
2017-10-01 20:05:09 +02:00
}
2017-09-30 19:40:11 +02:00
var checksumFilenameRegexp = regexp.MustCompile("[^A-z0-9]")
// replaces invalid characters on filenames with "-"
func normalizeFilename(f string) string {
2017-09-30 19:40:11 +02:00
return checksumFilenameRegexp.ReplaceAllString(f, "-")
}