This PR is tring to fix issue #36996.
Currently for multi-stage build, if `--target` specified, the `--label` option
will be ignored. The root cause is the last stage build will remove the `LABEL`
command(s) node created from the `--label` option. In order to address this issue,
we can create `LABEL` command(s) and add it/tem to the last stage.
Signed-off-by: Dennis Chen <dennis.chen@arm.com>
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"io" |
| 8 | 8 |
"io/ioutil" |
| 9 |
+ "sort" |
|
| 9 | 10 |
"strings" |
| 10 | 11 |
"time" |
| 11 | 12 |
|
| ... | ... |
@@ -208,13 +209,26 @@ func newBuilder(clientCtx context.Context, options builderOptions) *Builder {
|
| 208 | 208 |
return b |
| 209 | 209 |
} |
| 210 | 210 |
|
| 211 |
+// Build 'LABEL' command(s) from '--label' options and add to the last stage |
|
| 212 |
+func buildLabelOptions(labels map[string]string, stages []instructions.Stage) {
|
|
| 213 |
+ keys := []string{}
|
|
| 214 |
+ for key := range labels {
|
|
| 215 |
+ keys = append(keys, key) |
|
| 216 |
+ } |
|
| 217 |
+ |
|
| 218 |
+ // Sort the label to have a repeatable order |
|
| 219 |
+ sort.Strings(keys) |
|
| 220 |
+ for _, key := range keys {
|
|
| 221 |
+ value := labels[key] |
|
| 222 |
+ stages[len(stages)-1].AddCommand(instructions.NewLabelCommand(key, value, true)) |
|
| 223 |
+ } |
|
| 224 |
+} |
|
| 225 |
+ |
|
| 211 | 226 |
// Build runs the Dockerfile builder by parsing the Dockerfile and executing |
| 212 | 227 |
// the instructions from the file. |
| 213 | 228 |
func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*builder.Result, error) {
|
| 214 | 229 |
defer b.imageSources.Unmount() |
| 215 | 230 |
|
| 216 |
- addNodesForLabelOption(dockerfile.AST, b.options.Labels) |
|
| 217 |
- |
|
| 218 | 231 |
stages, metaArgs, err := instructions.Parse(dockerfile.AST) |
| 219 | 232 |
if err != nil {
|
| 220 | 233 |
if instructions.IsUnknownInstruction(err) {
|
| ... | ... |
@@ -231,6 +245,9 @@ func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*buil |
| 231 | 231 |
stages = stages[:targetIx+1] |
| 232 | 232 |
} |
| 233 | 233 |
|
| 234 |
+ // Add 'LABEL' command specified by '--label' option to the last stage |
|
| 235 |
+ buildLabelOptions(b.options.Labels, stages) |
|
| 236 |
+ |
|
| 234 | 237 |
dockerfile.PrintWarnings(b.Stderr) |
| 235 | 238 |
dispatchState, err := b.dispatchDockerfileWithCancellation(stages, metaArgs, dockerfile.EscapeToken, source) |
| 236 | 239 |
if err != nil {
|
| ... | ... |
@@ -110,17 +110,37 @@ type MaintainerCommand struct {
|
| 110 | 110 |
Maintainer string |
| 111 | 111 |
} |
| 112 | 112 |
|
| 113 |
+// NewLabelCommand creates a new 'LABEL' command |
|
| 114 |
+func NewLabelCommand(k string, v string, NoExp bool) *LabelCommand {
|
|
| 115 |
+ kvp := KeyValuePair{Key: k, Value: v}
|
|
| 116 |
+ c := "LABEL " |
|
| 117 |
+ c += kvp.String() |
|
| 118 |
+ nc := withNameAndCode{code: c, name: "label"}
|
|
| 119 |
+ cmd := &LabelCommand{
|
|
| 120 |
+ withNameAndCode: nc, |
|
| 121 |
+ Labels: KeyValuePairs{
|
|
| 122 |
+ kvp, |
|
| 123 |
+ }, |
|
| 124 |
+ noExpand: NoExp, |
|
| 125 |
+ } |
|
| 126 |
+ return cmd |
|
| 127 |
+} |
|
| 128 |
+ |
|
| 113 | 129 |
// LabelCommand : LABEL some json data describing the image |
| 114 | 130 |
// |
| 115 | 131 |
// Sets the Label variable foo to bar, |
| 116 | 132 |
// |
| 117 | 133 |
type LabelCommand struct {
|
| 118 | 134 |
withNameAndCode |
| 119 |
- Labels KeyValuePairs // kvp slice instead of map to preserve ordering |
|
| 135 |
+ Labels KeyValuePairs // kvp slice instead of map to preserve ordering |
|
| 136 |
+ noExpand bool |
|
| 120 | 137 |
} |
| 121 | 138 |
|
| 122 | 139 |
// Expand variables |
| 123 | 140 |
func (c *LabelCommand) Expand(expander SingleWordExpander) error {
|
| 141 |
+ if c.noExpand {
|
|
| 142 |
+ return nil |
|
| 143 |
+ } |
|
| 124 | 144 |
return expandKvpsInPlace(c.Labels, expander) |
| 125 | 145 |
} |
| 126 | 146 |
|