Add initial Architectures support (and the beginnings of a "put-shared" subcommand for bringing all the SharedTags and arch-specific images together with manifest lists/indexes)
This commit is contained in:
parent
362855e06f
commit
fdf3501d49
|
|
@ -81,7 +81,7 @@ func cmdBuild(c *cli.Context) error {
|
|||
return cli.NewMultiError(fmt.Errorf(`failed fetching git repo for %q (tags %q)`, r.RepoName, entry.TagsString()), err)
|
||||
}
|
||||
|
||||
archive, err := gitArchive(commit, entry.Directory)
|
||||
archive, err := gitArchive(commit, entry.ArchDirectory(arch))
|
||||
if err != nil {
|
||||
return cli.NewMultiError(fmt.Errorf(`failed generating git archive for %q (tags %q)`, r.RepoName, entry.TagsString()), err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func cmdPutShared(c *cli.Context) error {
|
||||
repos, err := repos(c.Bool("all"), c.Args()...)
|
||||
if err != nil {
|
||||
return cli.NewMultiError(fmt.Errorf(`failed gathering repo list`), err)
|
||||
}
|
||||
|
||||
namespace := c.String("namespace")
|
||||
|
||||
if namespace == "" {
|
||||
return fmt.Errorf(`"--namespace" is a required flag for "put-shared"`)
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "warning: this subcommand is still a big WIP -- it doesn't do anything yet!\n")
|
||||
|
||||
for _, repo := range repos {
|
||||
r, err := fetch(repo)
|
||||
if err != nil {
|
||||
return cli.NewMultiError(fmt.Errorf(`failed fetching repo %q`, repo), err)
|
||||
}
|
||||
|
||||
// TODO handle all multi-architecture tags first (regardless of whether they have SharedTags)
|
||||
|
||||
targetRepo := path.Join(namespace, r.RepoName)
|
||||
for _, group := range r.Manifest.GetSharedTagGroups() {
|
||||
// TODO build up a YAML file
|
||||
entryTags := []string{}
|
||||
for _, entry := range group.Entries {
|
||||
entryTags = append(entryTags, entry.Tags[0])
|
||||
}
|
||||
fmt.Printf("Putting %s (tags %s) <= %s\n", targetRepo, strings.Join(group.SharedTags, ", "), strings.Join(entryTags, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ type FlagsConfigEntry struct {
|
|||
|
||||
Commands []string `delim:"," strip:"\n\r\t "`
|
||||
|
||||
// TODO arch namespace mappings (for intermediate pushing before put-shared, and for put-shared to pull from to join together in one big happy family)
|
||||
|
||||
Library string
|
||||
Cache string
|
||||
Debug string
|
||||
|
|
@ -26,6 +28,7 @@ type FlagsConfigEntry struct {
|
|||
BuildOrder string
|
||||
Pull string
|
||||
|
||||
Arch string
|
||||
Constraints []string `delim:"," strip:"\n\r\t "`
|
||||
ExclusiveConstraints string
|
||||
ApplyConstraints string
|
||||
|
|
@ -55,6 +58,9 @@ func (dst *FlagsConfigEntry) Apply(src FlagsConfigEntry) {
|
|||
if src.Pull != "" {
|
||||
dst.Pull = src.Pull
|
||||
}
|
||||
if src.Arch != "" {
|
||||
dst.Arch = src.Arch
|
||||
}
|
||||
if len(src.Constraints) > 0 {
|
||||
dst.Constraints = src.Constraints[:]
|
||||
}
|
||||
|
|
@ -73,6 +79,7 @@ func (config FlagsConfigEntry) Vars() map[string]map[string]interface{} {
|
|||
"cache": config.Cache,
|
||||
"debug": config.Debug,
|
||||
|
||||
"arch": config.Arch,
|
||||
"constraint": config.Constraints,
|
||||
"exclusive-constraints": config.ExclusiveConstraints,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ func (r Repo) DockerFrom(entry *manifest.Manifest2822Entry) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
dockerfileFile := path.Join(entry.Directory, "Dockerfile")
|
||||
dockerfileFile := path.Join(entry.ArchDirectory(arch), "Dockerfile")
|
||||
|
||||
cacheKey := strings.Join([]string{
|
||||
commit,
|
||||
|
|
@ -130,9 +130,9 @@ func (r Repo) dockerBuildUniqueBits(entry *manifest.Manifest2822Entry) ([]string
|
|||
dockerFromIdCache[from] = fromId
|
||||
}
|
||||
return []string{
|
||||
entry.GitRepo,
|
||||
entry.GitCommit,
|
||||
entry.Directory,
|
||||
entry.ArchGitRepo(arch),
|
||||
entry.ArchGitCommit(arch),
|
||||
entry.ArchDirectory(arch),
|
||||
fromId,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,12 +102,12 @@ var gitRepoCache = map[string]string{}
|
|||
|
||||
func (r Repo) fetchGitRepo(entry *manifest.Manifest2822Entry) (string, error) {
|
||||
cacheKey := strings.Join([]string{
|
||||
entry.GitRepo,
|
||||
entry.GitFetch,
|
||||
entry.GitCommit,
|
||||
entry.ArchGitRepo(arch),
|
||||
entry.ArchGitFetch(arch),
|
||||
entry.ArchGitCommit(arch),
|
||||
}, "\n")
|
||||
if commit, ok := gitRepoCache[cacheKey]; ok {
|
||||
entry.GitCommit = commit
|
||||
entry.SetGitCommit(arch, commit)
|
||||
return commit, nil
|
||||
}
|
||||
|
||||
|
|
@ -116,27 +116,27 @@ func (r Repo) fetchGitRepo(entry *manifest.Manifest2822Entry) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
if manifest.GitCommitRegex.MatchString(entry.GitCommit) {
|
||||
commit, err := getGitCommit(entry.GitCommit)
|
||||
if manifest.GitCommitRegex.MatchString(entry.ArchGitCommit(arch)) {
|
||||
commit, err := getGitCommit(entry.ArchGitCommit(arch))
|
||||
if err == nil {
|
||||
gitRepoCache[cacheKey] = commit
|
||||
entry.GitCommit = commit
|
||||
entry.SetGitCommit(arch, commit)
|
||||
return commit, nil
|
||||
}
|
||||
}
|
||||
|
||||
fetchString := entry.GitFetch + ":"
|
||||
if entry.GitCommit == "FETCH_HEAD" {
|
||||
fetchString := entry.ArchGitFetch(arch) + ":"
|
||||
if entry.ArchGitCommit(arch) == "FETCH_HEAD" {
|
||||
// fetch remote tag references to a local tag ref so that we can cache them and not re-fetch every time
|
||||
localRef := "refs/tags/" + gitNormalizeForTagUsage(cacheKey)
|
||||
commit, err := getGitCommit(localRef)
|
||||
if err == nil {
|
||||
gitRepoCache[cacheKey] = commit
|
||||
entry.GitCommit = commit
|
||||
entry.SetGitCommit(arch, commit)
|
||||
return commit, nil
|
||||
}
|
||||
fetchString += localRef
|
||||
} else if entry.GitFetch == manifest.DefaultLineBasedFetch {
|
||||
} else if entry.ArchGitFetch(arch) == manifest.DefaultLineBasedFetch {
|
||||
// backwards compat (see manifest/line-based.go in go-dockerlibrary)
|
||||
refBase := "refs/remotes"
|
||||
refBaseDir := filepath.Join(gitCache(), refBase)
|
||||
|
|
@ -154,17 +154,17 @@ func (r Repo) fetchGitRepo(entry *manifest.Manifest2822Entry) (string, error) {
|
|||
// we create a temporary remote dir so that we can clean it up completely afterwards
|
||||
}
|
||||
|
||||
if strings.HasPrefix(entry.GitRepo, "git://github.com/") {
|
||||
fmt.Fprintf(os.Stderr, "warning: insecure protocol git:// detected: %s\n", entry.GitRepo)
|
||||
entry.GitRepo = strings.Replace(entry.GitRepo, "git://", "https://", 1)
|
||||
if strings.HasPrefix(entry.ArchGitRepo(arch), "git://github.com/") {
|
||||
fmt.Fprintf(os.Stderr, "warning: insecure protocol git:// detected: %s\n", entry.ArchGitRepo(arch))
|
||||
entry.SetGitRepo(arch, strings.Replace(entry.ArchGitRepo(arch), "git://", "https://", 1))
|
||||
}
|
||||
|
||||
_, err = git("fetch", "--quiet", "--no-tags", entry.GitRepo, fetchString)
|
||||
_, err = git("fetch", "--quiet", "--no-tags", entry.ArchGitRepo(arch), fetchString)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
commit, err := getGitCommit(entry.GitCommit)
|
||||
commit, err := getGitCommit(entry.ArchGitCommit(arch))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -175,6 +175,6 @@ func (r Repo) fetchGitRepo(entry *manifest.Manifest2822Entry) (string, error) {
|
|||
}
|
||||
|
||||
gitRepoCache[cacheKey] = commit
|
||||
entry.GitCommit = commit
|
||||
entry.SetGitCommit(arch, commit)
|
||||
return commit, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
|
||||
"github.com/docker-library/go-dockerlibrary/manifest"
|
||||
)
|
||||
|
||||
// TODO somewhere, ensure that the Docker engine we're talking to is API version 1.22+ (Docker 1.10+)
|
||||
|
|
@ -18,6 +20,7 @@ var (
|
|||
defaultLibrary string
|
||||
defaultCache string
|
||||
|
||||
arch string
|
||||
constraints []string
|
||||
exclusiveConstraints bool
|
||||
|
||||
|
|
@ -27,6 +30,7 @@ var (
|
|||
// separated so that FlagsConfig.ApplyTo can access them
|
||||
flagEnvVars = map[string]string{
|
||||
"debug": "BASHBREW_DEBUG",
|
||||
"arch": "BASHBREW_ARCH",
|
||||
"config": "BASHBREW_CONFIG",
|
||||
"library": "BASHBREW_LIBRARY",
|
||||
"cache": "BASHBREW_CACHE",
|
||||
|
|
@ -72,6 +76,12 @@ func main() {
|
|||
Usage: "do not apply any sorting, even via --build-order",
|
||||
},
|
||||
|
||||
cli.StringFlag{
|
||||
Name: "arch",
|
||||
Value: manifest.DefaultArchitecture,
|
||||
EnvVar: flagEnvVars["arch"],
|
||||
Usage: "the current platform architecture",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "constraint",
|
||||
Usage: "build constraints (see Constraints in Manifest2822Entry)",
|
||||
|
|
@ -127,6 +137,7 @@ func main() {
|
|||
debugFlag = c.GlobalBool("debug")
|
||||
noSortFlag = c.GlobalBool("no-sort")
|
||||
|
||||
arch = c.GlobalString("arch")
|
||||
constraints = c.GlobalStringSlice("constraint")
|
||||
exclusiveConstraints = c.GlobalBool("exclusive-constraints")
|
||||
|
||||
|
|
@ -222,7 +233,18 @@ func main() {
|
|||
Before: subcommandBeforeFactory("push"),
|
||||
Action: cmdPush,
|
||||
},
|
||||
{
|
||||
Name: "put-shared",
|
||||
Usage: `updated shared tags in the registry`,
|
||||
Flags: []cli.Flag{
|
||||
commonFlags["all"],
|
||||
commonFlags["namespace"],
|
||||
},
|
||||
Before: subcommandBeforeFactory("put-shared"),
|
||||
Action: cmdPutShared,
|
||||
},
|
||||
|
||||
// TODO --depth flag for children and parents
|
||||
{
|
||||
Name: "children",
|
||||
Aliases: []string{
|
||||
|
|
|
|||
|
|
@ -79,6 +79,15 @@ var haveOutputSkippedMessage = map[string]bool{}
|
|||
func (r Repo) SkipConstraints(entry manifest.Manifest2822Entry) bool {
|
||||
repoTag := r.RepoName + ":" + entry.Tags[0]
|
||||
|
||||
// TODO decide if "arch" and "constraints" should be handled separately (but probably not)
|
||||
if !entry.HasArchitecture(arch) {
|
||||
if !haveOutputSkippedMessage[repoTag] {
|
||||
fmt.Fprintf(os.Stderr, "skipping %q (due to architecture %q; only %q supported)\n", repoTag, arch, entry.ArchitecturesString())
|
||||
haveOutputSkippedMessage[repoTag] = true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if len(entry.Constraints) == 0 {
|
||||
if exclusiveConstraints {
|
||||
if !haveOutputSkippedMessage[repoTag] {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
{
|
||||
"importpath": "github.com/docker-library/go-dockerlibrary",
|
||||
"repository": "https://github.com/docker-library/go-dockerlibrary",
|
||||
"revision": "08ef5a968ebdd83dcc42998a96b6528837b55273",
|
||||
"revision": "663a091da13fc848e27a16048fb39c4e4067056e",
|
||||
"branch": "master"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
# `import "github.com/docker-library/go-dockerlibrary/manifest"`
|
||||
|
||||
[](https://travis-ci.org/docker-library/go-dockerlibrary) [](https://godoc.org/github.com/docker-library/go-dockerlibrary) [](https://codecov.io/gh/docker-library/go-dockerlibrary)
|
||||
|
||||
This package contains the core parsing elements of [the `bashbrew` tool used by the Docker Official Images](https://github.com/docker-library/official-images/tree/master/bashbrew).
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker-library/go-dockerlibrary/manifest"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// TODO comment parsing
|
||||
man, err := manifest.Parse(bufio.NewReader(strings.NewReader(`# RFC 2822
|
||||
|
||||
# I LOVE CAKE
|
||||
|
||||
Maintainers: InfoSiftr <github@infosiftr.com> (@infosiftr),
|
||||
Johan Euphrosine <proppy@google.com> (@proppy)
|
||||
GitRepo: https://github.com/docker-library/golang.git
|
||||
GitFetch: refs/heads/master
|
||||
|
||||
|
||||
# hi
|
||||
|
||||
|
||||
# blasphemer
|
||||
|
||||
|
||||
# Go 1.6
|
||||
Tags: 1.6.1, 1.6, 1, latest
|
||||
GitCommit: 0ce80411b9f41e9c3a21fc0a1bffba6ae761825a
|
||||
Directory: 1.6
|
||||
|
||||
|
||||
# Go 1.5
|
||||
Tags: 1.5.3
|
||||
GitCommit: d7e2a8d90a9b8f5dfd5bcd428e0c33b68c40cc19
|
||||
Directory: 1.5
|
||||
|
||||
|
||||
Tags: 1.5
|
||||
GitCommit: d7e2a8d90a9b8f5dfd5bcd428e0c33b68c40cc19
|
||||
Directory: 1.5
|
||||
|
||||
|
||||
`)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("-------------\n2822:\n%s\n", man)
|
||||
|
||||
man, err = manifest.Parse(bufio.NewReader(strings.NewReader(`
|
||||
# first set
|
||||
a: b@c d
|
||||
e: b@c d
|
||||
|
||||
# second set
|
||||
f: g@h
|
||||
i: g@h j
|
||||
`)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("-------------\nline-based:\n%v\n", man)
|
||||
}
|
||||
192
go/vendor/src/github.com/docker-library/go-dockerlibrary/manifest/example_test.go
vendored
Normal file
192
go/vendor/src/github.com/docker-library/go-dockerlibrary/manifest/example_test.go
vendored
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
package manifest_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker-library/go-dockerlibrary/manifest"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
man, err := manifest.Parse(bufio.NewReader(strings.NewReader(`# RFC 2822
|
||||
|
||||
# I LOVE CAKE
|
||||
|
||||
Maintainers: InfoSiftr <github@infosiftr.com> (@infosiftr),
|
||||
Johan Euphrosine <proppy@google.com> (@proppy)
|
||||
GitFetch: refs/heads/master
|
||||
GitRepo: https://github.com/docker-library/golang.git
|
||||
SharedTags: latest
|
||||
arm64v8-GitRepo: https://github.com/docker-library/golang.git
|
||||
Architectures: amd64
|
||||
|
||||
|
||||
# hi
|
||||
|
||||
|
||||
# blasphemer
|
||||
|
||||
|
||||
# Go 1.6
|
||||
Tags: 1.6.1, 1.6, 1
|
||||
arm64v8-GitRepo: https://github.com/docker-library/golang.git
|
||||
Directory: 1.6
|
||||
GitCommit: 0ce80411b9f41e9c3a21fc0a1bffba6ae761825a
|
||||
Constraints: some-random-build-server
|
||||
|
||||
|
||||
# Go 1.5
|
||||
Tags: 1.5.3
|
||||
GitCommit: d7e2a8d90a9b8f5dfd5bcd428e0c33b68c40cc19
|
||||
SharedTags: 1.5.3-debian, 1.5-debian
|
||||
Directory: 1.5
|
||||
s390x-GitCommit: b6c460e7cd79b595267870a98013ec3078b490df
|
||||
i386-GitFetch: refs/heads/i386
|
||||
ppc64le-Directory: 1.5/ppc64le
|
||||
|
||||
|
||||
Tags: 1.5
|
||||
SharedTags: 1.5-debian
|
||||
GitCommit: d7e2a8d90a9b8f5dfd5bcd428e0c33b68c40cc19
|
||||
Directory: 1.5
|
||||
s390x-GitCommit: b6c460e7cd79b595267870a98013ec3078b490df
|
||||
i386-GitFetch: refs/heads/i386
|
||||
ppc64le-Directory: 1.5/ppc64le
|
||||
|
||||
SharedTags: raspbian
|
||||
GitCommit: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
|
||||
Tags: raspbian-s390x
|
||||
Architectures: s390x
|
||||
|
||||
|
||||
`)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("-------------\n2822:\n%s\n", man)
|
||||
|
||||
fmt.Printf("\nShared Tag Groups:\n")
|
||||
for _, group := range man.GetSharedTagGroups() {
|
||||
fmt.Printf("\n - %s\n", strings.Join(group.SharedTags, ", "))
|
||||
for _, entry := range group.Entries {
|
||||
fmt.Printf(" - %s\n", entry.TagsString())
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
man, err = manifest.Parse(bufio.NewReader(strings.NewReader(`
|
||||
# maintainer: InfoSiftr <github@infosiftr.com> (@infosiftr)
|
||||
# maintainer: John Smith <jsmith@example.com> (@example-jsmith)
|
||||
|
||||
# first set
|
||||
a: b@c d
|
||||
e: b@c d
|
||||
|
||||
# second set
|
||||
f: g@h
|
||||
i: g@h j
|
||||
`)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("-------------\nline-based:\n%v\n", man)
|
||||
|
||||
// Output:
|
||||
// -------------
|
||||
// 2822:
|
||||
// Maintainers: InfoSiftr <github@infosiftr.com> (@infosiftr), Johan Euphrosine <proppy@google.com> (@proppy)
|
||||
// SharedTags: latest
|
||||
// GitRepo: https://github.com/docker-library/golang.git
|
||||
// arm64v8-GitRepo: https://github.com/docker-library/golang.git
|
||||
//
|
||||
// Tags: 1.6.1, 1.6, 1
|
||||
// GitCommit: 0ce80411b9f41e9c3a21fc0a1bffba6ae761825a
|
||||
// Directory: 1.6
|
||||
// Constraints: some-random-build-server
|
||||
//
|
||||
// Tags: 1.5.3, 1.5
|
||||
// SharedTags: 1.5.3-debian, 1.5-debian
|
||||
// GitCommit: d7e2a8d90a9b8f5dfd5bcd428e0c33b68c40cc19
|
||||
// Directory: 1.5
|
||||
// i386-GitFetch: refs/heads/i386
|
||||
// ppc64le-Directory: 1.5/ppc64le
|
||||
// s390x-GitCommit: b6c460e7cd79b595267870a98013ec3078b490df
|
||||
//
|
||||
// Tags: raspbian-s390x
|
||||
// SharedTags: raspbian
|
||||
// Architectures: s390x
|
||||
// GitCommit: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
|
||||
//
|
||||
// Shared Tag Groups:
|
||||
//
|
||||
// - latest
|
||||
// - 1.6.1, 1.6, 1
|
||||
//
|
||||
// - 1.5.3-debian, 1.5-debian
|
||||
// - 1.5.3, 1.5
|
||||
//
|
||||
// - raspbian
|
||||
// - raspbian-s390x
|
||||
//
|
||||
// -------------
|
||||
// line-based:
|
||||
// Maintainers: InfoSiftr <github@infosiftr.com> (@infosiftr), John Smith <jsmith@example.com> (@example-jsmith)
|
||||
// GitFetch: refs/heads/*
|
||||
//
|
||||
// Tags: a, e
|
||||
// GitRepo: b
|
||||
// GitCommit: c
|
||||
// Directory: d
|
||||
//
|
||||
// Tags: f
|
||||
// GitRepo: g
|
||||
// GitFetch: refs/tags/h
|
||||
// GitCommit: FETCH_HEAD
|
||||
//
|
||||
// Tags: i
|
||||
// GitRepo: g
|
||||
// GitFetch: refs/tags/h
|
||||
// GitCommit: FETCH_HEAD
|
||||
// Directory: j
|
||||
}
|
||||
|
||||
func ExampleFetch_local() {
|
||||
repoName, tagName, man, err := manifest.Fetch("testdata", "bash:4.4")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s:%s\n\n", repoName, tagName)
|
||||
|
||||
fmt.Println(man.GetTag(tagName).ClearDefaults(manifest.DefaultManifestEntry).String())
|
||||
|
||||
// Output:
|
||||
// bash:4.4
|
||||
//
|
||||
// Maintainers: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||
// Tags: 4.4.12, 4.4, 4, latest
|
||||
// GitRepo: https://github.com/tianon/docker-bash.git
|
||||
// GitCommit: 1cbb5cf49b4c53bd5a986abf7a1afeb9a80eac1e
|
||||
// Directory: 4.4
|
||||
}
|
||||
|
||||
func ExampleFetch_remote() {
|
||||
repoName, tagName, man, err := manifest.Fetch("/home/jsmith/docker/official-images/library", "https://github.com/docker-library/official-images/raw/1a3c4cd6d5cd53bd538a6f56a69f94c5b35325a7/library/bash:4.4")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s:%s\n\n", repoName, tagName)
|
||||
|
||||
fmt.Println(man.GetTag(tagName).ClearDefaults(manifest.DefaultManifestEntry).String())
|
||||
|
||||
// Output:
|
||||
// bash:4.4
|
||||
//
|
||||
// Maintainers: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||
// Tags: 4.4.12, 4.4, 4, latest
|
||||
// GitRepo: https://github.com/tianon/docker-bash.git
|
||||
// GitCommit: 1cbb5cf49b4c53bd5a986abf7a1afeb9a80eac1e
|
||||
// Directory: 4.4
|
||||
}
|
||||
20
go/vendor/src/github.com/docker-library/go-dockerlibrary/manifest/parse_test.go
vendored
Normal file
20
go/vendor/src/github.com/docker-library/go-dockerlibrary/manifest/parse_test.go
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package manifest_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker-library/go-dockerlibrary/manifest"
|
||||
)
|
||||
|
||||
func TestParseError(t *testing.T) {
|
||||
invalidManifest := `this is just completely bogus and invalid no matter how you slice it`
|
||||
|
||||
man, err := manifest.Parse(strings.NewReader(invalidManifest))
|
||||
if err == nil {
|
||||
t.Errorf("Expected error, got valid manifest instead:\n%s", man)
|
||||
}
|
||||
if !strings.HasPrefix(err.Error(), "cannot parse manifest in either format:") {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker-library/go-dockerlibrary/pkg/stripper"
|
||||
|
|
@ -27,25 +28,37 @@ type Manifest2822Entry struct {
|
|||
|
||||
Maintainers []string `delim:"," strip:"\n\r\t "`
|
||||
|
||||
Tags []string `delim:"," strip:"\n\r\t "`
|
||||
Tags []string `delim:"," strip:"\n\r\t "`
|
||||
SharedTags []string `delim:"," strip:"\n\r\t "`
|
||||
|
||||
Architectures []string `delim:"," strip:"\n\r\t "`
|
||||
|
||||
GitRepo string
|
||||
GitFetch string
|
||||
GitCommit string
|
||||
Directory string
|
||||
// architecture-specific versions of the above fields are in Paragraph.Values as ARCH-Field, ala s390x-Directory
|
||||
|
||||
Constraints []string `delim:"," strip:"\n\r\t "`
|
||||
}
|
||||
|
||||
var DefaultManifestEntry = Manifest2822Entry{
|
||||
GitFetch: "refs/heads/master",
|
||||
Directory: ".",
|
||||
}
|
||||
var (
|
||||
DefaultArchitecture = "amd64"
|
||||
|
||||
DefaultManifestEntry = Manifest2822Entry{
|
||||
Architectures: []string{DefaultArchitecture},
|
||||
|
||||
GitFetch: "refs/heads/master",
|
||||
Directory: ".",
|
||||
}
|
||||
)
|
||||
|
||||
func (entry Manifest2822Entry) Clone() Manifest2822Entry {
|
||||
// SLICES! grr
|
||||
entry.Maintainers = append([]string{}, entry.Maintainers...)
|
||||
entry.Tags = append([]string{}, entry.Tags...)
|
||||
entry.SharedTags = append([]string{}, entry.SharedTags...)
|
||||
entry.Architectures = append([]string{}, entry.Architectures...)
|
||||
entry.Constraints = append([]string{}, entry.Constraints...)
|
||||
return entry
|
||||
}
|
||||
|
|
@ -60,23 +73,60 @@ func (entry Manifest2822Entry) TagsString() string {
|
|||
return strings.Join(entry.Tags, StringSeparator2822)
|
||||
}
|
||||
|
||||
func (entry Manifest2822Entry) SharedTagsString() string {
|
||||
return strings.Join(entry.SharedTags, StringSeparator2822)
|
||||
}
|
||||
|
||||
func (entry Manifest2822Entry) ArchitecturesString() string {
|
||||
return strings.Join(entry.Architectures, StringSeparator2822)
|
||||
}
|
||||
|
||||
func (entry Manifest2822Entry) ConstraintsString() string {
|
||||
return strings.Join(entry.Constraints, StringSeparator2822)
|
||||
}
|
||||
|
||||
// if this method returns "true", then a.Tags and b.Tags can safely be combined (for the purposes of building)
|
||||
func (a Manifest2822Entry) SameBuildArtifacts(b Manifest2822Entry) bool {
|
||||
return a.GitRepo == b.GitRepo && a.GitFetch == b.GitFetch && a.GitCommit == b.GitCommit && a.Directory == b.Directory && a.ConstraintsString() == b.ConstraintsString()
|
||||
// check xxxarch-GitRepo, etc. fields for sameness first
|
||||
for _, key := range append(a.archFields(), b.archFields()...) {
|
||||
if a.Paragraph.Values[key] != b.Paragraph.Values[key] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return a.ArchitecturesString() == b.ArchitecturesString() && a.GitRepo == b.GitRepo && a.GitFetch == b.GitFetch && a.GitCommit == b.GitCommit && a.Directory == b.Directory && a.ConstraintsString() == b.ConstraintsString()
|
||||
}
|
||||
|
||||
func isArchField(field string) bool {
|
||||
return strings.HasSuffix(field, "-GitRepo") || strings.HasSuffix(field, "-GitFetch") || strings.HasSuffix(field, "-GitCommit") || strings.HasSuffix(field, "-Directory")
|
||||
}
|
||||
|
||||
// returns a list of architecture-specific fields in an Entry
|
||||
func (entry Manifest2822Entry) archFields() []string {
|
||||
ret := []string{}
|
||||
for key, val := range entry.Paragraph.Values {
|
||||
if isArchField(key) && val != "" {
|
||||
ret = append(ret, key)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// returns a new Entry with any of the values that are equal to the values in "defaults" cleared
|
||||
func (entry Manifest2822Entry) ClearDefaults(defaults Manifest2822Entry) Manifest2822Entry {
|
||||
entry = entry.Clone() // make absolutely certain we have a deep clone
|
||||
if entry.MaintainersString() == defaults.MaintainersString() {
|
||||
entry.Maintainers = nil
|
||||
}
|
||||
if entry.TagsString() == defaults.TagsString() {
|
||||
entry.Tags = nil
|
||||
}
|
||||
if entry.SharedTagsString() == defaults.SharedTagsString() {
|
||||
entry.SharedTags = nil
|
||||
}
|
||||
if entry.ArchitecturesString() == defaults.ArchitecturesString() {
|
||||
entry.Architectures = nil
|
||||
}
|
||||
if entry.GitRepo == defaults.GitRepo {
|
||||
entry.GitRepo = ""
|
||||
}
|
||||
|
|
@ -89,6 +139,11 @@ func (entry Manifest2822Entry) ClearDefaults(defaults Manifest2822Entry) Manifes
|
|||
if entry.Directory == defaults.Directory {
|
||||
entry.Directory = ""
|
||||
}
|
||||
for _, key := range defaults.archFields() {
|
||||
if defaults.Paragraph.Values[key] == entry.Paragraph.Values[key] {
|
||||
delete(entry.Paragraph.Values, key)
|
||||
}
|
||||
}
|
||||
if entry.ConstraintsString() == defaults.ConstraintsString() {
|
||||
entry.Constraints = nil
|
||||
}
|
||||
|
|
@ -103,6 +158,12 @@ func (entry Manifest2822Entry) String() string {
|
|||
if str := entry.TagsString(); str != "" {
|
||||
ret = append(ret, "Tags: "+str)
|
||||
}
|
||||
if str := entry.SharedTagsString(); str != "" {
|
||||
ret = append(ret, "SharedTags: "+str)
|
||||
}
|
||||
if str := entry.ArchitecturesString(); str != "" {
|
||||
ret = append(ret, "Architectures: "+str)
|
||||
}
|
||||
if str := entry.GitRepo; str != "" {
|
||||
ret = append(ret, "GitRepo: "+str)
|
||||
}
|
||||
|
|
@ -115,6 +176,11 @@ func (entry Manifest2822Entry) String() string {
|
|||
if str := entry.Directory; str != "" {
|
||||
ret = append(ret, "Directory: "+str)
|
||||
}
|
||||
archFields := entry.archFields()
|
||||
sort.Strings(archFields) // consistent ordering
|
||||
for _, key := range archFields {
|
||||
ret = append(ret, key+": "+entry.Paragraph.Values[key])
|
||||
}
|
||||
if str := entry.ConstraintsString(); str != "" {
|
||||
ret = append(ret, "Constraints: "+str)
|
||||
}
|
||||
|
|
@ -136,6 +202,48 @@ func (manifest Manifest2822) String() string {
|
|||
return strings.Join(ret, "\n\n")
|
||||
}
|
||||
|
||||
func (entry *Manifest2822Entry) SetGitRepo(arch string, repo string) {
|
||||
if entry.Paragraph.Values == nil {
|
||||
entry.Paragraph.Values = map[string]string{}
|
||||
}
|
||||
entry.Paragraph.Values[arch+"-GitRepo"] = repo
|
||||
}
|
||||
|
||||
func (entry Manifest2822Entry) ArchGitRepo(arch string) string {
|
||||
if val, ok := entry.Paragraph.Values[arch+"-GitRepo"]; ok && val != "" {
|
||||
return val
|
||||
}
|
||||
return entry.GitRepo
|
||||
}
|
||||
|
||||
func (entry Manifest2822Entry) ArchGitFetch(arch string) string {
|
||||
if val, ok := entry.Paragraph.Values[arch+"-GitFetch"]; ok && val != "" {
|
||||
return val
|
||||
}
|
||||
return entry.GitFetch
|
||||
}
|
||||
|
||||
func (entry *Manifest2822Entry) SetGitCommit(arch string, commit string) {
|
||||
if entry.Paragraph.Values == nil {
|
||||
entry.Paragraph.Values = map[string]string{}
|
||||
}
|
||||
entry.Paragraph.Values[arch+"-GitCommit"] = commit
|
||||
}
|
||||
|
||||
func (entry Manifest2822Entry) ArchGitCommit(arch string) string {
|
||||
if val, ok := entry.Paragraph.Values[arch+"-GitCommit"]; ok && val != "" {
|
||||
return val
|
||||
}
|
||||
return entry.GitCommit
|
||||
}
|
||||
|
||||
func (entry Manifest2822Entry) ArchDirectory(arch string) string {
|
||||
if val, ok := entry.Paragraph.Values[arch+"-Directory"]; ok && val != "" {
|
||||
return val
|
||||
}
|
||||
return entry.Directory
|
||||
}
|
||||
|
||||
func (entry Manifest2822Entry) HasTag(tag string) bool {
|
||||
for _, existingTag := range entry.Tags {
|
||||
if tag == existingTag {
|
||||
|
|
@ -145,6 +253,26 @@ func (entry Manifest2822Entry) HasTag(tag string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// HasSharedTag returns true if the given tag exists in entry.SharedTags.
|
||||
func (entry Manifest2822Entry) HasSharedTag(tag string) bool {
|
||||
for _, existingTag := range entry.SharedTags {
|
||||
if tag == existingTag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HasArchitecture returns true if the given architecture exists in entry.Architectures
|
||||
func (entry Manifest2822Entry) HasArchitecture(arch string) bool {
|
||||
for _, existingArch := range entry.Architectures {
|
||||
if arch == existingArch {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (manifest Manifest2822) GetTag(tag string) *Manifest2822Entry {
|
||||
for _, entry := range manifest.Entries {
|
||||
if entry.HasTag(tag) {
|
||||
|
|
@ -154,6 +282,62 @@ func (manifest Manifest2822) GetTag(tag string) *Manifest2822Entry {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetSharedTag returns a list of entries with the given tag in entry.SharedTags (or the empty list if there are no entries with the given tag).
|
||||
func (manifest Manifest2822) GetSharedTag(tag string) []Manifest2822Entry {
|
||||
ret := []Manifest2822Entry{}
|
||||
for _, entry := range manifest.Entries {
|
||||
if entry.HasSharedTag(tag) {
|
||||
ret = append(ret, entry)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// GetAllSharedTags returns a list of the sum of all SharedTags in all entries of this image manifest (in the order they appear in the file).
|
||||
func (manifest Manifest2822) GetAllSharedTags() []string {
|
||||
fakeEntry := Manifest2822Entry{}
|
||||
for _, entry := range manifest.Entries {
|
||||
fakeEntry.SharedTags = append(fakeEntry.SharedTags, entry.SharedTags...)
|
||||
}
|
||||
fakeEntry.DeduplicateSharedTags()
|
||||
return fakeEntry.SharedTags
|
||||
}
|
||||
|
||||
type SharedTagGroup struct {
|
||||
SharedTags []string
|
||||
Entries []*Manifest2822Entry
|
||||
}
|
||||
|
||||
// GetSharedTagGroups returns a map of shared tag groups to the list of entries they share (as described in https://github.com/docker-library/go-dockerlibrary/pull/2#issuecomment-277853597).
|
||||
func (manifest Manifest2822) GetSharedTagGroups() []SharedTagGroup {
|
||||
inter := map[string][]string{}
|
||||
interOrder := []string{} // order matters, and maps randomize order
|
||||
interKeySep := ","
|
||||
for _, sharedTag := range manifest.GetAllSharedTags() {
|
||||
interKeyParts := []string{}
|
||||
for _, entry := range manifest.GetSharedTag(sharedTag) {
|
||||
interKeyParts = append(interKeyParts, entry.Tags[0])
|
||||
}
|
||||
interKey := strings.Join(interKeyParts, interKeySep)
|
||||
if _, ok := inter[interKey]; !ok {
|
||||
interOrder = append(interOrder, interKey)
|
||||
}
|
||||
inter[interKey] = append(inter[interKey], sharedTag)
|
||||
}
|
||||
ret := []SharedTagGroup{}
|
||||
for _, tags := range interOrder {
|
||||
group := SharedTagGroup{
|
||||
SharedTags: inter[tags],
|
||||
Entries: []*Manifest2822Entry{},
|
||||
}
|
||||
for _, tag := range strings.Split(tags, interKeySep) {
|
||||
group.Entries = append(group.Entries, manifest.GetTag(tag))
|
||||
}
|
||||
ret = append(ret, group)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (manifest *Manifest2822) AddEntry(entry Manifest2822Entry) error {
|
||||
if len(entry.Tags) < 1 {
|
||||
return fmt.Errorf("missing Tags")
|
||||
|
|
@ -165,20 +349,36 @@ func (manifest *Manifest2822) AddEntry(entry Manifest2822Entry) error {
|
|||
return fmt.Errorf("Tags %q has invalid Maintainers: %q (expected format %q)", strings.Join(invalidMaintainers, ", "), MaintainersFormat)
|
||||
}
|
||||
|
||||
entry.DeduplicateSharedTags()
|
||||
|
||||
seenTag := map[string]bool{}
|
||||
for _, tag := range entry.Tags {
|
||||
if otherEntry := manifest.GetTag(tag); otherEntry != nil {
|
||||
return fmt.Errorf("Tags %q includes duplicate tag: %q (duplicated in %q)", entry.TagsString(), tag, otherEntry.TagsString())
|
||||
}
|
||||
if otherEntries := manifest.GetSharedTag(tag); len(otherEntries) > 0 {
|
||||
return fmt.Errorf("Tags %q includes tag conflicting with a shared tag: %q (shared tag in %q)", entry.TagsString(), tag, otherEntries[0].TagsString())
|
||||
}
|
||||
if seenTag[tag] {
|
||||
return fmt.Errorf("Tags %q includes duplicate tag: %q", entry.TagsString(), tag)
|
||||
}
|
||||
seenTag[tag] = true
|
||||
}
|
||||
for _, tag := range entry.SharedTags {
|
||||
if otherEntry := manifest.GetTag(tag); otherEntry != nil {
|
||||
return fmt.Errorf("Tags %q includes conflicting shared tag: %q (duplicated in %q)", entry.TagsString(), tag, otherEntry.TagsString())
|
||||
}
|
||||
if seenTag[tag] {
|
||||
return fmt.Errorf("Tags %q includes duplicate tag: %q (in SharedTags)", entry.TagsString(), tag)
|
||||
}
|
||||
seenTag[tag] = true
|
||||
}
|
||||
|
||||
for i, existingEntry := range manifest.Entries {
|
||||
if existingEntry.SameBuildArtifacts(entry) {
|
||||
manifest.Entries[i].Tags = append(existingEntry.Tags, entry.Tags...)
|
||||
manifest.Entries[i].SharedTags = append(existingEntry.SharedTags, entry.SharedTags...)
|
||||
manifest.Entries[i].DeduplicateSharedTags()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -210,20 +410,51 @@ func (entry Manifest2822Entry) InvalidMaintainers() []string {
|
|||
return invalid
|
||||
}
|
||||
|
||||
// DeduplicateSharedTags will remove duplicate values from entry.SharedTags, preserving order.
|
||||
func (entry *Manifest2822Entry) DeduplicateSharedTags() {
|
||||
aggregate := []string{}
|
||||
seen := map[string]bool{}
|
||||
for _, tag := range entry.SharedTags {
|
||||
if seen[tag] {
|
||||
continue
|
||||
}
|
||||
seen[tag] = true
|
||||
aggregate = append(aggregate, tag)
|
||||
}
|
||||
entry.SharedTags = aggregate
|
||||
}
|
||||
|
||||
type decoderWrapper struct {
|
||||
*control.Decoder
|
||||
}
|
||||
|
||||
func (decoder *decoderWrapper) Decode(entry *Manifest2822Entry) error {
|
||||
// reset Architectures and SharedTags so that they can be either inherited or replaced, not additive
|
||||
sharedTags := entry.SharedTags
|
||||
entry.SharedTags = nil
|
||||
arches := entry.Architectures
|
||||
entry.Architectures = nil
|
||||
|
||||
for {
|
||||
err := decoder.Decoder.Decode(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ignore empty paragraphs (blank lines at the start, excess blank lines between paragraphs, excess blank lines at EOF)
|
||||
if len(entry.Paragraph.Order) > 0 {
|
||||
return nil
|
||||
if len(entry.Paragraph.Order) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// if we had no SharedTags or Architectures, restore our "default" (original) values
|
||||
if len(entry.SharedTags) == 0 {
|
||||
entry.SharedTags = sharedTags
|
||||
}
|
||||
if len(entry.Architectures) == 0 {
|
||||
entry.Architectures = arches
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
38
go/vendor/src/github.com/docker-library/go-dockerlibrary/manifest/testdata/bash
vendored
Normal file
38
go/vendor/src/github.com/docker-library/go-dockerlibrary/manifest/testdata/bash
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# this is a snapshot of https://github.com/docker-library/official-images/raw/1a3c4cd6d5cd53bd538a6f56a69f94c5b35325a7/library/bash
|
||||
|
||||
# this file is generated via https://github.com/tianon/docker-bash/blob/cd1de3dfc885b3395cd354ddb988922350b092a7/generate-stackbrew-library.sh
|
||||
|
||||
Maintainers: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||
GitRepo: https://github.com/tianon/docker-bash.git
|
||||
|
||||
Tags: 4.4.12, 4.4, 4, latest
|
||||
GitCommit: 1cbb5cf49b4c53bd5a986abf7a1afeb9a80eac1e
|
||||
Directory: 4.4
|
||||
|
||||
Tags: 4.3.48, 4.3
|
||||
GitCommit: 1cbb5cf49b4c53bd5a986abf7a1afeb9a80eac1e
|
||||
Directory: 4.3
|
||||
|
||||
Tags: 4.2.53, 4.2
|
||||
GitCommit: 1cbb5cf49b4c53bd5a986abf7a1afeb9a80eac1e
|
||||
Directory: 4.2
|
||||
|
||||
Tags: 4.1.17, 4.1
|
||||
GitCommit: 1cbb5cf49b4c53bd5a986abf7a1afeb9a80eac1e
|
||||
Directory: 4.1
|
||||
|
||||
Tags: 4.0.44, 4.0
|
||||
GitCommit: 4438745d601d10d300e363f24205a3ca75307803
|
||||
Directory: 4.0
|
||||
|
||||
Tags: 3.2.57, 3.2, 3
|
||||
GitCommit: 1cbb5cf49b4c53bd5a986abf7a1afeb9a80eac1e
|
||||
Directory: 3.2
|
||||
|
||||
Tags: 3.1.23, 3.1
|
||||
GitCommit: 1cbb5cf49b4c53bd5a986abf7a1afeb9a80eac1e
|
||||
Directory: 3.1
|
||||
|
||||
Tags: 3.0.22, 3.0
|
||||
GitCommit: 1cbb5cf49b4c53bd5a986abf7a1afeb9a80eac1e
|
||||
Directory: 3.0
|
||||
26
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/execpipe/execpipe_example_test.go
vendored
Normal file
26
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/execpipe/execpipe_example_test.go
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
package execpipe_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/docker-library/go-dockerlibrary/pkg/execpipe"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
pipe, err := execpipe.RunCommand("go", "version")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer pipe.Close()
|
||||
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, pipe)
|
||||
|
||||
fmt.Println(strings.SplitN(buf.String(), " version ", 2)[0])
|
||||
|
||||
// Output:
|
||||
// go
|
||||
}
|
||||
31
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/execpipe/execpipe_test.go
vendored
Normal file
31
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/execpipe/execpipe_test.go
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package execpipe_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/docker-library/go-dockerlibrary/pkg/execpipe"
|
||||
)
|
||||
|
||||
func TestStdoutPipeError(t *testing.T) {
|
||||
cmd := exec.Command("nothing", "really", "matters", "in", "the", "end")
|
||||
|
||||
// set "Stdout" so that "cmd.StdoutPipe" fails
|
||||
// https://golang.org/src/os/exec/exec.go?s=16834:16883#L587
|
||||
cmd.Stdout = os.Stdout
|
||||
|
||||
_, err := execpipe.Run(cmd)
|
||||
if err == nil {
|
||||
t.Errorf("Expected execpipe.Run to fail -- it did not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartError(t *testing.T) {
|
||||
// craft a definitely-invalid command so that "cmd.Start" fails
|
||||
// https://golang.org/src/os/exec/exec.go?s=8739:8766#L303
|
||||
_, err := execpipe.RunCommand("nothing-really-matters-in-the-end--bogus-command")
|
||||
if err == nil {
|
||||
t.Errorf("Expected execpipe.RunCommand to fail -- it did not")
|
||||
}
|
||||
}
|
||||
32
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/stripper/comments_example_test.go
vendored
Normal file
32
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/stripper/comments_example_test.go
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package stripper_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker-library/go-dockerlibrary/pkg/stripper"
|
||||
)
|
||||
|
||||
func ExampleCommentStripper() {
|
||||
r := strings.NewReader(`
|
||||
# opening comment
|
||||
a: b
|
||||
# comment!
|
||||
c: d # not a comment
|
||||
|
||||
# another cheeky comment
|
||||
e: f
|
||||
`)
|
||||
|
||||
comStrip := stripper.NewCommentStripper(r)
|
||||
|
||||
// using CopyBuffer to force smaller Read sizes (better testing coverage that way)
|
||||
io.CopyBuffer(os.Stdout, comStrip, make([]byte, 32))
|
||||
|
||||
// Output:
|
||||
// a: b
|
||||
// c: d # not a comment
|
||||
//
|
||||
// e: f
|
||||
}
|
||||
8
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/templatelib/doc.go
vendored
Normal file
8
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/templatelib/doc.go
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
Package templatelib implements a group of useful functions for use with the stdlib text/template package.
|
||||
|
||||
Usage:
|
||||
|
||||
tmpl, err := template.New("some-template").Funcs(templatelib.FuncMap).Parse("Hi, {{ join " " .Names }}")
|
||||
*/
|
||||
package templatelib
|
||||
|
|
@ -67,12 +67,15 @@ func stringsModifierActionFactory(a func(string, string) string) func([]string,
|
|||
}
|
||||
}
|
||||
|
||||
// TODO write some tests for these
|
||||
|
||||
var FuncMap = template.FuncMap{
|
||||
// {{- $isGitHub := hasPrefix "https://github.com/" $url -}}
|
||||
// {{- $isHtml := hasSuffix ".html" $url -}}
|
||||
"hasPrefix": swapStringsFuncBoolArgsOrder(strings.HasPrefix),
|
||||
"hasSuffix": swapStringsFuncBoolArgsOrder(strings.HasSuffix),
|
||||
|
||||
// {{- $hugeIfTrue := .SomeValue | ternary "HUGE" "not so huge" -}}
|
||||
// if .SomeValue is truthy, $hugeIfTrue will be "HUGE"
|
||||
// (otherwise, "not so huge")
|
||||
"ternary": func(truthy interface{}, falsey interface{}, val interface{}) interface{} {
|
||||
if t, ok := template.IsTrue(val); !ok {
|
||||
panic(fmt.Sprintf(`template.IsTrue(%+v) says things are NOT OK`, val))
|
||||
|
|
@ -83,14 +86,26 @@ var FuncMap = template.FuncMap{
|
|||
}
|
||||
},
|
||||
|
||||
// First Tag: {{- .Tags | first -}}
|
||||
// Last Tag: {{- .Tags | last -}}
|
||||
"first": thingsActionFactory("first", true, func(args []interface{}, arg interface{}) interface{} { return arg }),
|
||||
"last": thingsActionFactory("last", false, func(args []interface{}, arg interface{}) interface{} { return arg }),
|
||||
|
||||
// JSON data dump: {{ json . }}
|
||||
// (especially nice for taking data and piping it to "jq")
|
||||
// (ie "some-tool inspect --format '{{ json . }}' some-things | jq .")
|
||||
"json": func(v interface{}) (string, error) {
|
||||
j, err := json.Marshal(v)
|
||||
return string(j), err
|
||||
},
|
||||
"join": stringsActionFactory("join", true, strings.Join),
|
||||
|
||||
// Everybody: {{- join ", " .Names -}}
|
||||
// Concat: {{- join "/" "https://github.com" "jsmith" "some-repo" -}}
|
||||
"join": stringsActionFactory("join", true, strings.Join),
|
||||
|
||||
// {{- $mungedUrl := $url | replace "git://" "https://" | trimSuffixes ".git" -}}
|
||||
// turns: git://github.com/jsmith/some-repo.git
|
||||
// into: https://github.com/jsmith/some-repo
|
||||
"trimPrefixes": stringsActionFactory("trimPrefixes", false, stringsModifierActionFactory(strings.TrimPrefix)),
|
||||
"trimSuffixes": stringsActionFactory("trimSuffixes", false, stringsModifierActionFactory(strings.TrimSuffix)),
|
||||
"replace": stringsActionFactory("replace", false, func(strs []string, str string) string {
|
||||
|
|
|
|||
193
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/templatelib/lib_example_test.go
vendored
Normal file
193
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/templatelib/lib_example_test.go
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
package templatelib_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/docker-library/go-dockerlibrary/pkg/templatelib"
|
||||
)
|
||||
|
||||
func Example_prefixSuffix() {
|
||||
tmpl, err := template.New("github-or-html").Funcs(templatelib.FuncMap).Parse(`
|
||||
{{- . -}}
|
||||
|
||||
{{- if hasPrefix "https://github.com/" . -}}
|
||||
{{- " " -}} GitHub
|
||||
{{- end -}}
|
||||
|
||||
{{- if hasSuffix ".html" . -}}
|
||||
{{- " " -}} HTML
|
||||
{{- end -}}
|
||||
|
||||
{{- "\n" -}}
|
||||
`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = tmpl.Execute(os.Stdout, "https://github.com/example/example")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = tmpl.Execute(os.Stdout, "https://example.com/test.html")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = tmpl.Execute(os.Stdout, "https://example.com")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = tmpl.Execute(os.Stdout, "https://github.com/example/example/raw/master/test.html")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// https://github.com/example/example GitHub
|
||||
// https://example.com/test.html HTML
|
||||
// https://example.com
|
||||
// https://github.com/example/example/raw/master/test.html GitHub HTML
|
||||
}
|
||||
|
||||
func Example_ternary() {
|
||||
tmpl, err := template.New("huge-if-true").Funcs(templatelib.FuncMap).Parse(`
|
||||
{{- range $a := . -}}
|
||||
{{ printf "%#v: %s\n" $a (ternary "HUGE" "not so huge" $a) }}
|
||||
{{- end -}}
|
||||
`)
|
||||
|
||||
err = tmpl.Execute(os.Stdout, []interface{}{
|
||||
true,
|
||||
false,
|
||||
"true",
|
||||
"false",
|
||||
"",
|
||||
nil,
|
||||
1,
|
||||
0,
|
||||
9001,
|
||||
[]bool{},
|
||||
[]bool{false},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true: HUGE
|
||||
// false: not so huge
|
||||
// "true": HUGE
|
||||
// "false": HUGE
|
||||
// "": not so huge
|
||||
// <nil>: not so huge
|
||||
// 1: HUGE
|
||||
// 0: not so huge
|
||||
// 9001: HUGE
|
||||
// []bool{}: not so huge
|
||||
// []bool{false}: HUGE
|
||||
}
|
||||
|
||||
func Example_firstLast() {
|
||||
tmpl, err := template.New("first-and-last").Funcs(templatelib.FuncMap).Parse(`First: {{ . | first }}, Last: {{ . | last }}`)
|
||||
|
||||
err = tmpl.Execute(os.Stdout, []interface{}{
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// First: a, Last: c
|
||||
}
|
||||
|
||||
func Example_json() {
|
||||
tmpl, err := template.New("json").Funcs(templatelib.FuncMap).Parse(`
|
||||
{{- json . -}}
|
||||
`)
|
||||
|
||||
err = tmpl.Execute(os.Stdout, map[string]interface{}{
|
||||
"a": []string{"1", "2", "3"},
|
||||
"b": map[string]bool{"1": true, "2": false, "3": true},
|
||||
"c": nil,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {"a":["1","2","3"],"b":{"1":true,"2":false,"3":true},"c":null}
|
||||
}
|
||||
|
||||
func Example_join() {
|
||||
tmpl, err := template.New("join").Funcs(templatelib.FuncMap).Parse(`
|
||||
Array: {{ . | join ", " }}{{ "\n" -}}
|
||||
Args: {{ join ", " "a" "b" "c" -}}
|
||||
`)
|
||||
|
||||
err = tmpl.Execute(os.Stdout, []string{
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Array: 1, 2, 3
|
||||
// Args: a, b, c
|
||||
}
|
||||
|
||||
func Example_trimReplaceGitToHttps() {
|
||||
tmpl, err := template.New("git-to-https").Funcs(templatelib.FuncMap).Parse(`
|
||||
{{- range . -}}
|
||||
{{- . | replace "git://" "https://" | trimSuffixes ".git" }}{{ "\n" -}}
|
||||
{{- end -}}
|
||||
`)
|
||||
|
||||
err = tmpl.Execute(os.Stdout, []string{
|
||||
"git://github.com/jsmith/some-repo.git",
|
||||
"https://github.com/jsmith/some-repo.git",
|
||||
"https://github.com/jsmith/some-repo",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// https://github.com/jsmith/some-repo
|
||||
// https://github.com/jsmith/some-repo
|
||||
// https://github.com/jsmith/some-repo
|
||||
}
|
||||
|
||||
func Example_trimReplaceGitToGo() {
|
||||
tmpl, err := template.New("git-to-go").Funcs(templatelib.FuncMap).Parse(`
|
||||
{{- range . -}}
|
||||
{{- . | trimPrefixes "git://" "http://" "https://" "ssh://" | trimSuffixes ".git" }}{{ "\n" -}}
|
||||
{{- end -}}
|
||||
`)
|
||||
|
||||
err = tmpl.Execute(os.Stdout, []string{
|
||||
"git://github.com/jsmith/some-repo.git",
|
||||
"https://github.com/jsmith/some-repo.git",
|
||||
"https://github.com/jsmith/some-repo",
|
||||
"ssh://github.com/jsmith/some-repo.git",
|
||||
"github.com/jsmith/some-repo",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// github.com/jsmith/some-repo
|
||||
// github.com/jsmith/some-repo
|
||||
// github.com/jsmith/some-repo
|
||||
// github.com/jsmith/some-repo
|
||||
// github.com/jsmith/some-repo
|
||||
}
|
||||
45
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/templatelib/lib_test.go
vendored
Normal file
45
go/vendor/src/github.com/docker-library/go-dockerlibrary/pkg/templatelib/lib_test.go
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package templatelib_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"text/template"
|
||||
"unsafe"
|
||||
|
||||
"github.com/docker-library/go-dockerlibrary/pkg/templatelib"
|
||||
)
|
||||
|
||||
func TestTernaryPanic(t *testing.T) {
|
||||
// one of the only places template.IsTrue will return "false" for the "ok" value is an UnsafePointer (hence this test)
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("Expected panic, executed successfully instead")
|
||||
} else if errText, ok := r.(string); !ok || errText != `template.IsTrue(<nil>) says things are NOT OK` {
|
||||
t.Errorf("Unexpected panic: %v", errText)
|
||||
}
|
||||
}()
|
||||
|
||||
tmpl, err := template.New("unsafe-pointer").Funcs(templatelib.FuncMap).Parse(`{{ ternary "true" "false" . }}`)
|
||||
|
||||
err = tmpl.Execute(nil, unsafe.Pointer(uintptr(0)))
|
||||
if err != nil {
|
||||
t.Errorf("Expected panic, got error instead: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJoinPanic(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("Expected panic, executed successfully instead")
|
||||
} else if errText, ok := r.(string); !ok || errText != `"join" requires at least one argument` {
|
||||
t.Errorf("Unexpected panic: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
tmpl, err := template.New("join-no-arg").Funcs(templatelib.FuncMap).Parse(`{{ join }}`)
|
||||
|
||||
err = tmpl.Execute(nil, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Expected panic, got error instead: %v", err)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue