chore: import upstream snapshot with attribution
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
package eval
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/zzet/gortex/internal/platform"
|
||||
)
|
||||
|
||||
// Cache provides filesystem-based index caching keyed by (repo_name, commit_hash).
|
||||
// Cache entries are stored under {cacheDir}/{repo_name}_{commit_hash}/ and contain
|
||||
// a .version file, graph.bin, and search.bleve/ directory.
|
||||
type Cache struct {
|
||||
dir string // root cache directory
|
||||
version string // current gortex version for compatibility checks
|
||||
}
|
||||
|
||||
// NewCache creates a Cache rooted at dir with the given gortex version string.
|
||||
//
|
||||
// If dir is empty the location is resolved by env: when $XDG_CACHE_HOME is
|
||||
// set it is honoured ($XDG_CACHE_HOME/gortex/eval-cache); otherwise the
|
||||
// historical default ~/.gortex-eval-cache/ is kept so an existing eval
|
||||
// cache is not orphaned.
|
||||
func NewCache(dir, version string) (*Cache, error) {
|
||||
if dir == "" {
|
||||
if v := os.Getenv("XDG_CACHE_HOME"); v != "" && filepath.IsAbs(v) {
|
||||
dir = filepath.Join(platform.CacheDir(), "eval-cache")
|
||||
} else {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cache: resolve home dir: %w", err)
|
||||
}
|
||||
dir = filepath.Join(home, ".gortex-eval-cache")
|
||||
}
|
||||
}
|
||||
return &Cache{dir: dir, version: version}, nil
|
||||
}
|
||||
|
||||
// CacheKey generates the cache directory name for a (repo, commit) pair.
|
||||
// The key format is {repo}_{commit}.
|
||||
func CacheKey(repo, commit string) string {
|
||||
return repo + "_" + commit
|
||||
}
|
||||
|
||||
// entryDir returns the full path to the cache entry directory.
|
||||
func (c *Cache) entryDir(repo, commit string) string {
|
||||
return filepath.Join(c.dir, CacheKey(repo, commit))
|
||||
}
|
||||
|
||||
// versionFile returns the path to the .version file inside a cache entry.
|
||||
func (c *Cache) versionFile(repo, commit string) string {
|
||||
return filepath.Join(c.entryDir(repo, commit), ".version")
|
||||
}
|
||||
|
||||
// Check returns true if a cached index exists for the (repo, commit) pair.
|
||||
// It verifies the entry directory exists and contains the expected files.
|
||||
func (c *Cache) Check(repo, commit string) bool {
|
||||
dir := c.entryDir(repo, commit)
|
||||
info, err := os.Stat(dir)
|
||||
if err != nil || !info.IsDir() {
|
||||
return false
|
||||
}
|
||||
// Verify .version file exists.
|
||||
if _, err := os.Stat(c.versionFile(repo, commit)); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Load returns the path to the cached index directory for the (repo, commit) pair.
|
||||
// Returns an error if the cache entry does not exist.
|
||||
func (c *Cache) Load(repo, commit string) (string, error) {
|
||||
dir := c.entryDir(repo, commit)
|
||||
info, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cache: entry not found for %s: %w", CacheKey(repo, commit), err)
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return "", fmt.Errorf("cache: entry %s is not a directory", CacheKey(repo, commit))
|
||||
}
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
// Store persists an index directory into the cache for the (repo, commit) pair.
|
||||
// It copies the contents of indexPath (graph.bin, search.bleve/) into the cache
|
||||
// entry directory and writes a .version file with the current gortex version.
|
||||
func (c *Cache) Store(repo, commit, indexPath string) error {
|
||||
dir := c.entryDir(repo, commit)
|
||||
|
||||
// Remove any existing entry to ensure a clean store.
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
return fmt.Errorf("cache: remove existing entry: %w", err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
return fmt.Errorf("cache: create entry dir: %w", err)
|
||||
}
|
||||
|
||||
// Copy contents from indexPath into the cache entry.
|
||||
if err := copyDir(indexPath, dir); err != nil {
|
||||
// Clean up on failure.
|
||||
_ = os.RemoveAll(dir)
|
||||
return fmt.Errorf("cache: copy index: %w", err)
|
||||
}
|
||||
|
||||
// Write .version file.
|
||||
if err := os.WriteFile(c.versionFile(repo, commit), []byte(c.version), 0o644); err != nil {
|
||||
_ = os.RemoveAll(dir)
|
||||
return fmt.Errorf("cache: write version file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks whether the cached index for (repo, commit) is compatible
|
||||
// with the current gortex version by comparing the .version file contents.
|
||||
func (c *Cache) Validate(repo, commit string) bool {
|
||||
data, err := os.ReadFile(c.versionFile(repo, commit))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.TrimSpace(string(data)) == c.version
|
||||
}
|
||||
|
||||
// Evict removes the cached index entry for the (repo, commit) pair.
|
||||
func (c *Cache) Evict(repo, commit string) error {
|
||||
dir := c.entryDir(repo, commit)
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
return fmt.Errorf("cache: evict %s: %w", CacheKey(repo, commit), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyDir recursively copies the contents of src into dst.
|
||||
// dst must already exist. Only regular files and directories are copied.
|
||||
func copyDir(src, dst string) error {
|
||||
entries, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(src, entry.Name())
|
||||
dstPath := filepath.Join(dst, entry.Name())
|
||||
|
||||
if entry.IsDir() {
|
||||
if err := os.MkdirAll(dstPath, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copyDir(srcPath, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := copyFile(srcPath, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyFile copies a single file from src to dst, preserving permissions.
|
||||
func copyFile(src, dst string) error {
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
srcInfo, err := srcFile.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dstFile, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, srcInfo.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
_, err = io.Copy(dstFile, srcFile)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user