commit
						8c3fc2619c
					
				
							
								
								
									
										6
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										6
									
								
								Makefile
								
								
								
								
							|  | @ -28,6 +28,10 @@ ${PREFIX}/bin/registry: version/version.go $(shell find . -type f -name '*.go') | ||||||
| 	@echo "+ $@" | 	@echo "+ $@" | ||||||
| 	@go build -tags "${DOCKER_BUILDTAGS}" -o $@ ${GO_LDFLAGS}  ${GO_GCFLAGS} ./cmd/registry | 	@go build -tags "${DOCKER_BUILDTAGS}" -o $@ ${GO_LDFLAGS}  ${GO_GCFLAGS} ./cmd/registry | ||||||
| 
 | 
 | ||||||
|  | ${PREFIX}/bin/digest: version/version.go $(shell find . -type f -name '*.go') | ||||||
|  | 	@echo "+ $@" | ||||||
|  | 	@go build -tags "${DOCKER_BUILDTAGS}" -o $@ ${GO_LDFLAGS}  ${GO_GCFLAGS} ./cmd/digest | ||||||
|  | 
 | ||||||
| ${PREFIX}/bin/registry-api-descriptor-template: version/version.go $(shell find . -type f -name '*.go') | ${PREFIX}/bin/registry-api-descriptor-template: version/version.go $(shell find . -type f -name '*.go') | ||||||
| 	@echo "+ $@" | 	@echo "+ $@" | ||||||
| 	@go build -o $@ ${GO_LDFLAGS} ${GO_GCFLAGS} ./cmd/registry-api-descriptor-template | 	@go build -o $@ ${GO_LDFLAGS} ${GO_GCFLAGS} ./cmd/registry-api-descriptor-template | ||||||
|  | @ -62,7 +66,7 @@ test-full: | ||||||
| 	@echo "+ $@" | 	@echo "+ $@" | ||||||
| 	@go test ./... | 	@go test ./... | ||||||
| 
 | 
 | ||||||
| binaries: ${PREFIX}/bin/registry ${PREFIX}/bin/registry-api-descriptor-template | binaries: ${PREFIX}/bin/registry ${PREFIX}/bin/digest ${PREFIX}/bin/registry-api-descriptor-template | ||||||
| 	@echo "+ $@" | 	@echo "+ $@" | ||||||
| 
 | 
 | ||||||
| clean: | clean: | ||||||
|  |  | ||||||
|  | @ -0,0 +1,129 @@ | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"flag" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/docker/distribution/digest" | ||||||
|  | 	"github.com/docker/distribution/version" | ||||||
|  | 	"github.com/docker/docker/pkg/tarsum" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	algorithm   = digest.Canonical | ||||||
|  | 	showVersion bool | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type job struct { | ||||||
|  | 	name   string | ||||||
|  | 	reader io.Reader | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	flag.Var(&algorithm, "a", "select the digest algorithm (shorthand)") | ||||||
|  | 	flag.Var(&algorithm, "algorithm", "select the digest algorithm") | ||||||
|  | 	flag.BoolVar(&showVersion, "version", false, "show the version and exit") | ||||||
|  | 
 | ||||||
|  | 	log.SetFlags(0) | ||||||
|  | 	log.SetPrefix(os.Args[0] + ": ") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func usage() { | ||||||
|  | 	fmt.Fprintf(os.Stderr, "usage: %s [files...]\n", os.Args[0]) | ||||||
|  | 	fmt.Fprintf(os.Stderr, ` | ||||||
|  | Calculate the digest of one or more input files, emitting the result | ||||||
|  | to standard out. If no files are provided, the digest of stdin will | ||||||
|  | be calculated. | ||||||
|  | 
 | ||||||
|  | `) | ||||||
|  | 	flag.PrintDefaults() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func unsupported() { | ||||||
|  | 	log.Fatalf("unsupported digest algorithm: %v", algorithm) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func main() { | ||||||
|  | 	var jobs []job | ||||||
|  | 
 | ||||||
|  | 	flag.Usage = usage | ||||||
|  | 	flag.Parse() | ||||||
|  | 	if showVersion { | ||||||
|  | 		version.PrintVersion() | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var fail bool // if we fail on one item, foul the exit code
 | ||||||
|  | 	if flag.NArg() > 0 { | ||||||
|  | 		for _, path := range flag.Args() { | ||||||
|  | 			fp, err := os.Open(path) | ||||||
|  | 
 | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Printf("%s: %v", path, err) | ||||||
|  | 				fail = true | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			defer fp.Close() | ||||||
|  | 
 | ||||||
|  | 			jobs = append(jobs, job{name: path, reader: fp}) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// just read stdin
 | ||||||
|  | 		jobs = append(jobs, job{name: "-", reader: os.Stdin}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	digestFn := algorithm.FromReader | ||||||
|  | 
 | ||||||
|  | 	if !algorithm.Available() { | ||||||
|  | 		// we cannot digest if is not available. An exception is made for
 | ||||||
|  | 		// tarsum.
 | ||||||
|  | 		if !strings.HasPrefix(algorithm.String(), "tarsum") { | ||||||
|  | 			unsupported() | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		var version tarsum.Version | ||||||
|  | 		if algorithm == "tarsum" { | ||||||
|  | 			// small hack: if we just have tarsum, use latest
 | ||||||
|  | 			version = tarsum.Version1 | ||||||
|  | 		} else { | ||||||
|  | 			var err error | ||||||
|  | 			version, err = tarsum.GetVersionFromTarsum(algorithm.String()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				unsupported() | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		digestFn = func(rd io.Reader) (digest.Digest, error) { | ||||||
|  | 			ts, err := tarsum.NewTarSum(rd, true, version) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return "", err | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if _, err := io.Copy(ioutil.Discard, ts); err != nil { | ||||||
|  | 				return "", err | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return digest.Digest(ts.Sum(nil)), nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, job := range jobs { | ||||||
|  | 		dgst, err := digestFn(job.reader) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Printf("%s: %v", job.name, err) | ||||||
|  | 			fail = true | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		fmt.Printf("%v\t%s\n", dgst, job.name) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if fail { | ||||||
|  | 		os.Exit(1) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -70,15 +70,10 @@ func ParseDigest(s string) (Digest, error) { | ||||||
| 	return d, d.Validate() | 	return d, d.Validate() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // FromReader returns the most valid digest for the underlying content.
 | // FromReader returns the most valid digest for the underlying content using
 | ||||||
|  | // the canonical digest algorithm.
 | ||||||
| func FromReader(rd io.Reader) (Digest, error) { | func FromReader(rd io.Reader) (Digest, error) { | ||||||
| 	digester := Canonical.New() | 	return Canonical.FromReader(rd) | ||||||
| 
 |  | ||||||
| 	if _, err := io.Copy(digester.Hash(), rd); err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return digester.Digest(), nil |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // FromTarArchive produces a tarsum digest from reader rd.
 | // FromTarArchive produces a tarsum digest from reader rd.
 | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ package digest | ||||||
| import ( | import ( | ||||||
| 	"crypto" | 	"crypto" | ||||||
| 	"hash" | 	"hash" | ||||||
|  | 	"io" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Algorithm identifies and implementation of a digester by an identifier.
 | // Algorithm identifies and implementation of a digester by an identifier.
 | ||||||
|  | @ -49,6 +50,22 @@ func (a Algorithm) Available() bool { | ||||||
| 	return h.Available() | 	return h.Available() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (a Algorithm) String() string { | ||||||
|  | 	return string(a) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Set implemented to allow use of Algorithm as a command line flag.
 | ||||||
|  | func (a *Algorithm) Set(value string) error { | ||||||
|  | 	if value == "" { | ||||||
|  | 		*a = Canonical | ||||||
|  | 	} else { | ||||||
|  | 		// just do a type conversion, support is queried with Available.
 | ||||||
|  | 		*a = Algorithm(value) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // New returns a new digester for the specified algorithm. If the algorithm
 | // New returns a new digester for the specified algorithm. If the algorithm
 | ||||||
| // does not have a digester implementation, nil will be returned. This can be
 | // does not have a digester implementation, nil will be returned. This can be
 | ||||||
| // checked by calling Available before calling New.
 | // checked by calling Available before calling New.
 | ||||||
|  | @ -69,6 +86,17 @@ func (a Algorithm) Hash() hash.Hash { | ||||||
| 	return algorithms[a].New() | 	return algorithms[a].New() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // FromReader returns the digest of the reader using the algorithm.
 | ||||||
|  | func (a Algorithm) FromReader(rd io.Reader) (Digest, error) { | ||||||
|  | 	digester := a.New() | ||||||
|  | 
 | ||||||
|  | 	if _, err := io.Copy(digester.Hash(), rd); err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return digester.Digest(), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // TODO(stevvooe): Allow resolution of verifiers using the digest type and
 | // TODO(stevvooe): Allow resolution of verifiers using the digest type and
 | ||||||
| // this registration system.
 | // this registration system.
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue