From 50a0b459ef4d6bda1eef343c2fa29e83998e1f8d Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Wed, 14 Nov 2018 15:30:12 -0500 Subject: [PATCH] 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 --- core/commands/add.go | 14 +++-- core/commands/cmdenv/cidbase.go | 82 ++++++++++++++++++++++++++++++ core/commands/root.go | 4 ++ core/commands/tar.go | 8 ++- core/coreapi/interface/unixfs.go | 7 +-- core/coreunix/add.go | 10 ++-- test/sharness/t0040-add-and-cat.sh | 49 ++++++++++++++++++ test/sharness/t0210-tar.sh | 9 ++++ 8 files changed, 171 insertions(+), 12 deletions(-) create mode 100644 core/commands/cmdenv/cidbase.go diff --git a/core/commands/add.go b/core/commands/add.go index a6c809aa1827..c9785eb9951b 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -225,6 +225,11 @@ You can now check what blocks have been created by: outChan := make(chan interface{}) req := res.Request() + _, err := cmdenv.ProcCidBaseClientSide(req) + if err != nil { + return err + } + sizeFile, ok := req.Files.(files.SizeFile) if ok { // Could be slow. @@ -279,8 +284,9 @@ You can now check what blocks have been created by: break LOOP } output := out.(*coreiface.AddEvent) - if len(output.Hash) > 0 { - lastHash = output.Hash + hash := output.Hash.String() + if len(hash) > 0 { + lastHash = hash if quieter { continue } @@ -290,9 +296,9 @@ You can now check what blocks have been created by: fmt.Fprintf(os.Stderr, "\033[2K\r") } if quiet { - fmt.Fprintf(os.Stdout, "%s\n", output.Hash) + fmt.Fprintf(os.Stdout, "%s\n", hash) } else { - fmt.Fprintf(os.Stdout, "added %s %s\n", output.Hash, output.Name) + fmt.Fprintf(os.Stdout, "added %s %s\n", hash, output.Name) } } else { diff --git a/core/commands/cmdenv/cidbase.go b/core/commands/cmdenv/cidbase.go new file mode 100644 index 000000000000..e155559445a7 --- /dev/null +++ b/core/commands/cmdenv/cidbase.go @@ -0,0 +1,82 @@ +package cmdenv + +import ( + cidenc "gx/ipfs/QmWf8NwKFLbTBvAvZst3bYF7WEEetzxWyMhvQ885cj9MM8/go-cidutil/cidenc" + cmds "gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds" + cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit" + mbase "gx/ipfs/QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd/go-multibase" +) + +var OptionCidBase = cmdkit.StringOption("cid-base", "mbase", "Multi-base encoding used for version 1 CIDs in output.") +var OptionOutputCidV1 = cmdkit.BoolOption("output-cidv1", "Upgrade CID version 0 to version 1 in output.") + +// ProcCidBase processes the `cid-base` and `output-cidv1` options. +// In the future it may also be used to process relevant config +// settings. +func ProcCidBase(req *cmds.Request, opts ...ProcCidBaseOption) (*CidBaseInfo, error) { + h := &CidBaseInfo{} + h.base, _ = req.Options["cid-base"].(string) + h.upgrade, h.upgradeDefined = req.Options["output-cidv1"].(bool) + + for _, opt := range opts { + if err := opt(h); err != nil { + return nil, err + } + } + + e := cidenc.Default + + if h.base != "" { + var err error + e.Base, err = mbase.EncoderByName(h.base) + if err != nil { + return h, err + } + if !h.upgradeDefined { + e.Upgrade = true + } + } + + if h.upgradeDefined { + e.Upgrade = h.upgrade + } + + if h.enc == nil { + h.enc = &cidenc.Encoder{} + } + *h.enc = e + return h, nil +} + +func ProcCidBaseClientSide(req *cmds.Request, opts ...ProcCidBaseOption) (*CidBaseInfo, error) { + return ProcCidBase(req, append([]ProcCidBaseOption{UseGlobal(true)}, opts...)...) +} + +type ProcCidBaseOption func(*CidBaseInfo) error + +// UseGlobal enables the use of the global default. This is somewhat +// of a hack and should be used with care. In particular it should +// only be used on the client side and not the server side. +func UseGlobal(yes bool) ProcCidBaseOption { + return func(h *CidBaseInfo) error { + if yes { + h.enc = &cidenc.Default + } else { + h.enc = nil + } + return nil + } +} + +// CidBaseInfo is a returned by ProcCidBase +type CidBaseInfo struct { + base string + upgrade bool + upgradeDefined bool + enc *cidenc.Encoder +} + +// Encoder returns a copy of the underlying Encoder +func (h *CidBaseInfo) Encoder() cidenc.Encoder { + return *h.enc +} diff --git a/core/commands/root.go b/core/commands/root.go index 7a28525115f6..7681abd0a9ff 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -4,6 +4,7 @@ import ( "errors" lgc "github.com/ipfs/go-ipfs/commands/legacy" + cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" dag "github.com/ipfs/go-ipfs/core/commands/dag" name "github.com/ipfs/go-ipfs/core/commands/name" ocmd "github.com/ipfs/go-ipfs/core/commands/object" @@ -97,6 +98,9 @@ The CLI will exit with one of the following values: cmdkit.StringOption(ApiOption, "Use a specific API instance (defaults to /ip4/127.0.0.1/tcp/5001)"), // global options, added to every command + cmdenv.OptionCidBase, + cmdenv.OptionOutputCidV1, + cmds.OptionEncodingType, cmds.OptionStreamChannels, cmds.OptionTimeout, diff --git a/core/commands/tar.go b/core/commands/tar.go index 012e5c1077fe..10e41c3e8dc6 100644 --- a/core/commands/tar.go +++ b/core/commands/tar.go @@ -10,6 +10,7 @@ import ( tar "github.com/ipfs/go-ipfs/tar" "gx/ipfs/QmRG3XuGwT7GYuAqgWDJBKTzdaHMwAnc1x7J2KHEXNHxzG/go-path" + apicid "gx/ipfs/QmWf8NwKFLbTBvAvZst3bYF7WEEetzxWyMhvQ885cj9MM8/go-cidutil/apicid" cmds "gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds" dag "gx/ipfs/QmaDBne4KeY3UepeqSVKYpSmQGa3q9zP6x3LfVF2UjF3Hc/go-merkledag" cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit" @@ -59,12 +60,17 @@ represent it. fi.FileName() return cmds.EmitOnce(res, &coreiface.AddEvent{ Name: fi.FileName(), - Hash: c.String(), + Hash: apicid.FromCid(c), }) }, Type: coreiface.AddEvent{}, Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *coreiface.AddEvent) error { + _, err := cmdenv.ProcCidBaseClientSide(req) + if err != nil { + return err + } + fmt.Fprintln(w, out.Hash) return nil }), diff --git a/core/coreapi/interface/unixfs.go b/core/coreapi/interface/unixfs.go index 002635d99361..382b0d9e48bc 100644 --- a/core/coreapi/interface/unixfs.go +++ b/core/coreapi/interface/unixfs.go @@ -6,6 +6,7 @@ import ( options "github.com/ipfs/go-ipfs/core/coreapi/interface/options" + apicid "gx/ipfs/QmWf8NwKFLbTBvAvZst3bYF7WEEetzxWyMhvQ885cj9MM8/go-cidutil/apicid" files "gx/ipfs/QmZMWMvWMVKCbHetJ4RgndbuEF1io2UpUxwQwtNjtYPzSC/go-ipfs-files" ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format" ) @@ -13,9 +14,9 @@ import ( // TODO: ideas on making this more coreapi-ish without breaking the http API? type AddEvent struct { Name string - Hash string `json:",omitempty"` - Bytes int64 `json:",omitempty"` - Size string `json:",omitempty"` + Hash apicid.Hash `json:",omitempty"` + Bytes int64 `json:",omitempty"` + Size string `json:",omitempty"` } type UnixfsFile interface { diff --git a/core/coreunix/add.go b/core/coreunix/add.go index 3ceee3d6ae5a..067ea9d22b83 100644 --- a/core/coreunix/add.go +++ b/core/coreunix/add.go @@ -18,6 +18,7 @@ import ( posinfo "gx/ipfs/QmR6YMs8EkXQLXNwQKxLnQp2VBZSepoEJ8KCZAyanJHhJu/go-ipfs-posinfo" cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid" bstore "gx/ipfs/QmSNLNnL3kq3A1NGdQA9AtgxM9CWKiiSEup3W435jCkRQS/go-ipfs-blockstore" + apicid "gx/ipfs/QmWf8NwKFLbTBvAvZst3bYF7WEEetzxWyMhvQ885cj9MM8/go-cidutil/apicid" unixfs "gx/ipfs/QmXLCwhHh7bxRsBnCKNE9BAN87V44aSxXLquZYTtjr6fZ3/go-unixfs" balanced "gx/ipfs/QmXLCwhHh7bxRsBnCKNE9BAN87V44aSxXLquZYTtjr6fZ3/go-unixfs/importer/balanced" ihelper "gx/ipfs/QmXLCwhHh7bxRsBnCKNE9BAN87V44aSxXLquZYTtjr6fZ3/go-unixfs/importer/helpers" @@ -37,12 +38,13 @@ const progressReaderIncrement = 1024 * 256 var liveCacheSize = uint64(256 << 10) type Link struct { - Name, Hash string - Size uint64 + Name string + Hash apicid.Hash + Size uint64 } type Object struct { - Hash string + Hash apicid.Hash Links []Link Size string } @@ -599,7 +601,7 @@ func getOutput(dagnode ipld.Node) (*Object, error) { } output := &Object{ - Hash: c.String(), + Hash: apicid.FromCid(c), Size: strconv.FormatUint(s, 10), Links: make([]Link, len(dagnode.Links())), } diff --git a/test/sharness/t0040-add-and-cat.sh b/test/sharness/t0040-add-and-cat.sh index 50b7e1ea2d6b..48004ee9b74b 100755 --- a/test/sharness/t0040-add-and-cat.sh +++ b/test/sharness/t0040-add-and-cat.sh @@ -272,6 +272,36 @@ test_add_cat_file() { echo "added QmZQWnfcqJ6hNkkPvrY9Q5X39GP3jUnUbAV4AbmbbR3Cb1 test_current_dir" > expected test_cmp expected actual ' + + # --cid-base=base32 + + test_expect_success "ipfs add --cid-base=base32 succeeds" ' + echo "Hello Worlds!" >mountdir/hello.txt && + ipfs add --cid-base=base32 mountdir/hello.txt >actual + ' + + test_expect_success "ipfs add output looks good" ' + HASH="bafybeidpq7lcjx4w5c6yr4vuthzvlav54hgxsremwk73to5ferdc2rxhai" && + echo "added $HASH hello.txt" >expected && + test_cmp expected actual + ' + + test_expect_success "ipfs add --cid-base=base32 --only-hash succeeds" ' + ipfs add --cid-base=base32 --only-hash mountdir/hello.txt > oh_actual + ' + + test_expect_success "ipfs add --only-hash output looks good" ' + test_cmp expected oh_actual + ' + + test_expect_success "ipfs cat succeeds" ' + ipfs cat "$HASH" >actual + ' + + test_expect_success "ipfs cat output looks good" ' + echo "Hello Worlds!" >expected && + test_cmp expected actual + ' } test_add_cat_5MB() { @@ -312,6 +342,25 @@ test_add_cat_5MB() { test_expect_success FUSE "cat ipfs/bigfile looks good" ' test_cmp mountdir/bigfile actual ' + + test_expect_success "get base32 version of CID" ' + ipfs cid base32 $EXP_HASH > base32_cid && + BASE32_HASH=`cat base32_cid` + ' + + test_expect_success "ipfs add --cid-base=base32 bigfile' succeeds" ' + ipfs add $ADD_FLAGS --cid-base=base32 mountdir/bigfile >actual || + test_fsh cat daemon_err + ' + + test_expect_success "'ipfs add bigfile --cid-base=base32' output looks good" ' + echo "added $BASE32_HASH bigfile" >expected && + test_cmp expected actual + ' + + test_expect_success "'ipfs cat $BASE32_HASH' succeeds" ' + ipfs cat "$BASE32_HASH" >actual + ' } test_add_cat_raw() { diff --git a/test/sharness/t0210-tar.sh b/test/sharness/t0210-tar.sh index d3ca3745b912..d2b9105507b0 100755 --- a/test/sharness/t0210-tar.sh +++ b/test/sharness/t0210-tar.sh @@ -46,4 +46,13 @@ test_expect_success "files look right" ' [ -x foo/script ] ' +test_expect_success "'ipfs tar add --cid-base=base32' succeeds" ' + ipfs tar add --cid-base=base32 files.tar > actual +' + +test_expect_success "'ipfs tar add --cid-base=base32' has correct hash" ' + ipfs cid base32 $TAR_HASH > expected && + test_cmp expected actual +' + test_done