From 177b4914c5a754e0f211a3e1960c690d686cbeae Mon Sep 17 00:00:00 2001 From: Serge Zaitsev Date: Wed, 2 Oct 2019 09:41:39 +0200 Subject: [PATCH] add go mod download vcs provider --- pkg/api/api.go | 10 +++--- pkg/vcs/gomod.go | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 pkg/vcs/gomod.go diff --git a/pkg/api/api.go b/pkg/api/api.go index 9230e44..75c68b1 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -183,7 +183,7 @@ func (api *api) vcs(ctx context.Context, module string) vcs.VCS { return path.vcs(module) } } - return vcs.NewGit(api.log, api.gitdir, module, vcs.NoAuth()) + return vcs.NewGoMod(api.log, module) } func (api *api) module(ctx context.Context, module string, version vcs.Version) ([]byte, time.Time, error) { @@ -236,7 +236,7 @@ func (api *api) list(w http.ResponseWriter, r *http.Request, module, version str if err != nil { api.log("api.list", "module", module, "error", err) httpErrors.Add(module, 1) - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusNotFound) return } @@ -252,7 +252,7 @@ func (api *api) info(w http.ResponseWriter, r *http.Request, module, version str if err != nil { api.log("api.info", "module", module, "version", version, "error", err) httpErrors.Add(module, 1) - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusNotFound) return } @@ -287,7 +287,7 @@ func (api *api) zip(w http.ResponseWriter, r *http.Request, module, version stri if err != nil { api.log("api.zip", "module", module, "version", version, "error", err) httpErrors.Add(module, 1) - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusNotFound) return } io.Copy(w, bytes.NewReader(b)) @@ -296,7 +296,7 @@ func (api *api) zip(w http.ResponseWriter, r *http.Request, module, version stri func (api *api) delete(w http.ResponseWriter, r *http.Request, module, version string) { for _, store := range api.stores { if err := store.Del(r.Context(), module, vcs.Version(version)); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusNotFound) return } } diff --git a/pkg/vcs/gomod.go b/pkg/vcs/gomod.go new file mode 100644 index 0000000..d9860cc --- /dev/null +++ b/pkg/vcs/gomod.go @@ -0,0 +1,87 @@ +package vcs + +import ( + "bytes" + "context" + "encoding/json" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "time" +) + +type goVCS struct { + dir string + log logger + module string +} + +func NewGoMod(l logger, module string) VCS { + return &goVCS{log: l, module: module, dir: "/tmp/_go"} +} + +func (g *goVCS) List(ctx context.Context) ([]Version, error) { + if err := g.download(ctx, "latest"); err != nil { + return nil, err + } + b, err := g.file("list") + if err != nil { + return nil, err + } + versions := []Version{} + for _, line := range strings.Split(string(b), "\n") { + versions = append(versions, Version(line)) + } + return versions, nil +} + +func (g *goVCS) Timestamp(ctx context.Context, version Version) (time.Time, error) { + if err := g.download(ctx, version.String()); err != nil { + return time.Time{}, err + } + b, err := g.file(version.String() + ".info") + if err != nil { + return time.Time{}, err + } + info := struct { + Version string + Time time.Time + }{} + if json.Unmarshal(b, &info) == nil { + return info.Time, nil + } + if t, err := time.Parse(time.RFC3339, string(b)); err == nil { + return t, nil + } + if sec, err := strconv.ParseInt(string(b), 10, 64); err == nil { + return time.Unix(sec, 0), nil + } + return time.Time{}, nil +} + +func (g *goVCS) Zip(ctx context.Context, version Version) (io.ReadCloser, error) { + if err := g.download(ctx, version.String()); err != nil { + return nil, err + } + b, err := g.file(version.String() + ".zip") + if err != nil { + return nil, err + } + return ioutil.NopCloser(bytes.NewReader(b)), nil +} + +func (g *goVCS) download(ctx context.Context, version string) error { + cmd := exec.Command("go", "mod", "download", g.module+"@"+version) + cmd.Env = append(os.Environ(), "GOPATH="+g.dir) + cmd.Stderr = os.Stderr + return cmd.Run() +} + +func (g *goVCS) file(name string) ([]byte, error) { + path := filepath.Join(g.dir, "pkg", "mod", "cache", "download", g.module, "@v", name) + return ioutil.ReadFile(path) +}