From 9a5e79025138bd2f439bb00140f77521be196570 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 2 Jan 2024 16:44:04 +0100 Subject: [PATCH] feat: add --detailed option to ipfs pin ls --- core/commands/pin/pin.go | 17 +++++++------ core/coreapi/pin.go | 14 +++++------ core/coreiface/options/pin.go | 12 +++++++++- docs/changelogs/v0.26.md | 5 ++++ docs/examples/kubo-as-a-library/go.mod | 2 +- docs/examples/kubo-as-a-library/go.sum | 4 ++-- gc/gc.go | 6 ++--- go.mod | 2 +- go.sum | 4 ++-- test/cli/pins_test.go | 33 ++++++++++++++++++++++++++ test/dependencies/go.mod | 2 +- test/dependencies/go.sum | 4 ++-- 12 files changed, 78 insertions(+), 27 deletions(-) diff --git a/core/commands/pin/pin.go b/core/commands/pin/pin.go index 3d3ccffc7e60..f0535afe6135 100644 --- a/core/commands/pin/pin.go +++ b/core/commands/pin/pin.go @@ -280,9 +280,10 @@ ipfs pin ls -t indirect } const ( - pinTypeOptionName = "type" - pinQuietOptionName = "quiet" - pinStreamOptionName = "stream" + pinTypeOptionName = "type" + pinQuietOptionName = "quiet" + pinStreamOptionName = "stream" + pinDetailedOptionName = "detailed" ) var listPinCmd = &cmds.Command{ @@ -336,6 +337,7 @@ Example: cmds.StringOption(pinTypeOptionName, "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\".").WithDefault("all"), cmds.BoolOption(pinQuietOptionName, "q", "Write just hashes of objects."), cmds.BoolOption(pinStreamOptionName, "s", "Enable streaming of pins as they are discovered."), + cmds.BoolOption(pinDetailedOptionName, "d", "Enable displaying additional information, such as pin names (slower)."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) @@ -345,6 +347,7 @@ Example: typeStr, _ := req.Options[pinTypeOptionName].(string) stream, _ := req.Options[pinStreamOptionName].(bool) + detailed, _ := req.Options[pinDetailedOptionName].(bool) switch typeStr { case "all", "direct", "indirect", "recursive": @@ -370,7 +373,7 @@ Example: if len(req.Arguments) > 0 { err = pinLsKeys(req, typeStr, api, emit) } else { - err = pinLsAll(req, typeStr, api, emit) + err = pinLsAll(req, typeStr, detailed, api, emit) } if err != nil { return err @@ -510,7 +513,7 @@ func pinLsKeys(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fu return nil } -func pinLsAll(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit func(value PinLsOutputWrapper) error) error { +func pinLsAll(req *cmds.Request, typeStr string, detailed bool, api coreiface.CoreAPI, emit func(value PinLsOutputWrapper) error) error { enc, err := cmdenv.GetCidEncoder(req) if err != nil { return err @@ -528,7 +531,7 @@ func pinLsAll(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fun panic("unhandled pin type") } - pins, err := api.Pin().Ls(req.Context, opt) + pins, err := api.Pin().Ls(req.Context, opt, options.Pin.Ls.Detailed(detailed)) if err != nil { return err } @@ -757,7 +760,7 @@ func pinVerify(ctx context.Context, n *core.IpfsNode, opts pinVerifyOpts, enc ci out := make(chan any) go func() { defer close(out) - for p := range n.Pinning.RecursiveKeys(ctx) { + for p := range n.Pinning.RecursiveKeys(ctx, false) { if p.Err != nil { out <- PinVerifyRes{Err: p.Err.Error()} return diff --git a/core/coreapi/pin.go b/core/coreapi/pin.go index e0aeff692987..8db582a4ffa9 100644 --- a/core/coreapi/pin.go +++ b/core/coreapi/pin.go @@ -67,7 +67,7 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan c return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.Type) } - return api.pinLsAll(ctx, settings.Type), nil + return api.pinLsAll(ctx, settings.Type, settings.Detailed), nil } func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.PinIsPinnedOption) (string, bool, error) { @@ -231,7 +231,7 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro out := make(chan coreiface.PinStatus) go func() { defer close(out) - for p := range api.pinning.RecursiveKeys(ctx) { + for p := range api.pinning.RecursiveKeys(ctx, false) { var res *pinStatus if p.Err != nil { res = &pinStatus{err: p.Err} @@ -276,7 +276,7 @@ func (p *pinInfo) Err() error { // // The caller must keep reading results until the channel is closed to prevent // leaking the goroutine that is fetching pins. -func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreiface.Pin { +func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string, detailed bool) <-chan coreiface.Pin { out := make(chan coreiface.Pin, 1) emittedSet := cid.NewSet() @@ -302,7 +302,7 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac var rkeys []cid.Cid var err error if typeStr == "recursive" || typeStr == "all" { - for streamedCid := range api.pinning.RecursiveKeys(ctx) { + for streamedCid := range api.pinning.RecursiveKeys(ctx, detailed) { if streamedCid.Err != nil { out <- &pinInfo{err: streamedCid.Err} return @@ -315,7 +315,7 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac } } if typeStr == "direct" || typeStr == "all" { - for streamedCid := range api.pinning.DirectKeys(ctx) { + for streamedCid := range api.pinning.DirectKeys(ctx, detailed) { if streamedCid.Err != nil { out <- &pinInfo{err: streamedCid.Err} return @@ -330,7 +330,7 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac // We need to first visit the direct pins that have priority // without emitting them - for streamedCid := range api.pinning.DirectKeys(ctx) { + for streamedCid := range api.pinning.DirectKeys(ctx, detailed) { if streamedCid.Err != nil { out <- &pinInfo{err: streamedCid.Err} return @@ -338,7 +338,7 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac emittedSet.Add(streamedCid.Pin.Key) } - for streamedCid := range api.pinning.RecursiveKeys(ctx) { + for streamedCid := range api.pinning.RecursiveKeys(ctx, detailed) { if streamedCid.Err != nil { out <- &pinInfo{err: streamedCid.Err} return diff --git a/core/coreiface/options/pin.go b/core/coreiface/options/pin.go index 38aa9a597f33..0efd853ef225 100644 --- a/core/coreiface/options/pin.go +++ b/core/coreiface/options/pin.go @@ -10,7 +10,8 @@ type PinAddSettings struct { // PinLsSettings represent the settings for PinAPI.Ls type PinLsSettings struct { - Type string + Type string + Detailed bool } // PinIsPinnedSettings represent the settings for PinAPI.IsPinned @@ -195,6 +196,15 @@ func (pinLsOpts) pinType(t string) PinLsOption { } } +// Detailed is an option for [Pin.Ls] which sets whether or not to return +// detailed information, such as pin names and modes. +func (pinLsOpts) Detailed(detailed bool) PinLsOption { + return func(settings *PinLsSettings) error { + settings.Detailed = detailed + return nil + } +} + type pinIsPinnedOpts struct{} // All is an option for Pin.IsPinned which will make it search in all type of pins. diff --git a/docs/changelogs/v0.26.md b/docs/changelogs/v0.26.md index 3a9f088cac62..c56d07be7b39 100644 --- a/docs/changelogs/v0.26.md +++ b/docs/changelogs/v0.26.md @@ -7,6 +7,7 @@ - [Overview](#overview) - [๐Ÿ”ฆ Highlights](#-highlights) - [Several deprecated commands have been removed](#several-deprecated-commands-have-been-removed) + - [Support optional pin names](#support-optional-pin-names) - [๐Ÿ“ Changelog](#-changelog) - [๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Contributors](#-contributors) @@ -30,6 +31,10 @@ Several deprecated commands have been removed: - `ipfs dns` deprecated in [April 2022, Kubo 0.13](https://github.com/ipfs/kubo/commit/76ae33a9f3f9abd166d1f6f23d6a8a0511510e3c), use `ipfs resolve /ipns/{name}` instead. - `ipfs tar` deprecated [April 2022, Kubo 0.13](https://github.com/ipfs/kubo/pull/8849) +#### Support optional pin names + +You can now add a name to a pin when pinning a CID. To do so, use `ipfs pin add --name "Some Name" bafy...`. You can list your pins, including their names, with `ipfs pin ls --detailed`. + ### ๐Ÿ“ Changelog - Export a `kubo.Start` function so users can programmatically start Kubo from within a go program. diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod index d44d61e4f318..57cb97f35deb 100644 --- a/docs/examples/kubo-as-a-library/go.mod +++ b/docs/examples/kubo-as-a-library/go.mod @@ -7,7 +7,7 @@ go 1.20 replace github.com/ipfs/kubo => ./../../.. require ( - github.com/ipfs/boxo v0.16.1-0.20240102112808-a73b1877dbf8 + github.com/ipfs/boxo v0.16.1-0.20240102133734-dc2f8b06ce71 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000 github.com/libp2p/go-libp2p v0.32.2 github.com/multiformats/go-multiaddr v0.12.0 diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum index 8eb5f7ccf10d..8ee7f2913f33 100644 --- a/docs/examples/kubo-as-a-library/go.sum +++ b/docs/examples/kubo-as-a-library/go.sum @@ -303,8 +303,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.16.1-0.20240102112808-a73b1877dbf8 h1:J7v8ilV3rJDSFuEIIfQfEwqYBrdoksTenVRdpUzrpiU= -github.com/ipfs/boxo v0.16.1-0.20240102112808-a73b1877dbf8/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0= +github.com/ipfs/boxo v0.16.1-0.20240102133734-dc2f8b06ce71 h1:4WeZGWkOD4Wr2aGm7xXWdwGgPZbCYHjaz+gVaxx1sJ8= +github.com/ipfs/boxo v0.16.1-0.20240102133734-dc2f8b06ce71/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= diff --git a/gc/gc.go b/gc/gc.go index d8c84555abc1..51df59e54089 100644 --- a/gc/gc.go +++ b/gc/gc.go @@ -226,7 +226,7 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo } return links, nil } - rkeys := pn.RecursiveKeys(ctx) + rkeys := pn.RecursiveKeys(ctx, false) err := Descendants(ctx, getLinks, gcs, rkeys) if err != nil { errors = true @@ -270,7 +270,7 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo } } - dkeys := pn.DirectKeys(ctx) + dkeys := pn.DirectKeys(ctx, false) for k := range dkeys { if k.Err != nil { return nil, k.Err @@ -278,7 +278,7 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo gcs.Add(toCidV1(k.Pin.Key)) } - ikeys := pn.InternalPins(ctx) + ikeys := pn.InternalPins(ctx, false) err = Descendants(ctx, getLinks, gcs, ikeys) if err != nil { errors = true diff --git a/go.mod b/go.mod index d7809c5fb389..0bdd3e19dab4 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/ipfs-shipyard/nopfs v0.0.12-0.20231027223058-cde3b5ba964c github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c - github.com/ipfs/boxo v0.16.1-0.20240102112808-a73b1877dbf8 + github.com/ipfs/boxo v0.16.1-0.20240102133734-dc2f8b06ce71 github.com/ipfs/go-block-format v0.2.0 github.com/ipfs/go-cid v0.4.1 github.com/ipfs/go-cidutil v0.1.0 diff --git a/go.sum b/go.sum index 97d136babcbe..bc5f58fe7774 100644 --- a/go.sum +++ b/go.sum @@ -337,8 +337,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.16.1-0.20240102112808-a73b1877dbf8 h1:J7v8ilV3rJDSFuEIIfQfEwqYBrdoksTenVRdpUzrpiU= -github.com/ipfs/boxo v0.16.1-0.20240102112808-a73b1877dbf8/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0= +github.com/ipfs/boxo v0.16.1-0.20240102133734-dc2f8b06ce71 h1:4WeZGWkOD4Wr2aGm7xXWdwGgPZbCYHjaz+gVaxx1sJ8= +github.com/ipfs/boxo v0.16.1-0.20240102133734-dc2f8b06ce71/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ= diff --git a/test/cli/pins_test.go b/test/cli/pins_test.go index 8a36d469523b..ea2d95058dd6 100644 --- a/test/cli/pins_test.go +++ b/test/cli/pins_test.go @@ -7,6 +7,7 @@ import ( "github.com/ipfs/go-cid" "github.com/ipfs/kubo/test/cli/harness" + "github.com/ipfs/kubo/test/cli/testutils" . "github.com/ipfs/kubo/test/cli/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -209,4 +210,36 @@ func TestPins(t *testing.T) { testPins(t, testPinsArgs{runDaemon: true, baseArg: "--cid-base=base32"}) testPins(t, testPinsArgs{runDaemon: true, lsArg: "--stream", baseArg: "--cid-base=base32"}) }) + + t.Run("test pinning with names", func(t *testing.T) { + t.Parallel() + + node := harness.NewT(t).NewNode().Init() + cidAStr := node.IPFSAddStr(testutils.RandomStr(1000), "--pin=false") + cidBStr := node.IPFSAddStr(testutils.RandomStr(1000), "--pin=false") + + _ = node.IPFS("pin", "add", "--name", "testPin", cidAStr) + + outARegular := cidAStr + " recursive" + outADetailed := outARegular + " testPin" + outBRegular := cidBStr + " recursive" + outBDetailed := outBRegular + " testPin" + + pinLs := func(args ...string) []string { + return strings.Split(node.IPFS(StrCat("pin", "ls", args)...).Stdout.Trimmed(), "\n") + } + + lsOut := pinLs("-t=recursive") + require.Contains(t, lsOut, outARegular) + require.NotContains(t, lsOut, outADetailed) + + lsOut = pinLs("-t=recursive", "--detailed") + require.Contains(t, lsOut, outADetailed) + require.NotContains(t, lsOut, outARegular) + + _ = node.IPFS("pin", "update", cidAStr, cidBStr) + lsOut = pinLs("-t=recursive", "--detailed") + require.Contains(t, lsOut, outBDetailed) + require.NotContains(t, lsOut, outADetailed) + }) } diff --git a/test/dependencies/go.mod b/test/dependencies/go.mod index 852a91b0d7fb..1d7426c78696 100644 --- a/test/dependencies/go.mod +++ b/test/dependencies/go.mod @@ -103,7 +103,7 @@ require ( github.com/hexops/gotextdiff v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/boxo v0.16.1-0.20240102112808-a73b1877dbf8 // indirect + github.com/ipfs/boxo v0.16.1-0.20240102133734-dc2f8b06ce71 // indirect github.com/ipfs/go-block-format v0.2.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-datastore v0.6.0 // indirect diff --git a/test/dependencies/go.sum b/test/dependencies/go.sum index c470f8830d28..2b655ae2f92a 100644 --- a/test/dependencies/go.sum +++ b/test/dependencies/go.sum @@ -342,8 +342,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.16.1-0.20240102112808-a73b1877dbf8 h1:J7v8ilV3rJDSFuEIIfQfEwqYBrdoksTenVRdpUzrpiU= -github.com/ipfs/boxo v0.16.1-0.20240102112808-a73b1877dbf8/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0= +github.com/ipfs/boxo v0.16.1-0.20240102133734-dc2f8b06ce71 h1:4WeZGWkOD4Wr2aGm7xXWdwGgPZbCYHjaz+gVaxx1sJ8= +github.com/ipfs/boxo v0.16.1-0.20240102133734-dc2f8b06ce71/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0= github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=