X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=list.go;h=8567877d336b49a3c51ffceb63ef942399d086da;hb=3bbd67eb5067bf180ed260acee4a2c1a6f6db9ec;hp=48a9d71498fc7cbaebe315bd76cba7d76b1871d2;hpb=60bbf40bfc8b720f176faef55b5403986db86f8c;p=gocheese.git diff --git a/list.go b/list.go index 48a9d71..8567877 100644 --- a/list.go +++ b/list.go @@ -1,6 +1,6 @@ /* GoCheese -- Python private package repository and caching proxy -Copyright (C) 2019-2021 Sergey Matveev +Copyright (C) 2019-2022 Sergey Matveev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,54 +19,37 @@ package main import ( "bytes" + _ "embed" "encoding/hex" "errors" + "fmt" "html/template" "io/fs" - "io/ioutil" "log" "net/http" "os" "path/filepath" "sort" + "strconv" "strings" "time" ) // https://warehouse.pypa.io/api-reference/legacy.html var ( - HTMLRootTmpl = template.Must(template.New("root").Parse(` - - - - Links for root - - {{$Refresh := .RefreshURLPath}}{{range .Packages}} - {{.}}
-{{- end}} - - -`)) - HTMLReleasesTmpl = template.Must(template.New("list").Parse(` - - - - Links for {{.PkgName}} - - {{$Refresh := .RefreshURLPath}}{{$PkgName := .PkgName}}{{range .Releases}} - {{.Filename}}
-{{- end}} - - -`)) - KnownExts = []string{".tar.bz2", ".tar.gz", ".whl", ".zip", ".egg", + //go:embed root.tmpl + HTMLRootTmplRaw string + HTMLRootTmpl = template.Must(template.New("root").Parse(HTMLRootTmplRaw)) + + //go:embed list.tmpl + HTMLReleasesTmplRaw string + HTMLReleasesTmpl = template.Must(template.New("list").Parse(HTMLReleasesTmplRaw)) + KnownExts = []string{".tar.bz2", ".tar.gz", ".whl", ".zip", ".egg", ".exe", ".dmg", ".msi", ".rpm", ".deb", ".tgz"} ) func listRoot(w http.ResponseWriter, r *http.Request) { - files, err := ioutil.ReadDir(Root) + files, err := os.ReadDir(Root) if err != nil { log.Println("error", r.RemoteAddr, "root", err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -137,7 +120,7 @@ func filenameToVersion(fn string) string { return cols[0] } -func listDir(pkgName string, doSize bool) (int, []*PkgReleaseInfo, error) { +func listDir(pkgName string, doSize bool) (int64, []*PkgReleaseInfo, error) { dirPath := filepath.Join(Root, pkgName) entries, err := os.ReadDir(dirPath) if err != nil { @@ -163,7 +146,7 @@ func listDir(pkgName string, doSize bool) (int, []*PkgReleaseInfo, error) { continue } delete(files, fn) - digest, err := ioutil.ReadFile(filepath.Join(dirPath, fn)) + digest, err := os.ReadFile(filepath.Join(dirPath, fn)) if err != nil { return 0, nil, err } @@ -206,7 +189,15 @@ func listDir(pkgName string, doSize bool) (int, []*PkgReleaseInfo, error) { releases = append(releases, release) } sort.Sort(PkgReleaseInfoByName(releases)) - return len(entries), releases, nil + fi, err := os.Stat(dirPath) + if err != nil { + return 0, nil, err + } + serial := fi.ModTime().Unix() + if fi, err = os.Stat(filepath.Join(dirPath, MDFile)); err == nil { + serial += fi.ModTime().Unix() + } + return serial, releases, nil } func serveListDir( @@ -224,7 +215,7 @@ func serveListDir( !refreshDir(w, r, pkgName, "", false) { return } - _, releases, err := listDir(pkgName, false) + serial, releases, err := listDir(pkgName, false) if err != nil { log.Println("error", r.RemoteAddr, "list", pkgName, err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -258,5 +249,7 @@ func serveListDir( http.Error(w, err.Error(), http.StatusInternalServerError) return } + w.Header().Set("X-PyPI-Last-Serial", strconv.FormatInt(serial, 10)) w.Write(buf.Bytes()) + w.Write([]byte(fmt.Sprintf("\n", serial))) }