Merge pull request #3397 from tonistiigi/update-buildkit-v0.24.0-rc2
vendor: update buildkit to v0.24.0-rc2
This commit is contained in:
+5
-1
@@ -32,8 +32,12 @@ func ReadRemoteFiles(ctx context.Context, nodes []builder.Node, url string, name
|
||||
var sessions []session.Attachable
|
||||
var filename string
|
||||
|
||||
st, ok := dockerui.DetectGitContext(url, false)
|
||||
keepGitDir := false
|
||||
st, ok, err := dockerui.DetectGitContext(url, &keepGitDir)
|
||||
if ok {
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if ssh, err := build.CreateSSH([]*buildflags.SSH{{
|
||||
ID: "default",
|
||||
Paths: strings.Split(os.Getenv("BUILDX_BAKE_GIT_SSH"), ","),
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ func IsRemoteURL(c string) bool {
|
||||
if isHTTPURL(c) {
|
||||
return true
|
||||
}
|
||||
if _, err := dfgitutil.ParseGitRef(c); err == nil {
|
||||
if _, ok, _ := dfgitutil.ParseGitRef(c); ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -332,7 +332,7 @@ func valueFiler(key, value, sep string) matchFunc {
|
||||
recValue = v
|
||||
} else {
|
||||
if context, ok := rec.FrontendAttrs["context"]; ok {
|
||||
if ref, err := dfgitutil.ParseGitRef(context); err == nil {
|
||||
if ref, _, err := dfgitutil.ParseGitRef(context); err == nil {
|
||||
recValue = ref.Remote
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ require (
|
||||
github.com/hashicorp/hcl/v2 v2.23.0
|
||||
github.com/in-toto/in-toto-golang v0.9.0
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/moby/buildkit v0.24.0-rc1
|
||||
github.com/moby/buildkit v0.24.0-rc2
|
||||
github.com/moby/go-archive v0.1.0
|
||||
github.com/moby/sys/atomicwriter v0.1.0
|
||||
github.com/moby/sys/mountinfo v0.7.2
|
||||
|
||||
@@ -255,8 +255,8 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/moby/buildkit v0.24.0-rc1 h1:taA+MPeYWtGyRQ1SGbdTHVk5khWKFR7f9WI2coW/Ggs=
|
||||
github.com/moby/buildkit v0.24.0-rc1/go.mod h1:4qovICAdR2H4C7+EGMRva5zgHW1gyhT4/flHI7F5F9k=
|
||||
github.com/moby/buildkit v0.24.0-rc2 h1:1Z9+R162yauf3SYvn8cGjBPnglMDK4bO+00dNlJSgZI=
|
||||
github.com/moby/buildkit v0.24.0-rc2/go.mod h1:4qovICAdR2H4C7+EGMRva5zgHW1gyhT4/flHI7F5F9k=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
||||
|
||||
+50
-11
@@ -247,9 +247,13 @@ const (
|
||||
// Formats that utilize SSH may need to supply credentials as a [GitOption].
|
||||
// You may need to check the source code for a full list of supported formats.
|
||||
//
|
||||
// Fragment can be used to pass ref:subdir format that can set in (old-style)
|
||||
// Docker Git URL format after # . This is provided for backwards compatibility.
|
||||
// It is recommended to leave it empty and call GitRef(), GitSubdir() options instead.
|
||||
//
|
||||
// By default the git repository is cloned with `--depth=1` to reduce the amount of data downloaded.
|
||||
// Additionally the ".git" directory is removed after the clone, you can keep ith with the [KeepGitDir] [GitOption].
|
||||
func Git(url, ref string, opts ...GitOption) State {
|
||||
func Git(url, fragment string, opts ...GitOption) State {
|
||||
remote, err := gitutil.ParseURL(url)
|
||||
if errors.Is(err, gitutil.ErrUnknownProtocol) {
|
||||
url = "https://" + url
|
||||
@@ -259,6 +263,20 @@ func Git(url, ref string, opts ...GitOption) State {
|
||||
url = remote.Remote
|
||||
}
|
||||
|
||||
gi := &GitInfo{
|
||||
AuthHeaderSecret: GitAuthHeaderKey,
|
||||
AuthTokenSecret: GitAuthTokenKey,
|
||||
}
|
||||
ref, subdir, ok := strings.Cut(fragment, ":")
|
||||
if ref != "" {
|
||||
GitRef(ref).SetGitOption(gi)
|
||||
}
|
||||
if ok && subdir != "" {
|
||||
GitSubDir(subdir).SetGitOption(gi)
|
||||
}
|
||||
for _, o := range opts {
|
||||
o.SetGitOption(gi)
|
||||
}
|
||||
var id string
|
||||
if err != nil {
|
||||
// If we can't parse the URL, just use the full URL as the ID. The git
|
||||
@@ -269,18 +287,13 @@ func Git(url, ref string, opts ...GitOption) State {
|
||||
// for different protocols (e.g. https and ssh) that have the same
|
||||
// host/path/fragment combination.
|
||||
id = remote.Host + path.Join("/", remote.Path)
|
||||
if ref != "" {
|
||||
id += "#" + ref
|
||||
if gi.Ref != "" || gi.SubDir != "" {
|
||||
id += "#" + gi.Ref
|
||||
if gi.SubDir != "" {
|
||||
id += ":" + gi.SubDir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gi := &GitInfo{
|
||||
AuthHeaderSecret: GitAuthHeaderKey,
|
||||
AuthTokenSecret: GitAuthTokenKey,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o.SetGitOption(gi)
|
||||
}
|
||||
attrs := map[string]string{}
|
||||
if gi.KeepGitDir {
|
||||
attrs[pb.AttrKeepGitDir] = "true"
|
||||
@@ -328,6 +341,11 @@ func Git(url, ref string, opts ...GitOption) State {
|
||||
addCap(&gi.Constraints, pb.CapSourceGitChecksum)
|
||||
}
|
||||
|
||||
if gi.SkipSubmodules {
|
||||
attrs[pb.AttrGitSkipSubmodules] = "true"
|
||||
addCap(&gi.Constraints, pb.CapSourceGitSkipSubmodules)
|
||||
}
|
||||
|
||||
addCap(&gi.Constraints, pb.CapSourceGit)
|
||||
|
||||
source := NewSource("git://"+id, attrs, gi.Constraints)
|
||||
@@ -352,6 +370,27 @@ type GitInfo struct {
|
||||
KnownSSHHosts string
|
||||
MountSSHSock string
|
||||
Checksum string
|
||||
Ref string
|
||||
SubDir string
|
||||
SkipSubmodules bool
|
||||
}
|
||||
|
||||
func GitRef(v string) GitOption {
|
||||
return gitOptionFunc(func(gi *GitInfo) {
|
||||
gi.Ref = v
|
||||
})
|
||||
}
|
||||
|
||||
func GitSubDir(v string) GitOption {
|
||||
return gitOptionFunc(func(gi *GitInfo) {
|
||||
gi.SubDir = v
|
||||
})
|
||||
}
|
||||
|
||||
func GitSkipSubmodules() GitOption {
|
||||
return gitOptionFunc(func(gi *GitInfo) {
|
||||
gi.SkipSubmodules = true
|
||||
})
|
||||
}
|
||||
|
||||
func KeepGitDir() GitOption {
|
||||
|
||||
+125
-17
@@ -3,6 +3,7 @@ package dfgitutil
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
@@ -23,9 +24,12 @@ type GitRef struct {
|
||||
// e.g., "bar" for "https://github.com/foo/bar.git"
|
||||
ShortName string
|
||||
|
||||
// Commit is a commit hash, a tag, or branch name.
|
||||
// Commit is optional.
|
||||
Commit string
|
||||
// Ref is a commit hash, a tag, or branch name.
|
||||
// Ref is optional.
|
||||
Ref string
|
||||
|
||||
// Checksum is a commit hash.
|
||||
Checksum string
|
||||
|
||||
// SubDir is a directory path inside the repo.
|
||||
// SubDir is optional.
|
||||
@@ -46,12 +50,16 @@ type GitRef struct {
|
||||
// Discouraged, although not deprecated.
|
||||
// Instead, consider using an encrypted TCP connection such as "git@github.com/foo/bar.git" or "https://github.com/foo/bar.git".
|
||||
UnencryptedTCP bool
|
||||
|
||||
// KeepGitDir is true for URL that controls whether to keep the .git directory.
|
||||
KeepGitDir *bool
|
||||
|
||||
// Submodules is true for URL that controls whether to fetch git submodules.
|
||||
Submodules *bool
|
||||
}
|
||||
|
||||
// var gitURLPathWithFragmentSuffix = regexp.MustCompile(`\.git(?:#.+)?$`)
|
||||
|
||||
// ParseGitRef parses a git ref.
|
||||
func ParseGitRef(ref string) (*GitRef, error) {
|
||||
func ParseGitRef(ref string) (*GitRef, bool, error) {
|
||||
res := &GitRef{}
|
||||
|
||||
var (
|
||||
@@ -60,21 +68,25 @@ func ParseGitRef(ref string) (*GitRef, error) {
|
||||
)
|
||||
|
||||
if strings.HasPrefix(ref, "./") || strings.HasPrefix(ref, "../") {
|
||||
return nil, cerrdefs.ErrInvalidArgument
|
||||
return nil, false, errors.WithStack(cerrdefs.ErrInvalidArgument)
|
||||
} else if strings.HasPrefix(ref, "github.com/") {
|
||||
res.IndistinguishableFromLocal = true // Deprecated
|
||||
remote = gitutil.FromURL(&url.URL{
|
||||
Scheme: "https",
|
||||
Host: "github.com",
|
||||
Path: strings.TrimPrefix(ref, "github.com/"),
|
||||
})
|
||||
u, err := url.Parse(ref)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
u.Scheme = "https"
|
||||
remote, err = gitutil.FromURL(u)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
} else {
|
||||
remote, err = gitutil.ParseURL(ref)
|
||||
if errors.Is(err, gitutil.ErrUnknownProtocol) {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
switch remote.Scheme {
|
||||
@@ -86,7 +98,7 @@ func ParseGitRef(ref string) (*GitRef, error) {
|
||||
// An HTTP(S) URL is considered to be a valid git ref only when it has the ".git[...]" suffix.
|
||||
case gitutil.HTTPProtocol, gitutil.HTTPSProtocol:
|
||||
if !strings.HasSuffix(remote.Path, ".git") {
|
||||
return nil, cerrdefs.ErrInvalidArgument
|
||||
return nil, false, errors.WithStack(cerrdefs.ErrInvalidArgument)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,11 +108,107 @@ func ParseGitRef(ref string) (*GitRef, error) {
|
||||
_, res.Remote, _ = strings.Cut(res.Remote, "://")
|
||||
}
|
||||
if remote.Opts != nil {
|
||||
res.Commit, res.SubDir = remote.Opts.Ref, remote.Opts.Subdir
|
||||
res.Ref, res.SubDir = remote.Opts.Ref, remote.Opts.Subdir
|
||||
}
|
||||
|
||||
repoSplitBySlash := strings.Split(res.Remote, "/")
|
||||
res.ShortName = strings.TrimSuffix(repoSplitBySlash[len(repoSplitBySlash)-1], ".git")
|
||||
|
||||
return res, nil
|
||||
if err := res.loadQuery(remote.Query); err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
|
||||
return res, true, nil
|
||||
}
|
||||
|
||||
func (gf *GitRef) loadQuery(query url.Values) error {
|
||||
if len(query) == 0 {
|
||||
return nil
|
||||
}
|
||||
var tag, branch string
|
||||
for k, v := range query {
|
||||
switch len(v) {
|
||||
case 0, 1:
|
||||
if len(v) == 0 || v[0] == "" {
|
||||
switch k {
|
||||
case "submodules", "keep-git-dir":
|
||||
v = nil
|
||||
default:
|
||||
return errors.Errorf("query %q has no value", k)
|
||||
}
|
||||
}
|
||||
// NOP
|
||||
default:
|
||||
return errors.Errorf("query %q has multiple values", k)
|
||||
}
|
||||
switch k {
|
||||
case "ref":
|
||||
if gf.Ref != "" && gf.Ref != v[0] {
|
||||
return errors.Errorf("ref conflicts: %q vs %q", gf.Ref, v[0])
|
||||
}
|
||||
gf.Ref = v[0]
|
||||
case "tag":
|
||||
tag = v[0]
|
||||
case "branch":
|
||||
branch = v[0]
|
||||
case "subdir":
|
||||
if gf.SubDir != "" && gf.SubDir != v[0] {
|
||||
return errors.Errorf("subdir conflicts: %q vs %q", gf.SubDir, v[0])
|
||||
}
|
||||
gf.SubDir = v[0]
|
||||
case "checksum", "commit":
|
||||
gf.Checksum = v[0]
|
||||
case "keep-git-dir":
|
||||
var vv bool
|
||||
if len(v) == 0 {
|
||||
vv = true
|
||||
} else {
|
||||
var err error
|
||||
vv, err = strconv.ParseBool(v[0])
|
||||
if err != nil {
|
||||
return errors.Errorf("invalid keep-git-dir value: %q", v[0])
|
||||
}
|
||||
}
|
||||
gf.KeepGitDir = &vv
|
||||
case "submodules":
|
||||
var vv bool
|
||||
if len(v) == 0 {
|
||||
vv = true
|
||||
} else {
|
||||
var err error
|
||||
vv, err = strconv.ParseBool(v[0])
|
||||
if err != nil {
|
||||
return errors.Errorf("invalid submodules value: %q", v[0])
|
||||
}
|
||||
}
|
||||
gf.Submodules = &vv
|
||||
default:
|
||||
return errors.Errorf("unexpected query %q", k)
|
||||
}
|
||||
}
|
||||
if tag != "" {
|
||||
const tagPrefix = "refs/tags/"
|
||||
if !strings.HasPrefix(tag, tagPrefix) {
|
||||
tag = tagPrefix + tag
|
||||
}
|
||||
if gf.Ref != "" && gf.Ref != tag {
|
||||
return errors.Errorf("ref conflicts: %q vs %q", gf.Ref, tag)
|
||||
}
|
||||
gf.Ref = tag
|
||||
}
|
||||
if branch != "" {
|
||||
if tag != "" {
|
||||
// TODO: consider allowing this, when the tag actually exists on the branch
|
||||
return errors.New("branch conflicts with tag")
|
||||
}
|
||||
const branchPrefix = "refs/heads/"
|
||||
if !strings.HasPrefix(branch, branchPrefix) {
|
||||
branch = branchPrefix + branch
|
||||
}
|
||||
if gf.Ref != "" && gf.Ref != branch {
|
||||
return errors.Errorf("ref conflicts: %q vs %q", gf.Ref, branch)
|
||||
}
|
||||
gf.Ref = branch
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+27
-13
@@ -69,11 +69,14 @@ func (bc *Client) initContext(ctx context.Context) (*buildContext, error) {
|
||||
bctx.dockerfileLocalName = v
|
||||
}
|
||||
|
||||
keepGit := false
|
||||
var keepGit *bool
|
||||
if v, err := strconv.ParseBool(opts[keyContextKeepGitDirArg]); err == nil {
|
||||
keepGit = v
|
||||
keepGit = &v
|
||||
}
|
||||
if st, ok := DetectGitContext(opts[localNameContext], keepGit); ok {
|
||||
if st, ok, err := DetectGitContext(opts[localNameContext], keepGit); ok {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bctx.context = st
|
||||
bctx.dockerfile = st
|
||||
} else if st, filename, ok := DetectHTTPContext(opts[localNameContext]); ok {
|
||||
@@ -140,22 +143,33 @@ func (bc *Client) initContext(ctx context.Context) (*buildContext, error) {
|
||||
return bctx, nil
|
||||
}
|
||||
|
||||
func DetectGitContext(ref string, keepGit bool) (*llb.State, bool) {
|
||||
g, err := dfgitutil.ParseGitRef(ref)
|
||||
func DetectGitContext(ref string, keepGit *bool) (*llb.State, bool, error) {
|
||||
g, isGit, err := dfgitutil.ParseGitRef(ref)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
return nil, isGit, err
|
||||
}
|
||||
commit := g.Commit
|
||||
if g.SubDir != "" {
|
||||
commit += ":" + g.SubDir
|
||||
gitOpts := []llb.GitOption{
|
||||
llb.GitRef(g.Ref),
|
||||
WithInternalName("load git source " + ref),
|
||||
}
|
||||
gitOpts := []llb.GitOption{WithInternalName("load git source " + ref)}
|
||||
if keepGit {
|
||||
if g.KeepGitDir != nil && *g.KeepGitDir {
|
||||
gitOpts = append(gitOpts, llb.KeepGitDir())
|
||||
}
|
||||
if keepGit != nil && *keepGit {
|
||||
gitOpts = append(gitOpts, llb.KeepGitDir())
|
||||
}
|
||||
if g.SubDir != "" {
|
||||
gitOpts = append(gitOpts, llb.GitSubDir(g.SubDir))
|
||||
}
|
||||
if g.Checksum != "" {
|
||||
gitOpts = append(gitOpts, llb.GitChecksum(g.Checksum))
|
||||
}
|
||||
if g.Submodules != nil && !*g.Submodules {
|
||||
gitOpts = append(gitOpts, llb.GitSkipSubmodules())
|
||||
}
|
||||
|
||||
st := llb.Git(g.Remote, commit, gitOpts...)
|
||||
return &st, true
|
||||
st := llb.Git(g.Remote, "", gitOpts...)
|
||||
return &st, true, nil
|
||||
}
|
||||
|
||||
func DetectHTTPContext(ref string) (*llb.State, string, bool) {
|
||||
|
||||
+8
-2
@@ -138,17 +138,23 @@ func (nc *NamedContext) load(ctx context.Context, count int) (*llb.State, *docke
|
||||
}
|
||||
return &st, &img, nil
|
||||
case "git":
|
||||
st, ok := DetectGitContext(nc.input, true)
|
||||
st, ok, err := DetectGitContext(nc.input, nil)
|
||||
if !ok {
|
||||
return nil, nil, errors.Errorf("invalid git context %s", nc.input)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return st, nil, nil
|
||||
case "http", "https":
|
||||
st, ok := DetectGitContext(nc.input, true)
|
||||
st, ok, err := DetectGitContext(nc.input, nil)
|
||||
if !ok {
|
||||
httpst := llb.HTTP(nc.input, llb.WithCustomName("[context "+nc.nameWithPlatform+"] "+nc.input))
|
||||
st = &httpst
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return st, nil, nil
|
||||
case "oci-layout":
|
||||
refSpec := strings.TrimPrefix(vv[1], "//")
|
||||
|
||||
+1
@@ -7,6 +7,7 @@ const AttrAuthTokenSecret = "git.authtokensecret"
|
||||
const AttrKnownSSHHosts = "git.knownsshhosts"
|
||||
const AttrMountSSHSock = "git.mountsshsock"
|
||||
const AttrGitChecksum = "git.checksum"
|
||||
const AttrGitSkipSubmodules = "git.skipsubmodules"
|
||||
|
||||
const AttrLocalSessionID = "local.session"
|
||||
const AttrLocalUniqueID = "local.unique"
|
||||
|
||||
+15
-8
@@ -23,14 +23,15 @@ const (
|
||||
CapSourceLocalDiffer apicaps.CapID = "source.local.differ"
|
||||
CapSourceMetadataTransfer apicaps.CapID = "source.local.metadatatransfer"
|
||||
|
||||
CapSourceGit apicaps.CapID = "source.git"
|
||||
CapSourceGitKeepDir apicaps.CapID = "source.git.keepgitdir"
|
||||
CapSourceGitFullURL apicaps.CapID = "source.git.fullurl"
|
||||
CapSourceGitHTTPAuth apicaps.CapID = "source.git.httpauth"
|
||||
CapSourceGitKnownSSHHosts apicaps.CapID = "source.git.knownsshhosts"
|
||||
CapSourceGitMountSSHSock apicaps.CapID = "source.git.mountsshsock"
|
||||
CapSourceGitSubdir apicaps.CapID = "source.git.subdir"
|
||||
CapSourceGitChecksum apicaps.CapID = "source.git.checksum"
|
||||
CapSourceGit apicaps.CapID = "source.git"
|
||||
CapSourceGitKeepDir apicaps.CapID = "source.git.keepgitdir"
|
||||
CapSourceGitFullURL apicaps.CapID = "source.git.fullurl"
|
||||
CapSourceGitHTTPAuth apicaps.CapID = "source.git.httpauth"
|
||||
CapSourceGitKnownSSHHosts apicaps.CapID = "source.git.knownsshhosts"
|
||||
CapSourceGitMountSSHSock apicaps.CapID = "source.git.mountsshsock"
|
||||
CapSourceGitSubdir apicaps.CapID = "source.git.subdir"
|
||||
CapSourceGitChecksum apicaps.CapID = "source.git.checksum"
|
||||
CapSourceGitSkipSubmodules apicaps.CapID = "source.git.skipsubmodules"
|
||||
|
||||
CapSourceHTTP apicaps.CapID = "source.http"
|
||||
CapSourceHTTPAuth apicaps.CapID = "source.http.auth"
|
||||
@@ -229,6 +230,12 @@ func init() {
|
||||
Status: apicaps.CapStatusExperimental,
|
||||
})
|
||||
|
||||
Caps.Init(apicaps.Cap{
|
||||
ID: CapSourceGitSkipSubmodules,
|
||||
Enabled: true,
|
||||
Status: apicaps.CapStatusExperimental,
|
||||
})
|
||||
|
||||
Caps.Init(apicaps.Cap{
|
||||
ID: CapSourceHTTP,
|
||||
Enabled: true,
|
||||
|
||||
+21
-8
@@ -47,16 +47,17 @@ type GitURL struct {
|
||||
Path string
|
||||
// User is the username/password to access the host
|
||||
User *url.Userinfo
|
||||
// Query is the query parameters for the URL
|
||||
Query url.Values
|
||||
// Opts can contain additional metadata
|
||||
Opts *GitURLOpts
|
||||
|
||||
// Remote is a valid URL remote to pass into the Git CLI tooling (i.e.
|
||||
// without the fragment metadata)
|
||||
Remote string
|
||||
}
|
||||
|
||||
// GitURLOpts is the buildkit-specific metadata extracted from the fragment
|
||||
// of a remote URL.
|
||||
// or the query of a remote URL.
|
||||
type GitURLOpts struct {
|
||||
// Ref is the git reference
|
||||
Ref string
|
||||
@@ -86,11 +87,11 @@ func ParseURL(remote string) (*GitURL, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return FromURL(url), nil
|
||||
return FromURL(url)
|
||||
}
|
||||
|
||||
if url, err := sshutil.ParseSCPStyleURL(remote); err == nil {
|
||||
return fromSCPStyleURL(url), nil
|
||||
return fromSCPStyleURL(url)
|
||||
}
|
||||
|
||||
return nil, ErrUnknownProtocol
|
||||
@@ -105,28 +106,40 @@ func IsGitTransport(remote string) bool {
|
||||
return sshutil.IsImplicitSSHTransport(remote)
|
||||
}
|
||||
|
||||
func FromURL(url *url.URL) *GitURL {
|
||||
func FromURL(url *url.URL) (*GitURL, error) {
|
||||
withoutOpts := *url
|
||||
withoutOpts.Fragment = ""
|
||||
withoutOpts.RawQuery = ""
|
||||
q := url.Query()
|
||||
if len(q) == 0 {
|
||||
q = nil
|
||||
}
|
||||
return &GitURL{
|
||||
Scheme: url.Scheme,
|
||||
User: url.User,
|
||||
Host: url.Host,
|
||||
Path: url.Path,
|
||||
Query: q,
|
||||
Opts: parseOpts(url.Fragment),
|
||||
Remote: withoutOpts.String(),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func fromSCPStyleURL(url *sshutil.SCPStyleURL) *GitURL {
|
||||
func fromSCPStyleURL(url *sshutil.SCPStyleURL) (*GitURL, error) {
|
||||
withoutOpts := *url
|
||||
withoutOpts.Fragment = ""
|
||||
withoutOpts.Query = nil
|
||||
q := url.Query
|
||||
if len(q) == 0 {
|
||||
q = nil
|
||||
}
|
||||
return &GitURL{
|
||||
Scheme: SSHProtocol,
|
||||
User: url.User,
|
||||
Host: url.Host,
|
||||
Path: url.Path,
|
||||
Query: q,
|
||||
Opts: parseOpts(url.Fragment),
|
||||
Remote: withoutOpts.String(),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
+26
-8
@@ -1,13 +1,14 @@
|
||||
package sshutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var gitSSHRegex = regexp.MustCompile("^([a-zA-Z0-9-_]+)@([a-zA-Z0-9-.]+):(.*?)(?:#(.*))?$")
|
||||
var gitSSHRegex = regexp.MustCompile(`^([a-zA-Z0-9-_]+)@([a-zA-Z0-9-.]+):(.*?)(?:\?(.*?))?(?:#(.*))?$`)
|
||||
|
||||
func IsImplicitSSHTransport(s string) bool {
|
||||
return gitSSHRegex.MatchString(s)
|
||||
@@ -18,6 +19,7 @@ type SCPStyleURL struct {
|
||||
Host string
|
||||
|
||||
Path string
|
||||
Query url.Values
|
||||
Fragment string
|
||||
}
|
||||
|
||||
@@ -26,18 +28,34 @@ func ParseSCPStyleURL(raw string) (*SCPStyleURL, error) {
|
||||
if matches == nil {
|
||||
return nil, errors.New("invalid scp-style url")
|
||||
}
|
||||
|
||||
rawQuery := matches[4]
|
||||
vals := url.Values{}
|
||||
if rawQuery != "" {
|
||||
var err error
|
||||
vals, err = url.ParseQuery(rawQuery)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "invalid query in scp-style url")
|
||||
}
|
||||
}
|
||||
|
||||
return &SCPStyleURL{
|
||||
User: url.User(matches[1]),
|
||||
Host: matches[2],
|
||||
Path: matches[3],
|
||||
Fragment: matches[4],
|
||||
Query: vals,
|
||||
Fragment: matches[5],
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (url *SCPStyleURL) String() string {
|
||||
base := fmt.Sprintf("%s@%s:%s", url.User.String(), url.Host, url.Path)
|
||||
if url.Fragment == "" {
|
||||
return base
|
||||
func (u *SCPStyleURL) String() string {
|
||||
s := fmt.Sprintf("%s@%s:%s", u.User.String(), u.Host, u.Path)
|
||||
|
||||
if len(u.Query) > 0 {
|
||||
s += "?" + u.Query.Encode()
|
||||
}
|
||||
return base + "#" + url.Fragment
|
||||
if u.Fragment != "" {
|
||||
s += "#" + u.Fragment
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -450,7 +450,7 @@ github.com/mitchellh/go-wordwrap
|
||||
# github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
## explicit; go 1.14
|
||||
github.com/mitchellh/hashstructure/v2
|
||||
# github.com/moby/buildkit v0.24.0-rc1
|
||||
# github.com/moby/buildkit v0.24.0-rc2
|
||||
## explicit; go 1.23.0
|
||||
github.com/moby/buildkit/api/services/control
|
||||
github.com/moby/buildkit/api/types
|
||||
|
||||
Reference in New Issue
Block a user