@@ -16,6 +16,7 @@ package build
16
16
17
17
import (
18
18
"archive/tar"
19
+ "bufio"
19
20
"bytes"
20
21
"context"
21
22
"errors"
@@ -68,7 +69,7 @@ type buildContext struct {
68
69
creationTime v1.Time
69
70
ip string
70
71
dir string
71
- env []string
72
+ mergedEnv []string
72
73
platform v1.Platform
73
74
config Config
74
75
}
@@ -267,6 +268,8 @@ func getGoBinary() string {
267
268
}
268
269
269
270
func build (ctx context.Context , buildCtx buildContext ) (string , error ) {
271
+ // Create the set of build arguments from the config flags/ldflags with any
272
+ // template parameters applied.
270
273
buildArgs , err := createBuildArgs (ctx , buildCtx )
271
274
if err != nil {
272
275
return "" , err
@@ -275,12 +278,6 @@ func build(ctx context.Context, buildCtx buildContext) (string, error) {
275
278
args := make ([]string , 0 , 4 + len (buildArgs ))
276
279
args = append (args , "build" )
277
280
args = append (args , buildArgs ... )
278
-
279
- env , err := buildEnv (buildCtx .platform , os .Environ (), buildCtx .env , buildCtx .config .Env )
280
- if err != nil {
281
- return "" , fmt .Errorf ("could not create env for %s: %w" , buildCtx .ip , err )
282
- }
283
-
284
281
tmpDir := ""
285
282
286
283
if dir := os .Getenv ("KOCACHE" ); dir != "" {
@@ -316,7 +313,7 @@ func build(ctx context.Context, buildCtx buildContext) (string, error) {
316
313
gobin := getGoBinary ()
317
314
cmd := exec .CommandContext (ctx , gobin , args ... )
318
315
cmd .Dir = buildCtx .dir
319
- cmd .Env = env
316
+ cmd .Env = buildCtx . mergedEnv
320
317
321
318
var output bytes.Buffer
322
319
cmd .Stderr = & output
@@ -325,13 +322,49 @@ func build(ctx context.Context, buildCtx buildContext) (string, error) {
325
322
log .Printf ("Building %s for %s" , buildCtx .ip , buildCtx .platform )
326
323
if err := cmd .Run (); err != nil {
327
324
if os .Getenv ("KOCACHE" ) == "" {
328
- os .RemoveAll (tmpDir )
325
+ _ = os .RemoveAll (tmpDir )
329
326
}
330
327
return "" , fmt .Errorf ("go build: %w: %s" , err , output .String ())
331
328
}
332
329
return file , nil
333
330
}
334
331
332
+ func goenv (ctx context.Context ) (map [string ]string , error ) {
333
+ gobin := getGoBinary ()
334
+ cmd := exec .CommandContext (ctx , gobin , "env" )
335
+ var output bytes.Buffer
336
+ cmd .Stdout = & output
337
+ cmd .Stderr = & output
338
+ if err := cmd .Run (); err != nil {
339
+ return nil , fmt .Errorf ("go env: %w: %s" , err , output .String ())
340
+ }
341
+
342
+ env := make (map [string ]string )
343
+ scanner := bufio .NewScanner (bytes .NewReader (output .Bytes ()))
344
+
345
+ line := 0
346
+ for scanner .Scan () {
347
+ line ++
348
+ kv := strings .SplitN (scanner .Text (), "=" , 2 )
349
+ if len (kv ) != 2 {
350
+ return nil , fmt .Errorf ("go env: failed parsing line: %d" , line )
351
+ }
352
+ key := strings .TrimSpace (kv [0 ])
353
+ value := strings .TrimSpace (kv [1 ])
354
+
355
+ // Unquote the value. Handle single or double quoted strings.
356
+ if len (value ) > 1 && ((value [0 ] == '\'' && value [len (value )- 1 ] == '\'' ) ||
357
+ (value [0 ] == '"' && value [len (value )- 1 ] == '"' )) {
358
+ value = value [1 : len (value )- 1 ]
359
+ }
360
+ env [key ] = value
361
+ }
362
+ if err := scanner .Err (); err != nil {
363
+ return nil , fmt .Errorf ("go env: failed parsing: %w" , err )
364
+ }
365
+ return env , nil
366
+ }
367
+
335
368
func goversionm (ctx context.Context , file string , appPath string , appFileName string , se oci.SignedEntity , dir string ) ([]byte , types.MediaType , error ) {
336
369
gobin := getGoBinary ()
337
370
@@ -724,15 +757,31 @@ func (g *gobuild) tarKoData(ref reference, platform *v1.Platform) (*bytes.Buffer
724
757
return buf , walkRecursive (tw , root , chroot , creationTime , platform )
725
758
}
726
759
727
- func createTemplateData (ctx context.Context , buildCtx buildContext ) map [string ]interface {} {
760
+ func createTemplateData (ctx context.Context , buildCtx buildContext ) ( map [string ]interface {}, error ) {
728
761
envVars := map [string ]string {
729
762
"LDFLAGS" : "" ,
730
763
}
731
- for _ , entry := range os . Environ () {
764
+ for _ , entry := range buildCtx . mergedEnv {
732
765
kv := strings .SplitN (entry , "=" , 2 )
766
+ if len (kv ) != 2 {
767
+ return nil , fmt .Errorf ("invalid environment variable entry: %q" , entry )
768
+ }
733
769
envVars [kv [0 ]] = kv [1 ]
734
770
}
735
771
772
+ // Get the go environment.
773
+ goEnv , err := goenv (ctx )
774
+ if err != nil {
775
+ return nil , err
776
+ }
777
+
778
+ // Override go env with any matching values from the environment variables.
779
+ for k , v := range envVars {
780
+ if _ , ok := goEnv [k ]; ok {
781
+ goEnv [k ] = v
782
+ }
783
+ }
784
+
736
785
// Get the git information, if available.
737
786
info , err := git .GetInfo (ctx , buildCtx .dir )
738
787
if err != nil {
@@ -747,10 +796,11 @@ func createTemplateData(ctx context.Context, buildCtx buildContext) map[string]i
747
796
748
797
return map [string ]interface {}{
749
798
"Env" : envVars ,
799
+ "GoEnv" : goEnv ,
750
800
"Git" : info .TemplateValue (),
751
801
"Date" : date .Format (time .RFC3339 ),
752
802
"Timestamp" : date .UTC ().Unix (),
753
- }
803
+ }, nil
754
804
}
755
805
756
806
func applyTemplating (list []string , data map [string ]interface {}) ([]string , error ) {
@@ -775,7 +825,10 @@ func applyTemplating(list []string, data map[string]interface{}) ([]string, erro
775
825
func createBuildArgs (ctx context.Context , buildCtx buildContext ) ([]string , error ) {
776
826
var args []string
777
827
778
- data := createTemplateData (ctx , buildCtx )
828
+ data , err := createTemplateData (ctx , buildCtx )
829
+ if err != nil {
830
+ return nil , err
831
+ }
779
832
780
833
if len (buildCtx .config .Flags ) > 0 {
781
834
flags , err := applyTemplating (buildCtx .config .Flags , data )
@@ -865,13 +918,21 @@ func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, pl
865
918
if ! g .platformMatcher .matches (platform ) {
866
919
return nil , fmt .Errorf ("base image platform %q does not match desired platforms %v" , platform , g .platformMatcher .platforms )
867
920
}
868
- // Do the build into a temporary file.
921
+
869
922
config := g .configForImportPath (ref .Path ())
923
+
924
+ // Merge the system, global, and build config environment variables.
925
+ mergedEnv , err := buildEnv (* platform , os .Environ (), g .env , config .Env )
926
+ if err != nil {
927
+ return nil , fmt .Errorf ("could not create env for %s: %w" , ref .Path (), err )
928
+ }
929
+
930
+ // Do the build into a temporary file.
870
931
file , err := g .build (ctx , buildContext {
871
932
creationTime : g .creationTime ,
872
933
ip : ref .Path (),
873
934
dir : g .dir ,
874
- env : g . env ,
935
+ mergedEnv : mergedEnv ,
875
936
platform : * platform ,
876
937
config : config ,
877
938
})
@@ -1101,7 +1162,7 @@ func (g *gobuild) buildAll(ctx context.Context, ref string, baseRef name.Referen
1101
1162
return nil , err
1102
1163
}
1103
1164
1104
- matches := []v1.Descriptor {}
1165
+ matches := make ( []v1.Descriptor , 0 )
1105
1166
for _ , desc := range im .Manifests {
1106
1167
// Nested index is pretty rare. We could support this in theory, but return an error for now.
1107
1168
if desc .MediaType != types .OCIManifestSchema1 && desc .MediaType != types .DockerManifestSchema2 {
@@ -1226,7 +1287,7 @@ func parseSpec(spec []string) (*platformMatcher, error) {
1226
1287
return & platformMatcher {spec : spec }, nil
1227
1288
}
1228
1289
1229
- platforms := []v1.Platform {}
1290
+ platforms := make ( []v1.Platform , 0 )
1230
1291
for _ , s := range spec {
1231
1292
p , err := v1 .ParsePlatform (s )
1232
1293
if err != nil {
0 commit comments