Files
awesome-docker/internal/cache/cache.go
T
Julien Bisconti 29222bfcb5
Deploy to GitHub Pages / build (push) Failing after 51s
Deploy to GitHub Pages / deploy (push) Has been skipped
Pull Requests / Weekly QA / test (push) Failing after 1m13s
Broken Links Report / check-links (push) Failing after 45s
feat: add prune subcommand, drop archived/stale entries (#1441)
* feat: add prune subcommand, drop archived/stale entries, add container-explorer

Add a new `awesome-docker prune` subcommand that removes README entries
whose repository health status matches a configurable set (default:
archived,stale). URLs are read from the local health cache, or from a
markdown report file via --from-report when the cache is outdated.

Apply it against the issue #1439 health report to remove 5 entries
that survived the recent reorg: stitchocker, docker-consul,
blockbridge-docker-volume, docker-explorer, dockdash.

Add google/container-explorer in the Security section as the actively
maintained successor to the now-archived google/docker-explorer.

Co-Authored-By: Claude <noreply@anthropic.com>

* golangci-lint config

* fix: address golangci-lint findings

Fixes errcheck on bufio.Writer.WriteString, gocritic rangeValCopy via
indexed loops with pointer locals, gosec G703 on user-supplied CLI
output path, noctx by switching to exec.CommandContext with a timeout
in the TUI url opener, prealloc in the scorer test, plus fieldalignment
struct reorders and golines line breaks from --fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-18 23:46:32 +02:00

101 lines
2.4 KiB
Markdown

package cache
import (
"os"
"strings"
"time"
"gopkg.in/yaml.v3"
)
// ExcludeList holds URL prefixes to skip during checking.
type ExcludeList struct {
Domains []string `yaml:"domains"`
}
// IsExcluded returns true if the URL starts with any excluded prefix.
func (e *ExcludeList) IsExcluded(url string) bool {
for _, d := range e.Domains {
if strings.HasPrefix(url, d) {
return true
}
}
return false
}
// LoadExcludeList reads an exclude.yaml file.
func LoadExcludeList(path string) (*ExcludeList, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var excl ExcludeList
if err := yaml.Unmarshal(data, &excl); err != nil {
return nil, err
}
return &excl, nil
}
// HealthEntry stores metadata about a single entry.
type HealthEntry struct {
LastPush time.Time `yaml:"last_push,omitempty"`
CheckedAt time.Time `yaml:"checked_at"`
URL string `yaml:"url"`
Name string `yaml:"name"`
Status string `yaml:"status"`
Category string `yaml:"category,omitempty"`
Description string `yaml:"description,omitempty"`
Stars int `yaml:"stars,omitempty"`
Forks int `yaml:"forks,omitempty"`
HasLicense bool `yaml:"has_license,omitempty"`
HasReadme bool `yaml:"has_readme,omitempty"`
}
// HealthCache is the full YAML cache file.
type HealthCache struct {
Entries []HealthEntry `yaml:"entries"`
}
// LoadHealthCache reads a health_cache.yaml file. Returns empty cache if file doesn't exist.
func LoadHealthCache(path string) (*HealthCache, error) {
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return &HealthCache{}, nil
}
return nil, err
}
var hc HealthCache
if err := yaml.Unmarshal(data, &hc); err != nil {
return nil, err
}
return &hc, nil
}
// SaveHealthCache writes the cache to a YAML file.
func SaveHealthCache(path string, hc *HealthCache) error {
data, err := yaml.Marshal(hc)
if err != nil {
return err
}
return os.WriteFile(path, data, 0o644)
}
// Merge updates the cache with new entries, replacing existing ones by URL.
func (hc *HealthCache) Merge(entries []HealthEntry) {
index := make(map[string]int)
for i := range hc.Entries {
e := &hc.Entries[i]
index[e.URL] = i
}
for i := range entries {
e := &entries[i]
if j, exists := index[e.URL]; exists {
hc.Entries[j] = *e
} else {
index[e.URL] = len(hc.Entries)
hc.Entries = append(hc.Entries, *e)
}
}
}