diff --git a/build/utils.go b/build/utils.go index 52d501886719..e0f891c465fc 100644 --- a/build/utils.go +++ b/build/utils.go @@ -36,7 +36,7 @@ func IsRemoteURL(c string) bool { if isHTTPURL(c) { return true } - if _, err := gitutil.ParseGitRef(c); err == nil { + if _, err := gitutil.ParseURL(c); err == nil { return true } return false diff --git a/commands/history/utils.go b/commands/history/utils.go index 2e64889fca1b..cacc2889e6b1 100644 --- a/commands/history/utils.go +++ b/commands/history/utils.go @@ -332,7 +332,7 @@ func valueFiler(key, value, sep string) matchFunc { recValue = v } else { if context, ok := rec.FrontendAttrs["context"]; ok { - if ref, err := gitutil.ParseGitRef(context); err == nil { + if ref, err := gitutil.ParseURL(context); err == nil { recValue = ref.Remote } } diff --git a/go.mod b/go.mod index 4420a82a02be..ea2958746f01 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,7 @@ require ( go.opentelemetry.io/otel/trace v1.35.0 go.yaml.in/yaml/v3 v3.0.4 golang.org/x/mod v0.24.0 - golang.org/x/sync v0.14.0 + golang.org/x/sync v0.16.0 golang.org/x/sys v0.33.0 golang.org/x/term v0.31.0 golang.org/x/text v0.24.0 @@ -183,3 +183,5 @@ exclude ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 ) + +replace github.com/moby/buildkit => github.com/AkihiroSuda/buildkit_poc v0.3.2-0.20250822084057-35db37f482db diff --git a/go.sum b/go.sum index b6ab7e69b2ef..b085ef7b9227 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/AkihiroSuda/buildkit_poc v0.3.2-0.20250822084057-35db37f482db h1:DnWyqVaJ9Z6pbF0YApuPfKqOtIHnpNK64PC9x/6LTuA= +github.com/AkihiroSuda/buildkit_poc v0.3.2-0.20250822084057-35db37f482db/go.mod h1:y26Pe5wkRx9WW45Aqz/gvggTsnZNekavQ7Kt5SPx1e0= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -254,8 +256,6 @@ 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.23.0-rc1.0.20250806140246-955c2b2f7d01 h1:ua0f++eVvjBLs77tBmg5Ko2x6BTgjULihEu03ogLBC8= -github.com/moby/buildkit v0.23.0-rc1.0.20250806140246-955c2b2f7d01/go.mod h1:8qy9VSHDZuin0BnQzxbRGSXFKQiT0cgeKLWiNRw4/5Q= 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= @@ -468,8 +468,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/moby/buildkit/client/llb/source.go b/vendor/github.com/moby/buildkit/client/llb/source.go index d6eba0758981..d124f8dac0e4 100644 --- a/vendor/github.com/moby/buildkit/client/llb/source.go +++ b/vendor/github.com/moby/buildkit/client/llb/source.go @@ -249,7 +249,10 @@ const ( // // 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]. +// +// Git is planned to be deprecated. Use [Git2] instead whenever possible. func Git(url, ref string, opts ...GitOption) State { + // The logic is complicated for compatibility reason. remote, err := gitutil.ParseURL(url) if errors.Is(err, gitutil.ErrUnknownProtocol) { url = "https://" + url @@ -257,23 +260,34 @@ func Git(url, ref string, opts ...GitOption) State { } if remote != nil { url = remote.Remote + if remote.Opts != nil { + opts = append(opts, GitChecksum(remote.Opts.Checksum)) + } + } + if url != "" { + opts = append(opts, GitFullURL(url)) } - var id string if err != nil { // If we can't parse the URL, just use the full URL as the ID. The git // operation will fail later on. - id = url - } else { - // We construct the ID manually here, so that we can create the same ID - // 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 - } + return git(url, nil, opts...) } + opts = append(opts, GitIDSuffix(ref)) + return Git2(remote.GitURLBase, opts...) +} + +// Git2 is similar to Git but takes [gitutil.GitURLBase] as the argument. +func Git2(remote gitutil.GitURLBase, opts ...GitOption) State { + // We construct the ID manually here, so that we can create the same ID + // for different protocols (e.g. https and ssh) that have the same + // host/path/fragment combination. + id := remote.Host + path.Join("/", remote.Path) + return git(id, &remote, opts...) +} + +func git(id string, remote *gitutil.GitURLBase, opts ...GitOption) State { gi := &GitInfo{ AuthHeaderSecret: GitAuthHeaderKey, AuthTokenSecret: GitAuthTokenKey, @@ -281,13 +295,16 @@ func Git(url, ref string, opts ...GitOption) State { for _, o := range opts { o.SetGitOption(gi) } + if gi.IDSuffix != "" { + id += "#" + gi.IDSuffix + } attrs := map[string]string{} if gi.KeepGitDir { attrs[pb.AttrKeepGitDir] = "true" addCap(&gi.Constraints, pb.CapSourceGitKeepDir) } - if url != "" { - attrs[pb.AttrFullRemoteURL] = url + if gi.FullURL != "" { + attrs[pb.AttrFullRemoteURL] = gi.FullURL addCap(&gi.Constraints, pb.CapSourceGitFullURL) } if gi.AuthTokenSecret != "" { @@ -352,6 +369,8 @@ type GitInfo struct { KnownSSHHosts string MountSSHSock string Checksum string + FullURL string + IDSuffix string // Appended after '#'. Exists only for sake of compatibility. } func KeepGitDir() GitOption { @@ -386,6 +405,18 @@ func GitChecksum(v string) GitOption { }) } +func GitFullURL(v string) GitOption { + return gitOptionFunc(func(gi *GitInfo) { + gi.FullURL = v + }) +} + +func GitIDSuffix(v string) GitOption { + return gitOptionFunc(func(gi *GitInfo) { + gi.IDSuffix = v + }) +} + // AuthOption can be used with either HTTP or Git sources. type AuthOption interface { GitOption diff --git a/vendor/github.com/moby/buildkit/util/gitutil/git_ref.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dfgitutil/git_ref.go similarity index 78% rename from vendor/github.com/moby/buildkit/util/gitutil/git_ref.go rename to vendor/github.com/moby/buildkit/frontend/dockerfile/dfgitutil/git_ref.go index cb562acf5481..1f76b47279a0 100644 --- a/vendor/github.com/moby/buildkit/util/gitutil/git_ref.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dfgitutil/git_ref.go @@ -1,10 +1,12 @@ -package gitutil +// Package dfgitutil provides Dockerfile-specific utilities for git refs. +package dfgitutil import ( "net/url" "strings" cerrdefs "github.com/containerd/errdefs" + "github.com/moby/buildkit/util/gitutil" "github.com/pkg/errors" ) @@ -25,6 +27,10 @@ type GitRef struct { // Commit is optional. Commit string + // Checksum verifies the Commit if specified. + // Checksum is optional. + Checksum string + // SubDir is a directory path inside the repo. // SubDir is optional. SubDir string @@ -44,6 +50,12 @@ 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 + + gitURL *gitutil.GitURL +} + +func (r *GitRef) GitURL() *gitutil.GitURL { + return r.gitURL } // var gitURLPathWithFragmentSuffix = regexp.MustCompile(`\.git(?:#.+)?$`) @@ -53,7 +65,7 @@ func ParseGitRef(ref string) (*GitRef, error) { res := &GitRef{} var ( - remote *GitURL + remote *gitutil.GitURL err error ) @@ -61,14 +73,17 @@ func ParseGitRef(ref string) (*GitRef, error) { return nil, cerrdefs.ErrInvalidArgument } else if strings.HasPrefix(ref, "github.com/") { res.IndistinguishableFromLocal = true // Deprecated - remote = fromURL(&url.URL{ + remote, err = gitutil.FromURL(&url.URL{ Scheme: "https", Host: "github.com", Path: strings.TrimPrefix(ref, "github.com/"), }) + if err != nil { + return nil, err + } } else { - remote, err = ParseURL(ref) - if errors.Is(err, ErrUnknownProtocol) { + remote, err = gitutil.ParseURL(ref) + if errors.Is(err, gitutil.ErrUnknownProtocol) { return nil, err } if err != nil { @@ -76,13 +91,13 @@ func ParseGitRef(ref string) (*GitRef, error) { } switch remote.Scheme { - case HTTPProtocol, GitProtocol: + case gitutil.HTTPProtocol, gitutil.GitProtocol: res.UnencryptedTCP = true // Discouraged, but not deprecated } switch remote.Scheme { // An HTTP(S) URL is considered to be a valid git ref only when it has the ".git[...]" suffix. - case HTTPProtocol, HTTPSProtocol: + case gitutil.HTTPProtocol, gitutil.HTTPSProtocol: if !strings.HasSuffix(remote.Path, ".git") { return nil, cerrdefs.ErrInvalidArgument } @@ -94,11 +109,12 @@ 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.Commit, res.Checksum, res.SubDir = remote.Opts.Ref, remote.Opts.Checksum, remote.Opts.Subdir } repoSplitBySlash := strings.Split(res.Remote, "/") res.ShortName = strings.TrimSuffix(repoSplitBySlash[len(repoSplitBySlash)-1], ".git") + res.gitURL = remote return res, nil } diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/linter/ruleset.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/linter/ruleset.go index 63cc0013ef2b..7a94c76aaa21 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/linter/ruleset.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/linter/ruleset.go @@ -174,4 +174,22 @@ var ( }, Experimental: true, } + RuleExposeProtoCasing = LinterRule[func(string) string]{ + Name: "ExposeProtoCasing", + Description: "Protocol in EXPOSE instruction should be lowercase", + URL: "https://docs.docker.com/go/dockerfile/rule/expose-proto-casing/", + Format: func(port string) string { + return fmt.Sprintf("Defined protocol '%s' in EXPOSE instruction should be lowercase", port) + }, + } + RuleExposeInvalidFormat = LinterRule[func(string) string]{ + Name: "ExposeInvalidFormat", + Description: "IP address and host-port mapping should not be used in EXPOSE instruction. This will become an error in a future release", + URL: "https://docs.docker.com/go/dockerfile/rule/expose-invalid-format/", + Format: func(port string) string { + return fmt.Sprintf("EXPOSE instruction should not define an IP address or host-port mapping, found '%s'", port) + }, + // TODO(crazy-max): deprecate this rule in the future and error out instead + // Deprecated: true, + } ) diff --git a/vendor/github.com/moby/buildkit/frontend/dockerui/context.go b/vendor/github.com/moby/buildkit/frontend/dockerui/context.go index 3173558fd67f..ecd54a50c25a 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerui/context.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerui/context.go @@ -9,9 +9,9 @@ import ( "strconv" "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/frontend/dockerfile/dfgitutil" "github.com/moby/buildkit/frontend/gateway/client" gwpb "github.com/moby/buildkit/frontend/gateway/pb" - "github.com/moby/buildkit/util/gitutil" "github.com/pkg/errors" ) @@ -141,7 +141,7 @@ func (bc *Client) initContext(ctx context.Context) (*buildContext, error) { } func DetectGitContext(ref string, keepGit bool) (*llb.State, bool) { - g, err := gitutil.ParseGitRef(ref) + g, err := dfgitutil.ParseGitRef(ref) if err != nil { return nil, false } @@ -149,12 +149,17 @@ func DetectGitContext(ref string, keepGit bool) (*llb.State, bool) { if g.SubDir != "" { commit += ":" + g.SubDir } - gitOpts := []llb.GitOption{WithInternalName("load git source " + ref)} + gu := g.GitURL() + fullURL := ref + if gu.Remote != "" { + fullURL = gu.Remote + } + gitOpts := []llb.GitOption{WithInternalName("load git source " + ref), llb.GitChecksum(g.Checksum), + llb.GitIDSuffix(commit), llb.GitFullURL(fullURL)} if keepGit { gitOpts = append(gitOpts, llb.KeepGitDir()) } - - st := llb.Git(g.Remote, commit, gitOpts...) + st := llb.Git2(gu.GitURLBase, gitOpts...) return &st, true } diff --git a/vendor/github.com/moby/buildkit/util/gitutil/git_url.go b/vendor/github.com/moby/buildkit/util/gitutil/git_url.go index 338893b279e1..0310864b1633 100644 --- a/vendor/github.com/moby/buildkit/util/gitutil/git_url.go +++ b/vendor/github.com/moby/buildkit/util/gitutil/git_url.go @@ -30,6 +30,22 @@ var supportedProtos = map[string]struct{}{ var protoRegexp = regexp.MustCompile(`^[a-zA-Z0-9]+://`) +// GitURLBase is a simplified representation of GitURL. +type GitURLBase struct { + // Scheme is the protocol over which the git repo can be accessed + Scheme string + + // Host is the remote host that hosts the git repo + Host string + + // Path is the path on the host to access the repo + Path string + + // Remote is a valid URL remote to pass into the Git CLI tooling (i.e. + // without the fragment metadata) + Remote string +} + // URL is a custom URL type that points to a remote Git repository. // // URLs can be parsed from both standard URLs (e.g. @@ -38,40 +54,93 @@ var protoRegexp = regexp.MustCompile(`^[a-zA-Z0-9]+://`) // // See https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols type GitURL struct { - // Scheme is the protocol over which the git repo can be accessed - Scheme string - - // Host is the remote host that hosts the git repo - Host string - // Path is the path on the host to access the repo - Path string + GitURLBase // User is the username/password to access the host User *url.Userinfo // 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 + // Checksum is the commit hash + Checksum string // Subdir is the sub-directory inside the git repository to use Subdir string } +// GitURLOptsError is returned for invalid GitURLOpts. +type GitURLOptsError struct { + error +} + // parseOpts splits a git URL fragment into its respective git // reference and subdirectory components. -func parseOpts(fragment string) *GitURLOpts { - if fragment == "" { - return nil +func parseOpts(fragment string, query url.Values) (*GitURLOpts, error) { + if fragment == "" && len(query) == 0 { + return nil, nil + } + opts := &GitURLOpts{} + if fragment != "" { + opts.Ref, opts.Subdir, _ = strings.Cut(fragment, ":") + } + var tag, branch string + for k, v := range query { + switch len(v) { + case 0: + return nil, errors.Errorf("query %q has no value", k) + case 1: + if v[0] == "" { + return nil, errors.Errorf("query %q has no value", k) + } + // NOP + default: + return nil, errors.Errorf("query %q has multiple values", k) + } + switch k { + case "ref": + if opts.Ref != "" && opts.Ref != v[0] { + return nil, errors.Errorf("ref conflicts: %q vs %q", opts.Ref, v[0]) + } + opts.Ref = v[0] + case "tag": + tag = v[0] + case "branch": + branch = v[0] + case "checksum", "commit": + opts.Checksum = v[0] + case "subdir": + if opts.Subdir != "" && opts.Subdir != v[0] { + return nil, errors.Errorf("subdir conflicts: %q vs %q", opts.Subdir, v[0]) + } + opts.Subdir = v[0] + default: + return nil, errors.Errorf("unexpected query %q", k) + } + } + if tag != "" { + if opts.Ref != "" { + return nil, errors.New("tag conflicts with ref") + } + opts.Ref = "refs/tags/" + tag } - ref, subdir, _ := strings.Cut(fragment, ":") - return &GitURLOpts{Ref: ref, Subdir: subdir} + if branch != "" { + if tag != "" { + // TODO: consider allowing this, when the tag actually exists on the branch + return nil, errors.New("branch conflicts with tag") + } + if opts.Ref != "" { + return nil, errors.New("branch conflicts with ref") + } + opts.Ref = "refs/heads/" + branch + } + if opts.Checksum != "" && opts.Ref == "" { + opts.Ref = opts.Checksum + } + return opts, nil } // ParseURL parses a BuildKit-style Git URL (that may contain additional @@ -86,16 +155,28 @@ 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 } +// ParseURLBasic is a simplified version of ParseURL that only returns the basic components. +// When hasOpts is true, there are optional information in the URL fragment or query. +// Those optional information are omitted in this function. Use [ParseURL] to obtain them. +func ParseURLBasic(remote string) (parsedBasic *GitURLBase, hasOpts bool, err error) { + parsed, err := ParseURL(remote) + if parsed != nil { + parsedBasic = &parsed.GitURLBase + hasOpts = parsed.Opts != nil + } + return +} + func IsGitTransport(remote string) bool { if proto := protoRegexp.FindString(remote); proto != "" { proto = strings.ToLower(strings.TrimSuffix(proto, "://")) @@ -105,28 +186,47 @@ 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 = "" - return &GitURL{ - Scheme: url.Scheme, - User: url.User, - Host: url.Host, - Path: url.Path, - Opts: parseOpts(url.Fragment), - Remote: withoutOpts.String(), + withoutOpts.RawQuery = "" + opts, err := parseOpts(url.Fragment, url.Query()) + if err != nil { + return nil, &GitURLOptsError{ + error: errors.Wrapf(err, "failed to parse git URL opts %q", url.Redacted()), + } } + return &GitURL{ + GitURLBase: GitURLBase{ + Scheme: url.Scheme, + Host: url.Host, + Path: url.Path, + Remote: withoutOpts.String(), + }, + User: url.User, + Opts: opts, + }, nil } -func fromSCPStyleURL(url *sshutil.SCPStyleURL) *GitURL { +func fromSCPStyleURL(url *sshutil.SCPStyleURL) (*GitURL, error) { withoutOpts := *url withoutOpts.Fragment = "" - return &GitURL{ - Scheme: SSHProtocol, - User: url.User, - Host: url.Host, - Path: url.Path, - Opts: parseOpts(url.Fragment), - Remote: withoutOpts.String(), + withoutOpts.Query = nil + opts, err := parseOpts(url.Fragment, url.Query) + if err != nil { + return nil, &GitURLOptsError{ + // *sshutil.SCPStyleURL.String() does not contain password + error: errors.Wrapf(err, "failed to parse git URL opts %q", url.String()), + } } + return &GitURL{ + GitURLBase: GitURLBase{ + Scheme: SSHProtocol, + Host: url.Host, + Path: url.Path, + Remote: withoutOpts.String(), + }, + User: url.User, + Opts: opts, + }, nil } diff --git a/vendor/github.com/moby/buildkit/util/sshutil/scpurl.go b/vendor/github.com/moby/buildkit/util/sshutil/scpurl.go index 10491f32f08e..5d85f09a0ba6 100644 --- a/vendor/github.com/moby/buildkit/util/sshutil/scpurl.go +++ b/vendor/github.com/moby/buildkit/util/sshutil/scpurl.go @@ -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() + } + if u.Fragment != "" { + s += "#" + u.Fragment } - return base + "#" + url.Fragment + return s } diff --git a/vendor/github.com/moby/buildkit/util/tracing/multi_span_exporter.go b/vendor/github.com/moby/buildkit/util/tracing/multi_span_exporter.go index d856de3b7e85..533e80d94ecf 100644 --- a/vendor/github.com/moby/buildkit/util/tracing/multi_span_exporter.go +++ b/vendor/github.com/moby/buildkit/util/tracing/multi_span_exporter.go @@ -2,35 +2,29 @@ package tracing import ( "context" + stderrors "errors" - "github.com/hashicorp/go-multierror" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) type MultiSpanExporter []sdktrace.SpanExporter -func (m MultiSpanExporter) ExportSpans(ctx context.Context, spans []sdktrace.ReadOnlySpan) (err error) { +func (m MultiSpanExporter) ExportSpans(ctx context.Context, spans []sdktrace.ReadOnlySpan) error { + var errs []error for _, exp := range m { if e := exp.ExportSpans(ctx, spans); e != nil { - if err != nil { - err = multierror.Append(err, e) - continue - } - err = e + errs = append(errs, e) } } - return err + return stderrors.Join(errs...) } -func (m MultiSpanExporter) Shutdown(ctx context.Context) (err error) { +func (m MultiSpanExporter) Shutdown(ctx context.Context) error { + var errs []error for _, exp := range m { if e := exp.Shutdown(ctx); e != nil { - if err != nil { - err = multierror.Append(err, e) - continue - } - err = e + errs = append(errs, e) } } - return err + return stderrors.Join(errs...) } diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go index cfafed5b54c6..1d8cffae8cfc 100644 --- a/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -12,8 +12,6 @@ package errgroup import ( "context" "fmt" - "runtime" - "runtime/debug" "sync" ) @@ -33,10 +31,6 @@ type Group struct { errOnce sync.Once err error - - mu sync.Mutex - panicValue any // = PanicError | PanicValue; non-nil if some Group.Go goroutine panicked. - abnormal bool // some Group.Go goroutine terminated abnormally (panic or goexit). } func (g *Group) done() { @@ -56,80 +50,47 @@ func WithContext(ctx context.Context) (*Group, context.Context) { return &Group{cancel: cancel}, ctx } -// Wait blocks until all function calls from the Go method have returned -// normally, then returns the first non-nil error (if any) from them. -// -// If any of the calls panics, Wait panics with a [PanicValue]; -// and if any of them calls [runtime.Goexit], Wait calls runtime.Goexit. +// Wait blocks until all function calls from the Go method have returned, then +// returns the first non-nil error (if any) from them. func (g *Group) Wait() error { g.wg.Wait() if g.cancel != nil { g.cancel(g.err) } - if g.panicValue != nil { - panic(g.panicValue) - } - if g.abnormal { - runtime.Goexit() - } return g.err } // Go calls the given function in a new goroutine. -// The first call to Go must happen before a Wait. -// It blocks until the new goroutine can be added without the number of -// active goroutines in the group exceeding the configured limit. // +// The first call to Go must happen before a Wait. // It blocks until the new goroutine can be added without the number of // goroutines in the group exceeding the configured limit. // -// The first goroutine in the group that returns a non-nil error, panics, or -// invokes [runtime.Goexit] will cancel the associated Context, if any. +// The first goroutine in the group that returns a non-nil error will +// cancel the associated Context, if any. The error will be returned +// by Wait. func (g *Group) Go(f func() error) { if g.sem != nil { g.sem <- token{} } - g.add(f) -} - -func (g *Group) add(f func() error) { g.wg.Add(1) go func() { defer g.done() - normalReturn := false - defer func() { - if normalReturn { - return - } - v := recover() - g.mu.Lock() - defer g.mu.Unlock() - if !g.abnormal { - if g.cancel != nil { - g.cancel(g.err) - } - g.abnormal = true - } - if v != nil && g.panicValue == nil { - switch v := v.(type) { - case error: - g.panicValue = PanicError{ - Recovered: v, - Stack: debug.Stack(), - } - default: - g.panicValue = PanicValue{ - Recovered: v, - Stack: debug.Stack(), - } - } - } - }() - err := f() - normalReturn = true - if err != nil { + // It is tempting to propagate panics from f() + // up to the goroutine that calls Wait, but + // it creates more problems than it solves: + // - it delays panics arbitrarily, + // making bugs harder to detect; + // - it turns f's panic stack into a mere value, + // hiding it from crash-monitoring tools; + // - it risks deadlocks that hide the panic entirely, + // if f's panic leaves the program in a state + // that prevents the Wait call from being reached. + // See #53757, #74275, #74304, #74306. + + if err := f(); err != nil { g.errOnce.Do(func() { g.err = err if g.cancel != nil { @@ -154,7 +115,19 @@ func (g *Group) TryGo(f func() error) bool { } } - g.add(f) + g.wg.Add(1) + go func() { + defer g.done() + + if err := f(); err != nil { + g.errOnce.Do(func() { + g.err = err + if g.cancel != nil { + g.cancel(g.err) + } + }) + } + }() return true } @@ -176,33 +149,3 @@ func (g *Group) SetLimit(n int) { } g.sem = make(chan token, n) } - -// PanicError wraps an error recovered from an unhandled panic -// when calling a function passed to Go or TryGo. -type PanicError struct { - Recovered error - Stack []byte // result of call to [debug.Stack] -} - -func (p PanicError) Error() string { - // A Go Error method conventionally does not include a stack dump, so omit it - // here. (Callers who care can extract it from the Stack field.) - return fmt.Sprintf("recovered from errgroup.Group: %v", p.Recovered) -} - -func (p PanicError) Unwrap() error { return p.Recovered } - -// PanicValue wraps a value that does not implement the error interface, -// recovered from an unhandled panic when calling a function passed to Go or -// TryGo. -type PanicValue struct { - Recovered any - Stack []byte // result of call to [debug.Stack] -} - -func (p PanicValue) String() string { - if len(p.Stack) > 0 { - return fmt.Sprintf("recovered from errgroup.Group: %v\n%s", p.Recovered, p.Stack) - } - return fmt.Sprintf("recovered from errgroup.Group: %v", p.Recovered) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 072f9523afee..7f5a8177d29d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -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.23.0-rc1.0.20250806140246-955c2b2f7d01 +# github.com/moby/buildkit v0.23.0-rc1.0.20250806140246-955c2b2f7d01 => github.com/AkihiroSuda/buildkit_poc v0.3.2-0.20250822084057-35db37f482db ## explicit; go 1.23.0 github.com/moby/buildkit/api/services/control github.com/moby/buildkit/api/types @@ -471,6 +471,7 @@ github.com/moby/buildkit/exporter/containerimage/exptypes github.com/moby/buildkit/exporter/exptypes github.com/moby/buildkit/frontend/attestations github.com/moby/buildkit/frontend/dockerfile/command +github.com/moby/buildkit/frontend/dockerfile/dfgitutil github.com/moby/buildkit/frontend/dockerfile/linter github.com/moby/buildkit/frontend/dockerfile/parser github.com/moby/buildkit/frontend/dockerfile/shell @@ -847,7 +848,7 @@ golang.org/x/net/websocket ## explicit; go 1.23.0 golang.org/x/oauth2 golang.org/x/oauth2/internal -# golang.org/x/sync v0.14.0 +# golang.org/x/sync v0.16.0 ## explicit; go 1.23.0 golang.org/x/sync/errgroup golang.org/x/sync/semaphore @@ -1342,3 +1343,4 @@ sigs.k8s.io/structured-merge-diff/v4/value ## explicit; go 1.12 sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 +# github.com/moby/buildkit => github.com/AkihiroSuda/buildkit_poc v0.3.2-0.20250822084057-35db37f482db