1// Command wlbsync vendors upstream Wayland protocol XML into spec/ and writes
2// spec/manifest.json.
3//
4// Usage:
5//
6// wlbsync [-root DIR] [-check] [-notes FILE] [-pin-file FILE]
7//
8// With -check nothing under spec/ is written; the program prints
9// "changed=true" or "changed=false". With -notes, Markdown release notes
10// describing the difference to the current spec are written to FILE.
11// -pin-file reads a JSON object {"<source id>": "<tag|branch|40-hex commit>"}
12// overriding the default ref of each listed source.
13package main
14
15import (
16 "encoding/json"
17 "flag"
18 "fmt"
19 "io"
20 "os"
21)
22
23type options struct {
24 root string
25 check bool
26 notes string
27 pinFile string
28}
29
30func main() {
31 var o options
32 flag.StringVar(&o.root, "root", ".", "repository root containing spec/")
33 flag.BoolVar(&o.check, "check", false, "do not write spec/; print changed=true|false")
34 flag.StringVar(&o.notes, "notes", "", "write Markdown release notes to `FILE`")
35 flag.StringVar(&o.pinFile, "pin-file", "", "JSON file mapping source id to the ref to use")
36 flag.Parse()
37 if flag.NArg() != 0 {
38 fmt.Fprintln(os.Stderr, "wlbsync: unexpected arguments")
39 os.Exit(2)
40 }
41 if err := run(o, defaultSources(), gitFetcher{}, os.Stdout); err != nil {
42 fmt.Fprintln(os.Stderr, "wlbsync:", err)
43 os.Exit(1)
44 }
45}
46
47func loadPins(file string, srcs []upstream) (map[string]string, error) {
48 pins := map[string]string{}
49 if file == "" {
50 return pins, nil
51 }
52 b, err := os.ReadFile(file)
53 if err != nil {
54 return nil, err
55 }
56 if err := json.Unmarshal(b, &pins); err != nil {
57 return nil, fmt.Errorf("decode %s: %w", file, err)
58 }
59 known := map[string]bool{}
60 for _, s := range srcs {
61 known[s.ID] = true
62 }
63 for id := range pins {
64 if !known[id] {
65 return nil, fmt.Errorf("%s: unknown source %q", file, id)
66 }
67 }
68 return pins, nil
69}
70
71func run(o options, srcs []upstream, f Fetcher, stdout io.Writer) error {
72 pins, err := loadPins(o.pinFile, srcs)
73 if err != nil {
74 return err
75 }
76 cur, err := readState(o.root)
77 if err != nil {
78 return err
79 }
80 curParsed, err := parseOld(cur)
81 if err != nil {
82 return err
83 }
84 sources, cands, err := collect(srcs, pins, f)
85 if err != nil {
86 return err
87 }
88 t, err := build(sources, cands)
89 if err != nil {
90 return err
91 }
92 manifest, err := t.manifest.Marshal()
93 if err != nil {
94 return err
95 }
96 changed, err := cur.differs(t)
97 if err != nil {
98 return err
99 }
100
101 if o.notes != "" {
102 n, err := diff(cur, curParsed, t)
103 if err != nil {
104 return err
105 }
106 if err := os.WriteFile(o.notes, []byte(n.markdown()), 0o644); err != nil {
107 return err
108 }
109 }
110 if changed && !o.check {
111 if err := write(o.root, cur, t, manifest); err != nil {
112 return err
113 }
114 }
115 _, err = fmt.Fprintf(stdout, "changed=%t\n", changed)
116 return err
117}