2 GoCheese -- Python private package repository and caching proxy
3 Copyright (C) 2019-2021 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
30 "go.cypherpunks.ru/recfile"
33 func getMetadata(pkgName, version string) (*PkgMeta, []*PkgReleaseInfo, error) {
34 serial, releases, err := listDir(pkgName, true)
38 metadata, err := ioutil.ReadFile(filepath.Join(Root, pkgName, MetadataFile))
40 if !os.IsNotExist(err) {
44 info := PkgInfo{Name: pkgName}
45 if len(metadata) == 0 {
46 info.Version = releases[len(releases)-1].Version
48 m, err := recfile.NewReader(bytes.NewReader(metadata)).NextMapWithSlice()
52 if v, ok := m[metadataFieldToRecField(MetadataFieldVersion)]; ok {
55 if v, ok := m[metadataFieldToRecField(MetadataFieldSummary)]; ok {
58 if v, ok := m[metadataFieldToRecField(MetadataFieldDescriptionContentType)]; ok {
59 info.DescriptionContentType = v[0]
61 if v, ok := m[metadataFieldToRecField(MetadataFieldKeywords)]; ok {
64 if v, ok := m[metadataFieldToRecField(MetadataFieldHomePage)]; ok {
67 if v, ok := m[metadataFieldToRecField(MetadataFieldAuthor)]; ok {
70 if v, ok := m[metadataFieldToRecField(MetadataFieldAuthorEmail)]; ok {
71 info.AuthorEmail = v[0]
73 if v, ok := m[metadataFieldToRecField(MetadataFieldMaintainer)]; ok {
74 info.Maintainer = v[0]
76 if v, ok := m[metadataFieldToRecField(MetadataFieldMaintainerEmail)]; ok {
77 info.MaintainerEmail = v[0]
79 if v, ok := m[metadataFieldToRecField(MetadataFieldLicense)]; ok {
82 if v, ok := m[metadataFieldToRecField(MetadataFieldRequiresPython)]; ok {
83 info.RequiresPython = v[0]
85 if v, ok := m[metadataFieldToRecField(MetadataFieldDescription)]; ok {
86 info.Description = v[0]
88 info.Classifier = m[metadataFieldToRecField(MetadataFieldClassifier)]
89 info.Platform = m[metadataFieldToRecField(MetadataFieldPlatform)]
90 info.SupportedPlatform = m[metadataFieldToRecField(MetadataFieldSupportedPlatform)]
91 info.RequiresDist = m[metadataFieldToRecField(MetadataFieldRequiresDist)]
92 info.RequiresExternal = m[metadataFieldToRecField(MetadataFieldRequiresExternal)]
93 info.ProjectURL = m[metadataFieldToRecField(MetadataFieldProjectURL)]
94 info.ProvidesExtra = m[metadataFieldToRecField(MetadataFieldProvidesExtra)]
99 Releases: make(map[string][]*PkgReleaseInfo),
101 var lastVersion string
102 for _, release := range releases {
103 meta.Releases[release.Version] = append(
104 meta.Releases[release.Version], release,
106 lastVersion = release.Version
109 lastVersion = version
111 meta.URLs = meta.Releases[lastVersion]
112 return &meta, releases, nil
115 // https://warehouse.pypa.io/api-reference/json.html
116 func serveJSON(w http.ResponseWriter, r *http.Request) {
117 path := strings.TrimPrefix(r.URL.Path, *JSONURLPath)
118 parts := strings.Split(strings.TrimSuffix(path, "/"), "/")
119 if len(parts) < 2 || parts[len(parts)-1] != "json" {
120 http.Error(w, "invalid JSON API action", http.StatusBadRequest)
129 meta, _, err := getMetadata(pkgName, version)
131 if os.IsNotExist(err) {
134 log.Println("error", r.RemoteAddr, "json", pkgName, err)
135 http.Error(w, err.Error(), http.StatusInternalServerError)
139 w.Header().Set("Content-Type", "application/json")
140 buf, err := json.Marshal(&meta)
142 log.Println("error", r.RemoteAddr, "json", pkgName, err)
143 http.Error(w, err.Error(), http.StatusInternalServerError)