mirror of
https://github.com/go-task/task.git
synced 2025-11-23 22:24:45 +02:00
feat: remote taskfile improvements (cache/expiry) (#2176)
* feat: cache as node, RemoteNode and cache-first approach * feat: cache expiry * feat: pass ctx into reader methods instead of timeout * docs: updated remote taskfiles experiment doc * feat: use cache if download fails
This commit is contained in:
113
taskfile/node_cache.go
Normal file
113
taskfile/node_cache.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package taskfile
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
const remoteCacheDir = "remote"
|
||||
|
||||
type CacheNode struct {
|
||||
*BaseNode
|
||||
source RemoteNode
|
||||
}
|
||||
|
||||
func NewCacheNode(source RemoteNode, dir string) *CacheNode {
|
||||
return &CacheNode{
|
||||
BaseNode: &BaseNode{
|
||||
dir: filepath.Join(dir, remoteCacheDir),
|
||||
},
|
||||
source: source,
|
||||
}
|
||||
}
|
||||
|
||||
func (node *CacheNode) Read() ([]byte, error) {
|
||||
return os.ReadFile(node.Location())
|
||||
}
|
||||
|
||||
func (node *CacheNode) Write(data []byte) error {
|
||||
if err := node.CreateCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(node.Location(), data, 0o644)
|
||||
}
|
||||
|
||||
func (node *CacheNode) ReadTimestamp() time.Time {
|
||||
b, err := os.ReadFile(node.timestampPath())
|
||||
if err != nil {
|
||||
return time.Time{}.UTC()
|
||||
}
|
||||
timestamp, err := time.Parse(time.RFC3339, string(b))
|
||||
if err != nil {
|
||||
return time.Time{}.UTC()
|
||||
}
|
||||
return timestamp.UTC()
|
||||
}
|
||||
|
||||
func (node *CacheNode) WriteTimestamp(t time.Time) error {
|
||||
if err := node.CreateCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(node.timestampPath(), []byte(t.Format(time.RFC3339)), 0o644)
|
||||
}
|
||||
|
||||
func (node *CacheNode) ReadChecksum() string {
|
||||
b, _ := os.ReadFile(node.checksumPath())
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (node *CacheNode) WriteChecksum(checksum string) error {
|
||||
if err := node.CreateCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(node.checksumPath(), []byte(checksum), 0o644)
|
||||
}
|
||||
|
||||
func (node *CacheNode) CreateCacheDir() error {
|
||||
if err := os.MkdirAll(node.dir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (node *CacheNode) ChecksumPrompt(checksum string) string {
|
||||
cachedChecksum := node.ReadChecksum()
|
||||
switch {
|
||||
|
||||
// If the checksum doesn't exist, prompt the user to continue
|
||||
case cachedChecksum == "":
|
||||
return taskfileUntrustedPrompt
|
||||
|
||||
// If there is a cached hash, but it doesn't match the expected hash, prompt the user to continue
|
||||
case cachedChecksum != checksum:
|
||||
return taskfileChangedPrompt
|
||||
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (node *CacheNode) Location() string {
|
||||
return node.filePath("yaml")
|
||||
}
|
||||
|
||||
func (node *CacheNode) checksumPath() string {
|
||||
return node.filePath("checksum")
|
||||
}
|
||||
|
||||
func (node *CacheNode) timestampPath() string {
|
||||
return node.filePath("timestamp")
|
||||
}
|
||||
|
||||
func (node *CacheNode) filePath(suffix string) string {
|
||||
return filepath.Join(node.dir, fmt.Sprintf("%s.%s", node.source.CacheKey(), suffix))
|
||||
}
|
||||
|
||||
func checksum(b []byte) string {
|
||||
h := sha256.New()
|
||||
h.Write(b)
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
Reference in New Issue
Block a user