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:
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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=
|
||||
|
@ -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
|
||||
}
|
||||
|
16
gc/gc.go
16
gc/gc.go
@ -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
|
||||
|
@ -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
2
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.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
4
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.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=
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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=
|
||||
|
Reference in New Issue
Block a user