feat: lazysecrets list prints everything lazysecrets can find, for fzf and editor pickers #70
No files matched your search
+15
-7
@@ -25,23 +25,31 @@ import (
|
|||||||
// listCmd prints every source, vault and secret lazysecrets can find, one
|
// listCmd prints every source, vault and secret lazysecrets can find, one
|
||||||
// per line, for fzf, editor pickers and scripts:
|
// per line, for fzf, editor pickers and scripts:
|
||||||
//
|
//
|
||||||
// lazysecrets list | fzf --ansi --delimiter='\t' --with-nth=3 | cut -f1
|
// lazysecrets list | fzf --ansi --delimiter='\t' --with-nth=1 | cut -f2
|
||||||
//
|
//
|
||||||
// The name is coloured from the theme, with the provider's icon (as in
|
// Each line is the name, then the link: the name coloured from the theme,
|
||||||
// the TUI: --icons, LAZYSECRETS_ICONS, ui.icons); the link never is.
|
// with the provider's icon (as in the TUI: --icons, LAZYSECRETS_ICONS,
|
||||||
|
// ui.icons); the link never is.
|
||||||
//
|
//
|
||||||
// What's cached prints at once; what's missing or older than --max-age
|
// What's cached prints at once; what's missing or older than --max-age
|
||||||
// follows as it loads. Lists that can't be read are reported on stderr.
|
// follows as it loads. Lists that can't be read are reported to errOut:
|
||||||
func listCmd(providers []provider.Provider, cachePath string, timeout func(provider.Kind) time.Duration, theme styles.Styles, withIcons bool, args []string, out, errOut io.Writer) error {
|
// stderr when the output is on the terminal, nothing when it goes into
|
||||||
|
// fzf, whose screen they'd draw over; --errors reports them to stderr
|
||||||
|
// either way.
|
||||||
|
func listCmd(providers []provider.Provider, cachePath string, timeout func(provider.Kind) time.Duration, theme styles.Styles, withIcons bool, args []string, out, errOut, stderr io.Writer) error {
|
||||||
fs := flag.NewFlagSet("list", flag.ContinueOnError)
|
fs := flag.NewFlagSet("list", flag.ContinueOnError)
|
||||||
cached := fs.Bool("cached", false, "only what's cached, and repos: load nothing from Azure or Databricks")
|
cached := fs.Bool("cached", false, "only what's cached, and repos: load nothing from Azure or Databricks")
|
||||||
maxAge := fs.Duration("max-age", 2*time.Minute, "load cached lists older than this again")
|
maxAge := fs.Duration("max-age", 2*time.Minute, "load cached lists older than this again")
|
||||||
format := fs.String("format", "text", "text: link, kind and name, tab-separated; json: an object per line")
|
format := fs.String("format", "text", "text: name and link, tab-separated; json: an object per line")
|
||||||
color := fs.String("color", "always", "colour the names (text): always or never; fzf needs --ansi")
|
color := fs.String("color", "always", "colour the names (text): always or never; fzf needs --ansi")
|
||||||
iconsOn := fs.Bool("icons", withIcons, "put the provider's Nerd Font icon before names (text)")
|
iconsOn := fs.Bool("icons", withIcons, "put the provider's Nerd Font icon before names (text)")
|
||||||
|
showErrors := fs.Bool("errors", false, "report lists that can't be read on stderr also when the output goes into a pipe")
|
||||||
if err := fs.Parse(args); err != nil {
|
if err := fs.Parse(args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if *showErrors {
|
||||||
|
errOut = stderr
|
||||||
|
}
|
||||||
if fs.NArg() > 0 {
|
if fs.NArg() > 0 {
|
||||||
return fmt.Errorf("usage: lazysecrets list [--cached] [--max-age 2m] [--format text|json]")
|
return fmt.Errorf("usage: lazysecrets list [--cached] [--max-age 2m] [--format text|json]")
|
||||||
}
|
}
|
||||||
@@ -56,7 +64,7 @@ func listCmd(providers []provider.Provider, cachePath string, timeout func(provi
|
|||||||
switch *format {
|
switch *format {
|
||||||
case "text":
|
case "text":
|
||||||
write = func(e listing.Entry) error {
|
write = func(e listing.Entry) error {
|
||||||
_, err := fmt.Fprintf(out, "%s\t%s\t%s\n", e.Link, e.Kind, nameOf(e, theme, iconSet, *color == "always"))
|
_, err := fmt.Fprintf(out, "%s\t%s\n", nameOf(e, theme, iconSet, *color == "always"), e.Link)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "json":
|
case "json":
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
tea "charm.land/bubbletea/v2"
|
tea "charm.land/bubbletea/v2"
|
||||||
|
"golang.org/x/term"
|
||||||
|
|
||||||
"git.kebcloud.no/keb/lazysecrets"
|
"git.kebcloud.no/keb/lazysecrets"
|
||||||
"git.kebcloud.no/keb/lazysecrets/internal/commands"
|
"git.kebcloud.no/keb/lazysecrets/internal/commands"
|
||||||
@@ -122,7 +123,7 @@ func run() error {
|
|||||||
lazysecrets [flags] get <ref> print the value a lazysecrets:// link points at,
|
lazysecrets [flags] get <ref> print the value a lazysecrets:// link points at,
|
||||||
for scripts: VAR=$(lazysecrets get <ref>)
|
for scripts: VAR=$(lazysecrets get <ref>)
|
||||||
lazysecrets [flags] list [--cached] [--max-age 2m] [--format text|json]
|
lazysecrets [flags] list [--cached] [--max-age 2m] [--format text|json]
|
||||||
[--color always|never] [--icons=false]
|
[--color always|never] [--icons=false] [--errors]
|
||||||
print every source, vault and secret it can
|
print every source, vault and secret it can
|
||||||
find, one per line, for fzf and pickers:
|
find, one per line, for fzf and pickers:
|
||||||
what's cached at once, then what loads
|
what's cached at once, then what loads
|
||||||
@@ -357,7 +358,12 @@ Flags:
|
|||||||
if d, err := config.CacheDir(); err == nil && !*demo && config.On(cfg.Storage.Cache) {
|
if d, err := config.CacheDir(); err == nil && !*demo && config.On(cfg.Storage.Cache) {
|
||||||
cachePath = filepath.Join(d, "cache.json")
|
cachePath = filepath.Join(d, "cache.json")
|
||||||
}
|
}
|
||||||
return listCmd(providers, cachePath, timeoutFor, theme, *icons, listArgs, os.Stdout, os.Stderr)
|
// Into a pipe (fzf), stderr would draw over what reads it.
|
||||||
|
errOut := io.Discard
|
||||||
|
if term.IsTerminal(int(os.Stdout.Fd())) {
|
||||||
|
errOut = os.Stderr
|
||||||
|
}
|
||||||
|
return listCmd(providers, cachePath, timeoutFor, theme, *icons, listArgs, os.Stdout, errOut, os.Stderr)
|
||||||
}
|
}
|
||||||
if shareArgs != nil {
|
if shareArgs != nil {
|
||||||
// The files from a repo, the key from whichever provider it's
|
// The files from a repo, the key from whichever provider it's
|
||||||
|
|||||||
+12
-9
@@ -139,22 +139,24 @@ a newline only on a terminal.
|
|||||||
### Listing, for fzf and pickers
|
### Listing, for fzf and pickers
|
||||||
|
|
||||||
`lazysecrets list` prints every source, vault and secret, one per line:
|
`lazysecrets list` prints every source, vault and secret, one per line:
|
||||||
its link, its kind (`source`, `vault`, `secret`, `key`, `certificate`)
|
its name (`platform-prod / kv-app-prod / db-password`), then its link,
|
||||||
and its name, tab-separated. It's what Go to searches, so fzf, or an
|
tab-separated. It's what Go to searches, so fzf, or an editor's picker,
|
||||||
editor's picker, can search it instead:
|
can search it instead, showing the names and acting on the links:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
lazysecrets list | fzf --ansi --delimiter='\t' --with-nth=3 \
|
lazysecrets list | fzf --ansi --delimiter='\t' --with-nth=1 \
|
||||||
--bind 'enter:become(lazysecrets open {1})' \
|
--bind 'enter:become(lazysecrets open {2})' \
|
||||||
--bind 'ctrl-y:execute-silent(lazysecrets get {1} | pbcopy)'
|
--bind 'ctrl-y:execute-silent(lazysecrets get {2} | pbcopy)'
|
||||||
```
|
```
|
||||||
|
|
||||||
What's [cached](config.md#cache) prints at once. Then, like Go to, it loads
|
What's [cached](config.md#cache) prints at once. Then, like Go to, it loads
|
||||||
what's missing or older than `--max-age` (2m), and what's new in it follows
|
what's missing or older than `--max-age` (2m), and what's new in it follows
|
||||||
as it arrives: fzf shows it while you type. `--cached` loads nothing from
|
as it arrives: fzf shows it while you type. `--cached` loads nothing from
|
||||||
Azure or Databricks, for an answer at once. Repos are always read, from
|
Azure or Databricks, for an answer at once. Repos are always read, from
|
||||||
disk. What it loads is cached for the TUI too. Lists it can't read are
|
disk. What it loads is cached for the TUI too. It stops when the reader
|
||||||
reported on stderr; it stops when the reader goes, after a pick in fzf.
|
goes, after a pick in fzf. Lists it can't read are reported on stderr when
|
||||||
|
it prints to the terminal; into a pipe they'd draw over fzf, so only with
|
||||||
|
`--errors`.
|
||||||
|
|
||||||
The name is coloured from your [theme](config.md#theme), with the
|
The name is coloured from your [theme](config.md#theme), with the
|
||||||
provider's icon when [icons](config.md#theme) are on (`ui.icons`); fzf
|
provider's icon when [icons](config.md#theme) are on (`ui.icons`); fzf
|
||||||
@@ -162,7 +164,8 @@ shows the colours with `--ansi`. `--color never` leaves them out, for
|
|||||||
scripts, and `--icons=false` the icons. The link is never coloured.
|
scripts, and `--icons=false` the icons. The link is never coloured.
|
||||||
|
|
||||||
`--format json` prints an object per line instead, for editor plugins,
|
`--format json` prints an object per line instead, for editor plugins,
|
||||||
without colours or icons:
|
without colours or icons, with each entry's kind (`source`, `vault`,
|
||||||
|
`secret`, `key` or `certificate`):
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{"link":"lazysecrets://azure/kv-app-prod.vault.azure.net/secrets/db-password","kind":"secret","provider":"azure","path":["platform-prod","kv-app-prod","db-password"],"account":"alice"}
|
{"link":"lazysecrets://azure/kv-app-prod.vault.azure.net/secrets/db-password","kind":"secret","provider":"azure","path":["platform-prod","kv-app-prod","db-password"],"account":"alice"}
|
||||||
|
|||||||
Reference in new issue
Block a user