@@ -56,7 +56,7 @@ type GitURL struct {
5656}
5757
5858// GitURLOpts is the buildkit-specific metadata extracted from the fragment
59- // of a remote URL.
59+ // or the query of a remote URL.
6060type GitURLOpts struct {
6161 // Ref is the git reference
6262 Ref string
@@ -66,12 +66,63 @@ type GitURLOpts struct {
6666
6767// parseOpts splits a git URL fragment into its respective git
6868// reference and subdirectory components.
69- func parseOpts (fragment string ) * GitURLOpts {
70- if fragment == "" {
71- return nil
69+ func parseOpts (fragment string , query url. Values ) ( * GitURLOpts , error ) {
70+ if fragment == "" && len ( query ) == 0 {
71+ return nil , nil
7272 }
73- ref , subdir , _ := strings .Cut (fragment , ":" )
74- return & GitURLOpts {Ref : ref , Subdir : subdir }
73+ opts := & GitURLOpts {}
74+ if fragment != "" {
75+ opts .Ref , opts .Subdir , _ = strings .Cut (fragment , ":" )
76+ }
77+ var tag , branch string
78+ for k , v := range query {
79+ switch len (v ) {
80+ case 0 :
81+ return nil , errors .Errorf ("query %q has no value" , k )
82+ case 1 :
83+ if v [0 ] == "" {
84+ return nil , errors .Errorf ("query %q has no value" , k )
85+ }
86+ // NOP
87+ default :
88+ return nil , errors .Errorf ("query %q has multiple values" , k )
89+ }
90+ switch k {
91+ case "ref" :
92+ if opts .Ref != "" && opts .Ref != v [0 ] {
93+ return nil , errors .Errorf ("ref conflicts: %q vs %q" , opts .Ref , v [0 ])
94+ }
95+ opts .Ref = v [0 ]
96+ case "tag" :
97+ tag = v [0 ]
98+ case "branch" :
99+ branch = v [0 ]
100+ case "subdir" :
101+ if opts .Subdir != "" && opts .Subdir != v [0 ] {
102+ return nil , errors .Errorf ("subdir conflicts: %q vs %q" , opts .Subdir , v [0 ])
103+ }
104+ opts .Subdir = v [0 ]
105+ default :
106+ return nil , errors .Errorf ("unexpected query %q" , k )
107+ }
108+ }
109+ if tag != "" {
110+ if opts .Ref != "" {
111+ return nil , errors .New ("tag conflicts with ref" )
112+ }
113+ opts .Ref = "refs/tags/" + tag
114+ }
115+ if branch != "" {
116+ if tag != "" {
117+ // TODO: consider allowing this, when the tag actually exists on the branch
118+ return nil , errors .New ("branch conflicts with tag" )
119+ }
120+ if opts .Ref != "" {
121+ return nil , errors .New ("branch conflicts with ref" )
122+ }
123+ opts .Ref = "refs/heads/" + branch
124+ }
125+ return opts , nil
75126}
76127
77128// ParseURL parses a BuildKit-style Git URL (that may contain additional
@@ -86,11 +137,11 @@ func ParseURL(remote string) (*GitURL, error) {
86137 if err != nil {
87138 return nil , err
88139 }
89- return FromURL (url ), nil
140+ return FromURL (url )
90141 }
91142
92143 if url , err := sshutil .ParseSCPStyleURL (remote ); err == nil {
93- return fromSCPStyleURL (url ), nil
144+ return fromSCPStyleURL (url )
94145 }
95146
96147 return nil , ErrUnknownProtocol
@@ -105,28 +156,38 @@ func IsGitTransport(remote string) bool {
105156 return sshutil .IsImplicitSSHTransport (remote )
106157}
107158
108- func FromURL (url * url.URL ) * GitURL {
159+ func FromURL (url * url.URL ) ( * GitURL , error ) {
109160 withoutOpts := * url
110161 withoutOpts .Fragment = ""
162+ withoutOpts .RawQuery = ""
163+ opts , err := parseOpts (url .Fragment , url .Query ())
164+ if err != nil {
165+ return nil , err
166+ }
111167 return & GitURL {
112168 Scheme : url .Scheme ,
113169 User : url .User ,
114170 Host : url .Host ,
115171 Path : url .Path ,
116- Opts : parseOpts ( url . Fragment ) ,
172+ Opts : opts ,
117173 Remote : withoutOpts .String (),
118- }
174+ }, nil
119175}
120176
121- func fromSCPStyleURL (url * sshutil.SCPStyleURL ) * GitURL {
177+ func fromSCPStyleURL (url * sshutil.SCPStyleURL ) ( * GitURL , error ) {
122178 withoutOpts := * url
123179 withoutOpts .Fragment = ""
180+ withoutOpts .Query = nil
181+ opts , err := parseOpts (url .Fragment , url .Query )
182+ if err != nil {
183+ return nil , err
184+ }
124185 return & GitURL {
125186 Scheme : SSHProtocol ,
126187 User : url .User ,
127188 Host : url .Host ,
128189 Path : url .Path ,
129- Opts : parseOpts ( url . Fragment ) ,
190+ Opts : opts ,
130191 Remote : withoutOpts .String (),
131- }
192+ }, nil
132193}
0 commit comments