v2.31.0-dev20 020cc00

registry_image.go RawHistoryFolder

1package domain
2
3import "strings"
4
5// KnownGordonRegistryDomains returns the normalized set of Gordon-managed
6// registry domains, with the current domain first followed by legacy domains.
7// Empty values are ignored, trailing slashes are removed, and duplicates are
8// removed while preserving first-seen order.
9func KnownGordonRegistryDomains(current string, legacy []string) []string {
10	domains := make([]string, 0, 1+len(legacy))
11	seen := make(map[string]struct{}, 1+len(legacy))
12
13	add := func(domain string) {
14		normalized := normalizeRegistryDomain(domain)
15		if normalized == "" {
16			return
17		}
18
19		key := strings.ToLower(normalized)
20		if _, ok := seen[key]; ok {
21			return
22		}
23
24		seen[key] = struct{}{}
25		domains = append(domains, normalized)
26	}
27
28	add(current)
29	for _, domain := range legacy {
30		add(domain)
31	}
32
33	return domains
34}
35
36// StripKnownGordonRegistry removes the Gordon-managed registry host prefix from
37// an image reference when it matches the current or a legacy Gordon registry
38// domain. Bare references and external registries are returned unchanged.
39func StripKnownGordonRegistry(imageRef string, current string, legacy []string) string {
40	host, remainder, ok := splitRegistryImageRef(imageRef)
41	if !ok {
42		return imageRef
43	}
44	if !isKnownGordonRegistryDomain(host, current, legacy) {
45		return imageRef
46	}
47	return remainder
48}
49
50// ExtractGordonRepoName strips a known Gordon registry host, then removes any
51// tag or digest suffix, returning the repository name portion of the image
52// reference.
53func ExtractGordonRepoName(imageRef string, current string, legacy []string) string {
54	repo := StripKnownGordonRegistry(imageRef, current, legacy)
55
56	if idx := strings.Index(repo, "@"); idx != -1 {
57		repo = repo[:idx]
58	}
59	if idx := strings.LastIndex(repo, ":"); idx != -1 {
60		slashIdx := strings.LastIndex(repo, "/")
61		if idx > slashIdx {
62			repo = repo[:idx]
63		}
64	}
65
66	return repo
67}
68
69// CanonicalizeGordonImageRef rewrites Gordon-managed image references to use
70// the current Gordon registry domain. External registries and bare references
71// are returned unchanged. If the current domain is empty, the original image
72// reference is returned unchanged.
73func CanonicalizeGordonImageRef(imageRef, current string, legacy []string) string {
74	currentDomain := normalizeRegistryDomain(current)
75	if currentDomain == "" {
76		return imageRef
77	}
78
79	host, remainder, ok := splitRegistryImageRef(imageRef)
80	if !ok {
81		return imageRef
82	}
83	if !isKnownGordonRegistryDomain(host, currentDomain, legacy) {
84		return imageRef
85	}
86
87	return currentDomain + "/" + remainder
88}
89
90// IsGordonRegistryImageRef reports whether an image reference is explicitly
91// qualified with the current or a legacy Gordon registry domain.
92func IsGordonRegistryImageRef(imageRef, current string, legacy []string) bool {
93	host, _, ok := splitRegistryImageRef(imageRef)
94	if !ok {
95		return false
96	}
97	return isKnownGordonRegistryDomain(host, current, legacy)
98}
99
100func normalizeRegistryDomain(domain string) string {
101	domain = strings.TrimSpace(domain)
102	domain = strings.TrimRight(domain, "/")
103	return domain
104}
105
106func isKnownGordonRegistryDomain(host, current string, legacy []string) bool {
107	host = normalizeRegistryDomain(host)
108	if host == "" {
109		return false
110	}
111
112	for _, domain := range KnownGordonRegistryDomains(current, legacy) {
113		if strings.EqualFold(domain, host) {
114			return true
115		}
116	}
117	return false
118}
119
120func splitRegistryImageRef(imageRef string) (host string, remainder string, ok bool) {
121	host, remainder, ok = strings.Cut(imageRef, "/")
122	if !ok || host == "" || remainder == "" {
123		return "", "", false
124	}
125	if !looksLikeRegistryHost(host) {
126		return "", "", false
127	}
128	return host, remainder, true
129}
130
131func looksLikeRegistryHost(host string) bool {
132	return strings.Contains(host, ".") || strings.Contains(host, ":") || strings.EqualFold(host, "localhost")
133}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close