Skip to content

Commit b3ef242

Browse files
feat(cmd): Introduce "--sizes" to include sizes
The new parameter is not a bool flag and behaves as follows: - "human": Prints "humanized" sizes - "bytes": Prints the number of bytes without the measure unit - Anything else: Prints nothing Below is the updated help section. NAME: car list - List the blocks in a car USAGE: car list [command options] OPTIONS: --verbose, -v Show verbose information about contained blocks (default: false) --cids Include CIDs (default: true except for unixfs) --sizes value, -s value Include sizes (specify "human" or "bytes") (default: human for verbose, none otherwise) --unixfs Show unixfs filesystem (full paths) (default: false) --help, -h show help
1 parent 4683e15 commit b3ef242

2 files changed

Lines changed: 141 additions & 48 deletions

File tree

cmd/car/car.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,13 @@ func main1() int {
227227
Usage: "Include CIDs",
228228
DefaultText: "true except for unixfs",
229229
},
230+
&cli.StringFlag{
231+
Name: "sizes",
232+
Aliases: []string{"s"},
233+
Usage: "Include sizes (specify \"human\" or \"bytes\")",
234+
Value: "",
235+
DefaultText: "human for verbose, none otherwise",
236+
},
230237
&cli.BoolFlag{
231238
Name: "unixfs",
232239
Usage: "Show unixfs filesystem (full paths)",

cmd/car/list.go

Lines changed: 134 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io"
77
"os"
88
"path"
9+
"strings"
910

1011
"github.com/dustin/go-humanize"
1112
"github.com/ipfs/go-cid"
@@ -94,11 +95,16 @@ func ListCar(c *cli.Context) error {
9495
if pbl.Name.Exists() {
9596
name = pbl.Name.Must().String()
9697
}
97-
size := 0
98+
fmt.Fprintf(outStream, "\t\t%s", name)
99+
100+
size := uint64(0)
98101
if pbl.Tsize.Exists() {
99-
size = int(pbl.Tsize.Must().Int())
102+
size = uint64(pbl.Tsize.Must().Int())
103+
}
104+
sizePart := sizeStr(c, size)
105+
if sizePart != "" {
106+
fmt.Fprintf(outStream, "%s", sizePart)
100107
}
101-
fmt.Fprintf(outStream, "\t\t%s[%s]", name, humanize.Bytes(uint64(size)))
102108

103109
if c.Bool("cids") {
104110
hsh := "<unknown>"
@@ -125,8 +131,8 @@ func ListCar(c *cli.Context) error {
125131
}
126132
fmt.Fprintf(outStream, "\tUnixfs %s\n", data.DataTypeNames[ufd.FieldDataType().Int()])
127133
}
128-
} else if c.Bool("cids") {
129-
fmt.Fprintf(outStream, "%s\n", blk.Cid())
134+
} else {
135+
printEntry(c, blk.Cid(), "", uint64(len(blk.RawData())), outStream)
130136
}
131137
}
132138

@@ -161,86 +167,166 @@ func listUnixfs(c *cli.Context, outStream io.Writer) error {
161167
return err
162168
}
163169
for _, r := range roots {
164-
if err := printUnixFSNode(c, "", r, &ls, outStream); err != nil {
170+
if _, err := printUnixFSNode(c, "", r, &ls, outStream); err != nil {
165171
return err
166172
}
167173
}
168174
return nil
169175
}
170176

171-
func printUnixFSNode(c *cli.Context, prefix string, node cid.Cid, ls *ipld.LinkSystem, outStream io.Writer) error {
172-
// it might be a raw file (bytes) node. if so, not actually an error.
177+
func printUnixFSNode(c *cli.Context, prefix string, node cid.Cid, ls *ipld.LinkSystem, outStream io.Writer) (uint64, error) {
173178
if node.Prefix().Codec == cid.Raw {
174-
return nil
179+
link := cidlink.Link{Cid: node}
180+
181+
rawBytes, err := ls.LoadRaw(
182+
ipld.LinkContext{Ctx: c.Context},
183+
link,
184+
)
185+
186+
if err != nil {
187+
return 0, err
188+
}
189+
190+
return uint64(len(rawBytes)), nil
175191
}
176192

177193
pbn, err := ls.Load(ipld.LinkContext{}, cidlink.Link{Cid: node}, dagpb.Type.PBNode)
178194
if err != nil {
179-
return err
195+
return 0, err
180196
}
181197

182198
pbnode := pbn.(dagpb.PBNode)
183199

184200
ufd, err := data.DecodeUnixFSData(pbnode.Data.Must().Bytes())
185201
if err != nil {
186-
return err
202+
return 0, err
187203
}
188204

189-
// only show CIDs if explicitly requested
190-
printCids := c.IsSet("cids") && c.Bool("cids")
205+
var totalSize uint64 = 0
191206

192-
if ufd.FieldDataType().Int() == data.Data_Directory {
207+
switch ufd.FieldDataType().Int() {
208+
209+
case data.Data_Directory:
193210
i := pbnode.Links.Iterator()
194211
for !i.Done() {
195-
_, l := i.Next()
196-
name := path.Join(prefix, l.Name.Must().String())
197-
if printCids {
198-
cidL, _ := l.Hash.AsLink()
199-
fmt.Fprintf(outStream, "%s %s\n", cidL.(cidlink.Link).Cid, name)
200-
} else {
201-
fmt.Fprintf(outStream, "%s\n", name)
212+
_, link := i.Next()
213+
name := link.Name.Must().String()
214+
if name == "" {
215+
continue
202216
}
203-
// recurse into the file/directory
204-
cl, err := l.Hash.AsLink()
217+
218+
chPath := path.Join(prefix, name)
219+
220+
chLink, err := link.Hash.AsLink()
205221
if err != nil {
206-
return err
222+
return 0, err
207223
}
208-
if cidl, ok := cl.(cidlink.Link); ok {
209-
if err := printUnixFSNode(c, name, cidl.Cid, ls, outStream); err != nil {
210-
return err
211-
}
224+
225+
chCid := chLink.(cidlink.Link).Cid
226+
227+
chSize, err := printUnixFSNode(c, chPath, chCid, ls, outStream)
228+
if err != nil {
229+
return 0, err
212230
}
213231

232+
totalSize += chSize
233+
234+
printEntry(c, chCid, chPath, chSize, outStream)
214235
}
215-
} else if ufd.FieldDataType().Int() == data.Data_HAMTShard {
236+
237+
case data.Data_HAMTShard:
216238
hn, err := hamt.AttemptHAMTShardFromNode(c.Context, pbn, ls)
217239
if err != nil {
218-
return err
240+
return 0, err
219241
}
242+
220243
i := hn.Iterator()
221244
for !i.Done() {
222-
n, l := i.Next()
223-
if printCids {
224-
cl, _ := l.AsLink()
225-
fmt.Fprintf(outStream, "%s %s\n", cl.(cidlink.Link).Cid, path.Join(prefix, n.String()))
226-
} else {
227-
fmt.Fprintf(outStream, "%s\n", path.Join(prefix, n.String()))
228-
}
229-
// recurse into the file/directory
230-
cl, err := l.AsLink()
245+
key, val := i.Next()
246+
247+
chPath := path.Join(prefix, key.String())
248+
249+
chLink, err := val.AsLink()
231250
if err != nil {
232-
return err
251+
return 0, err
233252
}
234-
if cidl, ok := cl.(cidlink.Link); ok {
235-
if err := printUnixFSNode(c, path.Join(prefix, n.String()), cidl.Cid, ls, outStream); err != nil {
236-
return err
237-
}
253+
254+
chCid := chLink.(cidlink.Link).Cid
255+
256+
chSize, err := printUnixFSNode(c, chPath, chCid, ls, outStream)
257+
if err != nil {
258+
return 0, err
238259
}
260+
261+
totalSize += chSize
262+
263+
printEntry(c, chCid, chPath, chSize, outStream)
264+
}
265+
266+
case data.Data_File:
267+
size := uint64(0)
268+
if ufd.FieldFileSize().Exists() {
269+
size = uint64(ufd.FieldFileSize().Must().Int())
239270
}
240-
} else {
241-
// file, file chunk, symlink, other un-named entities.
242-
return nil
271+
272+
return size, nil
273+
274+
case data.Data_Raw:
275+
size := uint64(0)
276+
if ufd.FieldData().Exists() {
277+
size = uint64(len(ufd.FieldData().Must().Bytes()))
278+
}
279+
280+
return size, nil
281+
282+
default:
283+
return 0, nil
243284
}
244285

245-
return nil
286+
return totalSize, nil
287+
}
288+
289+
func printEntry(c *cli.Context, cid cid.Cid, path string, size uint64, outStream io.Writer) {
290+
parts := make([]string, 0, 3)
291+
292+
if path != "" {
293+
// For unixfs only show CIDs if explicitly requested
294+
if c.IsSet("cids") && c.Bool("cids") {
295+
parts = append(parts, cid.String())
296+
}
297+
298+
parts = append(parts, path)
299+
} else if c.Bool("cids") {
300+
parts = append(parts, cid.String())
301+
}
302+
303+
sizePart := sizeStr(c, size)
304+
if sizePart != "" {
305+
parts = append(parts, sizePart)
306+
}
307+
308+
if len(parts) == 0 {
309+
return
310+
}
311+
312+
fmt.Fprintln(outStream, strings.Join(parts, " "))
313+
}
314+
315+
func sizeStr(c *cli.Context, size uint64) string {
316+
mode := ""
317+
318+
if c.IsSet("sizes") {
319+
mode = c.String("sizes")
320+
} else if c.Bool("verbose") {
321+
mode = "human"
322+
}
323+
324+
switch mode {
325+
case "human":
326+
return fmt.Sprintf("[%s]", humanize.Bytes(uint64(size)))
327+
case "bytes":
328+
return fmt.Sprintf("[%d]", size)
329+
}
330+
331+
return ""
246332
}

0 commit comments

Comments
 (0)