Skip to content

Commit

Permalink
Add '--filter' option to cid-fmt utility.
Browse files Browse the repository at this point in the history
  • Loading branch information
kevina committed Dec 12, 2018
1 parent fe89746 commit e19f717
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 27 deletions.
94 changes: 67 additions & 27 deletions cid-fmt/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package main

import (
"bufio"
"fmt"
"io"
"os"
"strings"

Expand All @@ -12,7 +14,9 @@ import (
)

func usage() {
fmt.Fprintf(os.Stderr, "usage: %s [-b multibase-code] [-v cid-version] <fmt-str> <cid> ...\n\n", os.Args[0])
fmt.Fprintf(os.Stderr, "usage: %s [-b multibase-code] [-v cid-version] [--filter] <fmt-str> <cid> ...\n", os.Args[0])
fmt.Fprintf(os.Stderr, "--filter will read from stdin and convert anything that looks like a <cid>\n")
fmt.Fprintf(os.Stderr, " -- including any non-cids that are valid Multihashes).\n")
fmt.Fprintf(os.Stderr, "<fmt-str> is either 'prefix' or a printf style format string:\n%s", cidutil.FormatRef)
os.Exit(2)
}
Expand All @@ -24,8 +28,9 @@ func main() {
newBase := mb.Encoding(-1)
var verConv func(cid c.Cid) (c.Cid, error)
args := os.Args[1:]
filter := false
outer:
for {
for len(args) > 0 {
switch args[0] {
case "-b":
if len(args) < 2 {
Expand All @@ -52,11 +57,14 @@ outer:
os.Exit(2)
}
args = args[2:]
case "--filter":
filter = true
args = args[1:]
default:
break outer
}
}
if len(args) < 2 {
if len(args) < 1 {
usage()
}
fmtStr := args[0]
Expand All @@ -69,41 +77,73 @@ outer:
os.Exit(2)
}
}
for _, cidStr := range args[1:] {
cid, err := c.Decode(cidStr)
if err != nil {
fmt.Fprintf(os.Stdout, "!INVALID_CID!\n")
errorMsg("%s: %v", cidStr, err)
// Don't abort on a bad cid
continue
}
format := func(cid c.Cid, cidStr string) (string, error) {
base := newBase
if newBase == -1 {
if base == -1 {
base, _ = c.ExtractEncoding(cidStr)
}
var err error
if verConv != nil {
cid, err = verConv(cid)
if err != nil {
fmt.Fprintf(os.Stdout, "!ERROR!\n")
errorMsg("%s: %v", cidStr, err)
// Don't abort on a bad conversion
continue
return "", err
}
}
return cidutil.Format(fmtStr, base, cid)
}
if filter {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
buf := scanner.Bytes()
for {
i, j, cid, cidStr := cidutil.ScanForCid(buf)
os.Stdout.Write(buf[0:i])
if i == len(buf) {
os.Stdout.Write([]byte{'\n'})
break
}
str, err := format(cid, cidStr)
switch err.(type) {
case cidutil.FormatStringError:
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(2)
default:
// just use the orignal sting on non-fatal error
str = cidStr
case nil:
}
io.WriteString(os.Stdout, str)
buf = buf[j:]
}
}
str, err := cidutil.Format(fmtStr, base, cid)
switch err.(type) {
case cidutil.FormatStringError:
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(2)
default:
fmt.Fprintf(os.Stdout, "!ERROR!\n")
errorMsg("%s: %v", cidStr, err)
// Don't abort on cid specific errors
continue
case nil:
// no error
}
fmt.Fprintf(os.Stdout, "%s\n", str)
} else {
for _, cidStr := range args[1:] {
cid, err := c.Decode(cidStr)
if err != nil {
fmt.Fprintf(os.Stdout, "!INVALID_CID!\n")
errorMsg("%s: %v", cidStr, err)
// Don't abort on a bad cid
continue
}
str, err := format(cid, cidStr)
switch err.(type) {
case cidutil.FormatStringError:
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(2)
default:
fmt.Fprintf(os.Stdout, "!ERROR!\n")
errorMsg("%s: %v", cidStr, err)
// Don't abort on cid specific errors
continue
case nil:
// no error
}
fmt.Fprintf(os.Stdout, "%s\n", str)
}
}
os.Exit(exitCode)
}
Expand Down
45 changes: 45 additions & 0 deletions format.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,48 @@ func encode(base mb.Encoder, data []byte, strip bool) string {
}
return str
}

// ScanForCid scans bytes for anything resembling a CId. If one is
// found `i` will point to the begging of the cid and `j` to to the end
// and the cid will be returned, otherwise `i` will point the end of the
// buffer and the cid will be `Undef`.
func ScanForCid(buf []byte) (i, j int, cid c.Cid, cidStr string) {
i = 0
for {
i = j
for i < len(buf) && !asciiIsAlpha(buf[i]) {
i++
}
j = i
if i == len(buf) {
return
}
for j < len(buf) && asciiIsAlpha(buf[j]) {
j++
}
if j-i <= 1 || j-i > 128 || !supported[buf[i]] {
continue
}
var err error
cidStr = string(buf[i:j])
cid, err = c.Decode(cidStr)
if err == nil {
return
}
}
}

var supported = make([]bool, 256)

func init() {
// for now base64 encoding are not supported as they contain non
// alhphanumeric characters
supportedPrefixes := []byte("QfFbBcCvVtThzZ")
for _, b := range supportedPrefixes {
supported[b] = true
}
}

func asciiIsAlpha(b byte) bool {
return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z') || ('0' <= b && b <= '9')
}

0 comments on commit e19f717

Please sign in to comment.