diff --git a/core/commands/pin/pin.go b/core/commands/pin/pin.go index 3d3ccffc7e6..f0535afe613 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 e0aeff69298..8db582a4ffa 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 38aa9a597f3..0efd853ef22 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 3a9f088cac6..c56d07be7b3 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 d44d61e4f31..57cb97f35de 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 8eb5f7ccf10..8ee7f2913f3 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 d8c84555abc..51df59e5408 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 d7809c5fb38..0bdd3e19dab 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 97d136babcb..bc5f58fe777 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 8a36d469523..ea2d95058dd 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 852a91b0d7f..1d7426c7869 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 c470f8830d2..2b655ae2f92 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=