Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

store last access date in cache and delete 30 days #20

Merged
merged 1 commit into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions docs/reference/docker_runx_cache_prune.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
command: docker runx cache prune
short: Remove all cache entries
long: Remove all cache entries
short: Remove cache entries not accessed recently
long: |
By default remove cache entries not accessed in the last 30 days. Use --all/-a to remove all cache entries.
usage: docker runx cache prune
pname: docker runx cache
plink: docker_runx_cache.yaml
options:
- option: all
shorthand: a
value_type: bool
default_value: "false"
description: Remove all cache entries
deprecated: false
hidden: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
- option: force
shorthand: f
value_type: bool
Expand Down
8 changes: 4 additions & 4 deletions docs/reference/runx_cache.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ Manage Docker RunX cache and temporary files

### Subcommands

| Name | Description |
|:-------------------------------|:-------------------------|
| [`df`](runx_cache_df.md) | Show disk usage |
| [`prune`](runx_cache_prune.md) | Remove all cache entries |
| Name | Description |
|:-------------------------------|:-------------------------------------------|
| [`df`](runx_cache_df.md) | Show disk usage |
| [`prune`](runx_cache_prune.md) | Remove cache entries not accessed recently |



Expand Down
3 changes: 2 additions & 1 deletion docs/reference/runx_cache_prune.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# docker runx cache prune

<!---MARKER_GEN_START-->
Remove all cache entries
By default remove cache entries not accessed in the last 30 days. Use --all/-a to remove all cache entries.

### Options

| Name | Type | Default | Description |
|:----------------|:-------|:--------|:-------------------------------|
| `-a`, `--all` | `bool` | | Remove all cache entries |
| `-f`, `--force` | `bool` | | Do not prompt for confirmation |


Expand Down
15 changes: 14 additions & 1 deletion internal/commands/cache/df.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/spf13/cobra"

"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter/tabwriter"
"github.com/eunomie/docker-runx/runkit"
)

Expand All @@ -31,9 +32,21 @@ func dfNewCmd(dockerCli command.Cli) *cobra.Command {
str := strings.Builder{}
str.WriteString("Cache directory: " + cacheDir + "\n")
str.WriteString("\n")

w := tabwriter.NewWriter(&str, 0, 0, 1, ' ', 0)
_, _ = fmt.Fprintln(w, "Digest\tSize\tLast Access")
for _, e := range entries {
str.WriteString(fmt.Sprintf("%s: %s\n", e.Digest, humanize.Bytes(uint64(e.Size))))
t := "--"
if e.LastAccess != nil {
t = e.LastAccess.Format("2006-01-02 15:04:05")
}
_, _ = fmt.Fprintf(w,
"%s\t%s\t%s\n",
e.Digest,
humanize.Bytes(uint64(e.Size)),
t)
}
_ = w.Flush()
str.WriteString(fmt.Sprintf("Total: %s\n", humanize.Bytes(uint64(totalSize))))

_, _ = fmt.Fprintln(dockerCli.Out(), str.String())
Expand Down
21 changes: 16 additions & 5 deletions internal/commands/cache/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,28 @@ import (
"github.com/spf13/cobra"

"github.com/docker/cli/cli/command"
"github.com/eunomie/docker-runx/internal/sugar"
"github.com/eunomie/docker-runx/runkit"
)

var force bool
var (
force bool
all bool
)

func pruneNewCmd(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "prune",
Short: "Remove all cache entries",
Short: "Remove cache entries not accessed recently",
Long: "By default remove cache entries not accessed in the last 30 days. Use --all/-a to remove all cache entries.",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
var err error
cache := runkit.NewLocalCache(dockerCli)

if !force {
err := huh.NewConfirm().
Title("Are you sure you want to remove all cache entries?").
err = huh.NewConfirm().
Title(sugar.If(all, "Are you sure you want to remove all cache entries?", "Are you sure you want to remove cache entries not accessed in the last 30 days?")).
Value(&force).Run()
if err != nil {
return err
Expand All @@ -34,7 +40,11 @@ func pruneNewCmd(dockerCli command.Cli) *cobra.Command {
return nil
}

err := cache.Erase()
if !all {
err = cache.EraseNotAccessedInLast30Days()
} else {
err = cache.EraseAll()
}
if err != nil {
return err
}
Expand All @@ -46,6 +56,7 @@ func pruneNewCmd(dockerCli command.Cli) *cobra.Command {

flags := cmd.Flags()
flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation")
flags.BoolVarP(&all, "all", "a", false, "Remove all cache entries")

return cmd
}
55 changes: 50 additions & 5 deletions runkit/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"io/fs"
"os"
"path/filepath"
"strings"
"time"

"github.com/docker/cli/cli/command"
"github.com/eunomie/docker-runx/internal/constants"
Expand All @@ -13,6 +15,7 @@ import (
const (
runxConfigFile = "runx.yaml"
runxDocFile = "README.md"
accessFile = "access"
)

var subCacheDir = filepath.Join(constants.SubCommandName, "cache", "sha256")
Expand All @@ -23,8 +26,9 @@ type (
}

CacheEntry struct {
Digest string
Size int64
LastAccess *time.Time
Digest string
Size int64
}
)

Expand Down Expand Up @@ -66,12 +70,21 @@ func (c *LocalCache) Get(digest, src string) (*RunKit, error) {
}

if found {
if err := c.writeAccessFile(digest); err != nil {
return nil, err
}

rk.src = src
return rk, nil
}
return nil, nil
}

func (c *LocalCache) writeAccessFile(digest string) error {
accessDate := time.Now().Format(time.RFC3339)
return os.WriteFile(filepath.Join(c.cacheDir, digest, accessFile), []byte(accessDate), 0o644)
}

func (c *LocalCache) Set(digest string, runxConfig, runxDoc []byte) error {
digestDir := filepath.Join(c.cacheDir, digest)
if err := os.MkdirAll(digestDir, 0o755); err != nil {
Expand All @@ -89,6 +102,9 @@ func (c *LocalCache) Set(digest string, runxConfig, runxDoc []byte) error {
return err
}
}
if err := c.writeAccessFile(digest); err != nil {
return err
}
return nil
}

Expand All @@ -105,9 +121,11 @@ func (c *LocalCache) ListCache() (string, []CacheEntry, int64, error) {
return e
}
totalSize += s
t := c.lastAccess(path)
entries = append(entries, CacheEntry{
Digest: filepath.Base(path),
Size: s,
Digest: filepath.Base(path),
Size: s,
LastAccess: t,
})
return fs.SkipDir
}
Expand All @@ -122,10 +140,37 @@ func (c *LocalCache) ListCache() (string, []CacheEntry, int64, error) {
return c.cacheDir, entries, totalSize, nil
}

func (c *LocalCache) Erase() error {
func (c *LocalCache) EraseAll() error {
return os.RemoveAll(c.cacheDir)
}

func (c *LocalCache) EraseNotAccessedInLast30Days() error {
_, entries, _, err := c.ListCache()
if err != nil {
return err
}
for _, e := range entries {
if e.LastAccess != nil && time.Since(*e.LastAccess) > 30*24*time.Hour {
if err := os.RemoveAll(filepath.Join(c.cacheDir, e.Digest)); err != nil {
return err
}
}
}
return nil
}

func (c *LocalCache) lastAccess(path string) *time.Time {
b, err := os.ReadFile(filepath.Join(path, accessFile))
if err != nil {
return nil
}
if t, err := time.Parse(time.RFC3339, strings.TrimSpace(string(b))); err != nil {
return nil
} else {
return &t
}
}

func dirSize(path string) (int64, error) {
var size int64
err := filepath.Walk(path, func(path string, info fs.FileInfo, err error) error {
Expand Down
Loading