1package main 2 3import ( 4 "flag" 5 "fmt" 6 "io" 7 "log" 8 "os" 9 10 "github.com/docker/distribution/version" 11 "github.com/opencontainers/go-digest" 12 13 _ "crypto/sha256" 14 _ "crypto/sha512" 15) 16 17var ( 18 algorithm = digest.Canonical 19 showVersion bool 20) 21 22type job struct { 23 name string 24 reader io.Reader 25} 26 27func init() { 28 flag.Var(&algorithm, "a", "select the digest algorithm (shorthand)") 29 flag.Var(&algorithm, "algorithm", "select the digest algorithm") 30 flag.BoolVar(&showVersion, "version", false, "show the version and exit") 31 32 log.SetFlags(0) 33 log.SetPrefix(os.Args[0] + ": ") 34} 35 36func usage() { 37 fmt.Fprintf(os.Stderr, "usage: %s [files...]\n", os.Args[0]) 38 fmt.Fprint(os.Stderr, ` 39Calculate the digest of one or more input files, emitting the result 40to standard out. If no files are provided, the digest of stdin will 41be calculated. 42 43`) 44 flag.PrintDefaults() 45} 46 47func unsupported() { 48 log.Fatalf("unsupported digest algorithm: %v", algorithm) 49} 50 51func main() { 52 var jobs []job 53 54 flag.Usage = usage 55 flag.Parse() 56 if showVersion { 57 version.PrintVersion() 58 return 59 } 60 61 var fail bool // if we fail on one item, foul the exit code 62 if flag.NArg() > 0 { 63 for _, path := range flag.Args() { 64 fp, err := os.Open(path) 65 66 if err != nil { 67 log.Printf("%s: %v", path, err) 68 fail = true 69 continue 70 } 71 defer fp.Close() 72 73 jobs = append(jobs, job{name: path, reader: fp}) 74 } 75 } else { 76 // just read stdin 77 jobs = append(jobs, job{name: "-", reader: os.Stdin}) 78 } 79 80 digestFn := algorithm.FromReader 81 82 if !algorithm.Available() { 83 unsupported() 84 } 85 86 for _, job := range jobs { 87 dgst, err := digestFn(job.reader) 88 if err != nil { 89 log.Printf("%s: %v", job.name, err) 90 fail = true 91 continue 92 } 93 94 fmt.Printf("%v\t%s\n", dgst, job.name) 95 } 96 97 if fail { 98 os.Exit(1) 99 } 100} 101