From cf04a95d1f88ca327249161d4f95657a648acf02 Mon Sep 17 00:00:00 2001 From: Suraj Deshmukh Date: Tue, 23 Aug 2016 09:32:46 +0530 Subject: [PATCH] Added latest bits of docker build --- Godeps/Godeps.json | 30 +- builder.go | 8 +- builder_test.go | 15 +- dockerclient/client.go | 6 +- dockerclient/conformance_test.go | 8 +- evaluator.go | 4 +- .../docker/distribution/digest/digest.go | 139 -------- .../docker/distribution/digest/digester.go | 155 -------- .../docker/distribution/digest/doc.go | 42 --- .../docker/distribution/digest/set.go | 245 ------------- .../docker/distribution/digest/verifiers.go | 44 --- .../distribution/reference/reference.go | 334 ------------------ .../docker/distribution/reference/regexp.go | 124 ------- .../docker/docker/builder/command/command.go | 37 -- .../builder/dockerfile/command/command.go | 46 +++ .../{ => dockerfile}/parser/line_parsers.go | 178 +++++++--- .../builder/dockerfile/parser/parser.go | 215 +++++++++++ .../builder/{ => dockerfile}/parser/utils.go | 16 +- .../docker/docker/builder/parser/parser.go | 143 -------- .../types/reference/image_reference.go | 32 -- .../docker/engine-api/types/time/timestamp.go | 124 ------- vendor/github.com/golang/glog/glog.go | 8 - 22 files changed, 423 insertions(+), 1530 deletions(-) delete mode 100644 vendor/github.com/docker/distribution/digest/digest.go delete mode 100644 vendor/github.com/docker/distribution/digest/digester.go delete mode 100644 vendor/github.com/docker/distribution/digest/doc.go delete mode 100644 vendor/github.com/docker/distribution/digest/set.go delete mode 100644 vendor/github.com/docker/distribution/digest/verifiers.go delete mode 100644 vendor/github.com/docker/distribution/reference/reference.go delete mode 100644 vendor/github.com/docker/distribution/reference/regexp.go delete mode 100644 vendor/github.com/docker/docker/builder/command/command.go create mode 100644 vendor/github.com/docker/docker/builder/dockerfile/command/command.go rename vendor/github.com/docker/docker/builder/{ => dockerfile}/parser/line_parsers.go (54%) create mode 100644 vendor/github.com/docker/docker/builder/dockerfile/parser/parser.go rename vendor/github.com/docker/docker/builder/{ => dockerfile}/parser/utils.go (88%) delete mode 100644 vendor/github.com/docker/docker/builder/parser/parser.go delete mode 100644 vendor/github.com/docker/engine-api/types/reference/image_reference.go delete mode 100644 vendor/github.com/docker/engine-api/types/time/timestamp.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 7670ccc0..2f45cae9 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -7,22 +7,14 @@ ], "Deps": [ { - "ImportPath": "github.com/docker/distribution/digest", - "Rev": "596ca8b86acd3feebedae6bc08abf2a48d403a14" + "ImportPath": "github.com/docker/docker/builder/dockerfile/command", + "Comment": "docs-v1.12.0-rc4-2016-07-15-923-gd2fa978", + "Rev": "d2fa978d4d66622a197eb98f9a77fa217e25f449" }, { - "ImportPath": "github.com/docker/distribution/reference", - "Rev": "596ca8b86acd3feebedae6bc08abf2a48d403a14" - }, - { - "ImportPath": "github.com/docker/docker/builder/command", - "Comment": "v1.4.1-4831-g0f5c9d3", - "Rev": "0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d" - }, - { - "ImportPath": "github.com/docker/docker/builder/parser", - "Comment": "v1.4.1-4831-g0f5c9d3", - "Rev": "0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d" + "ImportPath": "github.com/docker/docker/builder/dockerfile/parser", + "Comment": "docs-v1.12.0-rc4-2016-07-15-923-gd2fa978", + "Rev": "d2fa978d4d66622a197eb98f9a77fa217e25f449" }, { "ImportPath": "github.com/docker/engine-api/types", @@ -49,11 +41,6 @@ "Comment": "v0.3.1-62-g3d72d39", "Rev": "3d72d392d07bece8d7d7b2a3b6b2e57c2df376a2" }, - { - "ImportPath": "github.com/docker/engine-api/types/reference", - "Comment": "v0.3.1-62-g3d72d39", - "Rev": "3d72d392d07bece8d7d7b2a3b6b2e57c2df376a2" - }, { "ImportPath": "github.com/docker/engine-api/types/registry", "Comment": "v0.3.1-62-g3d72d39", @@ -64,11 +51,6 @@ "Comment": "v0.3.1-62-g3d72d39", "Rev": "3d72d392d07bece8d7d7b2a3b6b2e57c2df376a2" }, - { - "ImportPath": "github.com/docker/engine-api/types/time", - "Comment": "v0.3.1-62-g3d72d39", - "Rev": "3d72d392d07bece8d7d7b2a3b6b2e57c2df376a2" - }, { "ImportPath": "github.com/docker/engine-api/types/versions", "Comment": "v0.3.1-62-g3d72d39", diff --git a/builder.go b/builder.go index bdfbe0e7..1134e448 100644 --- a/builder.go +++ b/builder.go @@ -12,8 +12,8 @@ import ( docker "github.com/fsouza/go-dockerclient" - "github.com/docker/docker/builder/command" - "github.com/docker/docker/builder/parser" + "github.com/docker/docker/builder/dockerfile/command" + "github.com/docker/docker/builder/dockerfile/parser" ) // Copy defines a copy operation required on the container. @@ -222,7 +222,9 @@ func (b *Builder) FromImage(image *docker.Image, node *parser.Node) error { if image.Config == nil || len(image.Config.OnBuild) == 0 { return nil } - extra, err := parser.Parse(bytes.NewBufferString(strings.Join(image.Config.OnBuild, "\n"))) + d := parser.Directive{LookingForDirectives: true} + parser.SetEscapeToken(parser.DefaultEscapeToken, &d) + extra, err := parser.Parse(bytes.NewBufferString(strings.Join(image.Config.OnBuild, "\n")), &d) if err != nil { return err } diff --git a/builder_test.go b/builder_test.go index d4563387..03dec71e 100644 --- a/builder_test.go +++ b/builder_test.go @@ -7,9 +7,10 @@ import ( "testing" "fmt" - "github.com/docker/docker/builder/parser" - docker "github.com/fsouza/go-dockerclient" "reflect" + + "github.com/docker/docker/builder/dockerfile/parser" + docker "github.com/fsouza/go-dockerclient" ) func TestRun(t *testing.T) { @@ -17,7 +18,9 @@ func TestRun(t *testing.T) { if err != nil { t.Fatal(err) } - node, err := parser.Parse(f) + d := parser.Directive{LookingForDirectives: true} + parser.SetEscapeToken(parser.DefaultEscapeToken, &d) + node, err := parser.Parse(f, &d) if err != nil { t.Fatal(err) } @@ -136,7 +139,7 @@ func TestBuilder(t *testing.T) { From: "busybox", Unrecognized: []Step{ Step{Command: "health", Message: "HEALTH ", Original: "HEALTH NONE", Args: []string{""}, Flags: []string{}, Env: []string{}}, - Step{Command: "shell", Message: "SHELL ", Original: "SHELL [\"/bin/sh\", \"-c\"]", Args: []string{""}, Flags: []string{}, Env: []string{}}, + Step{Command: "shell", Message: "SHELL /bin/sh -c", Original: "SHELL [\"/bin/sh\", \"-c\"]", Args: []string{"/bin/sh", "-c"}, Flags: []string{}, Env: []string{}, Attrs: map[string]bool{"json": true}}, Step{Command: "unrecognized", Message: "UNRECOGNIZED ", Original: "UNRECOGNIZED", Args: []string{""}, Env: []string{}}, }, Config: docker.Config{ @@ -178,7 +181,9 @@ func TestBuilder(t *testing.T) { t.Errorf("%d: %v", i, err) continue } - node, err := parser.Parse(bytes.NewBuffer(data)) + d := parser.Directive{LookingForDirectives: true} + parser.SetEscapeToken(parser.DefaultEscapeToken, &d) + node, err := parser.Parse(bytes.NewBuffer(data), &d) if err != nil { t.Errorf("%d: %v", i, err) continue diff --git a/dockerclient/client.go b/dockerclient/client.go index d92de196..9d5a87eb 100644 --- a/dockerclient/client.go +++ b/dockerclient/client.go @@ -13,7 +13,7 @@ import ( "strconv" "strings" - "github.com/docker/docker/builder/parser" + "github.com/docker/docker/builder/dockerfile/parser" dockertypes "github.com/docker/engine-api/types" docker "github.com/fsouza/go-dockerclient" "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive" @@ -105,7 +105,9 @@ func (e *ClientExecutor) Build(r io.Reader, args map[string]string) error { // TODO: check the Docker daemon version (1.20 is required for Upload) - node, err := parser.Parse(r) + d := parser.Directive{LookingForDirectives: true} + parser.SetEscapeToken(parser.DefaultEscapeToken, &d) + node, err := parser.Parse(r, &d) if err != nil { return err } diff --git a/dockerclient/conformance_test.go b/dockerclient/conformance_test.go index 4432b552..78a191ed 100644 --- a/dockerclient/conformance_test.go +++ b/dockerclient/conformance_test.go @@ -17,8 +17,8 @@ import ( "testing" "time" - "github.com/docker/docker/builder/command" - "github.com/docker/docker/builder/parser" + "github.com/docker/docker/builder/dockerfile/command" + "github.com/docker/docker/builder/dockerfile/parser" docker "github.com/fsouza/go-dockerclient" "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive" "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/fileutils" @@ -197,7 +197,9 @@ func conformanceTester(t *testing.T, c *docker.Client, test conformanceTest, i i t.Errorf("%d: unable to read Dockerfile %q: %v", i, input, err) return } - node, err := parser.Parse(bytes.NewBuffer(data)) + d := parser.Directive{LookingForDirectives: true} + parser.SetEscapeToken(parser.DefaultEscapeToken, &d) + node, err := parser.Parse(bytes.NewBuffer(data), &d) if err != nil { t.Errorf("%d: can't parse Dockerfile %q: %v", i, input, err) return diff --git a/evaluator.go b/evaluator.go index e17eea23..086491a2 100644 --- a/evaluator.go +++ b/evaluator.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" - "github.com/docker/docker/builder/command" - "github.com/docker/docker/builder/parser" + "github.com/docker/docker/builder/dockerfile/command" + "github.com/docker/docker/builder/dockerfile/parser" ) // Environment variable interpolation will happen on these statements only. diff --git a/vendor/github.com/docker/distribution/digest/digest.go b/vendor/github.com/docker/distribution/digest/digest.go deleted file mode 100644 index 31d821bb..00000000 --- a/vendor/github.com/docker/distribution/digest/digest.go +++ /dev/null @@ -1,139 +0,0 @@ -package digest - -import ( - "fmt" - "hash" - "io" - "regexp" - "strings" -) - -const ( - // DigestSha256EmptyTar is the canonical sha256 digest of empty data - DigestSha256EmptyTar = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" -) - -// Digest allows simple protection of hex formatted digest strings, prefixed -// by their algorithm. Strings of type Digest have some guarantee of being in -// the correct format and it provides quick access to the components of a -// digest string. -// -// The following is an example of the contents of Digest types: -// -// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc -// -// This allows to abstract the digest behind this type and work only in those -// terms. -type Digest string - -// NewDigest returns a Digest from alg and a hash.Hash object. -func NewDigest(alg Algorithm, h hash.Hash) Digest { - return NewDigestFromBytes(alg, h.Sum(nil)) -} - -// NewDigestFromBytes returns a new digest from the byte contents of p. -// Typically, this can come from hash.Hash.Sum(...) or xxx.SumXXX(...) -// functions. This is also useful for rebuilding digests from binary -// serializations. -func NewDigestFromBytes(alg Algorithm, p []byte) Digest { - return Digest(fmt.Sprintf("%s:%x", alg, p)) -} - -// NewDigestFromHex returns a Digest from alg and a the hex encoded digest. -func NewDigestFromHex(alg, hex string) Digest { - return Digest(fmt.Sprintf("%s:%s", alg, hex)) -} - -// DigestRegexp matches valid digest types. -var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+`) - -// DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match. -var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`) - -var ( - // ErrDigestInvalidFormat returned when digest format invalid. - ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format") - - // ErrDigestInvalidLength returned when digest has invalid length. - ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length") - - // ErrDigestUnsupported returned when the digest algorithm is unsupported. - ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm") -) - -// ParseDigest parses s and returns the validated digest object. An error will -// be returned if the format is invalid. -func ParseDigest(s string) (Digest, error) { - d := Digest(s) - - return d, d.Validate() -} - -// FromReader returns the most valid digest for the underlying content using -// the canonical digest algorithm. -func FromReader(rd io.Reader) (Digest, error) { - return Canonical.FromReader(rd) -} - -// FromBytes digests the input and returns a Digest. -func FromBytes(p []byte) Digest { - return Canonical.FromBytes(p) -} - -// Validate checks that the contents of d is a valid digest, returning an -// error if not. -func (d Digest) Validate() error { - s := string(d) - - if !DigestRegexpAnchored.MatchString(s) { - return ErrDigestInvalidFormat - } - - i := strings.Index(s, ":") - if i < 0 { - return ErrDigestInvalidFormat - } - - // case: "sha256:" with no hex. - if i+1 == len(s) { - return ErrDigestInvalidFormat - } - - switch algorithm := Algorithm(s[:i]); algorithm { - case SHA256, SHA384, SHA512: - if algorithm.Size()*2 != len(s[i+1:]) { - return ErrDigestInvalidLength - } - break - default: - return ErrDigestUnsupported - } - - return nil -} - -// Algorithm returns the algorithm portion of the digest. This will panic if -// the underlying digest is not in a valid format. -func (d Digest) Algorithm() Algorithm { - return Algorithm(d[:d.sepIndex()]) -} - -// Hex returns the hex digest portion of the digest. This will panic if the -// underlying digest is not in a valid format. -func (d Digest) Hex() string { - return string(d[d.sepIndex()+1:]) -} - -func (d Digest) String() string { - return string(d) -} - -func (d Digest) sepIndex() int { - i := strings.Index(string(d), ":") - - if i < 0 { - panic("could not find ':' in digest: " + d) - } - - return i -} diff --git a/vendor/github.com/docker/distribution/digest/digester.go b/vendor/github.com/docker/distribution/digest/digester.go deleted file mode 100644 index f3105a45..00000000 --- a/vendor/github.com/docker/distribution/digest/digester.go +++ /dev/null @@ -1,155 +0,0 @@ -package digest - -import ( - "crypto" - "fmt" - "hash" - "io" -) - -// Algorithm identifies and implementation of a digester by an identifier. -// Note the that this defines both the hash algorithm used and the string -// encoding. -type Algorithm string - -// supported digest types -const ( - SHA256 Algorithm = "sha256" // sha256 with hex encoding - SHA384 Algorithm = "sha384" // sha384 with hex encoding - SHA512 Algorithm = "sha512" // sha512 with hex encoding - - // Canonical is the primary digest algorithm used with the distribution - // project. Other digests may be used but this one is the primary storage - // digest. - Canonical = SHA256 -) - -var ( - // TODO(stevvooe): Follow the pattern of the standard crypto package for - // registration of digests. Effectively, we are a registerable set and - // common symbol access. - - // algorithms maps values to hash.Hash implementations. Other algorithms - // may be available but they cannot be calculated by the digest package. - algorithms = map[Algorithm]crypto.Hash{ - SHA256: crypto.SHA256, - SHA384: crypto.SHA384, - SHA512: crypto.SHA512, - } -) - -// Available returns true if the digest type is available for use. If this -// returns false, New and Hash will return nil. -func (a Algorithm) Available() bool { - h, ok := algorithms[a] - if !ok { - return false - } - - // check availability of the hash, as well - return h.Available() -} - -func (a Algorithm) String() string { - return string(a) -} - -// Size returns number of bytes returned by the hash. -func (a Algorithm) Size() int { - h, ok := algorithms[a] - if !ok { - return 0 - } - return h.Size() -} - -// 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 -// does not have a digester implementation, nil will be returned. This can be -// checked by calling Available before calling New. -func (a Algorithm) New() Digester { - return &digester{ - alg: a, - hash: a.Hash(), - } -} - -// Hash returns a new hash as used by the algorithm. If not available, the -// method will panic. Check Algorithm.Available() before calling. -func (a Algorithm) Hash() hash.Hash { - if !a.Available() { - // NOTE(stevvooe): A missing hash is usually a programming error that - // must be resolved at compile time. We don't import in the digest - // package to allow users to choose their hash implementation (such as - // when using stevvooe/resumable or a hardware accelerated package). - // - // Applications that may want to resolve the hash at runtime should - // call Algorithm.Available before call Algorithm.Hash(). - panic(fmt.Sprintf("%v not available (make sure it is imported)", a)) - } - - 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 -} - -// FromBytes digests the input and returns a Digest. -func (a Algorithm) FromBytes(p []byte) Digest { - digester := a.New() - - if _, err := digester.Hash().Write(p); err != nil { - // Writes to a Hash should never fail. None of the existing - // hash implementations in the stdlib or hashes vendored - // here can return errors from Write. Having a panic in this - // condition instead of having FromBytes return an error value - // avoids unnecessary error handling paths in all callers. - panic("write to hash function returned error: " + err.Error()) - } - - return digester.Digest() -} - -// TODO(stevvooe): Allow resolution of verifiers using the digest type and -// this registration system. - -// Digester calculates the digest of written data. Writes should go directly -// to the return value of Hash, while calling Digest will return the current -// value of the digest. -type Digester interface { - Hash() hash.Hash // provides direct access to underlying hash instance. - Digest() Digest -} - -// digester provides a simple digester definition that embeds a hasher. -type digester struct { - alg Algorithm - hash hash.Hash -} - -func (d *digester) Hash() hash.Hash { - return d.hash -} - -func (d *digester) Digest() Digest { - return NewDigest(d.alg, d.hash) -} diff --git a/vendor/github.com/docker/distribution/digest/doc.go b/vendor/github.com/docker/distribution/digest/doc.go deleted file mode 100644 index f64b0db3..00000000 --- a/vendor/github.com/docker/distribution/digest/doc.go +++ /dev/null @@ -1,42 +0,0 @@ -// Package digest provides a generalized type to opaquely represent message -// digests and their operations within the registry. The Digest type is -// designed to serve as a flexible identifier in a content-addressable system. -// More importantly, it provides tools and wrappers to work with -// hash.Hash-based digests with little effort. -// -// Basics -// -// The format of a digest is simply a string with two parts, dubbed the -// "algorithm" and the "digest", separated by a colon: -// -// : -// -// An example of a sha256 digest representation follows: -// -// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc -// -// In this case, the string "sha256" is the algorithm and the hex bytes are -// the "digest". -// -// Because the Digest type is simply a string, once a valid Digest is -// obtained, comparisons are cheap, quick and simple to express with the -// standard equality operator. -// -// Verification -// -// The main benefit of using the Digest type is simple verification against a -// given digest. The Verifier interface, modeled after the stdlib hash.Hash -// interface, provides a common write sink for digest verification. After -// writing is complete, calling the Verifier.Verified method will indicate -// whether or not the stream of bytes matches the target digest. -// -// Missing Features -// -// In addition to the above, we intend to add the following features to this -// package: -// -// 1. A Digester type that supports write sink digest calculation. -// -// 2. Suspend and resume of ongoing digest calculations to support efficient digest verification in the registry. -// -package digest diff --git a/vendor/github.com/docker/distribution/digest/set.go b/vendor/github.com/docker/distribution/digest/set.go deleted file mode 100644 index 4b9313c1..00000000 --- a/vendor/github.com/docker/distribution/digest/set.go +++ /dev/null @@ -1,245 +0,0 @@ -package digest - -import ( - "errors" - "sort" - "strings" - "sync" -) - -var ( - // ErrDigestNotFound is used when a matching digest - // could not be found in a set. - ErrDigestNotFound = errors.New("digest not found") - - // ErrDigestAmbiguous is used when multiple digests - // are found in a set. None of the matching digests - // should be considered valid matches. - ErrDigestAmbiguous = errors.New("ambiguous digest string") -) - -// Set is used to hold a unique set of digests which -// may be easily referenced by easily referenced by a string -// representation of the digest as well as short representation. -// The uniqueness of the short representation is based on other -// digests in the set. If digests are omitted from this set, -// collisions in a larger set may not be detected, therefore it -// is important to always do short representation lookups on -// the complete set of digests. To mitigate collisions, an -// appropriately long short code should be used. -type Set struct { - mutex sync.RWMutex - entries digestEntries -} - -// NewSet creates an empty set of digests -// which may have digests added. -func NewSet() *Set { - return &Set{ - entries: digestEntries{}, - } -} - -// checkShortMatch checks whether two digests match as either whole -// values or short values. This function does not test equality, -// rather whether the second value could match against the first -// value. -func checkShortMatch(alg Algorithm, hex, shortAlg, shortHex string) bool { - if len(hex) == len(shortHex) { - if hex != shortHex { - return false - } - if len(shortAlg) > 0 && string(alg) != shortAlg { - return false - } - } else if !strings.HasPrefix(hex, shortHex) { - return false - } else if len(shortAlg) > 0 && string(alg) != shortAlg { - return false - } - return true -} - -// Lookup looks for a digest matching the given string representation. -// If no digests could be found ErrDigestNotFound will be returned -// with an empty digest value. If multiple matches are found -// ErrDigestAmbiguous will be returned with an empty digest value. -func (dst *Set) Lookup(d string) (Digest, error) { - dst.mutex.RLock() - defer dst.mutex.RUnlock() - if len(dst.entries) == 0 { - return "", ErrDigestNotFound - } - var ( - searchFunc func(int) bool - alg Algorithm - hex string - ) - dgst, err := ParseDigest(d) - if err == ErrDigestInvalidFormat { - hex = d - searchFunc = func(i int) bool { - return dst.entries[i].val >= d - } - } else { - hex = dgst.Hex() - alg = dgst.Algorithm() - searchFunc = func(i int) bool { - if dst.entries[i].val == hex { - return dst.entries[i].alg >= alg - } - return dst.entries[i].val >= hex - } - } - idx := sort.Search(len(dst.entries), searchFunc) - if idx == len(dst.entries) || !checkShortMatch(dst.entries[idx].alg, dst.entries[idx].val, string(alg), hex) { - return "", ErrDigestNotFound - } - if dst.entries[idx].alg == alg && dst.entries[idx].val == hex { - return dst.entries[idx].digest, nil - } - if idx+1 < len(dst.entries) && checkShortMatch(dst.entries[idx+1].alg, dst.entries[idx+1].val, string(alg), hex) { - return "", ErrDigestAmbiguous - } - - return dst.entries[idx].digest, nil -} - -// Add adds the given digest to the set. An error will be returned -// if the given digest is invalid. If the digest already exists in the -// set, this operation will be a no-op. -func (dst *Set) Add(d Digest) error { - if err := d.Validate(); err != nil { - return err - } - dst.mutex.Lock() - defer dst.mutex.Unlock() - entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d} - searchFunc := func(i int) bool { - if dst.entries[i].val == entry.val { - return dst.entries[i].alg >= entry.alg - } - return dst.entries[i].val >= entry.val - } - idx := sort.Search(len(dst.entries), searchFunc) - if idx == len(dst.entries) { - dst.entries = append(dst.entries, entry) - return nil - } else if dst.entries[idx].digest == d { - return nil - } - - entries := append(dst.entries, nil) - copy(entries[idx+1:], entries[idx:len(entries)-1]) - entries[idx] = entry - dst.entries = entries - return nil -} - -// Remove removes the given digest from the set. An err will be -// returned if the given digest is invalid. If the digest does -// not exist in the set, this operation will be a no-op. -func (dst *Set) Remove(d Digest) error { - if err := d.Validate(); err != nil { - return err - } - dst.mutex.Lock() - defer dst.mutex.Unlock() - entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d} - searchFunc := func(i int) bool { - if dst.entries[i].val == entry.val { - return dst.entries[i].alg >= entry.alg - } - return dst.entries[i].val >= entry.val - } - idx := sort.Search(len(dst.entries), searchFunc) - // Not found if idx is after or value at idx is not digest - if idx == len(dst.entries) || dst.entries[idx].digest != d { - return nil - } - - entries := dst.entries - copy(entries[idx:], entries[idx+1:]) - entries = entries[:len(entries)-1] - dst.entries = entries - - return nil -} - -// All returns all the digests in the set -func (dst *Set) All() []Digest { - dst.mutex.RLock() - defer dst.mutex.RUnlock() - retValues := make([]Digest, len(dst.entries)) - for i := range dst.entries { - retValues[i] = dst.entries[i].digest - } - - return retValues -} - -// ShortCodeTable returns a map of Digest to unique short codes. The -// length represents the minimum value, the maximum length may be the -// entire value of digest if uniqueness cannot be achieved without the -// full value. This function will attempt to make short codes as short -// as possible to be unique. -func ShortCodeTable(dst *Set, length int) map[Digest]string { - dst.mutex.RLock() - defer dst.mutex.RUnlock() - m := make(map[Digest]string, len(dst.entries)) - l := length - resetIdx := 0 - for i := 0; i < len(dst.entries); i++ { - var short string - extended := true - for extended { - extended = false - if len(dst.entries[i].val) <= l { - short = dst.entries[i].digest.String() - } else { - short = dst.entries[i].val[:l] - for j := i + 1; j < len(dst.entries); j++ { - if checkShortMatch(dst.entries[j].alg, dst.entries[j].val, "", short) { - if j > resetIdx { - resetIdx = j - } - extended = true - } else { - break - } - } - if extended { - l++ - } - } - } - m[dst.entries[i].digest] = short - if i >= resetIdx { - l = length - } - } - return m -} - -type digestEntry struct { - alg Algorithm - val string - digest Digest -} - -type digestEntries []*digestEntry - -func (d digestEntries) Len() int { - return len(d) -} - -func (d digestEntries) Less(i, j int) bool { - if d[i].val != d[j].val { - return d[i].val < d[j].val - } - return d[i].alg < d[j].alg -} - -func (d digestEntries) Swap(i, j int) { - d[i], d[j] = d[j], d[i] -} diff --git a/vendor/github.com/docker/distribution/digest/verifiers.go b/vendor/github.com/docker/distribution/digest/verifiers.go deleted file mode 100644 index 9af3be13..00000000 --- a/vendor/github.com/docker/distribution/digest/verifiers.go +++ /dev/null @@ -1,44 +0,0 @@ -package digest - -import ( - "hash" - "io" -) - -// Verifier presents a general verification interface to be used with message -// digests and other byte stream verifications. Users instantiate a Verifier -// from one of the various methods, write the data under test to it then check -// the result with the Verified method. -type Verifier interface { - io.Writer - - // Verified will return true if the content written to Verifier matches - // the digest. - Verified() bool -} - -// NewDigestVerifier returns a verifier that compares the written bytes -// against a passed in digest. -func NewDigestVerifier(d Digest) (Verifier, error) { - if err := d.Validate(); err != nil { - return nil, err - } - - return hashVerifier{ - hash: d.Algorithm().Hash(), - digest: d, - }, nil -} - -type hashVerifier struct { - digest Digest - hash hash.Hash -} - -func (hv hashVerifier) Write(p []byte) (n int, err error) { - return hv.hash.Write(p) -} - -func (hv hashVerifier) Verified() bool { - return hv.digest == NewDigest(hv.digest.Algorithm(), hv.hash) -} diff --git a/vendor/github.com/docker/distribution/reference/reference.go b/vendor/github.com/docker/distribution/reference/reference.go deleted file mode 100644 index bb09fa25..00000000 --- a/vendor/github.com/docker/distribution/reference/reference.go +++ /dev/null @@ -1,334 +0,0 @@ -// Package reference provides a general type to represent any way of referencing images within the registry. -// Its main purpose is to abstract tags and digests (content-addressable hash). -// -// Grammar -// -// reference := name [ ":" tag ] [ "@" digest ] -// name := [hostname '/'] component ['/' component]* -// hostname := hostcomponent ['.' hostcomponent]* [':' port-number] -// hostcomponent := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ -// port-number := /[0-9]+/ -// component := alpha-numeric [separator alpha-numeric]* -// alpha-numeric := /[a-z0-9]+/ -// separator := /[_.]|__|[-]*/ -// -// tag := /[\w][\w.-]{0,127}/ -// -// digest := digest-algorithm ":" digest-hex -// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ] -// digest-algorithm-separator := /[+.-_]/ -// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/ -// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value -package reference - -import ( - "errors" - "fmt" - - "github.com/docker/distribution/digest" -) - -const ( - // NameTotalLengthMax is the maximum total number of characters in a repository name. - NameTotalLengthMax = 255 -) - -var ( - // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. - ErrReferenceInvalidFormat = errors.New("invalid reference format") - - // ErrTagInvalidFormat represents an error while trying to parse a string as a tag. - ErrTagInvalidFormat = errors.New("invalid tag format") - - // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. - ErrDigestInvalidFormat = errors.New("invalid digest format") - - // ErrNameEmpty is returned for empty, invalid repository names. - ErrNameEmpty = errors.New("repository name must have at least one component") - - // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. - ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax) -) - -// Reference is an opaque object reference identifier that may include -// modifiers such as a hostname, name, tag, and digest. -type Reference interface { - // String returns the full reference - String() string -} - -// Field provides a wrapper type for resolving correct reference types when -// working with encoding. -type Field struct { - reference Reference -} - -// AsField wraps a reference in a Field for encoding. -func AsField(reference Reference) Field { - return Field{reference} -} - -// Reference unwraps the reference type from the field to -// return the Reference object. This object should be -// of the appropriate type to further check for different -// reference types. -func (f Field) Reference() Reference { - return f.reference -} - -// MarshalText serializes the field to byte text which -// is the string of the reference. -func (f Field) MarshalText() (p []byte, err error) { - return []byte(f.reference.String()), nil -} - -// UnmarshalText parses text bytes by invoking the -// reference parser to ensure the appropriately -// typed reference object is wrapped by field. -func (f *Field) UnmarshalText(p []byte) error { - r, err := Parse(string(p)) - if err != nil { - return err - } - - f.reference = r - return nil -} - -// Named is an object with a full name -type Named interface { - Reference - Name() string -} - -// Tagged is an object which has a tag -type Tagged interface { - Reference - Tag() string -} - -// NamedTagged is an object including a name and tag. -type NamedTagged interface { - Named - Tag() string -} - -// Digested is an object which has a digest -// in which it can be referenced by -type Digested interface { - Reference - Digest() digest.Digest -} - -// Canonical reference is an object with a fully unique -// name including a name with hostname and digest -type Canonical interface { - Named - Digest() digest.Digest -} - -// SplitHostname splits a named reference into a -// hostname and name string. If no valid hostname is -// found, the hostname is empty and the full value -// is returned as name -func SplitHostname(named Named) (string, string) { - name := named.Name() - match := anchoredNameRegexp.FindStringSubmatch(name) - if match == nil || len(match) != 3 { - return "", name - } - return match[1], match[2] -} - -// Parse parses s and returns a syntactically valid Reference. -// If an error was encountered it is returned, along with a nil Reference. -// NOTE: Parse will not handle short digests. -func Parse(s string) (Reference, error) { - matches := ReferenceRegexp.FindStringSubmatch(s) - if matches == nil { - if s == "" { - return nil, ErrNameEmpty - } - // TODO(dmcgowan): Provide more specific and helpful error - return nil, ErrReferenceInvalidFormat - } - - if len(matches[1]) > NameTotalLengthMax { - return nil, ErrNameTooLong - } - - ref := reference{ - name: matches[1], - tag: matches[2], - } - if matches[3] != "" { - var err error - ref.digest, err = digest.ParseDigest(matches[3]) - if err != nil { - return nil, err - } - } - - r := getBestReferenceType(ref) - if r == nil { - return nil, ErrNameEmpty - } - - return r, nil -} - -// ParseNamed parses s and returns a syntactically valid reference implementing -// the Named interface. The reference must have a name, otherwise an error is -// returned. -// If an error was encountered it is returned, along with a nil Reference. -// NOTE: ParseNamed will not handle short digests. -func ParseNamed(s string) (Named, error) { - ref, err := Parse(s) - if err != nil { - return nil, err - } - named, isNamed := ref.(Named) - if !isNamed { - return nil, fmt.Errorf("reference %s has no name", ref.String()) - } - return named, nil -} - -// WithName returns a named object representing the given string. If the input -// is invalid ErrReferenceInvalidFormat will be returned. -func WithName(name string) (Named, error) { - if len(name) > NameTotalLengthMax { - return nil, ErrNameTooLong - } - if !anchoredNameRegexp.MatchString(name) { - return nil, ErrReferenceInvalidFormat - } - return repository(name), nil -} - -// WithTag combines the name from "name" and the tag from "tag" to form a -// reference incorporating both the name and the tag. -func WithTag(name Named, tag string) (NamedTagged, error) { - if !anchoredTagRegexp.MatchString(tag) { - return nil, ErrTagInvalidFormat - } - return taggedReference{ - name: name.Name(), - tag: tag, - }, nil -} - -// WithDigest combines the name from "name" and the digest from "digest" to form -// a reference incorporating both the name and the digest. -func WithDigest(name Named, digest digest.Digest) (Canonical, error) { - if !anchoredDigestRegexp.MatchString(digest.String()) { - return nil, ErrDigestInvalidFormat - } - return canonicalReference{ - name: name.Name(), - digest: digest, - }, nil -} - -func getBestReferenceType(ref reference) Reference { - if ref.name == "" { - // Allow digest only references - if ref.digest != "" { - return digestReference(ref.digest) - } - return nil - } - if ref.tag == "" { - if ref.digest != "" { - return canonicalReference{ - name: ref.name, - digest: ref.digest, - } - } - return repository(ref.name) - } - if ref.digest == "" { - return taggedReference{ - name: ref.name, - tag: ref.tag, - } - } - - return ref -} - -type reference struct { - name string - tag string - digest digest.Digest -} - -func (r reference) String() string { - return r.name + ":" + r.tag + "@" + r.digest.String() -} - -func (r reference) Name() string { - return r.name -} - -func (r reference) Tag() string { - return r.tag -} - -func (r reference) Digest() digest.Digest { - return r.digest -} - -type repository string - -func (r repository) String() string { - return string(r) -} - -func (r repository) Name() string { - return string(r) -} - -type digestReference digest.Digest - -func (d digestReference) String() string { - return d.String() -} - -func (d digestReference) Digest() digest.Digest { - return digest.Digest(d) -} - -type taggedReference struct { - name string - tag string -} - -func (t taggedReference) String() string { - return t.name + ":" + t.tag -} - -func (t taggedReference) Name() string { - return t.name -} - -func (t taggedReference) Tag() string { - return t.tag -} - -type canonicalReference struct { - name string - digest digest.Digest -} - -func (c canonicalReference) String() string { - return c.name + "@" + c.digest.String() -} - -func (c canonicalReference) Name() string { - return c.name -} - -func (c canonicalReference) Digest() digest.Digest { - return c.digest -} diff --git a/vendor/github.com/docker/distribution/reference/regexp.go b/vendor/github.com/docker/distribution/reference/regexp.go deleted file mode 100644 index 9a7d366b..00000000 --- a/vendor/github.com/docker/distribution/reference/regexp.go +++ /dev/null @@ -1,124 +0,0 @@ -package reference - -import "regexp" - -var ( - // alphaNumericRegexp defines the alpha numeric atom, typically a - // component of names. This only allows lower case characters and digits. - alphaNumericRegexp = match(`[a-z0-9]+`) - - // separatorRegexp defines the separators allowed to be embedded in name - // components. This allow one period, one or two underscore and multiple - // dashes. - separatorRegexp = match(`(?:[._]|__|[-]*)`) - - // nameComponentRegexp restricts registry path component names to start - // with at least one letter or number, with following parts able to be - // separated by one period, one or two underscore and multiple dashes. - nameComponentRegexp = expression( - alphaNumericRegexp, - optional(repeated(separatorRegexp, alphaNumericRegexp))) - - // hostnameComponentRegexp restricts the registry hostname component of a - // repository name to start with a component as defined by hostnameRegexp - // and followed by an optional port. - hostnameComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`) - - // hostnameRegexp defines the structure of potential hostname components - // that may be part of image names. This is purposely a subset of what is - // allowed by DNS to ensure backwards compatibility with Docker image - // names. - hostnameRegexp = expression( - hostnameComponentRegexp, - optional(repeated(literal(`.`), hostnameComponentRegexp)), - optional(literal(`:`), match(`[0-9]+`))) - - // TagRegexp matches valid tag names. From docker/docker:graph/tags.go. - TagRegexp = match(`[\w][\w.-]{0,127}`) - - // anchoredTagRegexp matches valid tag names, anchored at the start and - // end of the matched string. - anchoredTagRegexp = anchored(TagRegexp) - - // DigestRegexp matches valid digests. - DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`) - - // anchoredDigestRegexp matches valid digests, anchored at the start and - // end of the matched string. - anchoredDigestRegexp = anchored(DigestRegexp) - - // NameRegexp is the format for the name component of references. The - // regexp has capturing groups for the hostname and name part omitting - // the separating forward slash from either. - NameRegexp = expression( - optional(hostnameRegexp, literal(`/`)), - nameComponentRegexp, - optional(repeated(literal(`/`), nameComponentRegexp))) - - // anchoredNameRegexp is used to parse a name value, capturing the - // hostname and trailing components. - anchoredNameRegexp = anchored( - optional(capture(hostnameRegexp), literal(`/`)), - capture(nameComponentRegexp, - optional(repeated(literal(`/`), nameComponentRegexp)))) - - // ReferenceRegexp is the full supported format of a reference. The regexp - // is anchored and has capturing groups for name, tag, and digest - // components. - ReferenceRegexp = anchored(capture(NameRegexp), - optional(literal(":"), capture(TagRegexp)), - optional(literal("@"), capture(DigestRegexp))) -) - -// match compiles the string to a regular expression. -var match = regexp.MustCompile - -// literal compiles s into a literal regular expression, escaping any regexp -// reserved characters. -func literal(s string) *regexp.Regexp { - re := match(regexp.QuoteMeta(s)) - - if _, complete := re.LiteralPrefix(); !complete { - panic("must be a literal") - } - - return re -} - -// expression defines a full expression, where each regular expression must -// follow the previous. -func expression(res ...*regexp.Regexp) *regexp.Regexp { - var s string - for _, re := range res { - s += re.String() - } - - return match(s) -} - -// optional wraps the expression in a non-capturing group and makes the -// production optional. -func optional(res ...*regexp.Regexp) *regexp.Regexp { - return match(group(expression(res...)).String() + `?`) -} - -// repeated wraps the regexp in a non-capturing group to get one or more -// matches. -func repeated(res ...*regexp.Regexp) *regexp.Regexp { - return match(group(expression(res...)).String() + `+`) -} - -// group wraps the regexp in a non-capturing group. -func group(res ...*regexp.Regexp) *regexp.Regexp { - return match(`(?:` + expression(res...).String() + `)`) -} - -// capture wraps the expression in a capturing group. -func capture(res ...*regexp.Regexp) *regexp.Regexp { - return match(`(` + expression(res...).String() + `)`) -} - -// anchored anchors the regular expression by adding start and end delimiters. -func anchored(res ...*regexp.Regexp) *regexp.Regexp { - return match(`^` + expression(res...).String() + `$`) -} diff --git a/vendor/github.com/docker/docker/builder/command/command.go b/vendor/github.com/docker/docker/builder/command/command.go deleted file mode 100644 index 8e5d9803..00000000 --- a/vendor/github.com/docker/docker/builder/command/command.go +++ /dev/null @@ -1,37 +0,0 @@ -// This package contains the set of Dockerfile commands. -package command - -const ( - Env = "env" - Label = "label" - Maintainer = "maintainer" - Add = "add" - Copy = "copy" - From = "from" - Onbuild = "onbuild" - Workdir = "workdir" - Run = "run" - Cmd = "cmd" - Entrypoint = "entrypoint" - Expose = "expose" - Volume = "volume" - User = "user" -) - -// Commands is list of all Dockerfile commands -var Commands = map[string]struct{}{ - Env: {}, - Label: {}, - Maintainer: {}, - Add: {}, - Copy: {}, - From: {}, - Onbuild: {}, - Workdir: {}, - Run: {}, - Cmd: {}, - Entrypoint: {}, - Expose: {}, - Volume: {}, - User: {}, -} diff --git a/vendor/github.com/docker/docker/builder/dockerfile/command/command.go b/vendor/github.com/docker/docker/builder/dockerfile/command/command.go new file mode 100644 index 00000000..f23c6874 --- /dev/null +++ b/vendor/github.com/docker/docker/builder/dockerfile/command/command.go @@ -0,0 +1,46 @@ +// Package command contains the set of Dockerfile commands. +package command + +// Define constants for the command strings +const ( + Add = "add" + Arg = "arg" + Cmd = "cmd" + Copy = "copy" + Entrypoint = "entrypoint" + Env = "env" + Expose = "expose" + From = "from" + Healthcheck = "healthcheck" + Label = "label" + Maintainer = "maintainer" + Onbuild = "onbuild" + Run = "run" + Shell = "shell" + StopSignal = "stopsignal" + User = "user" + Volume = "volume" + Workdir = "workdir" +) + +// Commands is list of all Dockerfile commands +var Commands = map[string]struct{}{ + Add: {}, + Arg: {}, + Cmd: {}, + Copy: {}, + Entrypoint: {}, + Env: {}, + Expose: {}, + From: {}, + Healthcheck: {}, + Label: {}, + Maintainer: {}, + Onbuild: {}, + Run: {}, + Shell: {}, + StopSignal: {}, + User: {}, + Volume: {}, + Workdir: {}, +} diff --git a/vendor/github.com/docker/docker/builder/parser/line_parsers.go b/vendor/github.com/docker/docker/builder/dockerfile/parser/line_parsers.go similarity index 54% rename from vendor/github.com/docker/docker/builder/parser/line_parsers.go rename to vendor/github.com/docker/docker/builder/dockerfile/parser/line_parsers.go index 8db360ca..dec7a757 100644 --- a/vendor/github.com/docker/docker/builder/parser/line_parsers.go +++ b/vendor/github.com/docker/docker/builder/dockerfile/parser/line_parsers.go @@ -12,6 +12,7 @@ import ( "fmt" "strings" "unicode" + "unicode/utf8" ) var ( @@ -20,7 +21,7 @@ var ( // ignore the current argument. This will still leave a command parsed, but // will not incorporate the arguments into the ast. -func parseIgnore(rest string) (*Node, map[string]bool, error) { +func parseIgnore(rest string, d *Directive) (*Node, map[string]bool, error) { return &Node{}, nil, nil } @@ -29,12 +30,12 @@ func parseIgnore(rest string) (*Node, map[string]bool, error) { // // ONBUILD RUN foo bar -> (onbuild (run foo bar)) // -func parseSubCommand(rest string) (*Node, map[string]bool, error) { +func parseSubCommand(rest string, d *Directive) (*Node, map[string]bool, error) { if rest == "" { return nil, nil, nil } - _, child, err := parseLine(rest) + _, child, err := ParseLine(rest, d) if err != nil { return nil, nil, err } @@ -42,15 +43,10 @@ func parseSubCommand(rest string) (*Node, map[string]bool, error) { return &Node{Children: []*Node{child}}, nil, nil } -// parse environment like statements. Note that this does *not* handle -// variable interpolation, which will be handled in the evaluator. -func parseNameVal(rest string, key string) (*Node, map[string]bool, error) { - // This is kind of tricky because we need to support the old - // variant: KEY name value - // as well as the new one: KEY name=value ... - // The trigger to know which one is being used will be whether we hit - // a space or = first. space ==> old, "=" ==> new - +// helper to parse words (i.e space delimited or quoted strings) in a statement. +// The quotes are preserved as part of this function and they are stripped later +// as part of processWords(). +func parseWords(rest string, d *Directive) []string { const ( inSpaces = iota // looking for start of a word inWord @@ -63,10 +59,11 @@ func parseNameVal(rest string, key string) (*Node, map[string]bool, error) { quote := '\000' blankOK := false var ch rune + var chWidth int - for pos := 0; pos <= len(rest); pos++ { + for pos := 0; pos <= len(rest); pos += chWidth { if pos != len(rest) { - ch = rune(rest[pos]) + ch, chWidth = utf8.DecodeRuneInString(rest[pos:]) } if phase == inSpaces { // Looking for start of word @@ -76,7 +73,7 @@ func parseNameVal(rest string, key string) (*Node, map[string]bool, error) { if unicode.IsSpace(ch) { // skip spaces continue } - phase = inWord // found it, fall thru + phase = inWord // found it, fall through } if (phase == inWord || phase == inQuote) && (pos == len(rest)) { if blankOK || len(word) > 0 { @@ -89,15 +86,6 @@ func parseNameVal(rest string, key string) (*Node, map[string]bool, error) { phase = inSpaces if blankOK || len(word) > 0 { words = append(words, word) - - // Look for = and if not there assume - // we're doing the old stuff and - // just read the rest of the line - if !strings.Contains(word, "=") { - word = strings.TrimSpace(rest[pos:]) - words = append(words, word) - break - } } word = "" blankOK = false @@ -108,16 +96,16 @@ func parseNameVal(rest string, key string) (*Node, map[string]bool, error) { blankOK = true phase = inQuote } - if ch == '\\' { - if pos+1 == len(rest) { - continue // just skip \ at end + if ch == d.EscapeToken { + if pos+chWidth == len(rest) { + continue // just skip an escape token at end of line } - // If we're not quoted and we see a \, then always just - // add \ plus the char to the word, even if the char + // If we're not quoted and we see an escape token, then always just + // add the escape token plus the char to the word, even if the char // is a quote. word += string(ch) - pos++ - ch = rune(rest[pos]) + pos += chWidth + ch, chWidth = utf8.DecodeRuneInString(rest[pos:]) } word += string(ch) continue @@ -126,32 +114,44 @@ func parseNameVal(rest string, key string) (*Node, map[string]bool, error) { if ch == quote { phase = inWord } - // \ is special except for ' quotes - can't escape anything for ' - if ch == '\\' && quote != '\'' { - if pos+1 == len(rest) { + // The escape token is special except for ' quotes - can't escape anything for ' + if ch == d.EscapeToken && quote != '\'' { + if pos+chWidth == len(rest) { phase = inWord - continue // just skip \ at end + continue // just skip the escape token at end } - pos++ - nextCh := rune(rest[pos]) + pos += chWidth word += string(ch) - ch = nextCh + ch, chWidth = utf8.DecodeRuneInString(rest[pos:]) } word += string(ch) } } + return words +} + +// parse environment like statements. Note that this does *not* handle +// variable interpolation, which will be handled in the evaluator. +func parseNameVal(rest string, key string, d *Directive) (*Node, map[string]bool, error) { + // This is kind of tricky because we need to support the old + // variant: KEY name value + // as well as the new one: KEY name=value ... + // The trigger to know which one is being used will be whether we hit + // a space or = first. space ==> old, "=" ==> new + + words := parseWords(rest, d) if len(words) == 0 { return nil, nil, nil } - // Old format (KEY name value) var rootnode *Node + // Old format (KEY name value) if !strings.Contains(words[0], "=") { node := &Node{} rootnode = node - strs := TOKEN_WHITESPACE.Split(rest, 2) + strs := tokenWhitespace.Split(rest, 2) if len(strs) < 2 { return nil, nil, fmt.Errorf(key + " must have two arguments") @@ -187,17 +187,49 @@ func parseNameVal(rest string, key string) (*Node, map[string]bool, error) { return rootnode, nil, nil } -func parseEnv(rest string) (*Node, map[string]bool, error) { - return parseNameVal(rest, "ENV") +func parseEnv(rest string, d *Directive) (*Node, map[string]bool, error) { + return parseNameVal(rest, "ENV", d) +} + +func parseLabel(rest string, d *Directive) (*Node, map[string]bool, error) { + return parseNameVal(rest, "LABEL", d) } -func parseLabel(rest string) (*Node, map[string]bool, error) { - return parseNameVal(rest, "LABEL") +// parses a statement containing one or more keyword definition(s) and/or +// value assignments, like `name1 name2= name3="" name4=value`. +// Note that this is a stricter format than the old format of assignment, +// allowed by parseNameVal(), in a way that this only allows assignment of the +// form `keyword=[]` like `name2=`, `name3=""`, and `name4=value` above. +// In addition, a keyword definition alone is of the form `keyword` like `name1` +// above. And the assignments `name2=` and `name3=""` are equivalent and +// assign an empty value to the respective keywords. +func parseNameOrNameVal(rest string, d *Directive) (*Node, map[string]bool, error) { + words := parseWords(rest, d) + if len(words) == 0 { + return nil, nil, nil + } + + var ( + rootnode *Node + prevNode *Node + ) + for i, word := range words { + node := &Node{} + node.Value = word + if i == 0 { + rootnode = node + } else { + prevNode.Next = node + } + prevNode = node + } + + return rootnode, nil, nil } // parses a whitespace-delimited set of arguments. The result is effectively a // linked list of string arguments. -func parseStringsWhitespaceDelimited(rest string) (*Node, map[string]bool, error) { +func parseStringsWhitespaceDelimited(rest string, d *Directive) (*Node, map[string]bool, error) { if rest == "" { return nil, nil, nil } @@ -205,7 +237,7 @@ func parseStringsWhitespaceDelimited(rest string) (*Node, map[string]bool, error node := &Node{} rootnode := node prevnode := node - for _, str := range TOKEN_WHITESPACE.Split(rest, -1) { // use regexp + for _, str := range tokenWhitespace.Split(rest, -1) { // use regexp prevnode = node node.Value = str node.Next = &Node{} @@ -221,7 +253,7 @@ func parseStringsWhitespaceDelimited(rest string) (*Node, map[string]bool, error } // parsestring just wraps the string in quotes and returns a working node. -func parseString(rest string) (*Node, map[string]bool, error) { +func parseString(rest string, d *Directive) (*Node, map[string]bool, error) { if rest == "" { return nil, nil, nil } @@ -231,14 +263,19 @@ func parseString(rest string) (*Node, map[string]bool, error) { } // parseJSON converts JSON arrays to an AST. -func parseJSON(rest string) (*Node, map[string]bool, error) { - var myJson []interface{} - if err := json.NewDecoder(strings.NewReader(rest)).Decode(&myJson); err != nil { +func parseJSON(rest string, d *Directive) (*Node, map[string]bool, error) { + rest = strings.TrimLeftFunc(rest, unicode.IsSpace) + if !strings.HasPrefix(rest, "[") { + return nil, nil, fmt.Errorf(`Error parsing "%s" as a JSON array`, rest) + } + + var myJSON []interface{} + if err := json.NewDecoder(strings.NewReader(rest)).Decode(&myJSON); err != nil { return nil, nil, err } var top, prev *Node - for _, str := range myJson { + for _, str := range myJSON { s, ok := str.(string) if !ok { return nil, nil, errDockerfileNotStringArray @@ -259,12 +296,12 @@ func parseJSON(rest string) (*Node, map[string]bool, error) { // parseMaybeJSON determines if the argument appears to be a JSON array. If // so, passes to parseJSON; if not, quotes the result and returns a single // node. -func parseMaybeJSON(rest string) (*Node, map[string]bool, error) { +func parseMaybeJSON(rest string, d *Directive) (*Node, map[string]bool, error) { if rest == "" { return nil, nil, nil } - node, attrs, err := parseJSON(rest) + node, attrs, err := parseJSON(rest, d) if err == nil { return node, attrs, nil @@ -281,8 +318,8 @@ func parseMaybeJSON(rest string) (*Node, map[string]bool, error) { // parseMaybeJSONToList determines if the argument appears to be a JSON array. If // so, passes to parseJSON; if not, attempts to parse it as a whitespace // delimited string. -func parseMaybeJSONToList(rest string) (*Node, map[string]bool, error) { - node, attrs, err := parseJSON(rest) +func parseMaybeJSONToList(rest string, d *Directive) (*Node, map[string]bool, error) { + node, attrs, err := parseJSON(rest, d) if err == nil { return node, attrs, nil @@ -291,5 +328,34 @@ func parseMaybeJSONToList(rest string) (*Node, map[string]bool, error) { return nil, nil, err } - return parseStringsWhitespaceDelimited(rest) + return parseStringsWhitespaceDelimited(rest, d) +} + +// The HEALTHCHECK command is like parseMaybeJSON, but has an extra type argument. +func parseHealthConfig(rest string, d *Directive) (*Node, map[string]bool, error) { + // Find end of first argument + var sep int + for ; sep < len(rest); sep++ { + if unicode.IsSpace(rune(rest[sep])) { + break + } + } + next := sep + for ; next < len(rest); next++ { + if !unicode.IsSpace(rune(rest[next])) { + break + } + } + + if sep == 0 { + return nil, nil, nil + } + + typ := rest[:sep] + cmd, attrs, err := parseMaybeJSON(rest[next:], d) + if err != nil { + return nil, nil, err + } + + return &Node{Value: typ, Next: cmd, Attributes: attrs}, nil, err } diff --git a/vendor/github.com/docker/docker/builder/dockerfile/parser/parser.go b/vendor/github.com/docker/docker/builder/dockerfile/parser/parser.go new file mode 100644 index 00000000..6fb84d92 --- /dev/null +++ b/vendor/github.com/docker/docker/builder/dockerfile/parser/parser.go @@ -0,0 +1,215 @@ +// Package parser implements a parser and parse tree dumper for Dockerfiles. +package parser + +import ( + "bufio" + "bytes" + "fmt" + "io" + "regexp" + "strings" + "unicode" + + "github.com/docker/docker/builder/dockerfile/command" +) + +// Node is a structure used to represent a parse tree. +// +// In the node there are three fields, Value, Next, and Children. Value is the +// current token's string value. Next is always the next non-child token, and +// children contains all the children. Here's an example: +// +// (value next (child child-next child-next-next) next-next) +// +// This data structure is frankly pretty lousy for handling complex languages, +// but lucky for us the Dockerfile isn't very complicated. This structure +// works a little more effectively than a "proper" parse tree for our needs. +// +type Node struct { + Value string // actual content + Next *Node // the next item in the current sexp + Children []*Node // the children of this sexp + Attributes map[string]bool // special attributes for this node + Original string // original line used before parsing + Flags []string // only top Node should have this set + StartLine int // the line in the original dockerfile where the node begins + EndLine int // the line in the original dockerfile where the node ends +} + +// Directive is the structure used during a build run to hold the state of +// parsing directives. +type Directive struct { + EscapeToken rune // Current escape token + LineContinuationRegex *regexp.Regexp // Current line contination regex + LookingForDirectives bool // Whether we are currently looking for directives + EscapeSeen bool // Whether the escape directive has been seen +} + +var ( + dispatch map[string]func(string, *Directive) (*Node, map[string]bool, error) + tokenWhitespace = regexp.MustCompile(`[\t\v\f\r ]+`) + tokenEscapeCommand = regexp.MustCompile(`^#[ \t]*escape[ \t]*=[ \t]*(?P.).*$`) + tokenComment = regexp.MustCompile(`^#.*$`) +) + +// DefaultEscapeToken is the default escape token +const DefaultEscapeToken = "\\" + +// SetEscapeToken sets the default token for escaping characters in a Dockerfile. +func SetEscapeToken(s string, d *Directive) error { + if s != "`" && s != "\\" { + return fmt.Errorf("invalid ESCAPE '%s'. Must be ` or \\", s) + } + d.EscapeToken = rune(s[0]) + d.LineContinuationRegex = regexp.MustCompile(`\` + s + `[ \t]*$`) + return nil +} + +func init() { + // Dispatch Table. see line_parsers.go for the parse functions. + // The command is parsed and mapped to the line parser. The line parser + // receives the arguments but not the command, and returns an AST after + // reformulating the arguments according to the rules in the parser + // functions. Errors are propagated up by Parse() and the resulting AST can + // be incorporated directly into the existing AST as a next. + dispatch = map[string]func(string, *Directive) (*Node, map[string]bool, error){ + command.Add: parseMaybeJSONToList, + command.Arg: parseNameOrNameVal, + command.Cmd: parseMaybeJSON, + command.Copy: parseMaybeJSONToList, + command.Entrypoint: parseMaybeJSON, + command.Env: parseEnv, + command.Expose: parseStringsWhitespaceDelimited, + command.From: parseString, + command.Healthcheck: parseHealthConfig, + command.Label: parseLabel, + command.Maintainer: parseString, + command.Onbuild: parseSubCommand, + command.Run: parseMaybeJSON, + command.Shell: parseMaybeJSON, + command.StopSignal: parseString, + command.User: parseString, + command.Volume: parseMaybeJSONToList, + command.Workdir: parseString, + } +} + +// ParseLine parse a line and return the remainder. +func ParseLine(line string, d *Directive) (string, *Node, error) { + // Handle the parser directive '# escape=. Parser directives must precede + // any builder instruction or other comments, and cannot be repeated. + if d.LookingForDirectives { + tecMatch := tokenEscapeCommand.FindStringSubmatch(strings.ToLower(line)) + if len(tecMatch) > 0 { + if d.EscapeSeen == true { + return "", nil, fmt.Errorf("only one escape parser directive can be used") + } + for i, n := range tokenEscapeCommand.SubexpNames() { + if n == "escapechar" { + if err := SetEscapeToken(tecMatch[i], d); err != nil { + return "", nil, err + } + d.EscapeSeen = true + return "", nil, nil + } + } + } + } + + d.LookingForDirectives = false + + if line = stripComments(line); line == "" { + return "", nil, nil + } + + if d.LineContinuationRegex.MatchString(line) { + line = d.LineContinuationRegex.ReplaceAllString(line, "") + return line, nil, nil + } + + cmd, flags, args, err := splitCommand(line) + if err != nil { + return "", nil, err + } + + node := &Node{} + node.Value = cmd + + sexp, attrs, err := fullDispatch(cmd, args, d) + if err != nil { + return "", nil, err + } + + node.Next = sexp + node.Attributes = attrs + node.Original = line + node.Flags = flags + + return "", node, nil +} + +// Parse is the main parse routine. +// It handles an io.ReadWriteCloser and returns the root of the AST. +func Parse(rwc io.Reader, d *Directive) (*Node, error) { + currentLine := 0 + root := &Node{} + root.StartLine = -1 + scanner := bufio.NewScanner(rwc) + + utf8bom := []byte{0xEF, 0xBB, 0xBF} + for scanner.Scan() { + scannedBytes := scanner.Bytes() + // We trim UTF8 BOM + if currentLine == 0 { + scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom) + } + scannedLine := strings.TrimLeftFunc(string(scannedBytes), unicode.IsSpace) + currentLine++ + line, child, err := ParseLine(scannedLine, d) + if err != nil { + return nil, err + } + startLine := currentLine + + if line != "" && child == nil { + for scanner.Scan() { + newline := scanner.Text() + currentLine++ + + if stripComments(strings.TrimSpace(newline)) == "" { + continue + } + + line, child, err = ParseLine(line+newline, d) + if err != nil { + return nil, err + } + + if child != nil { + break + } + } + if child == nil && line != "" { + _, child, err = ParseLine(line, d) + if err != nil { + return nil, err + } + } + } + + if child != nil { + // Update the line information for the current child. + child.StartLine = startLine + child.EndLine = currentLine + // Update the line information for the root. The starting line of the root is always the + // starting line of the first child and the ending line is the ending line of the last child. + if root.StartLine < 0 { + root.StartLine = currentLine + } + root.EndLine = currentLine + root.Children = append(root.Children, child) + } + } + + return root, nil +} diff --git a/vendor/github.com/docker/docker/builder/parser/utils.go b/vendor/github.com/docker/docker/builder/dockerfile/parser/utils.go similarity index 88% rename from vendor/github.com/docker/docker/builder/parser/utils.go rename to vendor/github.com/docker/docker/builder/dockerfile/parser/utils.go index 5d82e960..cd7af75e 100644 --- a/vendor/github.com/docker/docker/builder/parser/utils.go +++ b/vendor/github.com/docker/docker/builder/dockerfile/parser/utils.go @@ -7,8 +7,8 @@ import ( "unicode" ) -// dumps the AST defined by `node` as a list of sexps. Returns a string -// suitable for printing. +// Dump dumps the AST defined by `node` as a list of sexps. +// Returns a string suitable for printing. func (node *Node) Dump() string { str := "" str += node.Value @@ -36,7 +36,7 @@ func (node *Node) Dump() string { // performs the dispatch based on the two primal strings, cmd and args. Please // look at the dispatch table in parser.go to see how these dispatchers work. -func fullDispatch(cmd, args string) (*Node, map[string]bool, error) { +func fullDispatch(cmd, args string, d *Directive) (*Node, map[string]bool, error) { fn := dispatch[cmd] // Ignore invalid Dockerfile instructions @@ -44,7 +44,7 @@ func fullDispatch(cmd, args string) (*Node, map[string]bool, error) { fn = parseIgnore } - sexp, attrs, err := fn(args) + sexp, attrs, err := fn(args, d) if err != nil { return nil, nil, err } @@ -59,7 +59,7 @@ func splitCommand(line string) (string, []string, string, error) { var flags []string // Make sure we get the same results irrespective of leading/trailing spaces - cmdline := TOKEN_WHITESPACE.Split(strings.TrimSpace(line), 2) + cmdline := tokenWhitespace.Split(strings.TrimSpace(line), 2) cmd := strings.ToLower(cmdline[0]) if len(cmdline) == 2 { @@ -77,8 +77,8 @@ func splitCommand(line string) (string, []string, string, error) { // this function. func stripComments(line string) string { // string is already trimmed at this point - if TOKEN_COMMENT.MatchString(line) { - return TOKEN_COMMENT.ReplaceAllString(line, "") + if tokenComment.MatchString(line) { + return tokenComment.ReplaceAllString(line, "") } return line @@ -118,7 +118,7 @@ func extractBuilderFlags(line string) (string, []string, error) { return line[pos:], words, nil } - phase = inWord // found someting with "--", fall thru + phase = inWord // found someting with "--", fall through } if (phase == inWord || phase == inQuote) && (pos == len(line)) { if word != "--" && (blankOK || len(word) > 0) { diff --git a/vendor/github.com/docker/docker/builder/parser/parser.go b/vendor/github.com/docker/docker/builder/parser/parser.go deleted file mode 100644 index 2260cd52..00000000 --- a/vendor/github.com/docker/docker/builder/parser/parser.go +++ /dev/null @@ -1,143 +0,0 @@ -// This package implements a parser and parse tree dumper for Dockerfiles. -package parser - -import ( - "bufio" - "io" - "regexp" - "strings" - "unicode" - - "github.com/docker/docker/builder/command" -) - -// Node is a structure used to represent a parse tree. -// -// In the node there are three fields, Value, Next, and Children. Value is the -// current token's string value. Next is always the next non-child token, and -// children contains all the children. Here's an example: -// -// (value next (child child-next child-next-next) next-next) -// -// This data structure is frankly pretty lousy for handling complex languages, -// but lucky for us the Dockerfile isn't very complicated. This structure -// works a little more effectively than a "proper" parse tree for our needs. -// -type Node struct { - Value string // actual content - Next *Node // the next item in the current sexp - Children []*Node // the children of this sexp - Attributes map[string]bool // special attributes for this node - Original string // original line used before parsing - Flags []string // only top Node should have this set -} - -var ( - dispatch map[string]func(string) (*Node, map[string]bool, error) - TOKEN_WHITESPACE = regexp.MustCompile(`[\t\v\f\r ]+`) - TOKEN_LINE_CONTINUATION = regexp.MustCompile(`\\[ \t]*$`) - TOKEN_COMMENT = regexp.MustCompile(`^#.*$`) -) - -func init() { - // Dispatch Table. see line_parsers.go for the parse functions. - // The command is parsed and mapped to the line parser. The line parser - // recieves the arguments but not the command, and returns an AST after - // reformulating the arguments according to the rules in the parser - // functions. Errors are propagated up by Parse() and the resulting AST can - // be incorporated directly into the existing AST as a next. - dispatch = map[string]func(string) (*Node, map[string]bool, error){ - command.User: parseString, - command.Onbuild: parseSubCommand, - command.Workdir: parseString, - command.Env: parseEnv, - command.Label: parseLabel, - command.Maintainer: parseString, - command.From: parseString, - command.Add: parseMaybeJSONToList, - command.Copy: parseMaybeJSONToList, - command.Run: parseMaybeJSON, - command.Cmd: parseMaybeJSON, - command.Entrypoint: parseMaybeJSON, - command.Expose: parseStringsWhitespaceDelimited, - command.Volume: parseMaybeJSONToList, - } -} - -// parse a line and return the remainder. -func parseLine(line string) (string, *Node, error) { - if line = stripComments(line); line == "" { - return "", nil, nil - } - - if TOKEN_LINE_CONTINUATION.MatchString(line) { - line = TOKEN_LINE_CONTINUATION.ReplaceAllString(line, "") - return line, nil, nil - } - - cmd, flags, args, err := splitCommand(line) - if err != nil { - return "", nil, err - } - - node := &Node{} - node.Value = cmd - - sexp, attrs, err := fullDispatch(cmd, args) - if err != nil { - return "", nil, err - } - - node.Next = sexp - node.Attributes = attrs - node.Original = line - node.Flags = flags - - return "", node, nil -} - -// The main parse routine. Handles an io.ReadWriteCloser and returns the root -// of the AST. -func Parse(rwc io.Reader) (*Node, error) { - root := &Node{} - scanner := bufio.NewScanner(rwc) - - for scanner.Scan() { - scannedLine := strings.TrimLeftFunc(scanner.Text(), unicode.IsSpace) - line, child, err := parseLine(scannedLine) - if err != nil { - return nil, err - } - - if line != "" && child == nil { - for scanner.Scan() { - newline := scanner.Text() - - if stripComments(strings.TrimSpace(newline)) == "" { - continue - } - - line, child, err = parseLine(line + newline) - if err != nil { - return nil, err - } - - if child != nil { - break - } - } - if child == nil && line != "" { - line, child, err = parseLine(line) - if err != nil { - return nil, err - } - } - } - - if child != nil { - root.Children = append(root.Children, child) - } - } - - return root, nil -} diff --git a/vendor/github.com/docker/engine-api/types/reference/image_reference.go b/vendor/github.com/docker/engine-api/types/reference/image_reference.go deleted file mode 100644 index 74201582..00000000 --- a/vendor/github.com/docker/engine-api/types/reference/image_reference.go +++ /dev/null @@ -1,32 +0,0 @@ -package reference - -import ( - distreference "github.com/docker/distribution/reference" -) - -// Parse parses the given references and returns the repository and -// tag (if present) from it. If there is an error during parsing, it will -// return an error. -func Parse(ref string) (string, string, error) { - distributionRef, err := distreference.ParseNamed(ref) - if err != nil { - return "", "", err - } - - tag := GetTagFromNamedRef(distributionRef) - return distributionRef.Name(), tag, nil -} - -// GetTagFromNamedRef returns a tag from the specified reference. -// This function is necessary as long as the docker "server" api makes the distinction between repository -// and tags. -func GetTagFromNamedRef(ref distreference.Named) string { - var tag string - switch x := ref.(type) { - case distreference.Digested: - tag = x.Digest().String() - case distreference.NamedTagged: - tag = x.Tag() - } - return tag -} diff --git a/vendor/github.com/docker/engine-api/types/time/timestamp.go b/vendor/github.com/docker/engine-api/types/time/timestamp.go deleted file mode 100644 index d3695ba7..00000000 --- a/vendor/github.com/docker/engine-api/types/time/timestamp.go +++ /dev/null @@ -1,124 +0,0 @@ -package time - -import ( - "fmt" - "math" - "strconv" - "strings" - "time" -) - -// These are additional predefined layouts for use in Time.Format and Time.Parse -// with --since and --until parameters for `docker logs` and `docker events` -const ( - rFC3339Local = "2006-01-02T15:04:05" // RFC3339 with local timezone - rFC3339NanoLocal = "2006-01-02T15:04:05.999999999" // RFC3339Nano with local timezone - dateWithZone = "2006-01-02Z07:00" // RFC3339 with time at 00:00:00 - dateLocal = "2006-01-02" // RFC3339 with local timezone and time at 00:00:00 -) - -// GetTimestamp tries to parse given string as golang duration, -// then RFC3339 time and finally as a Unix timestamp. If -// any of these were successful, it returns a Unix timestamp -// as string otherwise returns the given value back. -// In case of duration input, the returned timestamp is computed -// as the given reference time minus the amount of the duration. -func GetTimestamp(value string, reference time.Time) (string, error) { - if d, err := time.ParseDuration(value); value != "0" && err == nil { - return strconv.FormatInt(reference.Add(-d).Unix(), 10), nil - } - - var format string - var parseInLocation bool - - // if the string has a Z or a + or three dashes use parse otherwise use parseinlocation - parseInLocation = !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3) - - if strings.Contains(value, ".") { - if parseInLocation { - format = rFC3339NanoLocal - } else { - format = time.RFC3339Nano - } - } else if strings.Contains(value, "T") { - // we want the number of colons in the T portion of the timestamp - tcolons := strings.Count(value, ":") - // if parseInLocation is off and we have a +/- zone offset (not Z) then - // there will be an extra colon in the input for the tz offset subtract that - // colon from the tcolons count - if !parseInLocation && !strings.ContainsAny(value, "zZ") && tcolons > 0 { - tcolons-- - } - if parseInLocation { - switch tcolons { - case 0: - format = "2006-01-02T15" - case 1: - format = "2006-01-02T15:04" - default: - format = rFC3339Local - } - } else { - switch tcolons { - case 0: - format = "2006-01-02T15Z07:00" - case 1: - format = "2006-01-02T15:04Z07:00" - default: - format = time.RFC3339 - } - } - } else if parseInLocation { - format = dateLocal - } else { - format = dateWithZone - } - - var t time.Time - var err error - - if parseInLocation { - t, err = time.ParseInLocation(format, value, time.FixedZone(reference.Zone())) - } else { - t, err = time.Parse(format, value) - } - - if err != nil { - // if there is a `-` then its an RFC3339 like timestamp otherwise assume unixtimestamp - if strings.Contains(value, "-") { - return "", err // was probably an RFC3339 like timestamp but the parser failed with an error - } - return value, nil // unixtimestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server) - } - - return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil -} - -// ParseTimestamps returns seconds and nanoseconds from a timestamp that has the -// format "%d.%09d", time.Unix(), int64(time.Nanosecond())) -// if the incoming nanosecond portion is longer or shorter than 9 digits it is -// converted to nanoseconds. The expectation is that the seconds and -// seconds will be used to create a time variable. For example: -// seconds, nanoseconds, err := ParseTimestamp("1136073600.000000001",0) -// if err == nil since := time.Unix(seconds, nanoseconds) -// returns seconds as def(aultSeconds) if value == "" -func ParseTimestamps(value string, def int64) (int64, int64, error) { - if value == "" { - return def, 0, nil - } - sa := strings.SplitN(value, ".", 2) - s, err := strconv.ParseInt(sa[0], 10, 64) - if err != nil { - return s, 0, err - } - if len(sa) != 2 { - return s, 0, nil - } - n, err := strconv.ParseInt(sa[1], 10, 64) - if err != nil { - return s, n, err - } - // should already be in nanoseconds but just in case convert n to nanoseonds - n = int64(float64(n) * math.Pow(float64(10), float64(9-len(sa[1])))) - return s, n, nil -} diff --git a/vendor/github.com/golang/glog/glog.go b/vendor/github.com/golang/glog/glog.go index 309727cb..3e63fffd 100644 --- a/vendor/github.com/golang/glog/glog.go +++ b/vendor/github.com/golang/glog/glog.go @@ -1046,14 +1046,6 @@ func (v Verbose) Infof(format string, args ...interface{}) { } } -// InfoDepth is equivalent to the global InfoDepth function, guarded by the value of v. -// See the documentation of V for usage. -func (v Verbose) InfoDepth(depth int, args ...interface{}) { - if v { - logging.printDepth(infoLog, depth, args...) - } -} - // Info logs to the INFO log. // Arguments are handled in the manner of fmt.Print; a newline is appended if missing. func Info(args ...interface{}) {