diff --git a/cmd/lazysecrets/list.go b/cmd/lazysecrets/list.go index 4b1b51a..d85933c 100644 --- a/cmd/lazysecrets/list.go +++ b/cmd/lazysecrets/list.go @@ -115,9 +115,9 @@ func listCmd(providers []provider.Provider, st *store.Store, cachePath string, t } f = listing.Run(context.Background(), listing.Options{ Providers: providers, Cache: f, MaxAge: *maxAge, Cached: *cached, Kinds: only, Timeout: timeout, - Mark: func(link, account string) (bool, bool) { + Mark: func(link, account string) (bool, time.Time, int) { n := st.Node(link) - return n.StarredFor(account), !n.LastUsed.IsZero() + return n.StarredFor(account), n.LastUsed, n.Uses }, }, emit) if cachePath != "" && !*cached { diff --git a/internal/listing/listing.go b/internal/listing/listing.go index 41fed54..42fac33 100644 --- a/internal/listing/listing.go +++ b/internal/listing/listing.go @@ -40,9 +40,11 @@ type Entry struct { // AccountLabel names the az account, when there are several. AccountLabel string `json:"accountLabel,omitempty"` // Starred is starred for this account; Recent is used lately (Recent, - // R, in the TUI). - Starred bool `json:"starred"` - Recent bool `json:"recent"` + // R, in the TUI): LastUsed is when, Uses how often. + Starred bool `json:"starred"` + Recent bool `json:"recent"` + LastUsed time.Time `json:"lastUsed,omitzero"` + Uses int `json:"uses,omitempty"` // Error says why a source's vaults or a vault's secrets couldn't be // listed. The entry is then that source or vault, again, or with an // account's sources unreadable, the account without a link. @@ -61,9 +63,10 @@ type Options struct { // Lists only needed for other kinds aren't loaded: sources and vaults // alone don't load any secrets. Lists that fail are always listed. Kinds []string - // Mark tells whether the entry with link is starred for account, and - // used lately; nil marks nothing. - Mark func(link, account string) (starred, recent bool) + // Mark tells whether the entry with link is starred for account, + // and when it was last used and how often (zero: not lately); nil + // marks nothing. + Mark func(link, account string) (starred bool, lastUsed time.Time, uses int) Timeout func(provider.Kind) time.Duration Now func() time.Time } @@ -225,7 +228,8 @@ func (l *lister) put(p provider.Provider, e Entry) { } e.Account = p.ID() if l.o.Mark != nil && e.Link != "" { - e.Starred, e.Recent = l.o.Mark(e.Link, e.Account) + e.Starred, e.LastUsed, e.Uses = l.o.Mark(e.Link, e.Account) + e.Recent = !e.LastUsed.IsZero() } id := p.ID() + "\x00" + e.Link + "\x00" + e.Error if l.stopped != nil || l.seen[id] { diff --git a/internal/listing/listing_test.go b/internal/listing/listing_test.go index 8945d45..f639480 100644 --- a/internal/listing/listing_test.go +++ b/internal/listing/listing_test.go @@ -229,11 +229,14 @@ func TestListMarks(t *testing.T) { az := fake.Azure(0) var starredLink string got, _, _ := run(t, Options{Providers: []provider.Provider{az}, MaxAge: time.Minute, Kinds: []string{"secret"}, - Mark: func(link, account string) (bool, bool) { + Mark: func(link, account string) (bool, time.Time, int) { if starredLink == "" && strings.HasSuffix(link, "/db-password") { starredLink = link } - return link == starredLink && account == az.ID(), strings.HasSuffix(link, "/api-key") + if strings.HasSuffix(link, "/api-key") { + return false, time.Now(), 3 + } + return link == starredLink && account == az.ID(), time.Time{}, 0 }}) var starred, recent int for _, e := range got { @@ -245,6 +248,11 @@ func TestListMarks(t *testing.T) { } if e.Recent { recent++ + if e.Uses != 3 || e.LastUsed.IsZero() { + t.Errorf("%s: %d uses, last %v", e.Link, e.Uses, e.LastUsed) + } + } else if e.Uses != 0 || !e.LastUsed.IsZero() { + t.Errorf("%s not recent, but %d uses, last %v", e.Link, e.Uses, e.LastUsed) } } if starred != 1 || recent == 0 {