diff options
| author | Eltrac <hi@guhub.cn> | 2025-11-21 13:46:10 +0800 |
|---|---|---|
| committer | Eltrac <hi@guhub.cn> | 2025-11-21 13:46:10 +0800 |
| commit | 5205a76de15203655f9807578c8b5586f98a82bc (patch) | |
| tree | b22d0aeead6000d364a8bf1bb42516846b0a8b2b | |
| parent | 963b66e9e7047a188cc31319212d21a78cff49b0 (diff) | |
perf: cache stats for fasterlookup
| -rw-r--r-- | brewcheck.go | 10 | ||||
| -rw-r--r-- | cache.go | 37 | ||||
| -rw-r--r-- | main.go | 35 | ||||
| -rw-r--r-- | statistics.go | 25 |
4 files changed, 87 insertions, 20 deletions
diff --git a/brewcheck.go b/brewcheck.go index d550db4..02546b1 100644 --- a/brewcheck.go +++ b/brewcheck.go @@ -4,20 +4,17 @@ import ( "fmt" "os" "os/exec" - "path/filepath" "time" - "github.com/adrg/xdg" "github.com/fatih/color" ) const TTL = 3 * 24 * time.Hour // 3 days +const cacheName = "brew-checked" func EnsureBrewAvailable() { - cache := filepath.Join(xdg.CacheHome, "wthis", "brew-checked") - // 1. check if cache file exists and is fresh - data, _ := os.ReadFile(cache) + data, _ := ReadCache(cacheName, TTL) t, _ := time.Parse(time.RFC3339, string(data)) if time.Since(t) < TTL { return @@ -32,6 +29,5 @@ func EnsureBrewAvailable() { } // 3. write cache - _ = os.MkdirAll(filepath.Dir(cache), 0o755) - _ = os.WriteFile(cache, []byte(time.Now().Format(time.RFC3339)), 0o644) + WriteCache(cacheName, []byte(time.Now().Format(time.RFC3339))) } diff --git a/cache.go b/cache.go new file mode 100644 index 0000000..d0b11e5 --- /dev/null +++ b/cache.go @@ -0,0 +1,37 @@ +package main + +import ( + "os" + "path/filepath" + "time" + + "github.com/adrg/xdg" +) + +func CachePath(rel string) string { + path := filepath.Join(xdg.CacheHome, "wthis", rel) + _ = os.MkdirAll(filepath.Dir(path), 0o755) + return path +} + +func ReadCache(relPath string, ttl time.Duration) ([]byte, bool) { + path := CachePath(relPath) + + info, err := os.Stat(path) + if err != nil { + return nil, false + } + if time.Since(info.ModTime()) > ttl { + return nil, false + } + b, err := os.ReadFile(path) + if err != nil { + return nil, false + } + return b, true +} + +func WriteCache(relPath string, data []byte) error { + path := CachePath(relPath) + return os.WriteFile(path, data, 0o644) +} @@ -24,21 +24,30 @@ func main() { pkgName := cmd.Args().First() // prompt showLoadingPrompt(fmt.Sprintf("What the heck is \"%s\"", pkgName)) - // search, tidy up, and print - fmlChan := make(chan *FormulaInfo) - caskChan := make(chan *CaskInfo) - rvsChan := make(chan []string) - go func() { - formula, cask := GetBrewInfo(pkgName) - fmlChan <- formula - caskChan <- cask - }() - go func() { - rvsChan <- GetBrewUses(pkgName) - }() - stat := NewStatistics(<-fmlChan, <-caskChan, pkgName,<-rvsChan) + // try reading from cache + var stat *statistics + if stat = NewStatisticsFromCache(pkgName); stat == nil { + fmt.Println("cache not hit") + // cache not hit, then search + fmlChan := make(chan *FormulaInfo) + caskChan := make(chan *CaskInfo) + rvsChan := make(chan []string) + // start 2 goroutines, fetching formula/cask info and uses + go func() { + formula, cask := GetBrewInfo(pkgName) + fmlChan <- formula + caskChan <- cask + }() + go func() { + rvsChan <- GetBrewUses(pkgName) + }() + stat = NewStatistics(<-fmlChan, <-caskChan, pkgName,<-rvsChan) + stat.Cache() + } + // print hideLoadingPrompt() stat.Print() + return nil }, } diff --git a/statistics.go b/statistics.go index 17a01d9..9feaf05 100644 --- a/statistics.go +++ b/statistics.go @@ -1,6 +1,7 @@ package main import ( + "encoding/json" "fmt" "os" "path/filepath" @@ -9,6 +10,7 @@ import ( ) type statistics struct { + PkgName string Name string Type string //formula or cask Desc string @@ -26,6 +28,8 @@ type statistics struct { ReverseDependencies []string } +const dataTTL = time.Hour / 2 + func NewStatistics(formula *FormulaInfo, cask *CaskInfo, pkgName string, rvs []string) *statistics { var statObject statistics @@ -59,6 +63,8 @@ func NewStatistics(formula *FormulaInfo, cask *CaskInfo, pkgName string, rvs []s // === general === // + statObject.PkgName = pkgName + // get system atime var atime time.Time binPath := filepath.Join("/opt/homebrew/bin", pkgName) @@ -75,6 +81,25 @@ func NewStatistics(formula *FormulaInfo, cask *CaskInfo, pkgName string, rvs []s return &statObject } +func NewStatisticsFromCache(pkgName string) *statistics { + raw, success := ReadCache("pkg/"+pkgName+".json", dataTTL) + if success { + var stat statistics + json.Unmarshal(raw, &stat) + return &stat + } + return nil +} + +func (s *statistics) Cache() { + data, err := json.Marshal(s) + if err != nil { + fmt.Println("Error marshaling statistics:", err) + return + } + WriteCache("pkg/"+s.PkgName+".json", data) +} + func (s *statistics) Print() { if s == nil { fmt.Println("Package not found.") |
