mirror of
https://github.com/ipfs/kubo.git
synced 2025-12-15 14:11:14 +08:00
feat(add): add support for naming pinned CIDs (#10877)
* feat(add): add support for naming pinned CID Signed-off-by: kapil <kapilsareen584@gmail.com> * fix(add): no double pinning and simplify pin-name - modify PinRoot to accept name parameter, eliminating double pinning - remove automatic filename fallback logic for cleaner behavior - only create named pins when explicitly requested via --pin-name=value - replace NoPinName constant with idiomatic empty string literals - Update help text and tests to reflect explicit-only behavior * docs: changelog * chore: lint * test: negative case for empty pin-name * chore: gofmt --------- Signed-off-by: kapil <kapilsareen584@gmail.com> Co-authored-by: Marcin Rataj <lidel@lidel.org>
This commit is contained in:
@@ -86,7 +86,7 @@ func addMigrationFiles(ctx context.Context, node *core.IpfsNode, paths []string,
|
||||
return err
|
||||
}
|
||||
|
||||
ipfsPath, err := ufs.Add(ctx, files.NewReaderStatFile(f, fi), options.Unixfs.Pin(pin))
|
||||
ipfsPath, err := ufs.Add(ctx, files.NewReaderStatFile(f, fi), options.Unixfs.Pin(pin, ""))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ const (
|
||||
// write-batch. The total size of the batch is limited by
|
||||
// BatchMaxnodes and BatchMaxSize.
|
||||
DefaultBatchMaxSize = 100 << 20 // 20MiB
|
||||
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -37,6 +37,7 @@ type AddEvent struct {
|
||||
}
|
||||
|
||||
const (
|
||||
pinNameOptionName = "pin-name"
|
||||
quietOptionName = "quiet"
|
||||
quieterOptionName = "quieter"
|
||||
silentOptionName = "silent"
|
||||
@@ -184,6 +185,7 @@ See 'dag export' and 'dag import' for more information.
|
||||
cmds.BoolOption(inlineOptionName, "Inline small blocks into CIDs. (experimental)"),
|
||||
cmds.IntOption(inlineLimitOptionName, "Maximum block size to inline. (experimental)").WithDefault(32),
|
||||
cmds.BoolOption(pinOptionName, "Pin locally to protect added files from garbage collection.").WithDefault(true),
|
||||
cmds.StringOption(pinNameOptionName, "Name to use for the pin. Requires explicit value (e.g., --pin-name=myname)."),
|
||||
cmds.StringOption(toFilesOptionName, "Add reference to Files API (MFS) at the provided path."),
|
||||
cmds.BoolOption(preserveModeOptionName, "Apply existing POSIX permissions to created UnixFS entries. Disables raw-leaves. (experimental)"),
|
||||
cmds.BoolOption(preserveMtimeOptionName, "Apply existing POSIX modification time to created UnixFS entries. Disables raw-leaves. (experimental)"),
|
||||
@@ -230,6 +232,7 @@ See 'dag export' and 'dag import' for more information.
|
||||
silent, _ := req.Options[silentOptionName].(bool)
|
||||
chunker, _ := req.Options[chunkerOptionName].(string)
|
||||
dopin, _ := req.Options[pinOptionName].(bool)
|
||||
pinName, pinNameSet := req.Options[pinNameOptionName].(string)
|
||||
rawblks, rbset := req.Options[rawLeavesOptionName].(bool)
|
||||
maxFileLinks, maxFileLinksSet := req.Options[maxFileLinksOptionName].(int)
|
||||
maxDirectoryLinks, maxDirectoryLinksSet := req.Options[maxDirectoryLinksOptionName].(int)
|
||||
@@ -260,6 +263,8 @@ See 'dag export' and 'dag import' for more information.
|
||||
cidVer = int(cfg.Import.CidVersion.WithDefault(config.DefaultCidVersion))
|
||||
}
|
||||
|
||||
// Pin names are only used when explicitly provided via --pin-name=value
|
||||
|
||||
if !rbset && cfg.Import.UnixFSRawLeaves != config.Default {
|
||||
rbset = true
|
||||
rawblks = cfg.Import.UnixFSRawLeaves.WithDefault(config.DefaultUnixFSRawLeaves)
|
||||
@@ -296,7 +301,9 @@ See 'dag export' and 'dag import' for more information.
|
||||
if onlyHash && toFilesSet {
|
||||
return fmt.Errorf("%s and %s options are not compatible", onlyHashOptionName, toFilesOptionName)
|
||||
}
|
||||
|
||||
if !dopin && pinNameSet {
|
||||
return fmt.Errorf("%s option requires %s to be set", pinNameOptionName, pinOptionName)
|
||||
}
|
||||
if wrap && toFilesSet {
|
||||
return fmt.Errorf("%s and %s options are not compatible", wrapOptionName, toFilesOptionName)
|
||||
}
|
||||
@@ -326,7 +333,7 @@ See 'dag export' and 'dag import' for more information.
|
||||
|
||||
options.Unixfs.Chunker(chunker),
|
||||
|
||||
options.Unixfs.Pin(dopin),
|
||||
options.Unixfs.Pin(dopin, pinName),
|
||||
options.Unixfs.HashOnly(onlyHash),
|
||||
options.Unixfs.FsCache(fscache),
|
||||
options.Unixfs.Nocopy(nocopy),
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestPathUnixFSHAMTPartial(t *testing.T) {
|
||||
dir[strconv.Itoa(i)] = files.NewBytesFile([]byte(strconv.Itoa(i)))
|
||||
}
|
||||
|
||||
r, err := a.Unixfs().Add(ctx, files.NewMapDirectory(dir), options.Unixfs.Pin(false))
|
||||
r, err := a.Unixfs().Add(ctx, files.NewMapDirectory(dir), options.Unixfs.Pin(false, ""))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options
|
||||
attribute.Bool("maxhamtfanoutset", settings.MaxHAMTFanoutSet),
|
||||
attribute.Int("layout", int(settings.Layout)),
|
||||
attribute.Bool("pin", settings.Pin),
|
||||
attribute.String("pin-name", settings.PinName),
|
||||
attribute.Bool("onlyhash", settings.OnlyHash),
|
||||
attribute.Bool("fscache", settings.FsCache),
|
||||
attribute.Bool("nocopy", settings.NoCopy),
|
||||
@@ -136,6 +137,9 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options
|
||||
fileAdder.Progress = settings.Progress
|
||||
}
|
||||
fileAdder.Pin = settings.Pin && !settings.OnlyHash
|
||||
if settings.Pin {
|
||||
fileAdder.PinName = settings.PinName
|
||||
}
|
||||
fileAdder.Silent = settings.Silent
|
||||
fileAdder.RawLeaves = settings.RawLeaves
|
||||
if settings.MaxFileLinksSet {
|
||||
|
||||
@@ -39,6 +39,7 @@ type UnixfsAddSettings struct {
|
||||
Layout Layout
|
||||
|
||||
Pin bool
|
||||
PinName string
|
||||
OnlyHash bool
|
||||
FsCache bool
|
||||
NoCopy bool
|
||||
@@ -83,6 +84,7 @@ func UnixfsAddOptions(opts ...UnixfsAddOption) (*UnixfsAddSettings, cid.Prefix,
|
||||
Layout: BalancedLayout,
|
||||
|
||||
Pin: false,
|
||||
PinName: "",
|
||||
OnlyHash: false,
|
||||
FsCache: false,
|
||||
NoCopy: false,
|
||||
@@ -280,9 +282,12 @@ func (unixfsOpts) Layout(layout Layout) UnixfsAddOption {
|
||||
}
|
||||
|
||||
// Pin tells the adder to pin the file root recursively after adding
|
||||
func (unixfsOpts) Pin(pin bool) UnixfsAddOption {
|
||||
func (unixfsOpts) Pin(pin bool, pinName string) UnixfsAddOption {
|
||||
return func(settings *UnixfsAddSettings) error {
|
||||
settings.Pin = pin
|
||||
if pin {
|
||||
settings.PinName = pinName
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,7 +539,7 @@ func (tp *TestSuite) TestAddPinned(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = api.Unixfs().Add(ctx, strFile(helloStr)(), options.Unixfs.Pin(true))
|
||||
_, err = api.Unixfs().Add(ctx, strFile(helloStr)(), options.Unixfs.Pin(true, ""))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ type Adder struct {
|
||||
Out chan<- interface{}
|
||||
Progress bool
|
||||
Pin bool
|
||||
PinName string
|
||||
Trickle bool
|
||||
RawLeaves bool
|
||||
MaxLinks int
|
||||
@@ -182,9 +183,10 @@ func (adder *Adder) curRootNode() (ipld.Node, error) {
|
||||
return root, err
|
||||
}
|
||||
|
||||
// Recursively pins the root node of Adder and
|
||||
// writes the pin state to the backing datastore.
|
||||
func (adder *Adder) PinRoot(ctx context.Context, root ipld.Node) error {
|
||||
// PinRoot recursively pins the root node of Adder with an optional name and
|
||||
// writes the pin state to the backing datastore. If name is empty, the pin
|
||||
// will be created without a name.
|
||||
func (adder *Adder) PinRoot(ctx context.Context, root ipld.Node, name string) error {
|
||||
ctx, span := tracing.Span(ctx, "CoreUnix.Adder", "PinRoot")
|
||||
defer span.End()
|
||||
|
||||
@@ -207,7 +209,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, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -369,7 +371,12 @@ func (adder *Adder) AddAllAndPin(ctx context.Context, file files.Node) (ipld.Nod
|
||||
if !adder.Pin {
|
||||
return nd, nil
|
||||
}
|
||||
return nd, adder.PinRoot(ctx, nd)
|
||||
|
||||
if err := adder.PinRoot(ctx, nd, adder.PinName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nd, nil
|
||||
}
|
||||
|
||||
func (adder *Adder) addFileNode(ctx context.Context, path string, file files.Node, toplevel bool) error {
|
||||
@@ -530,7 +537,7 @@ func (adder *Adder) maybePauseForGC(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = adder.PinRoot(ctx, rn)
|
||||
err = adder.PinRoot(ctx, rn, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ This release was brought to you by the [Interplanetary Shipyard](https://ipship
|
||||
- [Overview](#overview)
|
||||
- [🔦 Highlights](#-highlights)
|
||||
- [Clear provide queue when reprovide strategy changes](#clear-provide-queue-when-reprovide-strategy-changes)
|
||||
- [Named pins in `ipfs add` command](#-named-pins-in-ipfs-add-command)
|
||||
- [Removed unnecessary dependencies](#removed-unnecessary-dependencies)
|
||||
- [📦️ Important dependency updates](#-important-dependency-updates)
|
||||
- [📝 Changelog](#-changelog)
|
||||
@@ -31,6 +32,18 @@ A new `ipfs provide clear` command also allows manual queue clearing for debuggi
|
||||
> [!NOTE]
|
||||
> Upgrading to Kubo 0.37 will automatically clear any preexisting provide queue. The next time `Reprovider.Interval` hits, `Reprovider.Strategy` will be executed on a clean slate, ensuring consistent behavior with your current configuration.
|
||||
|
||||
#### 🧷 Named pins in `ipfs add` command
|
||||
|
||||
Added `--pin-name` flag to `ipfs add` for assigning names to pins.
|
||||
|
||||
```console
|
||||
$ ipfs add --pin-name=testname cat.jpg
|
||||
added bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi cat.jpg
|
||||
|
||||
$ ipfs pin ls --names
|
||||
bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi recursive testname
|
||||
```
|
||||
|
||||
#### Removed unnecessary dependencies
|
||||
|
||||
Kubo has been cleaned up by removing unnecessary dependencies and packages:
|
||||
|
||||
@@ -108,6 +108,44 @@ func TestAdd(t *testing.T) {
|
||||
require.Equal(t, shortStringCidV1NoRawLeaves, cidStr)
|
||||
})
|
||||
|
||||
t.Run("ipfs add --pin-name=foo", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
node := harness.NewT(t).NewNode().Init().StartDaemon()
|
||||
defer node.StopDaemon()
|
||||
|
||||
pinName := "test-pin-name"
|
||||
cidStr := node.IPFSAddStr(shortString, "--pin-name", pinName)
|
||||
require.Equal(t, shortStringCidV0, cidStr)
|
||||
|
||||
pinList := node.IPFS("pin", "ls", "--names").Stdout.Trimmed()
|
||||
require.Contains(t, pinList, shortStringCidV0)
|
||||
require.Contains(t, pinList, pinName)
|
||||
})
|
||||
|
||||
t.Run("ipfs add --pin=false --pin-name=foo returns an error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
node := harness.NewT(t).NewNode().Init().StartDaemon()
|
||||
defer node.StopDaemon()
|
||||
|
||||
// Use RunIPFS to allow for errors without assertion
|
||||
result := node.RunIPFS("add", "--pin=false", "--pin-name=foo")
|
||||
require.Error(t, result.Err, "Expected an error due to incompatible --pin and --pin-name")
|
||||
require.Contains(t, result.Stderr.String(), "pin-name option requires pin to be set")
|
||||
})
|
||||
|
||||
t.Run("ipfs add --pin-name without value should fail", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
node := harness.NewT(t).NewNode().Init().StartDaemon()
|
||||
defer node.StopDaemon()
|
||||
|
||||
// When --pin-name is passed without any value, it should fail
|
||||
result := node.RunIPFS("add", "--pin-name")
|
||||
require.Error(t, result.Err, "Expected an error when --pin-name has no value")
|
||||
require.Contains(t, result.Stderr.String(), "missing argument for option \"pin-name\"")
|
||||
})
|
||||
|
||||
t.Run("produced unixfs max file links: command flag --max-file-links overrides configuration in Import.UnixFSFileMaxLinks", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user