]> Cypherpunks.ru repositories - gocheese.git/blob - json.go
Missing error check
[gocheese.git] / json.go
1 /*
2 GoCheese -- Python private package repository and caching proxy
3 Copyright (C) 2019-2021 Sergey Matveev <stargrave@stargrave.org>
4
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.
8
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.
13
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/>.
16 */
17
18 package main
19
20 import (
21         "bytes"
22         "encoding/json"
23         "io/ioutil"
24         "log"
25         "net/http"
26         "os"
27         "path/filepath"
28         "strings"
29
30         "go.cypherpunks.ru/recfile"
31 )
32
33 func getMD(pkgName, version string) (*PkgMeta, []*PkgReleaseInfo, error) {
34         serial, releases, err := listDir(pkgName, true)
35         if err != nil {
36                 return nil, nil, err
37         }
38         md, err := ioutil.ReadFile(filepath.Join(Root, pkgName, MDFile))
39         if err != nil {
40                 if !os.IsNotExist(err) {
41                         return nil, nil, err
42                 }
43         }
44         info := PkgInfo{Name: pkgName}
45         if len(md) == 0 {
46                 info.Version = releases[len(releases)-1].Version
47         } else {
48                 m, err := recfile.NewReader(bytes.NewReader(md)).NextMapWithSlice()
49                 if err != nil {
50                         return nil, nil, err
51                 }
52                 if v, ok := m[MDFieldToRecField[MDFieldVersion]]; ok {
53                         info.Version = v[0]
54                 }
55                 if v, ok := m[MDFieldToRecField[MDFieldSummary]]; ok {
56                         info.Summary = v[0]
57                 }
58                 if v, ok := m[MDFieldToRecField[MDFieldDescriptionContentType]]; ok {
59                         info.DescriptionContentType = v[0]
60                 }
61                 if v, ok := m[MDFieldToRecField[MDFieldKeywords]]; ok {
62                         info.Keywords = v[0]
63                 }
64                 if v, ok := m[MDFieldToRecField[MDFieldHomePage]]; ok {
65                         info.HomePage = v[0]
66                 }
67                 if v, ok := m[MDFieldToRecField[MDFieldAuthor]]; ok {
68                         info.Author = v[0]
69                 }
70                 if v, ok := m[MDFieldToRecField[MDFieldAuthorEmail]]; ok {
71                         info.AuthorEmail = v[0]
72                 }
73                 if v, ok := m[MDFieldToRecField[MDFieldMaintainer]]; ok {
74                         info.Maintainer = v[0]
75                 }
76                 if v, ok := m[MDFieldToRecField[MDFieldMaintainerEmail]]; ok {
77                         info.MaintainerEmail = v[0]
78                 }
79                 if v, ok := m[MDFieldToRecField[MDFieldLicense]]; ok {
80                         info.License = v[0]
81                 }
82                 if v, ok := m[MDFieldToRecField[MDFieldRequiresPython]]; ok {
83                         info.RequiresPython = v[0]
84                 }
85                 if v, ok := m[MDFieldToRecField[MDFieldDescription]]; ok {
86                         info.Description = v[0]
87                 }
88                 info.Classifier = m[MDFieldToRecField[MDFieldClassifier]]
89                 info.Platform = m[MDFieldToRecField[MDFieldPlatform]]
90                 info.SupportedPlatform = m[MDFieldToRecField[MDFieldSupportedPlatform]]
91                 info.RequiresDist = m[MDFieldToRecField[MDFieldRequiresDist]]
92                 info.RequiresExternal = m[MDFieldToRecField[MDFieldRequiresExternal]]
93                 info.ProjectURL = m[MDFieldToRecField[MDFieldProjectURL]]
94                 info.ProvidesExtra = m[MDFieldToRecField[MDFieldProvidesExtra]]
95         }
96         meta := PkgMeta{
97                 Info:       info,
98                 LastSerial: serial,
99                 Releases:   make(map[string][]*PkgReleaseInfo),
100         }
101         var lastVersion string
102         for _, release := range releases {
103                 meta.Releases[release.Version] = append(
104                         meta.Releases[release.Version], release,
105                 )
106                 lastVersion = release.Version
107         }
108         if version != "" {
109                 lastVersion = version
110         }
111         meta.URLs = meta.Releases[lastVersion]
112         return &meta, releases, nil
113 }
114
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)
121                 return
122         }
123         var version string
124         if len(parts) == 3 {
125                 version = parts[1]
126         }
127         pkgName := parts[0]
128
129         meta, _, err := getMD(pkgName, version)
130         if err != nil {
131                 if os.IsNotExist(err) {
132                         http.NotFound(w, r)
133                 } else {
134                         log.Println("error", r.RemoteAddr, "json", pkgName, err)
135                         http.Error(w, err.Error(), http.StatusInternalServerError)
136                 }
137                 return
138         }
139         w.Header().Set("Content-Type", "application/json")
140         buf, err := json.Marshal(&meta)
141         if err != nil {
142                 log.Println("error", r.RemoteAddr, "json", pkgName, err)
143                 http.Error(w, err.Error(), http.StatusInternalServerError)
144                 return
145         }
146         w.Write(buf)
147 }