Skip to content

Commit c662bfd

Browse files
committed
remove last docker distribution dependency from api
1 parent d1fcf38 commit c662bfd

File tree

10 files changed

+1115
-6
lines changed

10 files changed

+1115
-6
lines changed

Diff for: hack/import-restrictions.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,14 @@
120120
"allowedImportPackageRoots": [
121121
"vendor/k8s.io/apimachinery",
122122
"vendor/github.com/gogo/protobuf",
123+
"github.com/openshift/origin/pkg/image/apis/image/internal",
123124
"github.com/openshift/origin/pkg/api/apihelpers"
124125
],
125126
"allowedImportPackages": [
126127
"vendor/k8s.io/kubernetes/pkg/api",
127128
"vendor/k8s.io/kubernetes/pkg/api/v1",
128129
"vendor/github.com/golang/glog",
129-
"vendor/github.com/docker/distribution/digest",
130-
"vendor/github.com/blang/semver",
131-
"github.com/openshift/origin/pkg/image/reference"
130+
"vendor/github.com/blang/semver"
132131
]
133132
},
134133

Diff for: pkg/image/apis/image/helper.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ import (
1414
"k8s.io/apimachinery/pkg/util/sets"
1515

1616
"github.com/blang/semver"
17-
"github.com/docker/distribution/digest"
1817
"github.com/golang/glog"
1918

20-
"github.com/openshift/origin/pkg/image/reference"
19+
"github.com/openshift/origin/pkg/image/apis/image/internal/digest"
2120
)
2221

2322
const (
@@ -145,7 +144,7 @@ func IsRegistryDockerHub(registry string) bool {
145144
func ParseDockerImageReference(spec string) (DockerImageReference, error) {
146145
var ref DockerImageReference
147146

148-
namedRef, err := reference.ParseNamedDockerImageReference(spec)
147+
namedRef, err := parseNamedDockerImageReference(spec)
149148
if err != nil {
150149
return ref, err
151150
}

Diff for: pkg/image/apis/image/internal/digest/digest.go

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package digest
2+
3+
import (
4+
"fmt"
5+
"hash"
6+
"io"
7+
"regexp"
8+
"strings"
9+
)
10+
11+
const (
12+
// DigestSha256EmptyTar is the canonical sha256 digest of empty data
13+
DigestSha256EmptyTar = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
14+
)
15+
16+
// Digest allows simple protection of hex formatted digest strings, prefixed
17+
// by their algorithm. Strings of type Digest have some guarantee of being in
18+
// the correct format and it provides quick access to the components of a
19+
// digest string.
20+
//
21+
// The following is an example of the contents of Digest types:
22+
//
23+
// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
24+
//
25+
// This allows to abstract the digest behind this type and work only in those
26+
// terms.
27+
type Digest string
28+
29+
// NewDigest returns a Digest from alg and a hash.Hash object.
30+
func NewDigest(alg Algorithm, h hash.Hash) Digest {
31+
return NewDigestFromBytes(alg, h.Sum(nil))
32+
}
33+
34+
// NewDigestFromBytes returns a new digest from the byte contents of p.
35+
// Typically, this can come from hash.Hash.Sum(...) or xxx.SumXXX(...)
36+
// functions. This is also useful for rebuilding digests from binary
37+
// serializations.
38+
func NewDigestFromBytes(alg Algorithm, p []byte) Digest {
39+
return Digest(fmt.Sprintf("%s:%x", alg, p))
40+
}
41+
42+
// NewDigestFromHex returns a Digest from alg and a the hex encoded digest.
43+
func NewDigestFromHex(alg, hex string) Digest {
44+
return Digest(fmt.Sprintf("%s:%s", alg, hex))
45+
}
46+
47+
// DigestRegexp matches valid digest types.
48+
var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+`)
49+
50+
// DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match.
51+
var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`)
52+
53+
var (
54+
// ErrDigestInvalidFormat returned when digest format invalid.
55+
ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format")
56+
57+
// ErrDigestInvalidLength returned when digest has invalid length.
58+
ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length")
59+
60+
// ErrDigestUnsupported returned when the digest algorithm is unsupported.
61+
ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
62+
)
63+
64+
// ParseDigest parses s and returns the validated digest object. An error will
65+
// be returned if the format is invalid.
66+
func ParseDigest(s string) (Digest, error) {
67+
d := Digest(s)
68+
69+
return d, d.Validate()
70+
}
71+
72+
// FromReader returns the most valid digest for the underlying content using
73+
// the canonical digest algorithm.
74+
func FromReader(rd io.Reader) (Digest, error) {
75+
return Canonical.FromReader(rd)
76+
}
77+
78+
// FromBytes digests the input and returns a Digest.
79+
func FromBytes(p []byte) Digest {
80+
return Canonical.FromBytes(p)
81+
}
82+
83+
// Validate checks that the contents of d is a valid digest, returning an
84+
// error if not.
85+
func (d Digest) Validate() error {
86+
s := string(d)
87+
88+
if !DigestRegexpAnchored.MatchString(s) {
89+
return ErrDigestInvalidFormat
90+
}
91+
92+
i := strings.Index(s, ":")
93+
if i < 0 {
94+
return ErrDigestInvalidFormat
95+
}
96+
97+
// case: "sha256:" with no hex.
98+
if i+1 == len(s) {
99+
return ErrDigestInvalidFormat
100+
}
101+
102+
switch algorithm := Algorithm(s[:i]); algorithm {
103+
case SHA256, SHA384, SHA512:
104+
if algorithm.Size()*2 != len(s[i+1:]) {
105+
return ErrDigestInvalidLength
106+
}
107+
break
108+
default:
109+
return ErrDigestUnsupported
110+
}
111+
112+
return nil
113+
}
114+
115+
// Algorithm returns the algorithm portion of the digest. This will panic if
116+
// the underlying digest is not in a valid format.
117+
func (d Digest) Algorithm() Algorithm {
118+
return Algorithm(d[:d.sepIndex()])
119+
}
120+
121+
// Hex returns the hex digest portion of the digest. This will panic if the
122+
// underlying digest is not in a valid format.
123+
func (d Digest) Hex() string {
124+
return string(d[d.sepIndex()+1:])
125+
}
126+
127+
func (d Digest) String() string {
128+
return string(d)
129+
}
130+
131+
func (d Digest) sepIndex() int {
132+
i := strings.Index(string(d), ":")
133+
134+
if i < 0 {
135+
panic("could not find ':' in digest: " + d)
136+
}
137+
138+
return i
139+
}

Diff for: pkg/image/apis/image/internal/digest/digester.go

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package digest
2+
3+
import (
4+
"crypto"
5+
"fmt"
6+
"hash"
7+
"io"
8+
)
9+
10+
// Algorithm identifies and implementation of a digester by an identifier.
11+
// Note the that this defines both the hash algorithm used and the string
12+
// encoding.
13+
type Algorithm string
14+
15+
// supported digest types
16+
const (
17+
SHA256 Algorithm = "sha256" // sha256 with hex encoding
18+
SHA384 Algorithm = "sha384" // sha384 with hex encoding
19+
SHA512 Algorithm = "sha512" // sha512 with hex encoding
20+
21+
// Canonical is the primary digest algorithm used with the distribution
22+
// project. Other digests may be used but this one is the primary storage
23+
// digest.
24+
Canonical = SHA256
25+
)
26+
27+
var (
28+
// TODO(stevvooe): Follow the pattern of the standard crypto package for
29+
// registration of digests. Effectively, we are a registerable set and
30+
// common symbol access.
31+
32+
// algorithms maps values to hash.Hash implementations. Other algorithms
33+
// may be available but they cannot be calculated by the digest package.
34+
algorithms = map[Algorithm]crypto.Hash{
35+
SHA256: crypto.SHA256,
36+
SHA384: crypto.SHA384,
37+
SHA512: crypto.SHA512,
38+
}
39+
)
40+
41+
// Available returns true if the digest type is available for use. If this
42+
// returns false, New and Hash will return nil.
43+
func (a Algorithm) Available() bool {
44+
h, ok := algorithms[a]
45+
if !ok {
46+
return false
47+
}
48+
49+
// check availability of the hash, as well
50+
return h.Available()
51+
}
52+
53+
func (a Algorithm) String() string {
54+
return string(a)
55+
}
56+
57+
// Size returns number of bytes returned by the hash.
58+
func (a Algorithm) Size() int {
59+
h, ok := algorithms[a]
60+
if !ok {
61+
return 0
62+
}
63+
return h.Size()
64+
}
65+
66+
// Set implemented to allow use of Algorithm as a command line flag.
67+
func (a *Algorithm) Set(value string) error {
68+
if value == "" {
69+
*a = Canonical
70+
} else {
71+
// just do a type conversion, support is queried with Available.
72+
*a = Algorithm(value)
73+
}
74+
75+
return nil
76+
}
77+
78+
// New returns a new digester for the specified algorithm. If the algorithm
79+
// does not have a digester implementation, nil will be returned. This can be
80+
// checked by calling Available before calling New.
81+
func (a Algorithm) New() Digester {
82+
return &digester{
83+
alg: a,
84+
hash: a.Hash(),
85+
}
86+
}
87+
88+
// Hash returns a new hash as used by the algorithm. If not available, the
89+
// method will panic. Check Algorithm.Available() before calling.
90+
func (a Algorithm) Hash() hash.Hash {
91+
if !a.Available() {
92+
// NOTE(stevvooe): A missing hash is usually a programming error that
93+
// must be resolved at compile time. We don't import in the digest
94+
// package to allow users to choose their hash implementation (such as
95+
// when using stevvooe/resumable or a hardware accelerated package).
96+
//
97+
// Applications that may want to resolve the hash at runtime should
98+
// call Algorithm.Available before call Algorithm.Hash().
99+
panic(fmt.Sprintf("%v not available (make sure it is imported)", a))
100+
}
101+
102+
return algorithms[a].New()
103+
}
104+
105+
// FromReader returns the digest of the reader using the algorithm.
106+
func (a Algorithm) FromReader(rd io.Reader) (Digest, error) {
107+
digester := a.New()
108+
109+
if _, err := io.Copy(digester.Hash(), rd); err != nil {
110+
return "", err
111+
}
112+
113+
return digester.Digest(), nil
114+
}
115+
116+
// FromBytes digests the input and returns a Digest.
117+
func (a Algorithm) FromBytes(p []byte) Digest {
118+
digester := a.New()
119+
120+
if _, err := digester.Hash().Write(p); err != nil {
121+
// Writes to a Hash should never fail. None of the existing
122+
// hash implementations in the stdlib or hashes vendored
123+
// here can return errors from Write. Having a panic in this
124+
// condition instead of having FromBytes return an error value
125+
// avoids unnecessary error handling paths in all callers.
126+
panic("write to hash function returned error: " + err.Error())
127+
}
128+
129+
return digester.Digest()
130+
}
131+
132+
// TODO(stevvooe): Allow resolution of verifiers using the digest type and
133+
// this registration system.
134+
135+
// Digester calculates the digest of written data. Writes should go directly
136+
// to the return value of Hash, while calling Digest will return the current
137+
// value of the digest.
138+
type Digester interface {
139+
Hash() hash.Hash // provides direct access to underlying hash instance.
140+
Digest() Digest
141+
}
142+
143+
// digester provides a simple digester definition that embeds a hasher.
144+
type digester struct {
145+
alg Algorithm
146+
hash hash.Hash
147+
}
148+
149+
func (d *digester) Hash() hash.Hash {
150+
return d.hash
151+
}
152+
153+
func (d *digester) Digest() Digest {
154+
return NewDigest(d.alg, d.hash)
155+
}

Diff for: pkg/image/apis/image/internal/digest/doc.go

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// digest is a copy from "github.com/docker/distribution/digest" that is kept because we want to avoid the godep,
2+
// this package has no non-standard dependencies, and if it changes lots of other docker registry stuff breaks.
3+
// Don't try this at home!
4+
// Changes here require sign-off from openshift/api-reviewers and they will be rejected.
5+
package digest

Diff for: pkg/image/apis/image/internal/reference/doc.go

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// reference is a copy from "github.com/docker/distribution/reference" that is kept because we want to avoid the godep,
2+
// this package has no non-standard dependencies, and if it changes lots of other docker registry stuff breaks.
3+
// Don't try this at home!
4+
// Changes here require sign-off from openshift/api-reviewers and they will be rejected.
5+
package reference

0 commit comments

Comments
 (0)