Files

144 lines
3.0 KiB
Go

package services
import (
"fmt"
"os"
"path/filepath"
"time"
)
// CacheCleanupResult holds the outcome of a cleanup operation.
type CacheCleanupResult struct {
RemovedCount int `json:"removed_count"`
FreedBytes int64 `json:"freed_bytes"`
RemovedPaths []string `json:"removed_paths"`
}
type repoEntry struct {
name string
path string
modTime time.Time
size int64
}
// CleanupExpiredRepos removes repos older than maxAge days from reposDir.
func CleanupExpiredRepos(reposDir string, maxAgeDays int) (*CacheCleanupResult, error) {
result := &CacheCleanupResult{}
cutoff := time.Now().AddDate(0, 0, -maxAgeDays)
entries, err := os.ReadDir(reposDir)
if err != nil {
if os.IsNotExist(err) {
return result, nil
}
return nil, fmt.Errorf("read repos dir: %w", err)
}
for _, entry := range entries {
if !entry.IsDir() {
continue
}
info, err := entry.Info()
if err != nil {
continue
}
if info.ModTime().Before(cutoff) {
repoPath := filepath.Join(reposDir, entry.Name())
size := dirSize(repoPath)
if err := os.RemoveAll(repoPath); err != nil {
continue
}
result.RemovedCount++
result.FreedBytes += size
result.RemovedPaths = append(result.RemovedPaths, entry.Name())
}
}
return result, nil
}
// CleanupBySize removes oldest repos until total size is under maxMB.
func CleanupBySize(reposDir string, maxMB int) (*CacheCleanupResult, error) {
result := &CacheCleanupResult{}
maxBytes := int64(maxMB) * 1024 * 1024
entries, err := os.ReadDir(reposDir)
if err != nil {
if os.IsNotExist(err) {
return result, nil
}
return nil, err
}
// Collect repo info with mod time
var repos []repoEntry
var totalSize int64
for _, entry := range entries {
if !entry.IsDir() {
continue
}
info, err := entry.Info()
if err != nil {
continue
}
repoPath := filepath.Join(reposDir, entry.Name())
size := dirSize(repoPath)
repos = append(repos, repoEntry{
name: entry.Name(),
path: repoPath,
modTime: info.ModTime(),
size: size,
})
totalSize += size
}
if totalSize <= maxBytes {
return result, nil
}
// Sort oldest first
sortReposByModTime(repos)
for _, repo := range repos {
if totalSize <= maxBytes {
break
}
if err := os.RemoveAll(repo.path); err != nil {
continue
}
totalSize -= repo.size
result.RemovedCount++
result.FreedBytes += repo.size
result.RemovedPaths = append(result.RemovedPaths, repo.name)
}
return result, nil
}
// GetCacheStats returns current cache statistics.
func GetCacheStats(reposDir string) (count int, totalBytes int64) {
entries, err := os.ReadDir(reposDir)
if err != nil {
return 0, 0
}
for _, entry := range entries {
if !entry.IsDir() {
continue
}
count++
totalBytes += dirSize(filepath.Join(reposDir, entry.Name()))
}
return
}
func sortReposByModTime(repos []repoEntry) {
for i := 0; i < len(repos); i++ {
for j := i + 1; j < len(repos); j++ {
if repos[j].modTime.Before(repos[i].modTime) {
repos[i], repos[j] = repos[j], repos[i]
}
}
}
}