Browse Source

support non-published releases

Brett Langdon 9 years ago
parent
commit
92120524a0
No known key found for this signature in database GPG Key ID: A2ECAB73CE12147F
4 changed files with 252 additions and 10 deletions
  1. +19
    -6
      asset.go
  2. +75
    -0
      client.go
  3. +8
    -4
      cmd/pypihub/main.go
  4. +150
    -0
      router.go

+ 19
- 6
asset.go View File

@ -1,12 +1,17 @@
package pypihub package pypihub
import "fmt"
import (
"fmt"
"io"
)
type Asset struct { type Asset struct {
ID int
Name string
Owner string
Repo string
ID int
Name string
Owner string
Repo string
Ref string
Format string
} }
func (a Asset) String() string { func (a Asset) String() string {
@ -14,5 +19,13 @@ func (a Asset) String() string {
} }
func (a Asset) URL() string { func (a Asset) URL() string {
return fmt.Sprintf("/%s/%s/%d/%s", a.Owner, a.Repo, a.ID, a.Name)
return fmt.Sprintf("/%s/%s/%s", a.Owner, a.Repo, a.Name)
}
func (a Asset) Download(c *Client) (io.ReadCloser, error) {
if a.Ref != "" && a.Format != "" {
return c.DownloadArchive(a)
}
return c.DownloadAsset(a)
} }

+ 75
- 0
client.go View File

@ -1,8 +1,11 @@
package pypihub package pypihub
import ( import (
"fmt"
"io" "io"
"log"
"net/http" "net/http"
"net/url"
"strings" "strings"
"github.com/google/go-github/github" "github.com/google/go-github/github"
@ -38,6 +41,32 @@ func (c *Client) splitRepoName(r string) (string, string) {
} }
} }
func (c *Client) getRepoTagAssets(owner string, repo string) ([]Asset, error) {
var tags []*github.RepositoryTag
var err error
tags, _, err = c.client.Repositories.ListTags(owner, repo, nil)
if err != nil {
return nil, err
}
var allAssets = make([]Asset, 0)
for _, tag := range tags {
// Remove any `v` prefix, e.g. `v1.0.0` -> `1.0.0`
var name = strings.Trim(*tag.Name, "v")
name = fmt.Sprintf("%s-%s.tar.gz", repo, name)
allAssets = append(allAssets, Asset{
Name: name,
Owner: owner,
Repo: repo,
Ref: *tag.Name,
Format: "tarball",
})
log.Printf("found asset %s/%s/%s/%s", owner, repo, *tag.Name, name)
}
return allAssets, nil
}
func (c *Client) GetRepoAssets(r string) ([]Asset, error) { func (c *Client) GetRepoAssets(r string) ([]Asset, error) {
var owner, repo string var owner, repo string
owner, repo = c.splitRepoName(r) owner, repo = c.splitRepoName(r)
@ -49,6 +78,10 @@ func (c *Client) GetRepoAssets(r string) ([]Asset, error) {
return nil, err return nil, err
} }
if len(releases) == 0 {
return c.getRepoTagAssets(owner, repo)
}
var allAssets = make([]Asset, 0) var allAssets = make([]Asset, 0)
for _, rel := range releases { for _, rel := range releases {
var assets []*github.ReleaseAsset var assets []*github.ReleaseAsset
@ -56,14 +89,35 @@ func (c *Client) GetRepoAssets(r string) ([]Asset, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
var hasTar = false
for _, a := range assets { for _, a := range assets {
if strings.HasSuffix(*a.Name, ".tar.gz") {
hasTar = true
}
allAssets = append(allAssets, Asset{ allAssets = append(allAssets, Asset{
ID: *a.ID, ID: *a.ID,
Name: *a.Name, Name: *a.Name,
Owner: owner, Owner: owner,
Repo: repo, Repo: repo,
}) })
log.Printf("found asset %s/%s/%s/%s", owner, repo, *rel.Name, *a.Name)
} }
if hasTar == false {
// Remove any `v` prefix, e.g. `v1.0.0` -> `1.0.0`
var name = strings.Trim(*rel.Name, "v")
name = fmt.Sprintf("%s-%s.tar.gz", repo, name)
allAssets = append(allAssets, Asset{
Name: name,
Owner: owner,
Repo: repo,
Ref: *rel.TagName,
Format: "tarball",
})
log.Printf("found asset %s/%s/%s/%s", owner, repo, *rel.Name, name)
}
} }
return allAssets, nil return allAssets, nil
} }
@ -98,3 +152,24 @@ func (c *Client) DownloadAsset(a Asset) (io.ReadCloser, error) {
} }
return rc, err return rc, err
} }
func (c *Client) DownloadArchive(a Asset) (io.ReadCloser, error) {
var f = github.Tarball
if a.Format == "zipball" {
f = github.Zipball
}
var u *url.URL
var err error
u, _, err = c.client.Repositories.GetArchiveLink(a.Owner, a.Repo, f, nil)
if err != nil {
return nil, err
}
var resp *http.Response
resp, err = http.Get(u.String())
if err != nil {
return nil, err
}
return resp.Body, nil
}

+ 8
- 4
cmd/pypihub/main.go View File

@ -1,12 +1,16 @@
package main package main
import "github.com/brettlangdon/pypihub"
import (
"log"
"github.com/brettlangdon/pypihub"
)
func main() { func main() {
var config pypihub.Config var config pypihub.Config
config = pypihub.ParseConfig() config = pypihub.ParseConfig()
var server *pypihub.Server
server = pypihub.NewServer(config)
panic(server.ListenAndServe())
var router *pypihub.Router
router = pypihub.NewRouter(config)
log.Fatal(router.Start())
} }

+ 150
- 0
router.go View File

@ -0,0 +1,150 @@
package pypihub
import (
"fmt"
"io"
"log"
"net/http"
"strings"
"time"
"github.com/gorilla/mux"
)
type Router struct {
config Config
client *Client
assets []Asset
timer *time.Timer
}
func NewRouter(config Config) *Router {
return &Router{
config: config,
client: NewClient(config),
assets: make([]Asset, 0),
}
}
func (r *Router) refetchAssets() {
go r.startAssetsTimer()
var err error
r.assets, err = r.client.GetAllAssets()
if err != nil {
log.Println(err)
}
}
func (r *Router) startAssetsTimer() {
if r.timer != nil {
r.timer.Stop()
}
r.timer = time.AfterFunc(5*time.Minute, r.refetchAssets)
}
func (r *Router) handleSimple(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "<html><title>Simple index</title><body>")
var projects = make(map[string]bool)
for _, a := range r.assets {
projects[strings.ToLower(a.Repo)] = true
}
for project := range projects {
fmt.Fprintf(w, "<a href=\"/%s\">%s</a> ", project, project)
}
fmt.Fprintf(w, "</body></html>")
}
func (r *Router) handleIndex(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "<html><title>Links for all projects</title><body>")
fmt.Fprintf(w, "<h1>Links for all projects</h1>")
for _, a := range r.assets {
fmt.Fprintf(w, "<a href=\"%s\">%s</a> ", a.URL(), a.Name)
}
fmt.Fprintf(w, "</body></html>")
}
func (r *Router) handleFavicon(w http.ResponseWriter, req *http.Request) {
}
func (r *Router) handleOwnerIndex(w http.ResponseWriter, req *http.Request) {
var vars map[string]string
vars = mux.Vars(req)
var owner = strings.ToLower(vars["owner"])
fmt.Fprintf(w, "<html><title>Packages for %s</title><body>", owner)
fmt.Fprintf(w, "<h1>Links for %s projects</h1>", owner)
for _, a := range r.assets {
if strings.ToLower(a.Owner) == owner {
fmt.Fprintf(w, "<a href=\"%s\">%s</a> ", a.URL(), a.Name)
}
}
fmt.Fprintf(w, "</body></html>")
}
func (r *Router) handleRepoIndex(w http.ResponseWriter, req *http.Request) {
var vars map[string]string
vars = mux.Vars(req)
var owner = strings.ToLower(vars["owner"])
var repo = strings.ToLower(vars["repo"])
fmt.Fprintf(w, "<html><title>Packages for %s/%s</title><body>", owner, repo)
for _, a := range r.assets {
if strings.ToLower(a.Owner) == owner && strings.ToLower(a.Repo) == repo {
fmt.Fprintf(w, "<a href=\"%s\">%s</a> ", a.URL(), a.Name)
}
}
fmt.Fprintf(w, "</body></html>")
}
func (r *Router) handleFetchAsset(w http.ResponseWriter, req *http.Request) {
var vars map[string]string
vars = mux.Vars(req)
var owner = strings.ToLower(vars["owner"])
var repo = strings.ToLower(vars["repo"])
var asset = vars["asset"]
for _, a := range r.assets {
if strings.ToLower(a.Owner) == owner && strings.ToLower(a.Repo) == repo && a.Name == asset {
var rc io.ReadCloser
var err error
rc, err = a.Download(r.client)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
io.Copy(w, rc)
return
}
}
w.WriteHeader(http.StatusNotFound)
}
func (r *Router) logRequests(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
log.Println(req.Method, req.URL.Path)
h.ServeHTTP(w, req)
})
}
func (r *Router) Handler() http.Handler {
var h *mux.Router
h = mux.NewRouter()
h.HandleFunc("/", r.handleIndex).Methods("GET")
h.HandleFunc("/favicon.ico", r.handleFavicon).Methods("GET")
h.HandleFunc("/simple", r.handleSimple).Methods("GET")
h.HandleFunc("/{owner}", r.handleOwnerIndex).Methods("GET")
h.HandleFunc("/{owner}/{repo}", r.handleRepoIndex).Methods("GET")
h.HandleFunc("/{owner}/{repo}", r.handleRepoIndex).Methods("GET")
h.HandleFunc("/{owner}/{repo}/{asset}", r.handleFetchAsset).Methods("GET")
return r.logRequests(h)
}
func (r *Router) Start() error {
r.refetchAssets()
http.Handle("/", r.Handler())
return http.ListenAndServe(r.config.Bind, nil)
}

Loading…
Cancel
Save