Skip to content

Commit 16ee061

Browse files
committed
Add global --cid-base option and enable it for ipfs add and tar commands.
This also adds a global --output-cidv1 option. License: MIT Signed-off-by: Kevin Atkinson <[email protected]>
1 parent 4f73615 commit 16ee061

File tree

10 files changed

+197
-26
lines changed

10 files changed

+197
-26
lines changed

core/commands/add.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ You can now check what blocks have been created by:
225225
outChan := make(chan interface{})
226226
req := res.Request()
227227

228+
_, err := cmdenv.ProcCidBaseClientSide(req)
229+
if err != nil {
230+
return err
231+
}
232+
228233
sizeFile, ok := req.Files.(files.SizeFile)
229234
if ok {
230235
// Could be slow.
@@ -279,8 +284,9 @@ You can now check what blocks have been created by:
279284
break LOOP
280285
}
281286
output := out.(*coreiface.AddEvent)
282-
if len(output.Hash) > 0 {
283-
lastHash = output.Hash
287+
hash := output.Hash.String()
288+
if len(hash) > 0 {
289+
lastHash = hash
284290
if quieter {
285291
continue
286292
}
@@ -290,9 +296,9 @@ You can now check what blocks have been created by:
290296
fmt.Fprintf(os.Stderr, "\033[2K\r")
291297
}
292298
if quiet {
293-
fmt.Fprintf(os.Stdout, "%s\n", output.Hash)
299+
fmt.Fprintf(os.Stdout, "%s\n", hash)
294300
} else {
295-
fmt.Fprintf(os.Stdout, "added %s %s\n", output.Hash, output.Name)
301+
fmt.Fprintf(os.Stdout, "added %s %s\n", hash, output.Name)
296302
}
297303

298304
} else {

core/commands/cmdenv/cidbase.go

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package cmdenv
2+
3+
import (
4+
cidenc "gx/ipfs/QmWf8NwKFLbTBvAvZst3bYF7WEEetzxWyMhvQ885cj9MM8/go-cidutil/cidenc"
5+
cmds "gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
6+
cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
7+
mbase "gx/ipfs/QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd/go-multibase"
8+
)
9+
10+
var OptionCidBase = cmdkit.StringOption("cid-base", "mbase", "Multi-base encoding used for version 1 CIDs in output.")
11+
var OptionOutputCidV1 = cmdkit.BoolOption("output-cidv1", "Upgrade CID version 0 to version 1 in output.")
12+
13+
// ProcCidBase processes the `cid-base` and `output-cidv1` options.
14+
// In the future it may also be used to process relevant config
15+
// settings.
16+
func ProcCidBase(req *cmds.Request, opts ...ProcCidBaseOption) (*CidBaseInfo, error) {
17+
h := &CidBaseInfo{}
18+
h.base, _ = req.Options["cid-base"].(string)
19+
h.upgrade, h.upgradeDefined = req.Options["output-cidv1"].(bool)
20+
21+
for _, opt := range opts {
22+
if err := opt(h); err != nil {
23+
return nil, err
24+
}
25+
}
26+
27+
e := cidenc.Default
28+
29+
if h.base != "" {
30+
var err error
31+
e.Base, err = mbase.EncoderByName(h.base)
32+
if err != nil {
33+
return h, err
34+
}
35+
if !h.upgradeDefined {
36+
e.Upgrade = true
37+
}
38+
}
39+
40+
if h.upgradeDefined {
41+
e.Upgrade = h.upgrade
42+
}
43+
44+
if h.enc == nil {
45+
h.enc = &cidenc.Encoder{}
46+
}
47+
*h.enc = e
48+
return h, nil
49+
}
50+
51+
func ProcCidBaseClientSide(req *cmds.Request, opts ...ProcCidBaseOption) (*CidBaseInfo, error) {
52+
return ProcCidBase(req, append([]ProcCidBaseOption{UseGlobal(true)}, opts...)...)
53+
}
54+
55+
type ProcCidBaseOption func(*CidBaseInfo) error
56+
57+
// UseGlobal enables the use of the global default. This is somewhat
58+
// of a hack and should be used with care. In particular it should
59+
// only be used on the client side and not the server side.
60+
func UseGlobal(yes bool) ProcCidBaseOption {
61+
return func(h *CidBaseInfo) error {
62+
if yes {
63+
h.enc = &cidenc.Default
64+
} else {
65+
h.enc = nil
66+
}
67+
return nil
68+
}
69+
}
70+
71+
// CidBaseInfo is a returned by ProcCidBase
72+
type CidBaseInfo struct {
73+
base string
74+
upgrade bool
75+
upgradeDefined bool
76+
enc *cidenc.Encoder
77+
}
78+
79+
// Encoder returns a copy of the underlying Encoder
80+
func (h *CidBaseInfo) Encoder() cidenc.Encoder {
81+
return *h.enc
82+
}

core/commands/root.go

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55

66
lgc "github.com/ipfs/go-ipfs/commands/legacy"
7+
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
78
dag "github.com/ipfs/go-ipfs/core/commands/dag"
89
name "github.com/ipfs/go-ipfs/core/commands/name"
910
ocmd "github.com/ipfs/go-ipfs/core/commands/object"
@@ -97,6 +98,9 @@ The CLI will exit with one of the following values:
9798
cmdkit.StringOption(ApiOption, "Use a specific API instance (defaults to /ip4/127.0.0.1/tcp/5001)"),
9899

99100
// global options, added to every command
101+
cmdenv.OptionCidBase,
102+
cmdenv.OptionOutputCidV1,
103+
100104
cmds.OptionEncodingType,
101105
cmds.OptionStreamChannels,
102106
cmds.OptionTimeout,

core/commands/tar.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
tar "github.com/ipfs/go-ipfs/tar"
1111

1212
"gx/ipfs/QmRG3XuGwT7GYuAqgWDJBKTzdaHMwAnc1x7J2KHEXNHxzG/go-path"
13+
apicid "gx/ipfs/QmWf8NwKFLbTBvAvZst3bYF7WEEetzxWyMhvQ885cj9MM8/go-cidutil/apicid"
1314
cmds "gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
1415
dag "gx/ipfs/QmaDBne4KeY3UepeqSVKYpSmQGa3q9zP6x3LfVF2UjF3Hc/go-merkledag"
1516
cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
@@ -59,12 +60,17 @@ represent it.
5960
fi.FileName()
6061
return cmds.EmitOnce(res, &coreiface.AddEvent{
6162
Name: fi.FileName(),
62-
Hash: c.String(),
63+
Hash: apicid.FromCid(c),
6364
})
6465
},
6566
Type: coreiface.AddEvent{},
6667
Encoders: cmds.EncoderMap{
6768
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *coreiface.AddEvent) error {
69+
_, err := cmdenv.ProcCidBaseClientSide(req)
70+
if err != nil {
71+
return err
72+
}
73+
6874
fmt.Fprintln(w, out.Hash)
6975
return nil
7076
}),

core/coreapi/interface/unixfs.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@ import (
66

77
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
88

9+
apicid "gx/ipfs/QmWf8NwKFLbTBvAvZst3bYF7WEEetzxWyMhvQ885cj9MM8/go-cidutil/apicid"
910
files "gx/ipfs/QmZMWMvWMVKCbHetJ4RgndbuEF1io2UpUxwQwtNjtYPzSC/go-ipfs-files"
1011
ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format"
1112
)
1213

1314
// TODO: ideas on making this more coreapi-ish without breaking the http API?
1415
type AddEvent struct {
1516
Name string
16-
Hash string `json:",omitempty"`
17-
Bytes int64 `json:",omitempty"`
18-
Size string `json:",omitempty"`
17+
Hash apicid.Hash `json:",omitempty"`
18+
Bytes int64 `json:",omitempty"`
19+
Size string `json:",omitempty"`
1920
}
2021

2122
type UnixfsFile interface {

core/coreapi/unixfs_test.go

+19-9
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ import (
2424
"github.com/ipfs/go-ipfs/repo"
2525

2626
ci "gx/ipfs/QmNiJiXwWE3kRhZrC5ej3kSjWHm337pYfhjLGSCDNKJP2s/go-libp2p-crypto"
27+
cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
2728
cbor "gx/ipfs/QmRoARq3nkUb13HSKZGepCZSWe5GrVPwx7xURJGZ7KWv9V/go-ipld-cbor"
2829
pstore "gx/ipfs/QmUymf8fJtideyv3z727BcZUifGBjMZMpCJqu3Gxk5aRUk/go-libp2p-peerstore"
30+
apicid "gx/ipfs/QmWf8NwKFLbTBvAvZst3bYF7WEEetzxWyMhvQ885cj9MM8/go-cidutil/apicid"
2931
unixfs "gx/ipfs/QmXLCwhHh7bxRsBnCKNE9BAN87V44aSxXLquZYTtjr6fZ3/go-unixfs"
3032
mocknet "gx/ipfs/QmXnpYYg2onGLXVxM4Q5PEFcx29k8zeJQkPeLAk9h9naxg/go-libp2p/p2p/net/mock"
3133
files "gx/ipfs/QmZMWMvWMVKCbHetJ4RgndbuEF1io2UpUxwQwtNjtYPzSC/go-ipfs-files"
@@ -165,6 +167,14 @@ func wrapped(f files.File) files.File {
165167
})
166168
}
167169

170+
func apiCid(hash string) apicid.Hash {
171+
c, err := cid.Decode(hash)
172+
if err != nil {
173+
panic(err)
174+
}
175+
return apicid.FromCid(c)
176+
}
177+
168178
func TestAdd(t *testing.T) {
169179
ctx := context.Background()
170180
_, api, err := makeAPI(ctx)
@@ -384,7 +394,7 @@ func TestAdd(t *testing.T) {
384394
data: strFile(helloStr),
385395
path: "/ipfs/zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd",
386396
events: []coreiface.AddEvent{
387-
{Name: "zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd", Hash: "zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd", Size: strconv.Itoa(len(helloStr))},
397+
{Name: "zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd", Hash: apiCid("zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd"), Size: strconv.Itoa(len(helloStr))},
388398
},
389399
opts: []options.UnixfsAddOption{options.Unixfs.RawLeaves(true)},
390400
},
@@ -393,8 +403,8 @@ func TestAdd(t *testing.T) {
393403
data: twoLevelDir(),
394404
path: "/ipfs/QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr",
395405
events: []coreiface.AddEvent{
396-
{Name: "t/abc", Hash: "QmU7nuGs2djqK99UNsNgEPGh6GV4662p6WtsgccBNGTDxt", Size: "62"},
397-
{Name: "t", Hash: "QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr", Size: "229"},
406+
{Name: "t/abc", Hash: apiCid("QmU7nuGs2djqK99UNsNgEPGh6GV4662p6WtsgccBNGTDxt"), Size: "62"},
407+
{Name: "t", Hash: apiCid("QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr"), Size: "229"},
398408
},
399409
recursive: true,
400410
opts: []options.UnixfsAddOption{options.Unixfs.Silent(true)},
@@ -404,11 +414,11 @@ func TestAdd(t *testing.T) {
404414
data: twoLevelDir(),
405415
path: "/ipfs/QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr",
406416
events: []coreiface.AddEvent{
407-
{Name: "t/abc/def", Hash: "QmNyJpQkU1cEkBwMDhDNFstr42q55mqG5GE5Mgwug4xyGk", Size: "13"},
408-
{Name: "t/bar", Hash: "QmS21GuXiRMvJKHos4ZkEmQDmRBqRaF5tQS2CQCu2ne9sY", Size: "14"},
409-
{Name: "t/foo", Hash: "QmfAjGiVpTN56TXi6SBQtstit5BEw3sijKj1Qkxn6EXKzJ", Size: "14"},
410-
{Name: "t/abc", Hash: "QmU7nuGs2djqK99UNsNgEPGh6GV4662p6WtsgccBNGTDxt", Size: "62"},
411-
{Name: "t", Hash: "QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr", Size: "229"},
417+
{Name: "t/abc/def", Hash: apiCid("QmNyJpQkU1cEkBwMDhDNFstr42q55mqG5GE5Mgwug4xyGk"), Size: "13"},
418+
{Name: "t/bar", Hash: apiCid("QmS21GuXiRMvJKHos4ZkEmQDmRBqRaF5tQS2CQCu2ne9sY"), Size: "14"},
419+
{Name: "t/foo", Hash: apiCid("QmfAjGiVpTN56TXi6SBQtstit5BEw3sijKj1Qkxn6EXKzJ"), Size: "14"},
420+
{Name: "t/abc", Hash: apiCid("QmU7nuGs2djqK99UNsNgEPGh6GV4662p6WtsgccBNGTDxt"), Size: "62"},
421+
{Name: "t", Hash: apiCid("QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr"), Size: "229"},
412422
},
413423
recursive: true,
414424
},
@@ -424,7 +434,7 @@ func TestAdd(t *testing.T) {
424434
{Name: "", Bytes: 524288},
425435
{Name: "", Bytes: 786432},
426436
{Name: "", Bytes: 1000000},
427-
{Name: "QmXXNNbwe4zzpdMg62ZXvnX1oU7MwSrQ3vAEtuwFKCm1oD", Hash: "QmXXNNbwe4zzpdMg62ZXvnX1oU7MwSrQ3vAEtuwFKCm1oD", Size: "1000256"},
437+
{Name: "QmXXNNbwe4zzpdMg62ZXvnX1oU7MwSrQ3vAEtuwFKCm1oD", Hash: apiCid("QmXXNNbwe4zzpdMg62ZXvnX1oU7MwSrQ3vAEtuwFKCm1oD"), Size: "1000256"},
428438
},
429439
recursive: true,
430440
opts: []options.UnixfsAddOption{options.Unixfs.Progress(true)},

core/coreunix/add.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
posinfo "gx/ipfs/QmR6YMs8EkXQLXNwQKxLnQp2VBZSepoEJ8KCZAyanJHhJu/go-ipfs-posinfo"
1919
cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
2020
bstore "gx/ipfs/QmSNLNnL3kq3A1NGdQA9AtgxM9CWKiiSEup3W435jCkRQS/go-ipfs-blockstore"
21+
apicid "gx/ipfs/QmWf8NwKFLbTBvAvZst3bYF7WEEetzxWyMhvQ885cj9MM8/go-cidutil/apicid"
2122
unixfs "gx/ipfs/QmXLCwhHh7bxRsBnCKNE9BAN87V44aSxXLquZYTtjr6fZ3/go-unixfs"
2223
balanced "gx/ipfs/QmXLCwhHh7bxRsBnCKNE9BAN87V44aSxXLquZYTtjr6fZ3/go-unixfs/importer/balanced"
2324
ihelper "gx/ipfs/QmXLCwhHh7bxRsBnCKNE9BAN87V44aSxXLquZYTtjr6fZ3/go-unixfs/importer/helpers"
@@ -37,12 +38,13 @@ const progressReaderIncrement = 1024 * 256
3738
var liveCacheSize = uint64(256 << 10)
3839

3940
type Link struct {
40-
Name, Hash string
41-
Size uint64
41+
Name string
42+
Hash apicid.Hash
43+
Size uint64
4244
}
4345

4446
type Object struct {
45-
Hash string
47+
Hash apicid.Hash
4648
Links []Link
4749
Size string
4850
}
@@ -599,7 +601,7 @@ func getOutput(dagnode ipld.Node) (*Object, error) {
599601
}
600602

601603
output := &Object{
602-
Hash: c.String(),
604+
Hash: apicid.FromCid(c),
603605
Size: strconv.FormatUint(s, 10),
604606
Links: make([]Link, len(dagnode.Links())),
605607
}

core/coreunix/add_test.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,11 @@ func TestAddGCLive(t *testing.T) {
9494

9595
}()
9696

97-
addedHashes := make(map[string]struct{})
97+
addedHashes := make(map[cid.Cid]struct{})
9898
select {
9999
case o := <-out:
100-
addedHashes[o.(*coreiface.AddEvent).Hash] = struct{}{}
100+
c, _ := o.(*coreiface.AddEvent).Hash.Cid()
101+
addedHashes[c] = struct{}{}
101102
case <-addDone:
102103
t.Fatal("add shouldnt complete yet")
103104
}
@@ -125,23 +126,24 @@ func TestAddGCLive(t *testing.T) {
125126

126127
// receive next object from adder
127128
o := <-out
128-
addedHashes[o.(*coreiface.AddEvent).Hash] = struct{}{}
129+
c, _ := o.(*coreiface.AddEvent).Hash.Cid()
130+
addedHashes[c] = struct{}{}
129131

130132
<-gcstarted
131133

132134
for r := range gcout {
133135
if r.Error != nil {
134136
t.Fatal(err)
135137
}
136-
if _, ok := addedHashes[r.KeyRemoved.String()]; ok {
138+
if _, ok := addedHashes[r.KeyRemoved]; ok {
137139
t.Fatal("gc'ed a hash we just added")
138140
}
139141
}
140142

141143
var last cid.Cid
142144
for a := range out {
143145
// wait for it to finish
144-
c, err := cid.Decode(a.(*coreiface.AddEvent).Hash)
146+
c, err := a.(*coreiface.AddEvent).Hash.Cid()
145147
if err != nil {
146148
t.Fatal(err)
147149
}

test/sharness/t0040-add-and-cat.sh

+49
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,36 @@ test_add_cat_file() {
272272
echo "added QmZQWnfcqJ6hNkkPvrY9Q5X39GP3jUnUbAV4AbmbbR3Cb1 test_current_dir" > expected
273273
test_cmp expected actual
274274
'
275+
276+
# --cid-base=base32
277+
278+
test_expect_success "ipfs add --cid-base=base32 succeeds" '
279+
echo "Hello Worlds!" >mountdir/hello.txt &&
280+
ipfs add --cid-base=base32 mountdir/hello.txt >actual
281+
'
282+
283+
test_expect_success "ipfs add output looks good" '
284+
HASH="bafybeidpq7lcjx4w5c6yr4vuthzvlav54hgxsremwk73to5ferdc2rxhai" &&
285+
echo "added $HASH hello.txt" >expected &&
286+
test_cmp expected actual
287+
'
288+
289+
test_expect_success "ipfs add --cid-base=base32 --only-hash succeeds" '
290+
ipfs add --cid-base=base32 --only-hash mountdir/hello.txt > oh_actual
291+
'
292+
293+
test_expect_success "ipfs add --only-hash output looks good" '
294+
test_cmp expected oh_actual
295+
'
296+
297+
test_expect_success "ipfs cat succeeds" '
298+
ipfs cat "$HASH" >actual
299+
'
300+
301+
test_expect_success "ipfs cat output looks good" '
302+
echo "Hello Worlds!" >expected &&
303+
test_cmp expected actual
304+
'
275305
}
276306

277307
test_add_cat_5MB() {
@@ -312,6 +342,25 @@ test_add_cat_5MB() {
312342
test_expect_success FUSE "cat ipfs/bigfile looks good" '
313343
test_cmp mountdir/bigfile actual
314344
'
345+
346+
test_expect_success "get base32 version of CID" '
347+
ipfs cid base32 $EXP_HASH > base32_cid &&
348+
BASE32_HASH=`cat base32_cid`
349+
'
350+
351+
test_expect_success "ipfs add --cid-base=base32 bigfile' succeeds" '
352+
ipfs add $ADD_FLAGS --cid-base=base32 mountdir/bigfile >actual ||
353+
test_fsh cat daemon_err
354+
'
355+
356+
test_expect_success "'ipfs add bigfile --cid-base=base32' output looks good" '
357+
echo "added $BASE32_HASH bigfile" >expected &&
358+
test_cmp expected actual
359+
'
360+
361+
test_expect_success "'ipfs cat $BASE32_HASH' succeeds" '
362+
ipfs cat "$BASE32_HASH" >actual
363+
'
315364
}
316365

317366
test_add_cat_raw() {

0 commit comments

Comments
 (0)