summaryrefslogtreecommitdiffstats
path: root/web/utils.go
diff options
context:
space:
mode:
Diffstat (limited to 'web/utils.go')
-rw-r--r--web/utils.go103
1 files changed, 103 insertions, 0 deletions
diff --git a/web/utils.go b/web/utils.go
new file mode 100644
index 0000000..18b5b52
--- /dev/null
+++ b/web/utils.go
@@ -0,0 +1,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"
+}