1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
package web
import (
"fmt"
"html/template"
"net/url"
"strings"
"time"
)
func templateFuncs() template.FuncMap {
return template.FuncMap{
"repoURL": repoURL,
"manifestURL": manifestURL,
"pull": pullAddress,
"size": formatSize,
"timestamp": timestamp,
"age": displayAge,
"join": strings.Join,
}
}
// sanitizeURLPath escapes each path segment separately, preserving slashes in
// names such as group/repository. Appends a trailing slash.
func sanitizeURLPath(path string) string {
parts := strings.Split(path, "/")
for i := range parts {
parts[i] = url.PathEscape(parts[i])
}
return strings.Join(parts, "/") + "/"
}
func repoURL(name string) string {
return "/r/" + sanitizeURLPath(name)
}
func manifestURL(repository, digest, tag string) string {
path := repoURL(repository) + "m/" + sanitizeURLPath(digest)
if tag != "" {
path += "?" + url.Values{"tag": {tag}}.Encode()
}
return path
}
func pullAddress(host, repository, tag, digest string) string {
address := strings.TrimSuffix(host, "/") + "/" + repository
if tag != "" {
address += ":" + tag
}
if digest != "" {
address += "@" + digest
}
return address
}
func formatSize(value int64) string {
if value >= 1024*1024 {
return fmt.Sprintf("%.1fMB", float64(value)/(1024*1024))
}
if value >= 1024 {
return fmt.Sprintf("%.1fKB", float64(value)/1024)
}
return fmt.Sprintf("%dB", value)
}
func timestamp(t time.Time) string {
if t.IsZero() {
return ""
}
return t.Format(time.DateTime + " MST")
}
func displayAge(updated time.Time, frozen string) string {
if frozen != "" {
return frozen
}
if updated.IsZero() {
return "unknown"
}
elapsed := time.Since(updated)
if elapsed < time.Minute {
return "just now"
}
for _, unit := range []struct {
duration time.Duration
label string
}{
{365 * 24 * time.Hour, "year"},
{30 * 24 * time.Hour, "month"},
{24 * time.Hour, "day"},
{time.Hour, "hour"},
{time.Minute, "minute"},
} {
if count := int(elapsed / unit.duration); count > 0 {
suffix := "s"
if count == 1 {
suffix = ""
}
return fmt.Sprintf("%d %s%s ago", count, unit.label, suffix)
}
}
return "just now"
}
|