]> Cypherpunks.ru repositories - gocheese.git/blob - hr.go
Download link for 3.0.0 release
[gocheese.git] / hr.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         "html/template"
23         "io/ioutil"
24         "log"
25         "net/http"
26         "os"
27         "sort"
28         "strings"
29 )
30
31 var (
32         HRRootTmpl = template.Must(template.New("hr-root").Parse(`<!DOCTYPE html>
33 <html>
34   <head>
35     <title>{{.Version}}: packages</title>
36   </head>
37   <body>
38     <ul>{{range .Packages}}
39       <li><a href="/hr/{{.}}/">{{.}}</a></li>
40 {{- end}}
41     </ul>
42   </body>
43 </html>
44 `))
45         HRPkgTmpl = template.Must(template.New("hr-pkg").Parse(`<!DOCTYPE html>
46 <html>
47   <head>
48     <title>{{.Version}}: package {{.PkgName}}</title>
49   </head>
50   <body>
51     <dl>
52       {{with .Info.Name}}<dt>Name</dt><dd>{{.}}</dd>{{end}}
53       {{with .Info.Version}}<dt>Version</dt><dd>{{.}}</dd>{{end}}
54
55       {{with .Info.Platform}}<dt>Platform</dt><dd><ul>
56       {{range .}}<li>{{.}}</li>
57       {{end}}</ul></dd>{{end}}
58
59       {{with .Info.SupportedPlatform}}<dt>SupportedPlatform</dt><dd><ul>
60       {{range .}}<li>{{.}}</li>
61       {{end}}</ul></dd>{{end}}
62
63       <dt>Summary</dt><dd>{{.Info.Summary}}</dd>
64       <dt>Description</dt><dd><pre>
65 {{.Info.Description}}
66       </pre></dd>
67
68       {{with .Info.DescriptionContentType}}<dt>DescriptionContentType</dt><dd>{{.}}</dd>{{end}}
69       {{with .Info.Keywords}}<dt>Keywords</dt><dd>{{.}}</dd>{{end}}
70       {{with .Info.HomePage}}<dt>HomePage</dt><dd>{{.}}</dd>{{end}}
71       {{with .Info.Author}}<dt>Author</dt><dd>{{.}}</dd>{{end}}
72       {{with .Info.AuthorEmail}}<dt>AuthorEmail</dt><dd>{{.}}</dd>{{end}}
73       {{with .Info.Maintainer}}<dt>Maintainer</dt><dd>{{.}}</dd>{{end}}
74       {{with .Info.MaintainerEmail}}<dt>MaintainerEmail</dt><dd>{{.}}</dd>{{end}}
75       {{with .Info.License}}<dt>License</dt><dd>{{.}}</dd>{{end}}
76
77       {{with .Info.Classifier}}<dt>Classifier</dt><dd><ul>
78       {{range .}}<li>{{.}}</li>
79       {{end}}</ul></dd>{{end}}
80
81       {{with .Info.RequiresDist}}<dt>RequiresDist</dt><dd><ul>
82       {{range .}}<li>{{.}}</li>
83       {{end}}</ul></dd>{{end}}
84
85       {{with .Info.RequiresPython}}<dt>RequiresPython</dt><dd>{{.}}</dd>{{end}}
86
87       {{with .Info.RequiresExternal}}<dt>RequiresExternal</dt><dd><ul>
88       {{range .}}<li>{{.}}</li>
89       {{end}}</ul></dd>{{end}}
90
91       {{with .Info.ProjectURL}}<dt>ProjectURL</dt><dd><ul>
92       {{range .}}<li>{{.}}</li>
93       {{end}}</ul></dd>{{end}}
94
95       {{with .Info.ProvidesExtra}}<dt>ProvidesExtra</dt><dd><ul>
96       {{range .}}<li>{{.}}</li>
97       {{end}}</ul></dd>{{end}}
98     </dl>
99
100     <h2>Releases</h2>
101     <table border=1>
102     <tr>
103       <th>Filename</th>
104       <th>Version</th>
105       <th>Uploaded</th>
106       <th>Size</th>
107       <th>Digests</th>
108     </tr>
109     {{range .Releases}}{{if .Size}}
110     <tr>
111       <td>{{.Filename}}</th>
112       <td>{{.Version}}</th>
113       <td>{{.UploadTimeISO8601}}</th>
114       <td>{{.Size}}</th>
115       <td><ul>{{range $a, $d := .Digests}}
116         <li>{{$a}}: <tt>{{$d}}</tt></li>
117       {{end}}</ul></td>
118     </tr>{{end}}{{end}}
119     </table>
120   </body>
121 </html>
122 `))
123 )
124
125 func serveHRRoot(w http.ResponseWriter, r *http.Request) {
126         files, err := ioutil.ReadDir(Root)
127         if err != nil {
128                 log.Println("error", r.RemoteAddr, "hr-root", err)
129                 http.Error(w, err.Error(), http.StatusInternalServerError)
130                 return
131         }
132         packages := make([]string, 0, len(files))
133         for _, f := range files {
134                 packages = append(packages, f.Name())
135         }
136         sort.Strings(packages)
137         var buf bytes.Buffer
138         err = HRRootTmpl.Execute(&buf, struct {
139                 Version  string
140                 Packages []string
141         }{
142                 Version:  UserAgent,
143                 Packages: packages,
144         })
145         if err != nil {
146                 log.Println("error", r.RemoteAddr, "hr-root", err)
147                 http.Error(w, err.Error(), http.StatusInternalServerError)
148                 return
149         }
150         w.Write(buf.Bytes())
151 }
152
153 func serveHRPkg(w http.ResponseWriter, r *http.Request) {
154         cols := strings.Split(strings.TrimRight(r.URL.Path, "/"), "/")
155         pkgName := cols[len(cols)-1]
156         meta, releases, err := getMetadata(pkgName, "")
157         if err != nil {
158                 if os.IsNotExist(err) {
159                         http.NotFound(w, r)
160                 } else {
161                         log.Println("error", r.RemoteAddr, "json", pkgName, err)
162                         http.Error(w, err.Error(), http.StatusInternalServerError)
163                 }
164                 return
165         }
166         var buf bytes.Buffer
167         err = HRPkgTmpl.Execute(&buf, struct {
168                 Version  string
169                 PkgName  string
170                 Info     PkgInfo
171                 Releases []*PkgReleaseInfo
172         }{
173                 Version:  UserAgent,
174                 PkgName:  pkgName,
175                 Info:     meta.Info,
176                 Releases: releases,
177         })
178         if err != nil {
179                 log.Println("error", r.RemoteAddr, "root", err)
180                 http.Error(w, err.Error(), http.StatusInternalServerError)
181                 return
182         }
183         w.Write(buf.Bytes())
184 }