Skip to content

Commit 3579ffc

Browse files
committed
cmd/vgo/internal/modfetch/gitrepo: add general git repo access
A goal of introducing modules was to move away from invoking version control tools directly, but it has become clear that we're not ready to do that today. GitHub in particular imposes draconian limits on HTTPS API access that they don't impose on ordinary Git access. And we can avoid for now breaking company setups using private Git servers. Because GitHub Enterprise now serves ?go-get=1 queries in a way that is compatible with old go get, dropping back to version control tools makes that compatible with vgo too. The next CL hooks this code into the rest of vgo. For golang/go#24915. For golang/go#23955. For golang/go#24076. Change-Id: I76bea30081047ab68286a5d095a0d55872c5a1a3 Reviewed-on: https://go-review.googlesource.com/107656 Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
1 parent 097bf26 commit 3579ffc

File tree

4 files changed

+1013
-4
lines changed

4 files changed

+1013
-4
lines changed

vendor/cmd/go/internal/modfetch/codehost/codehost.go

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,34 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
// Package codehost defines the interface implemented by a code hosting source,
6+
// along with support code for use by implementations.
57
package codehost
68

79
import (
10+
"bytes"
11+
"cmd/go/internal/str"
12+
"crypto/sha256"
13+
"fmt"
814
"io"
15+
"io/ioutil"
16+
"os"
17+
"os/exec"
18+
"path/filepath"
19+
"strings"
920
"time"
1021
)
1122

1223
// Downloaded size limits.
1324
const (
14-
MaxGoMod = 16 << 20
15-
MaxLICENSE = 16 << 20
16-
MaxZipFile = 100 << 20
25+
MaxGoMod = 16 << 20 // maximum size of go.mod file
26+
MaxLICENSE = 16 << 20 // maximum size of LICENSE file
27+
MaxZipFile = 100 << 20 // maximum size of downloaded zip file
1728
)
1829

19-
// A Repo represents a source code repository on a code-hosting service.
30+
// A Repo represents a code hosting source.
31+
// Typical implementations include local version control repositories,
32+
// remote version control servers, and code hosting sites.
2033
type Repo interface {
2134
// Root returns the import path of the root directory of the repository.
2235
Root() string
@@ -55,6 +68,7 @@ type RevInfo struct {
5568
Time time.Time // commit time
5669
}
5770

71+
// AllHex reports whether the revision rev is entirely lower-case hexadecimal digits.
5872
func AllHex(rev string) bool {
5973
for i := 0; i < len(rev); i++ {
6074
c := rev[i]
@@ -66,9 +80,98 @@ func AllHex(rev string) bool {
6680
return true
6781
}
6882

83+
// ShortenSHA1 shortens a SHA1 hash (40 hex digits) to the canonical length
84+
// used in pseudo-versions (12 hex digits).
6985
func ShortenSHA1(rev string) string {
7086
if AllHex(rev) && len(rev) == 40 {
7187
return rev[:12]
7288
}
7389
return rev
7490
}
91+
92+
// WorkRoot is the root of the cached work directory.
93+
// It is set by cmd/go/internal/vgo.InitMod.
94+
var WorkRoot string
95+
96+
// WorkDir returns the name of the cached work directory to use for the
97+
// given repository type and name.
98+
func WorkDir(typ, name string) (string, error) {
99+
if WorkRoot == "" {
100+
return "", fmt.Errorf("codehost.WorkRoot not set")
101+
}
102+
103+
// We name the work directory for the SHA256 hash of the type and name.
104+
// We intentionally avoid the actual name both because of possible
105+
// conflicts with valid file system paths and because we want to ensure
106+
// that one checkout is never nested inside another. That nesting has
107+
// led to security problems in the past.
108+
if strings.Contains(typ, ":") {
109+
return "", fmt.Errorf("codehost.WorkDir: type cannot contain colon")
110+
}
111+
key := typ + ":" + name
112+
dir := filepath.Join(WorkRoot, fmt.Sprintf("%x", sha256.Sum256([]byte(key))))
113+
data, err := ioutil.ReadFile(dir + ".info")
114+
if err == nil {
115+
have := strings.TrimSuffix(string(data), "\n")
116+
if have != key {
117+
return "", fmt.Errorf("%s exists with wrong content (have %q want %q)", dir+".info", have, key)
118+
}
119+
_, err := os.Stat(dir)
120+
if err != nil {
121+
return "", fmt.Errorf("%s exists but %s does not", dir+".info", dir)
122+
}
123+
return dir, nil
124+
}
125+
126+
os.RemoveAll(dir)
127+
if err := os.MkdirAll(dir, 0777); err != nil {
128+
return "", err
129+
}
130+
if err := ioutil.WriteFile(dir+".info", []byte(key), 0666); err != nil {
131+
os.RemoveAll(dir)
132+
return "", err
133+
}
134+
return dir, nil
135+
}
136+
137+
type RunError struct {
138+
Cmd string
139+
Err error
140+
Stderr []byte
141+
}
142+
143+
func (e *RunError) Error() string {
144+
text := e.Cmd + ": " + e.Err.Error()
145+
stderr := bytes.TrimRight(e.Stderr, "\n")
146+
if len(stderr) > 0 {
147+
text += ":\n\t" + strings.Replace(string(stderr), "\n", "\n\t", -1)
148+
}
149+
return text
150+
}
151+
152+
var DebugRun bool
153+
154+
// Run runs the command line in the given directory
155+
// (an empty dir means the current directory).
156+
// It returns the standard output and, for a non-zero exit,
157+
// a *RunError indicating the command, exit status, and standard error.
158+
// Standard error is unavailable for commands that exit successfully.
159+
func Run(dir string, cmdline ...interface{}) ([]byte, error) {
160+
cmd := str.StringList(cmdline...)
161+
if DebugRun {
162+
fmt.Fprintf(os.Stderr, "codehost.Run[%s]: %s\n", dir, strings.Join(cmd, " "))
163+
}
164+
// TODO: Impose limits on command output size.
165+
// TODO: Set environment to get English error messages.
166+
var stderr bytes.Buffer
167+
var stdout bytes.Buffer
168+
c := exec.Command(cmd[0], cmd[1:]...)
169+
c.Dir = dir
170+
c.Stderr = &stderr
171+
c.Stdout = &stdout
172+
err := c.Run()
173+
if err != nil {
174+
err = &RunError{Cmd: strings.Join(cmd, " ") + " in " + dir, Stderr: stderr.Bytes(), Err: err}
175+
}
176+
return stdout.Bytes(), err
177+
}

0 commit comments

Comments
 (0)