mirror of https://github.com/goproxyio/goproxy
parent
afb11b3683
commit
477f7b3d7a
|
@ -1,10 +1,10 @@
|
||||||
version: "2"
|
version: "2"
|
||||||
services:
|
services:
|
||||||
goproxy:
|
goproxy:
|
||||||
image: goproxyio/goproxy:latest
|
image: goproxy/goproxy:latest
|
||||||
command: "goproxy -listen=0.0.0.0:8080 -root=/ext"
|
command: "goproxy -listen=0.0.0.0:8081 -cacheDir=/ext"
|
||||||
ports:
|
ports:
|
||||||
- "80:8080"
|
- "8081:8081"
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ./go_repos:/ext
|
- ./go_repos:/ext
|
|
@ -1,6 +1,7 @@
|
||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -17,6 +18,11 @@ import (
|
||||||
var cacheDir string
|
var cacheDir string
|
||||||
var innerHandle http.Handler
|
var innerHandle http.Handler
|
||||||
|
|
||||||
|
type modInfo struct {
|
||||||
|
module.Version
|
||||||
|
suf string
|
||||||
|
}
|
||||||
|
|
||||||
func NewProxy(cache string) http.Handler {
|
func NewProxy(cache string) http.Handler {
|
||||||
modfetch.PkgMod = filepath.Join(cache, "pkg", "mod")
|
modfetch.PkgMod = filepath.Join(cache, "pkg", "mod")
|
||||||
codehost.WorkRoot = filepath.Join(modfetch.PkgMod, "cache", "vcs")
|
codehost.WorkRoot = filepath.Join(modfetch.PkgMod, "cache", "vcs")
|
||||||
|
@ -25,70 +31,88 @@ func NewProxy(cache string) http.Handler {
|
||||||
innerHandle = http.FileServer(http.Dir(cacheDir))
|
innerHandle = http.FileServer(http.Dir(cacheDir))
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Printf("goproxy: %s download %s\n", r.RemoteAddr, r.URL.Path)
|
log.Printf("goproxy: %s request %s\n", r.RemoteAddr, r.URL.Path)
|
||||||
if _, err := os.Stat(filepath.Join(cacheDir, r.URL.Path)); err != nil {
|
if _, err := os.Stat(filepath.Join(cacheDir, r.URL.Path)); err != nil {
|
||||||
suffix := path.Ext(r.URL.Path)
|
info, err := parseModInfoFromUrl(r.URL.Path)
|
||||||
if suffix == ".info" || suffix == ".mod" || suffix == ".zip" {
|
|
||||||
mod := strings.Split(r.URL.Path, "/@v/")
|
|
||||||
if len(mod) != 2 {
|
|
||||||
ReturnBadRequest(w, fmt.Errorf("bad module path:%s", r.URL.Path))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
version := strings.TrimSuffix(mod[1], suffix)
|
|
||||||
version, err = module.DecodeVersion(version)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ReturnInternalServerError(w, err)
|
ReturnBadRequest(w, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
modPath := strings.TrimPrefix(mod[0], "/")
|
|
||||||
modPath, err := module.DecodePath(modPath)
|
|
||||||
if err != nil {
|
|
||||||
ReturnInternalServerError(w, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
switch suf := info.suf; suf {
|
||||||
|
case "":
|
||||||
// ignore the error, incorrect tag may be given
|
// ignore the error, incorrect tag may be given
|
||||||
// forward to inner.ServeHTTP
|
// forward to inner.ServeHTTP
|
||||||
if err := downloadMod(modPath, version); err != nil {
|
if err := downloadMod(info.Path, info.Version.Version); err != nil {
|
||||||
errLogger.Printf("download get err %s", err)
|
errLogger.Printf("goproxy: download %s@%s get err %s", info.Path, info.Version.Version, err)
|
||||||
}
|
}
|
||||||
|
case "/@v/list", "/@latest":
|
||||||
|
repo, err := modfetch.Lookup(info.Path)
|
||||||
|
if err != nil {
|
||||||
|
errLogger.Printf("goproxy: lookup failed: %v", err)
|
||||||
|
ReturnInternalServerError(w, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
switch suf {
|
||||||
// fetch latest version
|
case "/@v/list":
|
||||||
if strings.HasSuffix(r.URL.Path, "/@latest") {
|
info, err := repo.Versions("")
|
||||||
modPath := strings.TrimSuffix(r.URL.Path, "/@latest")
|
|
||||||
modPath = strings.TrimPrefix(modPath, "/")
|
|
||||||
modPath, err := module.DecodePath(modPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ReturnInternalServerError(w, err)
|
ReturnInternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
repo, err := modfetch.Lookup(modPath)
|
data := strings.Join(info, "\n")
|
||||||
|
ReturnSuccess(w, []byte(data))
|
||||||
|
return
|
||||||
|
case "/@latest":
|
||||||
|
info, err := repo.Latest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errLogger.Printf("lookup failed: %v", err)
|
|
||||||
ReturnInternalServerError(w, err)
|
ReturnInternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rev, err := repo.Stat("latest")
|
data, err := json.Marshal(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errLogger.Printf("latest failed: %v", err)
|
// ignore
|
||||||
|
errLogger.Printf("goproxy: marshal mod version info get error: %s", err)
|
||||||
|
}
|
||||||
|
ReturnSuccess(w, data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := downloadMod(modPath, rev.Version); err != nil {
|
|
||||||
errLogger.Printf("download get err %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasSuffix(r.URL.Path, "/@v/list") {
|
|
||||||
// TODO
|
|
||||||
_, _ = w.Write([]byte(""))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
innerHandle.ServeHTTP(w, r)
|
innerHandle.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseModInfoFromUrl(url string) (*modInfo, error) {
|
||||||
|
|
||||||
|
var modPath, modVersion, suf string
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(url, "/@v/list"):
|
||||||
|
// /golang.org/x/net/@v/list
|
||||||
|
suf = "/@v/list"
|
||||||
|
modVersion = ""
|
||||||
|
modPath = strings.Trim(strings.TrimSuffix(url, suf), "/")
|
||||||
|
case strings.HasSuffix(url, "/@latest"):
|
||||||
|
// /golang.org/x/@latest
|
||||||
|
suf = "/@latest"
|
||||||
|
modVersion = "latest"
|
||||||
|
modPath = strings.Trim(strings.TrimSuffix(url, suf), "/")
|
||||||
|
case strings.HasSuffix(url, ".info"), strings.HasSuffix(url, ".mod"), strings.HasSuffix(url, ".zip"):
|
||||||
|
// /golang.org/x/net/@v/v0.0.0-20181220203305-927f97764cc3.info
|
||||||
|
// /golang.org/x/net/@v/v0.0.0-20181220203305-927f97764cc3.mod
|
||||||
|
// /golang.org/x/net/@v/v0.0.0-20181220203305-927f97764cc3.zip
|
||||||
|
ext := path.Ext(url)
|
||||||
|
tmp := strings.Split(url, "/@v/")
|
||||||
|
if len(tmp) != 2 {
|
||||||
|
return nil, fmt.Errorf("bad module path:%s", url)
|
||||||
|
}
|
||||||
|
modVersion = strings.TrimSuffix(tmp[1], ext)
|
||||||
|
modPath = strings.Trim(tmp[0], "/")
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("bad module path:%s", url)
|
||||||
|
}
|
||||||
|
return &modInfo{module.Version{Path: modPath, Version: modVersion}, suf}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func downloadMod(modPath, version string) error {
|
func downloadMod(modPath, version string) error {
|
||||||
if _, err := modfetch.InfoFile(modPath, version); err != nil {
|
if _, err := modfetch.InfoFile(modPath, version); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goproxyio/goproxy/pkg/modfetch"
|
||||||
|
"github.com/goproxyio/goproxy/pkg/modfetch/codehost"
|
||||||
|
"github.com/goproxyio/goproxy/pkg/module"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
tmpdir, err := ioutil.TempDir("", "goproxy-test-")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("init tmpdir failed: %s", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpdir)
|
||||||
|
modfetch.PkgMod = filepath.Join(tmpdir, "pkg/mod")
|
||||||
|
codehost.WorkRoot = filepath.Join(modfetch.PkgMod, "cache/vcs")
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetchInfo(t *testing.T) {
|
||||||
|
packagePath := "gopkg.in/check.v1"
|
||||||
|
version := "v0.0.0-20161208181325-20d25e280405"
|
||||||
|
info, err := modfetch.InfoFile(packagePath, version)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("fetch %s@%s info get error: %s", packagePath, version, err)
|
||||||
|
}
|
||||||
|
t.Logf("%s@%s info on %s", packagePath, version, info)
|
||||||
|
}
|
||||||
|
func TestFetchModFile(t *testing.T) {
|
||||||
|
packagePath := "gopkg.in/check.v1"
|
||||||
|
version := "v0.0.0-20161208181325-20d25e280405"
|
||||||
|
info, err := modfetch.GoModFile(packagePath, version)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("fetch %s@%s modfile get error: %s", packagePath, version, err)
|
||||||
|
}
|
||||||
|
t.Logf("%s@%s modfile on %s", packagePath, version, info)
|
||||||
|
}
|
||||||
|
func TestFetchModSum(t *testing.T) {
|
||||||
|
packagePath := "gopkg.in/check.v1"
|
||||||
|
version := "v0.0.0-20161208181325-20d25e280405"
|
||||||
|
info, err := modfetch.GoModSum(packagePath, version)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("fetch %s@%s modsum get error: %s", packagePath, version, err)
|
||||||
|
}
|
||||||
|
t.Logf("%s@%s modsum is %s", packagePath, version, info)
|
||||||
|
}
|
||||||
|
func TestFetchZip(t *testing.T) {
|
||||||
|
packagePath := "gopkg.in/check.v1"
|
||||||
|
version := "v0.0.0-20161208181325-20d25e280405"
|
||||||
|
mod := module.Version{Path: packagePath, Version: version}
|
||||||
|
info, err := modfetch.DownloadZip(mod)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("fetch %s@%s modsum get error: %s", packagePath, version, err)
|
||||||
|
}
|
||||||
|
t.Logf("%s@%s modsum on %s", packagePath, version, info)
|
||||||
|
}
|
||||||
|
func TestDownload(t *testing.T) {
|
||||||
|
packagePath := "gopkg.in/check.v1"
|
||||||
|
version := "v0.0.0-20161208181325-20d25e280405"
|
||||||
|
mod := module.Version{Path: packagePath, Version: version}
|
||||||
|
info, err := modfetch.Download(mod)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("fetch %s@%s modsum get error: %s", packagePath, version, err)
|
||||||
|
}
|
||||||
|
t.Logf("%s@%s modsum on %s", packagePath, version, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLatest(t *testing.T) {
|
||||||
|
packagePath := "golang.org/x/net"
|
||||||
|
version := "latest"
|
||||||
|
repo, err := modfetch.Lookup(packagePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("lookup %s get error %s", packagePath, err)
|
||||||
|
}
|
||||||
|
info, err := repo.Latest()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("fetch %s@%s info get error %s", packagePath, version, err)
|
||||||
|
}
|
||||||
|
t.Logf("%s@%s info is %s", packagePath, version, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestList(t *testing.T) {
|
||||||
|
packagePath := "golang.org/x/net"
|
||||||
|
version := "latest"
|
||||||
|
repo, err := modfetch.Lookup(packagePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("lookup %s get error %s", packagePath, err)
|
||||||
|
}
|
||||||
|
info, err := repo.Versions("")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("fetch %s@%s versions get error %s", packagePath, version, err)
|
||||||
|
}
|
||||||
|
t.Logf("%s@%s versions are %s", packagePath, version, info)
|
||||||
|
}
|
|
@ -22,3 +22,8 @@ func ReturnBadRequest(w http.ResponseWriter, err error) {
|
||||||
errLogger.Printf("goproxy: %s\n", msg)
|
errLogger.Printf("goproxy: %s\n", msg)
|
||||||
_, _ = w.Write([]byte(msg))
|
_, _ = w.Write([]byte(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReturnSuccess(w http.ResponseWriter, data []byte) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = w.Write(data)
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ After=network-online.target
|
||||||
User=root
|
User=root
|
||||||
Group=root
|
Group=root
|
||||||
LimitNOFILE=65536
|
LimitNOFILE=65536
|
||||||
Environment="GOPATH=/changeme/golang"
|
|
||||||
ExecStart=goproxy -listen=0.0.0.0:80
|
ExecStart=goproxy -listen=0.0.0.0:80
|
||||||
KillMode=control-group
|
KillMode=control-group
|
||||||
SuccessExitStatus=2
|
SuccessExitStatus=2
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<h1>goproxy.io</h1>
|
<h1>goproxy.io</h1>
|
||||||
|
|
||||||
|
@ -21,7 +20,7 @@
|
||||||
<a class="github-button" href="https://github.com/goproxyio/goproxy" data-show-count="true" aria-label="Star goproxyio/goproxy on GitHub">Github</a>
|
<a class="github-button" href="https://github.com/goproxyio/goproxy" data-show-count="true" aria-label="Star goproxyio/goproxy on GitHub">Github</a>
|
||||||
<br>
|
<br>
|
||||||
<p>
|
<p>
|
||||||
<i>Note: this proxy can't fetch your private repos of course.</i>
|
<i>Note: this proxy can't fetch your private repos of course.</i>
|
||||||
<br>
|
<br>
|
||||||
<i>Mail: admin@goproxy.io</i>
|
<i>Mail: admin@goproxy.io</i>
|
||||||
</p>
|
</p>
|
Loading…
Reference in New Issue