main 602baa7

main.go RawHistoryFolder

1// Command xtsync vendors the pinned xcb-proto sources. An explicit -source
2// directory supports offline refreshes; its provenance is retained in manifest.
3package main
4
5import (
6	"archive/tar"
7	"bytes"
8	"compress/gzip"
9	"crypto/sha256"
10	"encoding/hex"
11	"encoding/json"
12	"flag"
13	"fmt"
14	"io"
15	"net/http"
16	"os"
17	"path/filepath"
18	"time"
19)
20
21const upstream = "https://gitlab.freedesktop.org/xorg/proto/xcbproto"
22const tag = "xcb-proto-1.17.0"
23
24var files = []string{"xproto.xml", "bigreq.xml", "ge.xml", "xc_misc.xml", "composite.xml", "xfixes.xml", "res.xml", "render.xml", "shape.xml", "xcb.xsd", "COPYING"}
25
26type entry struct {
27	Path   string `json:"path"`
28	SHA256 string `json:"sha256"`
29}
30type manifest struct {
31	Upstream string  `json:"upstream"`
32	Tag      string  `json:"tag"`
33	Source   string  `json:"source"`
34	Files    []entry `json:"files"`
35}
36
37func main() {
38	source := flag.String("source", "", "local source directory (COPYING must be included)")
39	flag.Parse()
40	if err := syncFiles(*source); err != nil {
41		fmt.Fprintln(os.Stderr, err)
42		os.Exit(1)
43	}
44}
45func syncFiles(source string) error {
46	data := make(map[string][]byte)
47	provenance := source
48	if source != "" {
49		for _, name := range files {
50			b, err := os.ReadFile(filepath.Join(source, name))
51			if err != nil {
52				return err
53			}
54			data[name] = b
55		}
56	} else {
57		provenance = upstream + "/-/archive/" + tag + "/xcbproto-" + tag + ".tar.gz"
58		client := http.Client{Timeout: 30 * time.Second}
59		resp, err := client.Get(provenance)
60		if err != nil {
61			return err
62		}
63		defer resp.Body.Close()
64		if resp.StatusCode != http.StatusOK {
65			return fmt.Errorf("download: %s", resp.Status)
66		}
67		gz, err := gzip.NewReader(io.LimitReader(resp.Body, 16<<20))
68		if err != nil {
69			return err
70		}
71		defer gz.Close()
72		tr := tar.NewReader(gz)
73		for {
74			h, err := tr.Next()
75			if err == io.EOF {
76				break
77			}
78			if err != nil {
79				return err
80			}
81			for _, name := range files {
82				if h.Name == "xcbproto-"+tag+"/src/"+name || name == "COPYING" && h.Name == "xcbproto-"+tag+"/COPYING" {
83					b, err := io.ReadAll(io.LimitReader(tr, 4<<20))
84					if err != nil {
85						return err
86					}
87					data[name] = b
88				}
89			}
90		}
91	}
92	m := manifest{Upstream: upstream, Tag: tag, Source: provenance}
93	for _, name := range files {
94		if len(data[name]) == 0 {
95			return fmt.Errorf("missing source %s", name)
96		}
97	}
98	for _, name := range files {
99		dest := filepath.Join("spec", "xml", name)
100		if name == "xcb.xsd" {
101			dest = "spec/xcb.xsd"
102		}
103		if name == "COPYING" {
104			dest = "LICENSES/xcb-proto-COPYING"
105		}
106		if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
107			return err
108		}
109		if err := os.WriteFile(dest, data[name], 0644); err != nil {
110			return err
111		}
112		sum := sha256.Sum256(data[name])
113		m.Files = append(m.Files, entry{filepath.ToSlash(dest), hex.EncodeToString(sum[:])})
114	}
115	b, err := json.MarshalIndent(m, "", "  ")
116	if err != nil {
117		return err
118	}
119	b = append(b, '\n')
120	// Keep refresh deterministic, including when invoked repeatedly from CI.
121	old, _ := os.ReadFile("spec/manifest.json")
122	if bytes.Equal(old, b) {
123		return nil
124	}
125	return os.WriteFile("spec/manifest.json", b, 0644)
126}

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