config: introduce Import section (#10421)
Co-authored-by: Marcin Rataj <lidel@lidel.org>
Henrique Dias committed
May 14, 2024 at 16:17 UTC
8022e13a6b28d58a209e3d4eaefeb102b9e840e0
11 files changed
+305
-8
config/config.go
+1
@@ -36,6 +36,7 @@ type Config struct {
36
Experimental Experiments
37
Plugins Plugins
38
Pinning Pinning
39
+ Import Import
40
41
Internal Internal // experimental/unstable options
42
}
config/import.go
new
+17
@@ -0,0 +1,17 @@
1
+package config
2
+
3
+const (
4
+ DefaultCidVersion = 0
5
+ DefaultUnixFSRawLeaves = false
6
+ DefaultUnixFSChunker = "size-262144"
7
+ DefaultHashFunction = "sha2-256"
8
+)
9
+
10
+// Import configures the default options for ingesting data. This affects commands
11
+// that ingest data, such as 'ipfs add', 'ipfs dag put, 'ipfs block put', 'ipfs files write'.
12
+type Import struct {
13
+ CidVersion OptionalInteger
14
+ UnixFSRawLeaves Flag
15
+ UnixFSChunker OptionalString
16
+ HashFunction OptionalString
17
+}
config/profile.go
+22
@@ -204,6 +204,28 @@ fetching may be degraded.
204
return nil
205
},
206
},
207
+ "legacy-cid-v0": {
208
+ Description: `Makes UnixFS import produce legacy CIDv0 with no raw leaves, sha2-256 and 256 KiB chunks.`,
209
+
210
+ Transform: func(c *Config) error {
211
+ c.Import.CidVersion = *NewOptionalInteger(0)
212
+ c.Import.UnixFSRawLeaves = False
213
+ c.Import.UnixFSChunker = *NewOptionalString("size-262144")
214
+ c.Import.HashFunction = *NewOptionalString("sha2-256")
215
+ return nil
216
+ },
217
+ },
218
+ "test-cid-v1": {
219
+ Description: `Makes UnixFS import produce modern CIDv1 with raw leaves, sha2-256 and 1 MiB chunks.`,
220
+
221
+ Transform: func(c *Config) error {
222
+ c.Import.CidVersion = *NewOptionalInteger(1)
223
+ c.Import.UnixFSRawLeaves = True
224
+ c.Import.UnixFSChunker = *NewOptionalString("size-1048576")
225
+ c.Import.HashFunction = *NewOptionalString("sha2-256")
226
+ return nil
227
+ },
228
+ },
229
}
230
231
func getAvailablePort() (port int, err error) {
core/commands/add.go
+31
-2
@@ -8,6 +8,7 @@ import (
8
gopath "path"
9
"strings"
10
11
+ "github.com/ipfs/kubo/config"
12
"github.com/ipfs/kubo/core/commands/cmdenv"
13
14
"github.com/cheggaaa/pb"
@@ -155,12 +156,12 @@ See 'dag export' and 'dag import' for more information.
156
cmds.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."),
157
cmds.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."),
158
cmds.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."),
158
- cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm, size-[bytes], rabin-[min]-[avg]-[max] or buzhash").WithDefault("size-262144"),
159
+ cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm, size-[bytes], rabin-[min]-[avg]-[max] or buzhash"),
160
cmds.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes."),
161
cmds.BoolOption(noCopyOptionName, "Add the file using filestore. Implies raw-leaves. (experimental)"),
162
cmds.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. (experimental)"),
163
cmds.IntOption(cidVersionOptionName, "CID version. Defaults to 0 unless an option that depends on CIDv1 is passed. Passing version 1 will cause the raw-leaves option to default to true."),
163
- cmds.StringOption(hashOptionName, "Hash function to use. Implies CIDv1 if not sha2-256. (experimental)").WithDefault("sha2-256"),
164
+ cmds.StringOption(hashOptionName, "Hash function to use. Implies CIDv1 if not sha2-256. (experimental)"),
165
cmds.BoolOption(inlineOptionName, "Inline small blocks into CIDs. (experimental)"),
166
cmds.IntOption(inlineLimitOptionName, "Maximum block size to inline. (experimental)").WithDefault(32),
167
cmds.BoolOption(pinOptionName, "Pin locally to protect added files from garbage collection.").WithDefault(true),
@@ -191,6 +192,16 @@ See 'dag export' and 'dag import' for more information.
192
return err
193
}
194
195
+ nd, err := cmdenv.GetNode(env)
196
+ if err != nil {
197
+ return err
198
+ }
199
+
200
+ cfg, err := nd.Repo.Config()
201
+ if err != nil {
202
+ return err
203
+ }
204
+
205
progress, _ := req.Options[progressOptionName].(bool)
206
trickle, _ := req.Options[trickleOptionName].(bool)
207
wrap, _ := req.Options[wrapOptionName].(bool)
@@ -207,6 +218,24 @@ See 'dag export' and 'dag import' for more information.
218
inlineLimit, _ := req.Options[inlineLimitOptionName].(int)
219
toFilesStr, toFilesSet := req.Options[toFilesOptionName].(string)
220
221
+ if chunker == "" {
222
+ chunker = cfg.Import.UnixFSChunker.WithDefault(config.DefaultUnixFSChunker)
223
+ }
224
+
225
+ if hashFunStr == "" {
226
+ hashFunStr = cfg.Import.HashFunction.WithDefault(config.DefaultHashFunction)
227
+ }
228
+
229
+ if !cidVerSet && !cfg.Import.CidVersion.IsDefault() {
230
+ cidVerSet = true
231
+ cidVer = int(cfg.Import.CidVersion.WithDefault(config.DefaultCidVersion))
232
+ }
233
+
234
+ if !rbset && cfg.Import.UnixFSRawLeaves != config.Default {
235
+ rbset = true
236
+ rawblks = cfg.Import.UnixFSRawLeaves.WithDefault(config.DefaultUnixFSRawLeaves)
237
+ }
238
+
239
if onlyHash && toFilesSet {
240
return fmt.Errorf("%s and %s options are not compatible", onlyHashOptionName, toFilesOptionName)
241
}
core/commands/block.go
+16
-1
@@ -8,6 +8,7 @@ import (
8
9
"github.com/ipfs/boxo/files"
10
11
+ "github.com/ipfs/kubo/config"
12
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
13
"github.com/ipfs/kubo/core/commands/cmdutils"
14
@@ -153,7 +154,7 @@ only for backward compatibility when a legacy CIDv0 is required (--format=v0).
154
},
155
Options: []cmds.Option{
156
cmds.StringOption(blockCidCodecOptionName, "Multicodec to use in returned CID").WithDefault("raw"),
156
- cmds.StringOption(mhtypeOptionName, "Multihash hash function").WithDefault("sha2-256"),
157
+ cmds.StringOption(mhtypeOptionName, "Multihash hash function"),
158
cmds.IntOption(mhlenOptionName, "Multihash hash length").WithDefault(-1),
159
cmds.BoolOption(pinOptionName, "Pin added blocks recursively").WithDefault(false),
160
cmdutils.AllowBigBlockOption,
@@ -165,7 +166,21 @@ only for backward compatibility when a legacy CIDv0 is required (--format=v0).
166
return err
167
}
168
169
+ nd, err := cmdenv.GetNode(env)
170
+ if err != nil {
171
+ return err
172
+ }
173
+
174
+ cfg, err := nd.Repo.Config()
175
+ if err != nil {
176
+ return err
177
+ }
178
+
179
mhtype, _ := req.Options[mhtypeOptionName].(string)
180
+ if mhtype == "" {
181
+ mhtype = cfg.Import.HashFunction.WithDefault(config.DefaultHashFunction)
182
+ }
183
+
184
mhtval, ok := mh.Names[mhtype]
185
if !ok {
186
return fmt.Errorf("unrecognized multihash function: %s", mhtype)
core/commands/dag/dag.go
+1
-1
@@ -87,7 +87,7 @@ into an object of the specified format.
87
cmds.StringOption("store-codec", "Codec that the stored object will be encoded with").WithDefault("dag-cbor"),
88
cmds.StringOption("input-codec", "Codec that the input object is encoded in").WithDefault("dag-json"),
89
cmds.BoolOption("pin", "Pin this object when adding."),
90
- cmds.StringOption("hash", "Hash function to use").WithDefault("sha2-256"),
90
+ cmds.StringOption("hash", "Hash function to use"),
91
cmdutils.AllowBigBlockOption,
92
},
93
Run: dagPut,
core/commands/dag/put.go
+15
@@ -7,6 +7,7 @@ import (
7
blocks "github.com/ipfs/go-block-format"
8
"github.com/ipfs/go-cid"
9
ipldlegacy "github.com/ipfs/go-ipld-legacy"
10
+ "github.com/ipfs/kubo/config"
11
"github.com/ipfs/kubo/core/commands/cmdenv"
12
"github.com/ipfs/kubo/core/commands/cmdutils"
13
"github.com/ipld/go-ipld-prime/multicodec"
@@ -32,11 +33,25 @@ func dagPut(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) e
33
return err
34
}
35
36
+ nd, err := cmdenv.GetNode(env)
37
+ if err != nil {
38
+ return err
39
+ }
40
+
41
+ cfg, err := nd.Repo.Config()
42
+ if err != nil {
43
+ return err
44
+ }
45
+
46
inputCodec, _ := req.Options["input-codec"].(string)
47
storeCodec, _ := req.Options["store-codec"].(string)
48
hash, _ := req.Options["hash"].(string)
49
dopin, _ := req.Options["pin"].(bool)
50
51
+ if hash == "" {
52
+ hash = cfg.Import.HashFunction.WithDefault(config.DefaultHashFunction)
53
+ }
54
+
55
var icodec mc.Code
56
if err := icodec.Set(inputCodec); err != nil {
57
return err
core/commands/files.go
+15
-4
@@ -11,6 +11,7 @@ import (
11
"strings"
12
13
humanize "github.com/dustin/go-humanize"
14
+ "github.com/ipfs/kubo/config"
15
"github.com/ipfs/kubo/core"
16
"github.com/ipfs/kubo/core/commands/cmdenv"
17
@@ -802,18 +803,28 @@ See '--to-files' in 'ipfs add --help' for more information.
803
return err
804
}
805
806
+ nd, err := cmdenv.GetNode(env)
807
+ if err != nil {
808
+ return err
809
+ }
810
+
811
+ cfg, err := nd.Repo.Config()
812
+ if err != nil {
813
+ return err
814
+ }
815
+
816
create, _ := req.Options[filesCreateOptionName].(bool)
817
mkParents, _ := req.Options[filesParentsOptionName].(bool)
818
trunc, _ := req.Options[filesTruncateOptionName].(bool)
819
flush, _ := req.Options[filesFlushOptionName].(bool)
820
rawLeaves, rawLeavesDef := req.Options[filesRawLeavesOptionName].(bool)
821
811
- prefix, err := getPrefixNew(req)
812
- if err != nil {
813
- return err
822
+ if !rawLeavesDef && cfg.Import.UnixFSRawLeaves != config.Default {
823
+ rawLeavesDef = true
824
+ rawLeaves = cfg.Import.UnixFSRawLeaves.WithDefault(config.DefaultUnixFSRawLeaves)
825
}
826
816
- nd, err := cmdenv.GetNode(env)
827
+ prefix, err := getPrefixNew(req)
828
if err != nil {
829
return err
830
}
docs/changelogs/v0.29.md
+11
@@ -7,6 +7,7 @@
7
- [Overview](#overview)
8
- [🔦 Highlights](#-highlights)
9
- [Add search functionality for pin names](#add-search-functionality-for-pin-names)
10
+ - [Customizing `ipfs add` defaults](#customizing-ipfs-add-defaults)
11
- [📝 Changelog](#-changelog)
12
- [👨👩👧👦 Contributors](#-contributors)
13
@@ -18,6 +19,16 @@
19
20
It is now possible to search for pins by name. To do so, use `ipfs pin ls --name "SomeName"`. The search is case-sensitive and will return all pins having a name which contains the exact word provided.
21
22
+#### Customizing `ipfs add` defaults
23
+
24
+This release supports overriding global data ingestion defaults used by commands like `ipfs add` via user-defined [`Import.*` configuration options](../config.md#import).
25
+The hash function, CID version, or UnixFS raw leaves and chunker behaviors can be set once, and used as the new implicit default for `ipfs add`.
26
+
27
+> [!TIP]
28
+> As a convenience, two CID [profiles](../config.md#profile) are provided: `legacy-cid-v0` and `test-cid-v1`.
29
+> A test profile that defaults to modern CIDv1 can be applied via `ipfs config profile apply test-cid-v1`.
30
+> We encourage users to try it and report any issues.
31
+
32
### 📝 Changelog
33
34
### 👨👩👧👦 Contributors
docs/config.md
+58
@@ -175,6 +175,11 @@ config file at runtime.
175
- [`DNS`](#dns)
176
- [`DNS.Resolvers`](#dnsresolvers)
177
- [`DNS.MaxCacheTTL`](#dnsmaxcachettl)
178
+ - [`Import`](#import)
179
+ - [`Import.CidVersion`](#importcidversion)
180
+ - [`Import.UnixFSRawLeaves`](#importunixfsrawleaves)
181
+ - [`Import.UnixFSChunker`](#importunixfschunker)
182
+ - [`Import.HashFunction`](#importhashfunction)
183
184
## Profiles
185
@@ -265,6 +270,21 @@ documented in `ipfs config profile --help`.
270
271
Use this profile with caution.
272
273
+- `legacy-cid-v0`
274
+
275
+ Makes UnixFS import (`ipfs add`) produce legacy CIDv0 with no raw leaves, sha2-256 and 256 KiB chunks.
276
+
277
+ > [!WARNING]
278
+ > This profile is provided for legacy users and should not be used for new projects.
279
+
280
+- `test-cid-v1`
281
+
282
+ Makes UnixFS import (`ipfs add`) produce modern CIDv1 with raw leaves, sha2-256 and 1 MiB chunks.
283
+
284
+ > [!NOTE]
285
+ > This profile will become the new implicit default, provided for testing purposes.
286
+ > Follow [kubo#4143](https://github.com/ipfs/kubo/issues/4143) for more details.
287
+
288
## Types
289
290
This document refers to the standard JSON types (e.g., `null`, `string`,
@@ -2377,3 +2397,41 @@ Note: this does NOT work with Go's default DNS resolver. To make this a global s
2397
Default: Respect DNS Response TTL
2398
2399
Type: `optionalDuration`
2400
+
2401
+## `Import`
2402
+
2403
+Options to configure the default options used for ingesting data, in commands such as `ipfs add` or `ipfs block put`. All affected commands are detailed per option.
2404
+
2405
+Note that using flags will override the options defined here.
2406
+
2407
+### `Import.CidVersion`
2408
+
2409
+The default CID version. Commands affected: `ipfs add`.
2410
+
2411
+Default: `0`
2412
+
2413
+Type: `optionalInteger`
2414
+
2415
+### `Import.UnixFSRawLeaves`
2416
+
2417
+The default UnixFS raw leaves option. Commands affected: `ipfs add`, `ipfs files write`.
2418
+
2419
+Default: `false` if `CidVersion=0`; `true` if `CidVersion=1`
2420
+
2421
+Type: `flag`
2422
+
2423
+### `Import.UnixFSChunker`
2424
+
2425
+The default UnixFS chunker. Commands affected: `ipfs add`.
2426
+
2427
+Default: `size-262144`
2428
+
2429
+Type: `optionalString`
2430
+
2431
+### `Import.HashFunction`
2432
+
2433
+The default hash function. Commands affected: `ipfs add`, `ipfs block put`, `ipfs dag put`.
2434
+
2435
+Default: `sha2-256`
2436
+
2437
+Type: `optionalString`
test/cli/add_test.go
new
+118
@@ -0,0 +1,118 @@
1
+package cli
2
+
3
+import (
4
+ "testing"
5
+
6
+ "github.com/ipfs/kubo/config"
7
+ "github.com/ipfs/kubo/test/cli/harness"
8
+ "github.com/stretchr/testify/require"
9
+)
10
+
11
+func TestAdd(t *testing.T) {
12
+ t.Parallel()
13
+
14
+ var (
15
+ shortString = "hello world"
16
+ shortStringCidV0 = "Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD" // cidv0 - dag-pb - sha2-256
17
+ shortStringCidV1 = "bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e" // cidv1 - raw - sha2-256
18
+ shortStringCidV1NoRawLeaves = "bafybeihykld7uyxzogax6vgyvag42y7464eywpf55gxi5qpoisibh3c5wa" // cidv1 - dag-pb - sha2-256
19
+ shortStringCidV1Sha512 = "bafkrgqbqt3gerhas23vuzrapkdeqf4vu2dwxp3srdj6hvg6nhsug2tgyn6mj3u23yx7utftq3i2ckw2fwdh5qmhid5qf3t35yvkc5e5ottlw6"
20
+ )
21
+
22
+ t.Run("produced cid version: implicit default (CIDv0)", func(t *testing.T) {
23
+ t.Parallel()
24
+ node := harness.NewT(t).NewNode().Init().StartDaemon()
25
+ defer node.StopDaemon()
26
+
27
+ cidStr := node.IPFSAddStr(shortString)
28
+ require.Equal(t, shortStringCidV0, cidStr)
29
+ })
30
+
31
+ t.Run("produced cid version: follows user-set configuration Import.CidVersion=0", func(t *testing.T) {
32
+ t.Parallel()
33
+ node := harness.NewT(t).NewNode().Init()
34
+ node.UpdateConfig(func(cfg *config.Config) {
35
+ cfg.Import.CidVersion = *config.NewOptionalInteger(0)
36
+ })
37
+ node.StartDaemon()
38
+ defer node.StopDaemon()
39
+
40
+ cidStr := node.IPFSAddStr(shortString)
41
+ require.Equal(t, shortStringCidV0, cidStr)
42
+ })
43
+
44
+ t.Run("produced cid multihash: follows user-set configuration in Import.HashFunction", func(t *testing.T) {
45
+ t.Parallel()
46
+ node := harness.NewT(t).NewNode().Init()
47
+ node.UpdateConfig(func(cfg *config.Config) {
48
+ cfg.Import.HashFunction = *config.NewOptionalString("sha2-512")
49
+ })
50
+ node.StartDaemon()
51
+ defer node.StopDaemon()
52
+
53
+ cidStr := node.IPFSAddStr(shortString)
54
+ require.Equal(t, shortStringCidV1Sha512, cidStr)
55
+ })
56
+
57
+ t.Run("produced cid version: follows user-set configuration Import.CidVersion=1", func(t *testing.T) {
58
+ t.Parallel()
59
+ node := harness.NewT(t).NewNode().Init()
60
+ node.UpdateConfig(func(cfg *config.Config) {
61
+ cfg.Import.CidVersion = *config.NewOptionalInteger(1)
62
+ })
63
+ node.StartDaemon()
64
+ defer node.StopDaemon()
65
+
66
+ cidStr := node.IPFSAddStr(shortString)
67
+ require.Equal(t, shortStringCidV1, cidStr)
68
+ })
69
+
70
+ t.Run("produced cid version: command flag overrides configuration in Import.CidVersion", func(t *testing.T) {
71
+ t.Parallel()
72
+ node := harness.NewT(t).NewNode().Init()
73
+ node.UpdateConfig(func(cfg *config.Config) {
74
+ cfg.Import.CidVersion = *config.NewOptionalInteger(1)
75
+ })
76
+ node.StartDaemon()
77
+ defer node.StopDaemon()
78
+
79
+ cidStr := node.IPFSAddStr(shortString, "--cid-version", "0")
80
+ require.Equal(t, shortStringCidV0, cidStr)
81
+ })
82
+
83
+ t.Run("produced unixfs raw leaves: follows user-set configuration Import.UnixFSRawLeaves", func(t *testing.T) {
84
+ t.Parallel()
85
+ node := harness.NewT(t).NewNode().Init()
86
+ node.UpdateConfig(func(cfg *config.Config) {
87
+ // CIDv1 defaults to raw-leaves=true
88
+ cfg.Import.CidVersion = *config.NewOptionalInteger(1)
89
+ // disable manually
90
+ cfg.Import.UnixFSRawLeaves = config.False
91
+ })
92
+ node.StartDaemon()
93
+ defer node.StopDaemon()
94
+
95
+ cidStr := node.IPFSAddStr(shortString)
96
+ require.Equal(t, shortStringCidV1NoRawLeaves, cidStr)
97
+ })
98
+
99
+ t.Run("ipfs init --profile=legacy-cid-v0 sets config that produces legacy CIDv0", func(t *testing.T) {
100
+ t.Parallel()
101
+ node := harness.NewT(t).NewNode().Init("--profile=legacy-cid-v0")
102
+ node.StartDaemon()
103
+ defer node.StopDaemon()
104
+
105
+ cidStr := node.IPFSAddStr(shortString)
106
+ require.Equal(t, shortStringCidV0, cidStr)
107
+ })
108
+
109
+ t.Run("ipfs init --profile=test-cid-v1 produces modern CIDv1", func(t *testing.T) {
110
+ t.Parallel()
111
+ node := harness.NewT(t).NewNode().Init("--profile=test-cid-v1")
112
+ node.StartDaemon()
113
+ defer node.StopDaemon()
114
+
115
+ cidStr := node.IPFSAddStr(shortString)
116
+ require.Equal(t, shortStringCidV1, cidStr)
117
+ })
118
+}