v0.1.0 1a6c6c9

sources.go RawHistoryFolder

1package main
2
3import (
4	"path"
5	"regexp"
6	"strconv"
7	"strings"
8)
9
10// Stability ranks upstream protocol maturity; higher wins when several files
11// map to one package.
12type Stability int
13
14// Stability levels.
15const (
16	Unstable Stability = iota + 1
17	Staging
18	Stable
19)
20
21// PinKind says how the default ref of a source is chosen.
22type PinKind int
23
24const (
25	// PinTag follows the latest tag accepted by upstream.TagRe and upstream.TagOK.
26	PinTag PinKind = iota
27	// PinBranch follows the HEAD commit of upstream.Branch.
28	PinBranch
29)
30
31// upstream describes an upstream repository and which of its files are vendored.
32type upstream struct {
33	ID  string
34	URL string
35
36	Kind   PinKind
37	TagRe  *regexp.Regexp        // PinTag: tags must match
38	TagOK  func(tag string) bool // PinTag: optional extra filter
39	Branch string                // PinBranch: branch name
40
41	// Match reports whether the slash-separated repository path rel is a
42	// vendored protocol, and its stability.
43	Match func(rel string) (Stability, bool)
44}
45
46var (
47	tagThreeParts = regexp.MustCompile(`^\d+\.\d+\.\d+$`)
48	tagTwoParts   = regexp.MustCompile(`^\d+\.\d+$`)
49	tagVThreePart = regexp.MustCompile(`^v\d+\.\d+\.\d+$`)
50)
51
52// waylandTagOK accepts release tags X.Y.Z only; patch 90 and above are
53// release candidates regardless of the minor version.
54func waylandTagOK(tag string) bool {
55	v := versionParts(tag)
56	return len(v) == 3 && v[2] < 90
57}
58
59// exactly matches only the listed repository paths, all with stability s.
60func exactly(s Stability, paths ...string) func(string) (Stability, bool) {
61	set := make(map[string]bool, len(paths))
62	for _, p := range paths {
63		set[p] = true
64	}
65	return func(rel string) (Stability, bool) {
66		if !set[rel] {
67			return 0, false
68		}
69		return s, true
70	}
71}
72
73func matchWaylandProtocols(rel string) (Stability, bool) {
74	parts := strings.Split(rel, "/")
75	if len(parts) < 2 || !strings.HasSuffix(rel, ".xml") {
76		return 0, false
77	}
78	for _, p := range parts[:len(parts)-1] {
79		if p == "tests" || p == "experimental" {
80			return 0, false
81		}
82	}
83	switch parts[0] {
84	case "stable":
85		return Stable, true
86	case "staging":
87		return Staging, true
88	case "unstable":
89		return Unstable, true
90	}
91	return 0, false
92}
93
94func matchWlrProtocols(rel string) (Stability, bool) {
95	if path.Dir(rel) == "unstable" && strings.HasSuffix(rel, ".xml") {
96		return Unstable, true
97	}
98	return 0, false
99}
100
101// defaultSources lists the upstream repositories synced into spec/.
102func defaultSources() []upstream {
103	return []upstream{
104		{
105			ID:    "wayland",
106			URL:   "https://gitlab.freedesktop.org/wayland/wayland.git",
107			Kind:  PinTag,
108			TagRe: tagThreeParts,
109			TagOK: waylandTagOK,
110			Match: exactly(Stable, "protocol/wayland.xml"),
111		},
112		{
113			ID:    "wayland-protocols",
114			URL:   "https://gitlab.freedesktop.org/wayland/wayland-protocols.git",
115			Kind:  PinTag,
116			TagRe: tagTwoParts,
117			Match: matchWaylandProtocols,
118		},
119		{
120			ID:     "wlr-protocols",
121			URL:    "https://gitlab.freedesktop.org/wlroots/wlr-protocols.git",
122			Kind:   PinBranch,
123			Branch: "master",
124			Match:  matchWlrProtocols,
125		},
126		{
127			ID:    "wlroots",
128			URL:   "https://gitlab.freedesktop.org/wlroots/wlroots.git",
129			Kind:  PinTag,
130			TagRe: tagThreeParts,
131			Match: exactly(Unstable,
132				"protocol/input-method-unstable-v2.xml",
133				"protocol/virtual-keyboard-unstable-v1.xml"),
134		},
135		{
136			ID:    "plasma-wayland-protocols",
137			URL:   "https://invent.kde.org/libraries/plasma-wayland-protocols.git",
138			Kind:  PinTag,
139			TagRe: tagVThreePart,
140			Match: exactly(Unstable, "src/protocols/server-decoration.xml"),
141		},
142	}
143}
144
145// versionParts splits "v1.2.3" or "1.2" into its numeric components.
146func versionParts(tag string) []int {
147	var out []int
148	for _, f := range strings.Split(strings.TrimPrefix(tag, "v"), ".") {
149		n, err := strconv.Atoi(f)
150		if err != nil {
151			return nil
152		}
153		out = append(out, n)
154	}
155	return out
156}
157
158// compareVersions orders two tags numerically.
159func compareVersions(a, b string) int {
160	x, y := versionParts(a), versionParts(b)
161	for i := 0; i < len(x) && i < len(y); i++ {
162		if x[i] != y[i] {
163			if x[i] < y[i] {
164				return -1
165			}
166			return 1
167		}
168	}
169	return len(x) - len(y)
170}
171
172var majorSuffix = regexp.MustCompile(`-v(\d+)$`)
173
174// fileMajor returns the "vN" major of an XML file name; none means 1.
175func fileMajor(file string) int {
176	base := strings.TrimSuffix(path.Base(file), ".xml")
177	if m := majorSuffix.FindStringSubmatch(base); m != nil {
178		n, _ := strconv.Atoi(m[1])
179		return n
180	}
181	return 1
182}

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 1

Tags 1

↑↓ moveenter openesc close