mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Sort the build labels passed from build --labels
This fix tries to fix the issue in 29619 where labels passed from `build --labels` are not sorted. As a result, if multiple labels have been passed, each `docker build --labels A=A --labels B=B --labels C=C` will generate different layers. This fix fixes the issue by sort the Labels before they are concatenated to `LABEL ...`. A unit test has been added to cover the changes This fix fixes 29619. Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
parent
a8bcef6fdd
commit
d32efdbf8b
2 changed files with 79 additions and 10 deletions
|
@ -7,6 +7,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
@ -203,6 +204,28 @@ func sanitizeRepoAndTags(names []string) ([]reference.Named, error) {
|
||||||
return repoAndTags, nil
|
return repoAndTags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Builder) processLabels() error {
|
||||||
|
if len(b.options.Labels) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var labels []string
|
||||||
|
for k, v := range b.options.Labels {
|
||||||
|
labels = append(labels, fmt.Sprintf("%q='%s'", k, v))
|
||||||
|
}
|
||||||
|
// Sort the label to have a repeatable order
|
||||||
|
sort.Strings(labels)
|
||||||
|
|
||||||
|
line := "LABEL " + strings.Join(labels, " ")
|
||||||
|
_, node, err := parser.ParseLine(line, &b.directive, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.dockerfile.Children = append(b.dockerfile.Children, node)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// build runs the Dockerfile builder from a context and a docker object that allows to make calls
|
// build runs the Dockerfile builder from a context and a docker object that allows to make calls
|
||||||
// to Docker.
|
// to Docker.
|
||||||
//
|
//
|
||||||
|
@ -233,16 +256,8 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(b.options.Labels) > 0 {
|
if err := b.processLabels(); err != nil {
|
||||||
line := "LABEL "
|
return "", err
|
||||||
for k, v := range b.options.Labels {
|
|
||||||
line += fmt.Sprintf("%q='%s' ", k, v)
|
|
||||||
}
|
|
||||||
_, node, err := parser.ParseLine(line, &b.directive, false)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
b.dockerfile.Children = append(b.dockerfile.Children, node)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var shortImgID string
|
var shortImgID string
|
||||||
|
|
54
builder/dockerfile/builder_test.go
Normal file
54
builder/dockerfile/builder_test.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package dockerfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/builder/dockerfile/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildProcessLabels(t *testing.T) {
|
||||||
|
dockerfile := "FROM scratch"
|
||||||
|
d := parser.Directive{}
|
||||||
|
parser.SetEscapeToken(parser.DefaultEscapeToken, &d)
|
||||||
|
n, err := parser.Parse(strings.NewReader(dockerfile), &d)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error when parsing Dockerfile: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
options := &types.ImageBuildOptions{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"org.e": "cli-e",
|
||||||
|
"org.d": "cli-d",
|
||||||
|
"org.c": "cli-c",
|
||||||
|
"org.b": "cli-b",
|
||||||
|
"org.a": "cli-a",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
b := &Builder{
|
||||||
|
runConfig: &container.Config{},
|
||||||
|
options: options,
|
||||||
|
directive: d,
|
||||||
|
dockerfile: n,
|
||||||
|
}
|
||||||
|
err = b.processLabels()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error when processing labels: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []string{
|
||||||
|
"FROM scratch",
|
||||||
|
`LABEL "org.a"='cli-a' "org.b"='cli-b' "org.c"='cli-c' "org.d"='cli-d' "org.e"='cli-e'`,
|
||||||
|
}
|
||||||
|
if len(b.dockerfile.Children) != 2 {
|
||||||
|
t.Fatalf("Expect 2, got %d", len(b.dockerfile.Children))
|
||||||
|
}
|
||||||
|
for i, v := range b.dockerfile.Children {
|
||||||
|
if v.Original != expected[i] {
|
||||||
|
t.Fatalf("Expect '%s' for %dth children, got, '%s'", expected[i], i, v.Original)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue