Improve bashbrew SharedTags handling (explicitly allowed for "bashbrew cat", etc)

This commit is contained in:
Tianon Gravi 2019-01-28 16:16:50 -08:00
parent 1693d9a9e6
commit a93f9f538f
11 changed files with 68 additions and 38 deletions

View File

@ -44,7 +44,7 @@ func cmdBuild(c *cli.Context) error {
continue continue
} }
from, err := r.DockerFrom(&entry) from, err := r.DockerFrom(entry)
if err != nil { if err != nil {
return cli.NewMultiError(fmt.Errorf(`failed fetching/scraping FROM for %q (tags %q)`, r.RepoName, entry.TagsString()), err) return cli.NewMultiError(fmt.Errorf(`failed fetching/scraping FROM for %q (tags %q)`, r.RepoName, entry.TagsString()), err)
} }
@ -69,7 +69,7 @@ func cmdBuild(c *cli.Context) error {
} }
} }
cacheTag, err := r.DockerCacheName(&entry) cacheTag, err := r.DockerCacheName(entry)
if err != nil { if err != nil {
return cli.NewMultiError(fmt.Errorf(`failed calculating "cache hash" for %q (tags %q)`, r.RepoName, entry.TagsString()), err) return cli.NewMultiError(fmt.Errorf(`failed calculating "cache hash" for %q (tags %q)`, r.RepoName, entry.TagsString()), err)
} }
@ -79,7 +79,7 @@ func cmdBuild(c *cli.Context) error {
if err != nil { if err != nil {
fmt.Printf("Building %s (%s)\n", cacheTag, r.EntryIdentifier(entry)) fmt.Printf("Building %s (%s)\n", cacheTag, r.EntryIdentifier(entry))
if !dryRun { if !dryRun {
commit, err := r.fetchGitRepo(arch, &entry) commit, err := r.fetchGitRepo(arch, entry)
if err != nil { if err != nil {
return cli.NewMultiError(fmt.Errorf(`failed fetching git repo for %q (tags %q)`, r.RepoName, entry.TagsString()), err) return cli.NewMultiError(fmt.Errorf(`failed fetching git repo for %q (tags %q)`, r.RepoName, entry.TagsString()), err)
} }

View File

@ -13,8 +13,17 @@ import (
) )
var DefaultCatFormat = ` var DefaultCatFormat = `
{{- if i }}{{ "\n\n" }}{{ end -}} {{- if i -}}
{{- .TagName | ternary (.Manifest.GetTag .TagName) .Manifest -}} {{- "\n\n" -}}
{{- end -}}
{{- with .TagEntries -}}
{{- range $i, $e := . -}}
{{- if $i -}}{{- "\n\n" -}}{{- end -}}
{{- $e -}}
{{- end -}}
{{- else -}}
{{- .Manifest -}}
{{- end -}}
` `
func cmdCat(c *cli.Context) error { func cmdCat(c *cli.Context) error {

View File

@ -67,7 +67,7 @@ func cmdFamily(parents bool, c *cli.Context) error {
continue continue
} }
from, err := r.DockerFrom(&entry) from, err := r.DockerFrom(entry)
if err != nil { if err != nil {
return cli.NewMultiError(fmt.Errorf(`failed fetching/scraping FROM for %q (tags %q)`, r.RepoName, entry.TagsString()), err) return cli.NewMultiError(fmt.Errorf(`failed fetching/scraping FROM for %q (tags %q)`, r.RepoName, entry.TagsString()), err)
} }

View File

@ -27,7 +27,7 @@ func cmdFrom(c *cli.Context) error {
continue continue
} }
from, err := r.DockerFrom(&entry) from, err := r.DockerFrom(entry)
if err != nil { if err != nil {
return cli.NewMultiError(fmt.Errorf(`failed fetching/scraping FROM for %q (tags %q)`, r.RepoName, entry.TagsString()), err) return cli.NewMultiError(fmt.Errorf(`failed fetching/scraping FROM for %q (tags %q)`, r.RepoName, entry.TagsString()), err)
} }

View File

@ -36,14 +36,14 @@ func cmdList(c *cli.Context) error {
if r.TagEntry == nil { if r.TagEntry == nil {
fmt.Printf("%s\n", r.RepoName) fmt.Printf("%s\n", r.RepoName)
} else { } else {
for _, tag := range r.Tags(namespace, uniq, *r.TagEntry) { for _, tag := range r.Tags(namespace, uniq, r.TagEntry) {
fmt.Printf("%s\n", tag) fmt.Printf("%s\n", tag)
} }
} }
continue continue
} }
var entries []manifest.Manifest2822Entry var entries []*manifest.Manifest2822Entry
if buildOrder { if buildOrder {
entries, err = r.SortedEntries(applyConstraints) entries, err = r.SortedEntries(applyConstraints)
if err != nil { if err != nil {

View File

@ -19,7 +19,7 @@ func entriesToManifestToolYaml(singleArch bool, r Repo, entries ...*manifest.Man
expectedNumber := 0 expectedNumber := 0
entryIdentifiers := []string{} entryIdentifiers := []string{}
for _, entry := range entries { for _, entry := range entries {
entryIdentifiers = append(entryIdentifiers, r.EntryIdentifier(*entry)) entryIdentifiers = append(entryIdentifiers, r.EntryIdentifier(entry))
for _, entryArch := range entry.Architectures { for _, entryArch := range entry.Architectures {
if singleArch && entryArch != arch { if singleArch && entryArch != arch {
@ -36,7 +36,7 @@ func entriesToManifestToolYaml(singleArch bool, r Repo, entries ...*manifest.Man
var archNamespace string var archNamespace string
if archNamespace, ok = archNamespaces[entryArch]; !ok || archNamespace == "" { if archNamespace, ok = archNamespaces[entryArch]; !ok || archNamespace == "" {
fmt.Fprintf(os.Stderr, "warning: no arch-namespace specified for %q; skipping (%q)\n", entryArch, r.EntryIdentifier(*entry)) fmt.Fprintf(os.Stderr, "warning: no arch-namespace specified for %q; skipping (%q)\n", entryArch, r.EntryIdentifier(entry))
continue continue
} }
@ -106,7 +106,7 @@ func cmdPutShared(c *cli.Context) error {
// handle all multi-architecture tags first (regardless of whether they have SharedTags) // handle all multi-architecture tags first (regardless of whether they have SharedTags)
// turn them into SharedTagGroup objects so all manifest-tool invocations can be handled by a single process/loop // turn them into SharedTagGroup objects so all manifest-tool invocations can be handled by a single process/loop
for _, entry := range r.Entries() { for _, entry := range r.Entries() {
entryCopy := entry entryCopy := *entry
sharedTagGroups = append(sharedTagGroups, manifest.SharedTagGroup{ sharedTagGroups = append(sharedTagGroups, manifest.SharedTagGroup{
SharedTags: entry.Tags, SharedTags: entry.Tags,
Entries: []*manifest.Manifest2822Entry{&entryCopy}, Entries: []*manifest.Manifest2822Entry{&entryCopy},

View File

@ -51,16 +51,19 @@ type Repo struct {
TagName string TagName string
Manifest *manifest.Manifest2822 Manifest *manifest.Manifest2822
TagEntry *manifest.Manifest2822Entry TagEntry *manifest.Manifest2822Entry
// if "TagName" refers to a SharedTag, "TagEntry" will be the first match, this will contain all matches (otherwise it will be just "TagEntry")
TagEntries []*manifest.Manifest2822Entry
} }
func (r Repo) Identifier() string { func (r Repo) Identifier() string {
if r.TagEntry != nil { if r.TagEntry != nil {
return r.EntryIdentifier(*r.TagEntry) return r.EntryIdentifier(r.TagEntry)
} }
return r.RepoName return r.RepoName
} }
func (r Repo) EntryIdentifier(entry manifest.Manifest2822Entry) string { func (r Repo) EntryIdentifier(entry *manifest.Manifest2822Entry) string {
return r.RepoName + ":" + entry.Tags[0] return r.RepoName + ":" + entry.Tags[0]
} }
@ -76,7 +79,7 @@ func (r Repo) EntryRepo(entry *manifest.Manifest2822Entry) *Repo {
var haveOutputSkippedMessage = map[string]bool{} var haveOutputSkippedMessage = map[string]bool{}
func (r Repo) SkipConstraints(entry manifest.Manifest2822Entry) bool { func (r Repo) SkipConstraints(entry *manifest.Manifest2822Entry) bool {
repoTag := r.RepoName + ":" + entry.Tags[0] repoTag := r.RepoName + ":" + entry.Tags[0]
// TODO decide if "arch" and "constraints" should be handled separately (but probably not) // TODO decide if "arch" and "constraints" should be handled separately (but probably not)
@ -135,16 +138,19 @@ NextConstraint:
return false return false
} }
func (r Repo) Entries() []manifest.Manifest2822Entry { func (r Repo) Entries() []*manifest.Manifest2822Entry {
if r.TagName == "" { if r.TagName == "" {
return r.Manifest.Entries ret := []*manifest.Manifest2822Entry{}
for i := range r.Manifest.Entries {
ret = append(ret, &r.Manifest.Entries[i])
}
return ret
} else { } else {
// TODO what if r.TagName isn't a single entry, but is a SharedTag ? return r.TagEntries
return []manifest.Manifest2822Entry{*r.Manifest.GetTag(r.TagName)}
} }
} }
func (r Repo) Tags(namespace string, uniq bool, entry manifest.Manifest2822Entry) []string { func (r Repo) Tags(namespace string, uniq bool, entry *manifest.Manifest2822Entry) []string {
tagRepo := path.Join(namespace, r.RepoName) tagRepo := path.Join(namespace, r.RepoName)
ret := []string{} ret := []string{}
tags := append([]string{}, entry.Tags...) tags := append([]string{}, entry.Tags...)
@ -177,6 +183,14 @@ func fetch(repo string) (*Repo, error) {
} }
if tagName != "" { if tagName != "" {
r.TagEntry = man.GetTag(tagName) r.TagEntry = man.GetTag(tagName)
if r.TagEntry == nil {
// must be a SharedTag
r.TagEntries = man.GetSharedTag(tagName)
r.TagEntry = r.TagEntries[0]
} else {
// not a SharedTag, backfill TagEntries
r.TagEntries = []*manifest.Manifest2822Entry{r.TagEntry}
}
} }
repoCache[repo] = r repoCache[repo] = r
return r, nil return r, nil

View File

@ -38,7 +38,7 @@ func sortRepos(repos []string, applyConstraints bool) ([]string, error) {
return ret, nil return ret, nil
} }
func (r Repo) SortedEntries(applyConstraints bool) ([]manifest.Manifest2822Entry, error) { func (r Repo) SortedEntries(applyConstraints bool) ([]*manifest.Manifest2822Entry, error) {
entries := r.Entries() entries := r.Entries()
// short circuit if we don't have to go further // short circuit if we don't have to go further
@ -49,7 +49,7 @@ func (r Repo) SortedEntries(applyConstraints bool) ([]manifest.Manifest2822Entry
// create individual "Repo" objects for each entry in "r" so they can be sorted by the same "sortRepoObjects" function // create individual "Repo" objects for each entry in "r" so they can be sorted by the same "sortRepoObjects" function
rs := []*Repo{} rs := []*Repo{}
for i := range entries { for i := range entries {
rs = append(rs, r.EntryRepo(&entries[i])) rs = append(rs, r.EntryRepo(entries[i]))
} }
rs, err := sortRepoObjects(rs, applyConstraints) rs, err := sortRepoObjects(rs, applyConstraints)
@ -57,9 +57,9 @@ func (r Repo) SortedEntries(applyConstraints bool) ([]manifest.Manifest2822Entry
return nil, err return nil, err
} }
ret := []manifest.Manifest2822Entry{} ret := []*manifest.Manifest2822Entry{}
for _, entryR := range rs { for _, entryR := range rs {
ret = append(ret, *entryR.TagEntry) ret = append(ret, entryR.TagEntries...)
} }
return ret, nil return ret, nil
} }
@ -101,7 +101,7 @@ func sortRepoObjects(rs []*Repo, applyConstraints bool) ([]*Repo, error) {
continue continue
} }
from, err := r.DockerFrom(&entry) from, err := r.DockerFrom(entry)
if err != nil { if err != nil {
return nil, err return nil, err
} }

2
go/vendor/manifest vendored
View File

@ -10,7 +10,7 @@
{ {
"importpath": "github.com/docker-library/go-dockerlibrary", "importpath": "github.com/docker-library/go-dockerlibrary",
"repository": "https://github.com/docker-library/go-dockerlibrary", "repository": "https://github.com/docker-library/go-dockerlibrary",
"revision": "78186ac78fb8c1ce4e0f2f4847ae4d57a69cfcc3", "revision": "7e50189a05d4ff8233197dc948cc8fb11a780e33",
"branch": "master" "branch": "master"
}, },
{ {

View File

@ -9,6 +9,13 @@ import (
"strings" "strings"
) )
func validateTagName(man *Manifest2822, repoName, tagName string) error {
if tagName != "" && (man.GetTag(tagName) == nil && len(man.GetSharedTag(tagName)) == 0) {
return fmt.Errorf("tag not found in manifest for %q: %q", repoName, tagName)
}
return nil
}
// "library" is the default "library directory" // "library" is the default "library directory"
// returns the parsed version of (in order): // returns the parsed version of (in order):
// if "repo" is a URL, the remote contents of that URL // if "repo" is a URL, the remote contents of that URL
@ -33,11 +40,11 @@ func Fetch(library, repo string) (string, string, *Manifest2822, error) {
} }
defer resp.Body.Close() defer resp.Body.Close()
man, err := Parse(resp.Body) man, err := Parse(resp.Body)
if tagName != "" && man.GetTag(tagName) == nil { if err != nil {
return repoName, tagName, man, fmt.Errorf("tag not found in manifest for %q: %q", repoName, tagName)
}
return repoName, tagName, man, err return repoName, tagName, man, err
} }
return repoName, tagName, man, validateTagName(man, repoName, tagName)
}
// try file paths // try file paths
filePaths := []string{} filePaths := []string{}
@ -55,11 +62,11 @@ func Fetch(library, repo string) (string, string, *Manifest2822, error) {
if err == nil { if err == nil {
defer f.Close() defer f.Close()
man, err := Parse(f) man, err := Parse(f)
if tagName != "" && man.GetTag(tagName) == nil { if err != nil {
return repoName, tagName, man, fmt.Errorf("tag not found in manifest for %q: %q", repoName, tagName)
}
return repoName, tagName, man, err return repoName, tagName, man, err
} }
return repoName, tagName, man, validateTagName(man, repoName, tagName)
}
} }
return repoName, tagName, nil, fmt.Errorf("unable to find a manifest named %q (in %q or as a remote URL)", repo, library) return repoName, tagName, nil, fmt.Errorf("unable to find a manifest named %q (in %q or as a remote URL)", repo, library)

View File

@ -308,20 +308,20 @@ func (entry Manifest2822Entry) HasArchitecture(arch string) bool {
} }
func (manifest Manifest2822) GetTag(tag string) *Manifest2822Entry { func (manifest Manifest2822) GetTag(tag string) *Manifest2822Entry {
for _, entry := range manifest.Entries { for i, entry := range manifest.Entries {
if entry.HasTag(tag) { if entry.HasTag(tag) {
return &entry return &manifest.Entries[i]
} }
} }
return nil 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). // 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 { func (manifest Manifest2822) GetSharedTag(tag string) []*Manifest2822Entry {
ret := []Manifest2822Entry{} ret := []*Manifest2822Entry{}
for _, entry := range manifest.Entries { for i, entry := range manifest.Entries {
if entry.HasSharedTag(tag) { if entry.HasSharedTag(tag) {
ret = append(ret, entry) ret = append(ret, &manifest.Entries[i])
} }
} }
return ret return ret