1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-05-18 07:26:42 +08:00

feat: support optional pin names (#10261)

This commit is contained in:
Henrique Dias
2024-01-04 14:25:06 +01:00
committed by GitHub
parent 765cffe6c2
commit a8a6bbe929
22 changed files with 200 additions and 60 deletions

View File

@ -26,6 +26,7 @@ type pinRefKeyList struct {
type pin struct {
path path.ImmutablePath
typ string
name string
err error
}
@ -37,6 +38,10 @@ func (p pin) Path() path.ImmutablePath {
return p.path
}
func (p pin) Name() string {
return p.name
}
func (p pin) Type() string {
return p.typ
}
@ -53,6 +58,7 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp
type pinLsObject struct {
Cid string
Name string
Type string
}
@ -102,7 +108,7 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan i
}
select {
case ch <- pin{typ: out.Type, path: path.FromCid(c)}:
case ch <- pin{typ: out.Type, name: out.Name, path: path.FromCid(c)}:
case <-ctx.Done():
return
}

View File

@ -252,7 +252,7 @@ func initializeIpnsKeyspace(repoRoot string) error {
// pin recursively because this might already be pinned
// and doing a direct pin would throw an error in that case
err = nd.Pinning.Pin(ctx, emptyDir, true)
err = nd.Pinning.Pin(ctx, emptyDir, true, "")
if err != nil {
return err
}

View File

@ -152,7 +152,7 @@ func dagImport(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment
ret.PinErrorMsg = err.Error()
} else if nd, err := blockDecoder.DecodeNode(req.Context, block); err != nil {
ret.PinErrorMsg = err.Error()
} else if err := node.Pinning.Pin(req.Context, nd, true); err != nil {
} else if err := node.Pinning.Pin(req.Context, nd, true, ""); err != nil {
ret.PinErrorMsg = err.Error()
} else if err := node.Pinning.Flush(req.Context); err != nil {
ret.PinErrorMsg = err.Error()

View File

@ -57,6 +57,28 @@ var addPinCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Pin objects to local storage.",
ShortDescription: "Stores an IPFS object(s) from a given path locally to disk.",
LongDescription: `
Create a pin for the given object, protecting resolved CID from being garbage
collected.
An optional name can be provided, and read back via 'ipfs pin ls --names'.
Be mindful of defaults:
Default pin type is 'recursive' (entire DAG).
Pass -r=false to create a direct pin for a single block.
Use 'pin ls -t recursive' to only list roots of recursively pinned DAGs
(significantly faster when many big DAGs are pinned recursively)
Default pin name is empty. Pass '--name' to 'pin add' to set one
and use 'pin ls --names' to see it.
Pin add is idempotent: pinning CID which is already pinned won't change
the name, value passed with '--name' with the original pin is preserved.
To rename pin, use 'pin rm' and 'pin add --name'.
If daemon is running, any missing blocks will be retrieved from the network.
It may take some time. Pass '--progress' to track the progress.
`,
},
Arguments: []cmds.Argument{
@ -64,6 +86,7 @@ var addPinCmd = &cmds.Command{
},
Options: []cmds.Option{
cmds.BoolOption(pinRecursiveOptionName, "r", "Recursively pin the object linked to by the specified object(s).").WithDefault(true),
cmds.StringOption(pinNameOptionName, "n", "An optional name for created pin(s)."),
cmds.BoolOption(pinProgressOptionName, "Show progress"),
},
Type: AddPinOutput{},
@ -75,6 +98,7 @@ var addPinCmd = &cmds.Command{
// set recursive flag
recursive, _ := req.Options[pinRecursiveOptionName].(bool)
name, _ := req.Options[pinNameOptionName].(string)
showProgress, _ := req.Options[pinProgressOptionName].(bool)
if err := req.ParseBodyArgs(); err != nil {
@ -87,7 +111,7 @@ var addPinCmd = &cmds.Command{
}
if !showProgress {
added, err := pinAddMany(req.Context, api, enc, req.Arguments, recursive)
added, err := pinAddMany(req.Context, api, enc, req.Arguments, recursive, name)
if err != nil {
return err
}
@ -105,7 +129,7 @@ var addPinCmd = &cmds.Command{
ch := make(chan pinResult, 1)
go func() {
added, err := pinAddMany(ctx, api, enc, req.Arguments, recursive)
added, err := pinAddMany(ctx, api, enc, req.Arguments, recursive, name)
ch <- pinResult{pins: added, err: err}
}()
@ -181,7 +205,7 @@ var addPinCmd = &cmds.Command{
},
}
func pinAddMany(ctx context.Context, api coreiface.CoreAPI, enc cidenc.Encoder, paths []string, recursive bool) ([]string, error) {
func pinAddMany(ctx context.Context, api coreiface.CoreAPI, enc cidenc.Encoder, paths []string, recursive bool, name string) ([]string, error) {
added := make([]string, len(paths))
for i, b := range paths {
p, err := cmdutils.PathOrCidPath(b)
@ -194,7 +218,7 @@ func pinAddMany(ctx context.Context, api coreiface.CoreAPI, enc cidenc.Encoder,
return nil, err
}
if err := api.Pin().Add(ctx, rp, options.Pin.Recursive(recursive)); err != nil {
if err := api.Pin().Add(ctx, rp, options.Pin.Recursive(recursive), options.Pin.Name(name)); err != nil {
return nil, err
}
added[i] = enc.Encode(rp.RootCid())
@ -281,6 +305,7 @@ const (
pinTypeOptionName = "type"
pinQuietOptionName = "quiet"
pinStreamOptionName = "stream"
pinNamesOptionName = "names"
)
var listPinCmd = &cmds.Command{
@ -294,6 +319,7 @@ respectively.
`,
LongDescription: `
Returns a list of objects that are pinned locally.
By default, all pinned objects are returned, but the '--type' flag or
arguments can restrict that to a specific pin type or to some specific objects
respectively.
@ -306,6 +332,9 @@ Valid values are:
* "indirect": pinned indirectly by an ancestor (like a refcount)
* "all"
By default, pin names are not included (returned as empty).
Pass '--names' flag to return pin names (set with '--name' from 'pin add').
With arguments, the command fails if any of the arguments is not a pinned
object. And if --type=<type> is additionally used, the command will also fail
if any of the arguments is not of the specified type.
@ -334,6 +363,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(pinNamesOptionName, "n", "Enable displaying pin names (slower)."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env, req)
@ -343,6 +373,7 @@ Example:
typeStr, _ := req.Options[pinTypeOptionName].(string)
stream, _ := req.Options[pinStreamOptionName].(bool)
displayNames, _ := req.Options[pinNamesOptionName].(bool)
switch typeStr {
case "all", "direct", "indirect", "recursive":
@ -356,7 +387,7 @@ Example:
lgcList := map[string]PinLsType{}
if !stream {
emit = func(v PinLsOutputWrapper) error {
lgcList[v.PinLsObject.Cid] = PinLsType{Type: v.PinLsObject.Type}
lgcList[v.PinLsObject.Cid] = PinLsType{Type: v.PinLsObject.Type, Name: v.PinLsObject.Name}
return nil
}
} else {
@ -368,7 +399,7 @@ Example:
if len(req.Arguments) > 0 {
err = pinLsKeys(req, typeStr, api, emit)
} else {
err = pinLsAll(req, typeStr, api, emit)
err = pinLsAll(req, typeStr, displayNames, api, emit)
}
if err != nil {
return err
@ -402,8 +433,10 @@ Example:
if stream {
if quiet {
fmt.Fprintf(w, "%s\n", out.PinLsObject.Cid)
} else {
} else if out.PinLsObject.Name == "" {
fmt.Fprintf(w, "%s %s\n", out.PinLsObject.Cid, out.PinLsObject.Type)
} else {
fmt.Fprintf(w, "%s %s %s\n", out.PinLsObject.Cid, out.PinLsObject.Type, out.PinLsObject.Name)
}
return nil
}
@ -411,8 +444,10 @@ Example:
for k, v := range out.PinLsList.Keys {
if quiet {
fmt.Fprintf(w, "%s\n", k)
} else {
} else if v.Name == "" {
fmt.Fprintf(w, "%s %s\n", k, v.Type)
} else {
fmt.Fprintf(w, "%s %s %s\n", k, v.Type, v.Name)
}
}
@ -437,11 +472,13 @@ type PinLsList struct {
// PinLsType contains the type of a pin
type PinLsType struct {
Type string
Name string
}
// PinLsObject contains the description of a pin
type PinLsObject struct {
Cid string `json:",omitempty"`
Name string `json:",omitempty"`
Type string `json:",omitempty"`
}
@ -502,7 +539,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
@ -520,7 +557,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
}
@ -532,6 +569,7 @@ func pinLsAll(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fun
err = emit(PinLsOutputWrapper{
PinLsObject: PinLsObject{
Type: p.Type(),
Name: p.Name(),
Cid: enc.Encode(p.Path().RootCid()),
},
})
@ -748,15 +786,15 @@ 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
}
pinStatus := checkPin(p.C)
pinStatus := checkPin(p.Pin.Key)
if !pinStatus.Ok || opts.includeOk {
select {
case out <- PinVerifyRes{Cid: enc.Encode(p.C), PinStatus: pinStatus}:
case out <- PinVerifyRes{Cid: enc.Encode(p.Pin.Key), PinStatus: pinStatus}:
case <-ctx.Done():
return
}

View File

@ -60,7 +60,7 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc
}
if settings.Pin {
if err = api.pinning.PinWithMode(ctx, b.Cid(), pin.Recursive); err != nil {
if err = api.pinning.PinWithMode(ctx, b.Cid(), pin.Recursive, ""); err != nil {
return nil, err
}
if err := api.pinning.Flush(ctx); err != nil {

View File

@ -30,7 +30,7 @@ func (adder *pinningAdder) Add(ctx context.Context, nd ipld.Node) error {
return err
}
if err := adder.pinning.PinWithMode(ctx, nd.Cid(), pin.Recursive); err != nil {
if err := adder.pinning.PinWithMode(ctx, nd.Cid(), pin.Recursive, ""); err != nil {
return err
}
@ -51,7 +51,7 @@ func (adder *pinningAdder) AddMany(ctx context.Context, nds []ipld.Node) error {
for _, nd := range nds {
c := nd.Cid()
if cids.Visit(c) {
if err := adder.pinning.PinWithMode(ctx, c, pin.Recursive); err != nil {
if err := adder.pinning.PinWithMode(ctx, c, pin.Recursive, ""); err != nil {
return err
}
}

View File

@ -133,7 +133,7 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj
}
if options.Pin {
if err := api.pinning.PinWithMode(ctx, dagnode.Cid(), pin.Recursive); err != nil {
if err := api.pinning.PinWithMode(ctx, dagnode.Cid(), pin.Recursive, ""); err != nil {
return path.ImmutablePath{}, err
}

View File

@ -38,7 +38,7 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp
defer api.blockstore.PinLock(ctx).Unlock(ctx)
err = api.pinning.Pin(ctx, dagNode, settings.Recursive)
err = api.pinning.Pin(ctx, dagNode, settings.Recursive, settings.Name)
if err != nil {
return fmt.Errorf("pin: %s", err)
}
@ -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,12 +231,12 @@ 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}
} else {
res = checkPin(p.C)
res = checkPin(p.Pin.Key)
}
select {
case <-ctx.Done():
@ -252,6 +252,7 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro
type pinInfo struct {
pinType string
path path.ImmutablePath
name string
err error
}
@ -263,6 +264,10 @@ func (p *pinInfo) Type() string {
return p.pinType
}
func (p *pinInfo) Name() string {
return p.name
}
func (p *pinInfo) Err() error {
return p.err
}
@ -271,16 +276,17 @@ 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()
AddToResultKeys := func(c cid.Cid, typeStr string) error {
AddToResultKeys := func(c cid.Cid, name, typeStr string) error {
if emittedSet.Visit(c) {
select {
case out <- &pinInfo{
pinType: typeStr,
name: name,
path: path.FromCid(c),
}:
case <-ctx.Done():
@ -296,25 +302,25 @@ 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
}
if err = AddToResultKeys(streamedCid.C, "recursive"); err != nil {
if err = AddToResultKeys(streamedCid.Pin.Key, streamedCid.Pin.Name, "recursive"); err != nil {
out <- &pinInfo{err: err}
return
}
rkeys = append(rkeys, streamedCid.C)
rkeys = append(rkeys, streamedCid.Pin.Key)
}
}
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
}
if err = AddToResultKeys(streamedCid.C, "direct"); err != nil {
if err = AddToResultKeys(streamedCid.Pin.Key, streamedCid.Pin.Name, "direct"); err != nil {
out <- &pinInfo{err: err}
return
}
@ -324,21 +330,21 @@ 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
}
emittedSet.Add(streamedCid.C)
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
}
emittedSet.Add(streamedCid.C)
rkeys = append(rkeys, streamedCid.C)
emittedSet.Add(streamedCid.Pin.Key)
rkeys = append(rkeys, streamedCid.Pin.Key)
}
}
if typeStr == "indirect" || typeStr == "all" {
@ -353,7 +359,7 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac
if emittedSet.Has(c) {
return true // skipped
}
err := AddToResultKeys(c, "indirect")
err := AddToResultKeys(c, "", "indirect")
if err != nil {
out <- &pinInfo{err: err}
return false

View File

@ -5,11 +5,13 @@ import "fmt"
// PinAddSettings represent the settings for PinAPI.Add
type PinAddSettings struct {
Recursive bool
Name string
}
// PinLsSettings represent the settings for PinAPI.Ls
type PinLsSettings struct {
Type string
Detailed bool
}
// PinIsPinnedSettings represent the settings for PinAPI.IsPinned
@ -194,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.
@ -263,6 +274,14 @@ func (pinOpts) Recursive(recursive bool) PinAddOption {
}
}
// Name is an option for Pin.Add which specifies an optional name to add to the pin.
func (pinOpts) Name(name string) PinAddOption {
return func(settings *PinAddSettings) error {
settings.Name = name
return nil
}
}
// RmRecursive is an option for Pin.Rm which specifies whether to recursively
// unpin the object linked to by the specified object(s). This does not remove
// indirect pins referenced by other recursive pins.

View File

@ -13,6 +13,9 @@ type Pin interface {
// Path to the pinned object
Path() path.ImmutablePath
// Name is the name of the pin.
Name() string
// Type of the pin
Type() string

View File

@ -186,7 +186,7 @@ func (adder *Adder) PinRoot(ctx context.Context, root ipld.Node) error {
adder.tempRoot = rnk
}
err = adder.pinning.PinWithMode(ctx, rnk, pin.Recursive)
err = adder.pinning.PinWithMode(ctx, rnk, pin.Recursive, "")
if err != nil {
return err
}

View File

@ -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 --names`.
### 📝 Changelog
- Export a `kubo.Start` function so users can programmatically start Kubo from within a go program.

View File

@ -7,7 +7,7 @@ go 1.20
replace github.com/ipfs/kubo => ./../../..
require (
github.com/ipfs/boxo v0.16.0
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d
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

View File

@ -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.0 h1:A9dUmef5a+mEFki6kbyG7el5gl65CiUBzrDeZxzTWKY=
github.com/ipfs/boxo v0.16.0/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d h1:7tDzalCLHYr4tzrjNrfqZvIki2MEBSrpLBdc0bssDZk=
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d/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=

View File

@ -18,7 +18,7 @@ func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error {
emptyDir := ft.EmptyDirNode()
err := n.Pinning.Pin(ctx, emptyDir, false)
err := n.Pinning.Pin(ctx, emptyDir, false, "")
if err != nil {
return err
}

View File

@ -154,7 +154,7 @@ func GC(ctx context.Context, bs bstore.GCBlockstore, dstor dstore.Datastore, pn
// Descendants recursively finds all the descendants of the given roots and
// adds them to the given cid.Set, using the provided dag.GetLinks function
// to walk the tree.
func Descendants(ctx context.Context, getLinks dag.GetLinks, set *cid.Set, roots <-chan pin.StreamedCid) error {
func Descendants(ctx context.Context, getLinks dag.GetLinks, set *cid.Set, roots <-chan pin.StreamedPin) error {
verifyGetLinks := func(ctx context.Context, c cid.Cid) ([]*ipld.Link, error) {
err := verifcid.ValidateCid(verifcid.DefaultAllowlist, c)
if err != nil {
@ -188,7 +188,7 @@ func Descendants(ctx context.Context, getLinks dag.GetLinks, set *cid.Set, roots
}
// Walk recursively walks the dag and adds the keys to the given set
err := dag.Walk(ctx, verifyGetLinks, wrapper.C, func(k cid.Cid) bool {
err := dag.Walk(ctx, verifyGetLinks, wrapper.Pin.Key, func(k cid.Cid) bool {
return set.Visit(toCidV1(k))
}, dag.Concurrent())
if err != nil {
@ -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
@ -249,14 +249,14 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo
}
return links, nil
}
bestEffortRootsChan := make(chan pin.StreamedCid)
bestEffortRootsChan := make(chan pin.StreamedPin)
go func() {
defer close(bestEffortRootsChan)
for _, root := range bestEffortRoots {
select {
case <-ctx.Done():
return
case bestEffortRootsChan <- pin.StreamedCid{C: root}:
case bestEffortRootsChan <- pin.StreamedPin{Pin: pin.Pinned{Key: root}}:
}
}
}()
@ -270,15 +270,15 @@ 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
}
gcs.Add(toCidV1(k.C))
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

View File

@ -38,14 +38,14 @@ func TestGC(t *testing.T) {
// direct
root, _, err := daggen.MakeDagNode(dserv.Add, 0, 1)
require.NoError(t, err)
err = pinner.PinWithMode(ctx, root, pin.Direct)
err = pinner.PinWithMode(ctx, root, pin.Direct, "")
require.NoError(t, err)
expectedKept = append(expectedKept, root.Hash())
// recursive
root, allCids, err := daggen.MakeDagNode(dserv.Add, 5, 2)
require.NoError(t, err)
err = pinner.PinWithMode(ctx, root, pin.Recursive)
err = pinner.PinWithMode(ctx, root, pin.Recursive, "")
require.NoError(t, err)
expectedKept = append(expectedKept, toMHs(allCids)...)
}

2
go.mod
View File

@ -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.0
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d
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

4
go.sum
View File

@ -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.0 h1:A9dUmef5a+mEFki6kbyG7el5gl65CiUBzrDeZxzTWKY=
github.com/ipfs/boxo v0.16.0/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d h1:7tDzalCLHYr4tzrjNrfqZvIki2MEBSrpLBdc0bssDZk=
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d/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=

View File

@ -209,4 +209,67 @@ 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 cli text output", func(t *testing.T) {
t.Parallel()
node := harness.NewT(t).NewNode().Init()
cidAStr := node.IPFSAddStr(RandomStr(1000), "--pin=false")
cidBStr := node.IPFSAddStr(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", "--names")
require.Contains(t, lsOut, outADetailed)
require.NotContains(t, lsOut, outARegular)
_ = node.IPFS("pin", "update", cidAStr, cidBStr)
lsOut = pinLs("-t=recursive", "--names")
require.Contains(t, lsOut, outBDetailed)
require.NotContains(t, lsOut, outADetailed)
})
// JSON that is also the wire format of /api/v0
t.Run("test pinning with names json output", func(t *testing.T) {
t.Parallel()
node := harness.NewT(t).NewNode().Init()
cidAStr := node.IPFSAddStr(RandomStr(1000), "--pin=false")
cidBStr := node.IPFSAddStr(RandomStr(1000), "--pin=false")
_ = node.IPFS("pin", "add", "--name", "testPinJson", cidAStr)
outARegular := `"` + cidAStr + `":{"Type":"recursive"`
outADetailed := outARegular + `,"Name":"testPinJson"`
outBRegular := `"` + cidBStr + `":{"Type":"recursive"`
outBDetailed := outBRegular + `,"Name":"testPinJson"`
pinLs := func(args ...string) string {
return node.IPFS(StrCat("pin", "ls", "--enc=json", args)...).Stdout.Trimmed()
}
lsOut := pinLs("-t=recursive")
require.Contains(t, lsOut, outARegular)
require.NotContains(t, lsOut, outADetailed)
lsOut = pinLs("-t=recursive", "--names")
require.Contains(t, lsOut, outADetailed)
_ = node.IPFS("pin", "update", cidAStr, cidBStr)
lsOut = pinLs("-t=recursive", "--names")
require.Contains(t, lsOut, outBDetailed)
})
}

View File

@ -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.0 // indirect
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d // 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

View File

@ -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.0 h1:A9dUmef5a+mEFki6kbyG7el5gl65CiUBzrDeZxzTWKY=
github.com/ipfs/boxo v0.16.0/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d h1:7tDzalCLHYr4tzrjNrfqZvIki2MEBSrpLBdc0bssDZk=
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d/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=