Skip to content

Commit

Permalink
feat: add car inspect command to cmd pkg (#320)
Browse files Browse the repository at this point in the history
  • Loading branch information
rvagg authored Jul 15, 2022
1 parent e0b4de3 commit 3264624
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 75 deletions.
12 changes: 12 additions & 0 deletions cmd/car/car.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ func main1() int {
},
},
},
{
Name: "inspect",
Usage: "verifies a car and prints a basic report about its contents",
Action: InspectCar,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "full",
Value: false,
Usage: "Check that the block data hash digests match the CIDs",
},
},
},
{
Name: "list",
Aliases: []string{"l", "ls"},
Expand Down
127 changes: 127 additions & 0 deletions cmd/car/inspect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package main

import (
"bytes"
"fmt"
"os"
"sort"
"strings"

carv2 "github.com/ipld/go-car/v2"
"github.com/multiformats/go-multicodec"
"github.com/urfave/cli/v2"
)

// InspectCar verifies a CAR and prints a basic report about its contents
func InspectCar(c *cli.Context) (err error) {
inStream := os.Stdin
if c.Args().Len() >= 1 {
inStream, err = os.Open(c.Args().First())
if err != nil {
return err
}
}

rd, err := carv2.NewReader(inStream)
if err != nil {
return err
}
stats, err := rd.Inspect(c.IsSet("full"))
if err != nil {
return err
}

var v2s string
if stats.Version == 2 {
idx := "(none)"
if stats.IndexCodec != 0 {
idx = stats.IndexCodec.String()
}
var buf bytes.Buffer
stats.Header.Characteristics.WriteTo(&buf)
v2s = fmt.Sprintf(`Characteristics: %x
Data offset: %d
Data (payload) length: %d
Index offset: %d
Index type: %s
`, buf.Bytes(), stats.Header.DataOffset, stats.Header.DataSize, stats.Header.IndexOffset, idx)
}

var roots strings.Builder
switch len(stats.Roots) {
case 0:
roots.WriteString(" (none)")
case 1:
roots.WriteString(" ")
roots.WriteString(stats.Roots[0].String())
default:
for _, r := range stats.Roots {
roots.WriteString("\n\t")
roots.WriteString(r.String())
}
}

var codecs strings.Builder
{
keys := make([]int, len(stats.CodecCounts))
i := 0
for codec := range stats.CodecCounts {
keys[i] = int(codec)
i++
}
sort.Ints(keys)
for _, code := range keys {
codec := multicodec.Code(code)
codecs.WriteString(fmt.Sprintf("\n\t%s: %d", codec, stats.CodecCounts[codec]))
}
}

var hashers strings.Builder
{
keys := make([]int, len(stats.MhTypeCounts))
i := 0
for codec := range stats.MhTypeCounts {
keys[i] = int(codec)
i++
}
sort.Ints(keys)
for _, code := range keys {
codec := multicodec.Code(code)
hashers.WriteString(fmt.Sprintf("\n\t%s: %d", codec, stats.MhTypeCounts[codec]))
}
}

rp := "No"
if stats.RootsPresent {
rp = "Yes"
}

pfmt := `Version: %d
%sRoots:%s
Root blocks present in data: %s
Block count: %d
Min / average / max block length (bytes): %d / %d / %d
Min / average / max CID length (bytes): %d / %d / %d
Block count per codec:%s
CID count per multihash:%s
`

fmt.Printf(
pfmt,
stats.Version,
v2s,
roots.String(),
rp,
stats.BlockCount,
stats.MinBlockLength,
stats.AvgBlockLength,
stats.MaxBlockLength,
stats.MinCidLength,
stats.AvgCidLength,
stats.MaxCidLength,
codecs.String(),
hashers.String(),
)

return nil
}
1 change: 1 addition & 0 deletions cmd/car/testdata/inputs/badheaderlength.car
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
���� olLʔ<#oKg#H���*��� gversion
Binary file added cmd/car/testdata/inputs/badsectionlength.car
Binary file not shown.
2 changes: 1 addition & 1 deletion cmd/car/testdata/script/get-block.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ cmp stdout ${INPUTS}/${SAMPLE_CID}.block

# "get-block" on a missing CID.
! car get-block ${INPUTS}/sample-v1.car ${MISSING_CID}
stderr 'bafy2bzacebohz654namrgmwjjx4qmtwgxixsd7pn4tlanyrc3g3hwj75xxxxw not found'
stderr 'ipld: could not find bafy2bzacebohz654namrgmwjjx4qmtwgxixsd7pn4tlanyrc3g3hwj75xxxxw'
43 changes: 43 additions & 0 deletions cmd/car/testdata/script/inspect.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
car inspect ${INPUTS}/sample-v1.car
cmp stdout v1inspect.txt

car inspect ${INPUTS}/sample-wrapped-v2.car
cmp stdout v2inspect.txt

! car inspect ${INPUTS}/badheaderlength.car
stderr 'invalid header data'

! car inspect ${INPUTS}/badsectionlength.car
stderr 'invalid section data'

-- v1inspect.txt --
Version: 1
Roots: bafy2bzaced4ueelaegfs5fqu4tzsh6ywbbpfk3cxppupmxfdhbpbhzawfw5oy
Root blocks present in data: Yes
Block count: 1049
Min / average / max block length (bytes): 1 / 417 / 1342
Min / average / max CID length (bytes): 14 / 37 / 38
Block count per codec:
raw: 6
dag-cbor: 1043
CID count per multihash:
identity: 6
blake2b-256: 1043
-- v2inspect.txt --
Version: 2
Characteristics: 00000000000000000000000000000000
Data offset: 51
Data (payload) length: 479907
Index offset: 479958
Index type: car-multihash-index-sorted
Roots: bafy2bzaced4ueelaegfs5fqu4tzsh6ywbbpfk3cxppupmxfdhbpbhzawfw5oy
Root blocks present in data: Yes
Block count: 1049
Min / average / max block length (bytes): 1 / 417 / 1342
Min / average / max CID length (bytes): 14 / 37 / 38
Block count per codec:
raw: 6
dag-cbor: 1043
CID count per multihash:
identity: 6
blake2b-256: 1043
59 changes: 29 additions & 30 deletions cmd/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,70 +5,69 @@ go 1.17
require (
github.com/dustin/go-humanize v1.0.0
github.com/ipfs/go-block-format v0.0.3
github.com/ipfs/go-cid v0.1.0
github.com/ipfs/go-ipld-format v0.3.0
github.com/ipfs/go-cid v0.2.0
github.com/ipfs/go-ipld-format v0.4.0
github.com/ipfs/go-unixfsnode v1.4.0
github.com/ipld/go-car v0.4.0
github.com/ipld/go-car/v2 v2.4.1
github.com/ipld/go-codec-dagpb v1.3.1
github.com/ipld/go-ipld-prime v0.16.1-0.20220324131737-6e219a02ca16
github.com/ipld/go-codec-dagpb v1.4.1
github.com/ipld/go-ipld-prime v0.17.0
github.com/multiformats/go-multicodec v0.5.0
github.com/multiformats/go-multihash v0.1.0
github.com/multiformats/go-multihash v0.2.0
github.com/multiformats/go-varint v0.0.6
github.com/rogpeppe/go-internal v1.8.1
github.com/urfave/cli/v2 v2.3.0
github.com/urfave/cli/v2 v2.10.3
)

require (
github.com/Stebalien/go-bitfield v0.0.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
github.com/Stebalien/go-bitfield v1.0.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/ipfs/bbloom v0.0.4 // indirect
github.com/ipfs/go-bitfield v1.0.0 // indirect
github.com/ipfs/go-blockservice v0.3.0 // indirect
github.com/ipfs/go-datastore v0.5.1 // indirect
github.com/ipfs/go-ipfs-blockstore v1.2.0 // indirect
github.com/ipfs/go-ipfs-chunker v0.0.1 // indirect
github.com/ipfs/go-ipfs-chunker v0.0.5 // indirect
github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect
github.com/ipfs/go-ipfs-exchange-interface v0.1.0 // indirect
github.com/ipfs/go-ipfs-util v0.0.2 // indirect
github.com/ipfs/go-ipld-cbor v0.0.5 // indirect
github.com/ipfs/go-ipld-legacy v0.1.0 // indirect
github.com/ipfs/go-ipld-cbor v0.0.6 // indirect
github.com/ipfs/go-ipld-legacy v0.1.1 // indirect
github.com/ipfs/go-log v1.0.5 // indirect
github.com/ipfs/go-log/v2 v2.3.0 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/ipfs/go-merkledag v0.6.0 // indirect
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
github.com/ipfs/go-verifcid v0.0.1 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/klauspost/cpuid/v2 v2.0.14 // indirect
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-base32 v0.0.4 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multibase v0.0.3 // indirect
github.com/multiformats/go-multibase v0.1.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e // indirect
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 // indirect
github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c // indirect
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.16.0 // indirect
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
golang.org/x/exp v0.0.0-20210615023648-acb5c1269671 // indirect
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.27.1 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d // indirect
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/errgo.v2 v2.1.0 // indirect
lukechampine.com/blake3 v1.1.6 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
)
Loading

0 comments on commit 3264624

Please sign in to comment.