@@ -40,6 +40,7 @@ import (
40
40
"github.com/moby/buildkit/util/suggest"
41
41
"github.com/moby/buildkit/util/system"
42
42
dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
43
+ "github.com/moby/patternmatcher"
43
44
"github.com/moby/sys/signal"
44
45
digest "github.com/opencontainers/go-digest"
45
46
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
@@ -258,6 +259,9 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
258
259
if err != nil {
259
260
return nil , err
260
261
}
262
+ if len (stages ) == 0 {
263
+ return nil , errors .New ("dockerfile contains no stages to build" )
264
+ }
261
265
validateStageNames (stages , lint )
262
266
263
267
shlex := shell .NewLex (dockerfile .EscapeToken )
@@ -315,6 +319,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
315
319
platMatch , err := shlex .ProcessWordWithMatches (v , platEnv )
316
320
reportUnusedFromArgs (metaArgsKeys (optMetaArgs ), platMatch .Unmatched , st .Location , lint )
317
321
reportRedundantTargetPlatform (st .Platform , platMatch , st .Location , platEnv , lint )
322
+ reportConstPlatformDisallowed (st .Name , platMatch , st .Location , lint )
318
323
319
324
if err != nil {
320
325
return nil , parser .WithLocation (errors .Wrapf (err , "failed to process arguments for platform %s" , platMatch .Result ), st .Location )
@@ -590,6 +595,20 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
590
595
buildContext := & mutableOutput {}
591
596
ctxPaths := map [string ]struct {}{}
592
597
598
+ var dockerIgnoreMatcher * patternmatcher.PatternMatcher
599
+ if opt .Client != nil && opt .Client .CopyIgnoredCheckEnabled {
600
+ dockerIgnorePatterns , err := opt .Client .DockerIgnorePatterns (ctx )
601
+ if err != nil {
602
+ return nil , err
603
+ }
604
+ if len (dockerIgnorePatterns ) > 0 {
605
+ dockerIgnoreMatcher , err = patternmatcher .New (dockerIgnorePatterns )
606
+ if err != nil {
607
+ return nil , err
608
+ }
609
+ }
610
+ }
611
+
593
612
for _ , d := range allDispatchStates .states {
594
613
if ! opt .AllStages {
595
614
if _ , ok := allReachable [d ]; ! ok || d .noinit {
@@ -630,24 +649,27 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
630
649
return nil , parser .WithLocation (err , d .stage .Location )
631
650
}
632
651
}
652
+
633
653
d .state = d .state .Network (opt .NetworkMode )
654
+
634
655
opt := dispatchOpt {
635
- allDispatchStates : allDispatchStates ,
636
- metaArgs : optMetaArgs ,
637
- buildArgValues : opt .BuildArgs ,
638
- shlex : shlex ,
639
- buildContext : llb .NewState (buildContext ),
640
- proxyEnv : proxyEnv ,
641
- cacheIDNamespace : opt .CacheIDNamespace ,
642
- buildPlatforms : platformOpt .buildPlatforms ,
643
- targetPlatform : platformOpt .targetPlatform ,
644
- extraHosts : opt .ExtraHosts ,
645
- shmSize : opt .ShmSize ,
646
- ulimit : opt .Ulimits ,
647
- cgroupParent : opt .CgroupParent ,
648
- llbCaps : opt .LLBCaps ,
649
- sourceMap : opt .SourceMap ,
650
- lint : lint ,
656
+ allDispatchStates : allDispatchStates ,
657
+ metaArgs : optMetaArgs ,
658
+ buildArgValues : opt .BuildArgs ,
659
+ shlex : shlex ,
660
+ buildContext : llb .NewState (buildContext ),
661
+ proxyEnv : proxyEnv ,
662
+ cacheIDNamespace : opt .CacheIDNamespace ,
663
+ buildPlatforms : platformOpt .buildPlatforms ,
664
+ targetPlatform : platformOpt .targetPlatform ,
665
+ extraHosts : opt .ExtraHosts ,
666
+ shmSize : opt .ShmSize ,
667
+ ulimit : opt .Ulimits ,
668
+ cgroupParent : opt .CgroupParent ,
669
+ llbCaps : opt .LLBCaps ,
670
+ sourceMap : opt .SourceMap ,
671
+ lint : lint ,
672
+ dockerIgnoreMatcher : dockerIgnoreMatcher ,
651
673
}
652
674
653
675
if err = dispatchOnBuildTriggers (d , d .image .Config .OnBuild , opt ); err != nil {
@@ -806,22 +828,23 @@ func toCommand(ic instructions.Command, allDispatchStates *dispatchStates) (comm
806
828
}
807
829
808
830
type dispatchOpt struct {
809
- allDispatchStates * dispatchStates
810
- metaArgs []instructions.KeyValuePairOptional
811
- buildArgValues map [string ]string
812
- shlex * shell.Lex
813
- buildContext llb.State
814
- proxyEnv * llb.ProxyEnv
815
- cacheIDNamespace string
816
- targetPlatform ocispecs.Platform
817
- buildPlatforms []ocispecs.Platform
818
- extraHosts []llb.HostIP
819
- shmSize int64
820
- ulimit []pb.Ulimit
821
- cgroupParent string
822
- llbCaps * apicaps.CapSet
823
- sourceMap * llb.SourceMap
824
- lint * linter.Linter
831
+ allDispatchStates * dispatchStates
832
+ metaArgs []instructions.KeyValuePairOptional
833
+ buildArgValues map [string ]string
834
+ shlex * shell.Lex
835
+ buildContext llb.State
836
+ proxyEnv * llb.ProxyEnv
837
+ cacheIDNamespace string
838
+ targetPlatform ocispecs.Platform
839
+ buildPlatforms []ocispecs.Platform
840
+ extraHosts []llb.HostIP
841
+ shmSize int64
842
+ ulimit []pb.Ulimit
843
+ cgroupParent string
844
+ llbCaps * apicaps.CapSet
845
+ sourceMap * llb.SourceMap
846
+ lint * linter.Linter
847
+ dockerIgnoreMatcher * patternmatcher.PatternMatcher
825
848
}
826
849
827
850
func getEnv (state llb.State ) shell.EnvGetter {
@@ -908,6 +931,7 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
908
931
keepGitDir : c .KeepGitDir ,
909
932
checksum : checksum ,
910
933
location : c .Location (),
934
+ ignoreMatcher : opt .dockerIgnoreMatcher ,
911
935
opt : opt ,
912
936
})
913
937
}
@@ -942,12 +966,15 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
942
966
err = dispatchArg (d , c , & opt )
943
967
case * instructions.CopyCommand :
944
968
l := opt .buildContext
969
+ var ignoreMatcher * patternmatcher.PatternMatcher
945
970
if len (cmd .sources ) != 0 {
946
971
src := cmd .sources [0 ]
947
972
if ! src .noinit {
948
973
return errors .Errorf ("cannot copy from stage %q, it needs to be defined before current stage %q" , c .From , d .stageName )
949
974
}
950
975
l = src .state
976
+ } else {
977
+ ignoreMatcher = opt .dockerIgnoreMatcher
951
978
}
952
979
err = dispatchCopy (d , copyConfig {
953
980
params : c .SourcesAndDest ,
@@ -960,6 +987,7 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
960
987
link : c .Link ,
961
988
parents : c .Parents ,
962
989
location : c .Location (),
990
+ ignoreMatcher : ignoreMatcher ,
963
991
opt : opt ,
964
992
})
965
993
if err == nil {
@@ -1438,6 +1466,7 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error {
1438
1466
a = a .Copy (st , f , dest , opts ... )
1439
1467
}
1440
1468
} else {
1469
+ validateCopySourcePath (src , & cfg )
1441
1470
var patterns []string
1442
1471
if cfg .parents {
1443
1472
// detect optional pivot point
@@ -1554,6 +1583,7 @@ type copyConfig struct {
1554
1583
checksum digest.Digest
1555
1584
parents bool
1556
1585
location []parser.Range
1586
+ ignoreMatcher * patternmatcher.PatternMatcher
1557
1587
opt dispatchOpt
1558
1588
}
1559
1589
@@ -1867,6 +1897,27 @@ func addReachableStages(s *dispatchState, stages map[*dispatchState]struct{}) {
1867
1897
}
1868
1898
}
1869
1899
1900
+ func validateCopySourcePath (src string , cfg * copyConfig ) error {
1901
+ if cfg .ignoreMatcher == nil {
1902
+ return nil
1903
+ }
1904
+ cmd := "Copy"
1905
+ if cfg .isAddCommand {
1906
+ cmd = "Add"
1907
+ }
1908
+
1909
+ ok , err := cfg .ignoreMatcher .MatchesOrParentMatches (src )
1910
+ if err != nil {
1911
+ return err
1912
+ }
1913
+ if ok {
1914
+ msg := linter .RuleCopyIgnoredFile .Format (cmd , src )
1915
+ cfg .opt .lint .Run (& linter .RuleCopyIgnoredFile , cfg .location , msg )
1916
+ }
1917
+
1918
+ return nil
1919
+ }
1920
+
1870
1921
func validateCircularDependency (states []* dispatchState ) error {
1871
1922
var visit func (* dispatchState , []instructions.Command ) []instructions.Command
1872
1923
if states == nil {
@@ -2300,6 +2351,31 @@ func reportRedundantTargetPlatform(platformVar string, nameMatch shell.ProcessWo
2300
2351
}
2301
2352
}
2302
2353
2354
+ func reportConstPlatformDisallowed (stageName string , nameMatch shell.ProcessWordResult , location []parser.Range , lint * linter.Linter ) {
2355
+ if len (nameMatch .Matched ) > 0 || len (nameMatch .Unmatched ) > 0 {
2356
+ // Some substitution happened so the platform was not a constant.
2357
+ // Disable checking for this warning.
2358
+ return
2359
+ }
2360
+
2361
+ // Attempt to parse the platform result. If this fails, then it will fail
2362
+ // later so just ignore.
2363
+ p , err := platforms .Parse (nameMatch .Result )
2364
+ if err != nil {
2365
+ return
2366
+ }
2367
+
2368
+ // Check if the platform os or architecture is used in the stage name
2369
+ // at all. If it is, then disable this warning.
2370
+ if strings .Contains (stageName , p .OS ) || strings .Contains (stageName , p .Architecture ) {
2371
+ return
2372
+ }
2373
+
2374
+ // Report the linter warning.
2375
+ msg := linter .RuleFromPlatformFlagConstDisallowed .Format (nameMatch .Result )
2376
+ lint .Run (& linter .RuleFromPlatformFlagConstDisallowed , location , msg )
2377
+ }
2378
+
2303
2379
type instructionTracker struct {
2304
2380
Loc []parser.Range
2305
2381
IsSet bool
0 commit comments