Browse code

Fix shallow git clone in docker-build

If the HEAD request fails, use a GET request to properly test if git
server is smart-http.

Signed-off-by: Andrew He <he.andrew.mail@gmail.com>

Andrew He authored on 2017/06/16 04:15:02
Showing 1 changed files
... ...
@@ -1,7 +1,6 @@
1 1
 package git
2 2
 
3 3
 import (
4
-	"fmt"
5 4
 	"io/ioutil"
6 5
 	"net/http"
7 6
 	"net/url"
... ...
@@ -98,22 +97,46 @@ func getRefAndSubdir(fragment string) (ref string, subdir string) {
98 98
 
99 99
 func fetchArgs(remoteURL string, ref string) []string {
100 100
 	args := []string{"fetch", "--recurse-submodules=yes"}
101
-	shallow := true
102 101
 
103
-	if urlutil.IsURL(remoteURL) {
104
-		res, err := http.Head(fmt.Sprintf("%s/info/refs?service=git-upload-pack", remoteURL))
105
-		if err != nil || res.Header.Get("Content-Type") != "application/x-git-upload-pack-advertisement" {
106
-			shallow = false
107
-		}
108
-	}
109
-
110
-	if shallow {
102
+	if supportsShallowClone(remoteURL) {
111 103
 		args = append(args, "--depth", "1")
112 104
 	}
113 105
 
114 106
 	return append(args, "origin", ref)
115 107
 }
116 108
 
109
+// Check if a given git URL supports a shallow git clone,
110
+// i.e. it is a non-HTTP server or a smart HTTP server.
111
+func supportsShallowClone(remoteURL string) bool {
112
+	if urlutil.IsURL(remoteURL) {
113
+		// Check if the HTTP server is smart
114
+
115
+		// Smart servers must correctly respond to a query for the git-upload-pack service
116
+		serviceURL := remoteURL + "/info/refs?service=git-upload-pack"
117
+
118
+		// Try a HEAD request and fallback to a Get request on error
119
+		res, err := http.Head(serviceURL)
120
+		if err != nil || res.StatusCode != http.StatusOK {
121
+			res, err = http.Get(serviceURL)
122
+			if err == nil {
123
+				res.Body.Close()
124
+			}
125
+			if err != nil || res.StatusCode != http.StatusOK {
126
+				// request failed
127
+				return false
128
+			}
129
+		}
130
+
131
+		if res.Header.Get("Content-Type") != "application/x-git-upload-pack-advertisement" {
132
+			// Fallback, not a smart server
133
+			return false
134
+		}
135
+		return true
136
+	}
137
+	// Non-HTTP protocols always support shallow clones
138
+	return true
139
+}
140
+
117 141
 func checkoutGit(root, ref, subdir string) (string, error) {
118 142
 	// Try checking out by ref name first. This will work on branches and sets
119 143
 	// .git/HEAD to the current branch name