1 // Package opts helps to write commands which may take multihash
15 mh "github.com/multiformats/go-multihash"
20 ErrMatch = errors.New("multihash checksums did not match")
23 // Options is a struct used to parse cli flags.
33 // FlagValues are the values the various option flags can take.
34 var FlagValues = struct {
38 Encodings: []string{"raw", "hex", "base58", "base64"},
39 Algorithms: func() []string {
40 names := make([]string, 0, len(mh.Names))
41 for n := range mh.Names {
42 // There are too many of these for now.
43 // We can figure something better out later.
44 if strings.HasPrefix(n, "blake2") {
56 names = append(names, n)
63 // SetupFlags adds multihash related options to given flagset.
64 func SetupFlags(f *flag.FlagSet) *Options {
65 // TODO: add arg for adding opt prefix and/or overriding opts
68 algoStr := "one of: " + strings.Join(FlagValues.Algorithms, ", ")
69 f.StringVar(&o.Algorithm, "algorithm", "sha2-256", algoStr)
70 f.StringVar(&o.Algorithm, "a", "sha2-256", algoStr+" (shorthand)")
72 encStr := "one of: " + strings.Join(FlagValues.Encodings, ", ")
73 f.StringVar(&o.Encoding, "encoding", "base58", encStr)
74 f.StringVar(&o.Encoding, "e", "base58", encStr+" (shorthand)")
76 lengthStr := "checksums length in bits (truncate). -1 is default"
77 f.IntVar(&o.Length, "length", -1, lengthStr)
78 f.IntVar(&o.Length, "l", -1, lengthStr+" (shorthand)")
82 // Parse parses the values of flags from given argument slice.
83 // It is equivalent to flags.Parse(args)
84 func (o *Options) Parse(args []string) error {
85 if err := o.fs.Parse(args); err != nil {
91 // ParseError checks the parsed options for errors.
92 func (o *Options) ParseError() error {
93 if !strIn(o.Encoding, FlagValues.Encodings) {
94 return fmt.Errorf("encoding '%s' not %s", o.Encoding, FlagValues.Encodings)
97 if !strIn(o.Algorithm, FlagValues.Algorithms) {
98 return fmt.Errorf("algorithm '%s' not %s", o.Algorithm, FlagValues.Algorithms)
102 o.AlgorithmCode, found = mh.Names[o.Algorithm]
104 return fmt.Errorf("algorithm '%s' not found (lib error, pls report).", o.Algorithm)
109 return fmt.Errorf("length must be multiple of 8")
111 o.Length = o.Length / 8
113 if o.Length > mh.DefaultLengths[o.AlgorithmCode] {
114 o.Length = mh.DefaultLengths[o.AlgorithmCode]
120 // strIn checks wither string a is in set.
121 func strIn(a string, set []string) bool {
122 for _, s := range set {
130 // Check reads all the data in r, calculates its multihash,
131 // and checks it matches h1
132 func (o *Options) Check(r io.Reader, h1 mh.Multihash) error {
133 h2, err := o.Multihash(r)
138 if !bytes.Equal(h1, h2) {
139 return fmt.Errorf("computed checksum did not match")
145 // Multihash reads all the data in r and calculates its multihash.
146 func (o *Options) Multihash(r io.Reader) (mh.Multihash, error) {
147 b, err := ioutil.ReadAll(r)
152 return mh.Sum(b, o.AlgorithmCode, o.Length)