@@ -36,6 +36,7 @@ import (
3636 "github.com/moby/buildkit/identity"
3737 "github.com/moby/buildkit/solver/pb"
3838 "github.com/moby/buildkit/util/apicaps"
39+ "github.com/moby/buildkit/util/gitutil"
3940 "github.com/moby/buildkit/util/suggest"
4041 "github.com/moby/buildkit/util/system"
4142 dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
@@ -1472,7 +1473,15 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error {
14721473 if len (cfg .params .SourcePaths ) != 1 {
14731474 return errors .New ("checksum can't be specified for multiple sources" )
14741475 }
1475- if ! isHTTPSource (cfg .params .SourcePaths [0 ]) && ! isGitSource (cfg .params .SourcePaths [0 ]) {
1476+ isHTTPSourceV , err := isHTTPSource (cfg .params .SourcePaths [0 ])
1477+ if err != nil {
1478+ return err
1479+ }
1480+ isGitSourceV , err := isGitSource (cfg .params .SourcePaths [0 ])
1481+ if err != nil {
1482+ return err
1483+ }
1484+ if ! isHTTPSourceV && ! isGitSourceV {
14761485 return errors .New ("checksum requires HTTP(S) or Git sources" )
14771486 }
14781487 }
@@ -1537,96 +1546,102 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error {
15371546 } else {
15381547 a = a .Copy (st , "/" , dest , opts ... )
15391548 }
1540- } else if isHTTPSource (src ) {
1541- if ! cfg .isAddCommand {
1542- return errors .New ("source can't be a URL for COPY" )
1549+ } else {
1550+ isHTTPSourceV , err := isHTTPSource (src )
1551+ if err != nil {
1552+ return err
15431553 }
1554+ if isHTTPSourceV {
1555+ if ! cfg .isAddCommand {
1556+ return errors .New ("source can't be a URL for COPY" )
1557+ }
15441558
1545- // Resources from remote URLs are not decompressed.
1546- // https://docs.docker.com/engine/reference/builder/#add
1547- //
1548- // Note: mixing up remote archives and local archives in a single ADD instruction
1549- // would result in undefined behavior: https://github.com/moby/buildkit/pull/387#discussion_r189494717
1550- u , err := url .Parse (src )
1551- f := "__unnamed__"
1552- if err == nil {
1553- if base := path .Base (u .Path ); base != "." && base != "/" {
1554- f = base
1559+ // Resources from remote URLs are not decompressed.
1560+ // https://docs.docker.com/engine/reference/builder/#add
1561+ //
1562+ // Note: mixing up remote archives and local archives in a single ADD instruction
1563+ // would result in undefined behavior: https://github.com/moby/buildkit/pull/387#discussion_r189494717
1564+ u , err := url .Parse (src )
1565+ f := "__unnamed__"
1566+ if err == nil {
1567+ if base := path .Base (u .Path ); base != "." && base != "/" {
1568+ f = base
1569+ }
15551570 }
1556- }
15571571
1558- var checksum digest.Digest
1559- if cfg .checksum != "" {
1560- checksum , err = digest .Parse (cfg .checksum )
1561- if err != nil {
1562- return err
1572+ var checksum digest.Digest
1573+ if cfg .checksum != "" {
1574+ checksum , err = digest .Parse (cfg .checksum )
1575+ if err != nil {
1576+ return err
1577+ }
15631578 }
1564- }
15651579
1566- st := llb .HTTP (src , llb .Filename (f ), llb .WithCustomName (pgName ), llb .Checksum (checksum ), dfCmd (cfg .params ))
1580+ st := llb .HTTP (src , llb .Filename (f ), llb .WithCustomName (pgName ), llb .Checksum (checksum ), dfCmd (cfg .params ))
15671581
1568- var unpack bool
1569- if cfg .unpack != nil {
1570- unpack = * cfg .unpack
1571- }
1582+ var unpack bool
1583+ if cfg .unpack != nil {
1584+ unpack = * cfg .unpack
1585+ }
15721586
1573- opts := append ([]llb.CopyOption {& llb.CopyInfo {
1574- Mode : chopt ,
1575- CreateDestPath : true ,
1576- AttemptUnpack : unpack ,
1577- }}, copyOpt ... )
1587+ opts := append ([]llb.CopyOption {& llb.CopyInfo {
1588+ Mode : chopt ,
1589+ CreateDestPath : true ,
1590+ AttemptUnpack : unpack ,
1591+ }}, copyOpt ... )
15781592
1579- if a == nil {
1580- a = llb .Copy (st , f , dest , opts ... )
1581- } else {
1582- a = a .Copy (st , f , dest , opts ... )
1583- }
1584- } else {
1585- validateCopySourcePath (src , & cfg )
1586- var patterns []string
1587- if cfg .parents {
1588- // detect optional pivot point
1589- parent , pattern , ok := strings .Cut (src , "/./" )
1590- if ! ok {
1591- pattern = src
1592- src = "/"
1593+ if a == nil {
1594+ a = llb .Copy (st , f , dest , opts ... )
15931595 } else {
1594- src = parent
1596+ a = a . Copy ( st , f , dest , opts ... )
15951597 }
1598+ } else {
1599+ validateCopySourcePath (src , & cfg )
1600+ var patterns []string
1601+ if cfg .parents {
1602+ // detect optional pivot point
1603+ parent , pattern , ok := strings .Cut (src , "/./" )
1604+ if ! ok {
1605+ pattern = src
1606+ src = "/"
1607+ } else {
1608+ src = parent
1609+ }
15961610
1597- pattern , err = system .NormalizePath ("/" , pattern , d .platform .OS , false )
1611+ pattern , err = system .NormalizePath ("/" , pattern , d .platform .OS , false )
1612+ if err != nil {
1613+ return errors .Wrap (err , "removing drive letter" )
1614+ }
1615+
1616+ patterns = []string {strings .TrimPrefix (pattern , "/" )}
1617+ }
1618+
1619+ src , err = system .NormalizePath ("/" , src , d .platform .OS , false )
15981620 if err != nil {
15991621 return errors .Wrap (err , "removing drive letter" )
16001622 }
16011623
1602- patterns = []string {strings .TrimPrefix (pattern , "/" )}
1603- }
1604-
1605- src , err = system .NormalizePath ("/" , src , d .platform .OS , false )
1606- if err != nil {
1607- return errors .Wrap (err , "removing drive letter" )
1608- }
1609-
1610- unpack := cfg .isAddCommand
1611- if cfg .unpack != nil {
1612- unpack = * cfg .unpack
1613- }
1614-
1615- opts := append ([]llb.CopyOption {& llb.CopyInfo {
1616- Mode : chopt ,
1617- FollowSymlinks : true ,
1618- CopyDirContentsOnly : true ,
1619- IncludePatterns : patterns ,
1620- AttemptUnpack : unpack ,
1621- CreateDestPath : true ,
1622- AllowWildcard : true ,
1623- AllowEmptyWildcard : true ,
1624- }}, copyOpt ... )
1624+ unpack := cfg .isAddCommand
1625+ if cfg .unpack != nil {
1626+ unpack = * cfg .unpack
1627+ }
16251628
1626- if a == nil {
1627- a = llb .Copy (cfg .source , src , dest , opts ... )
1628- } else {
1629- a = a .Copy (cfg .source , src , dest , opts ... )
1629+ opts := append ([]llb.CopyOption {& llb.CopyInfo {
1630+ Mode : chopt ,
1631+ FollowSymlinks : true ,
1632+ CopyDirContentsOnly : true ,
1633+ IncludePatterns : patterns ,
1634+ AttemptUnpack : unpack ,
1635+ CreateDestPath : true ,
1636+ AllowWildcard : true ,
1637+ AllowEmptyWildcard : true ,
1638+ }}, copyOpt ... )
1639+
1640+ if a == nil {
1641+ a = llb .Copy (cfg .source , src , dest , opts ... )
1642+ } else {
1643+ a = a .Copy (cfg .source , src , dest , opts ... )
1644+ }
16301645 }
16311646 }
16321647 }
@@ -2262,19 +2277,26 @@ func commonImageNames() []string {
22622277 return out
22632278}
22642279
2265- func isHTTPSource (src string ) bool {
2280+ func isHTTPSource (src string ) ( bool , error ) {
22662281 if ! strings .HasPrefix (src , "http://" ) && ! strings .HasPrefix (src , "https://" ) {
2267- return false
2282+ return false , nil
22682283 }
2269- return ! isGitSource (src )
2284+ b , err := isGitSource (src )
2285+ return ! b , err
22702286}
22712287
2272- func isGitSource (src string ) bool {
2288+ func isGitSource (src string ) ( bool , error ) {
22732289 // https://github.com/ORG/REPO.git is a git source, not an http source
2274- if gitRef , gitErr := dfgitutil .ParseGitRef (src ); gitRef != nil && gitErr == nil {
2275- return true
2290+ gitRef , gitErr := dfgitutil .ParseGitRef (src )
2291+ var guoe * gitutil.GitURLOptsError
2292+ if errors .As (gitErr , & guoe ) {
2293+ // this is a git source, and it has invalid URL opts
2294+ return true , gitErr
2295+ }
2296+ if gitRef != nil && gitErr == nil {
2297+ return true , nil
22762298 }
2277- return false
2299+ return false , nil
22782300}
22792301
22802302func isEnabledForStage (stage string , value string ) bool {
0 commit comments