1#!/usr/bin/env python3
2
3"""
4Updates the capability definitions at irc/caps/defs.go
5
6To add a capability, add it to the CAPDEFS list below,
7then run `make capdefs` from the project root.
8"""
9
10import io
11import subprocess
12import sys
13from collections import namedtuple
14
15CapDef = namedtuple("CapDef", ['identifier', 'name', 'url', 'standard'])
16
17CAPDEFS = [
18    CapDef(
19        identifier="AccountNotify",
20        name="account-notify",
21        url="https://ircv3.net/specs/extensions/account-notify-3.1.html",
22        standard="IRCv3",
23    ),
24    CapDef(
25        identifier="AccountTag",
26        name="account-tag",
27        url="https://ircv3.net/specs/extensions/account-tag-3.2.html",
28        standard="IRCv3",
29    ),
30    CapDef(
31        identifier="AwayNotify",
32        name="away-notify",
33        url="https://ircv3.net/specs/extensions/away-notify-3.1.html",
34        standard="IRCv3",
35    ),
36    CapDef(
37        identifier="Batch",
38        name="batch",
39        url="https://ircv3.net/specs/extensions/batch-3.2.html",
40        standard="IRCv3",
41    ),
42    CapDef(
43        identifier="CapNotify",
44        name="cap-notify",
45        url="https://ircv3.net/specs/extensions/cap-notify-3.2.html",
46        standard="IRCv3",
47    ),
48    CapDef(
49        identifier="ChgHost",
50        name="chghost",
51        url="https://ircv3.net/specs/extensions/chghost-3.2.html",
52        standard="IRCv3",
53    ),
54    CapDef(
55        identifier="EchoMessage",
56        name="echo-message",
57        url="https://ircv3.net/specs/extensions/echo-message-3.2.html",
58        standard="IRCv3",
59    ),
60    CapDef(
61        identifier="ExtendedJoin",
62        name="extended-join",
63        url="https://ircv3.net/specs/extensions/extended-join-3.1.html",
64        standard="IRCv3",
65    ),
66    CapDef(
67        identifier="InviteNotify",
68        name="invite-notify",
69        url="https://ircv3.net/specs/extensions/invite-notify-3.2.html",
70        standard="IRCv3",
71    ),
72    CapDef(
73        identifier="LabeledResponse",
74        name="labeled-response",
75        url="https://ircv3.net/specs/extensions/labeled-response.html",
76        standard="IRCv3",
77    ),
78    CapDef(
79        identifier="Languages",
80        name="draft/languages",
81        url="https://gist.github.com/DanielOaks/8126122f74b26012a3de37db80e4e0c6",
82        standard="proposed IRCv3",
83    ),
84    CapDef(
85        identifier="MessageTags",
86        name="message-tags",
87        url="https://ircv3.net/specs/extensions/message-tags.html",
88        standard="IRCv3",
89    ),
90    CapDef(
91        identifier="MultiPrefix",
92        name="multi-prefix",
93        url="https://ircv3.net/specs/extensions/multi-prefix-3.1.html",
94        standard="IRCv3",
95    ),
96    CapDef(
97        identifier="Relaymsg",
98        name="draft/relaymsg",
99        url="https://github.com/ircv3/ircv3-specifications/pull/417",
100        standard="proposed IRCv3",
101    ),
102    CapDef(
103        identifier="ChannelRename",
104        name="draft/channel-rename",
105        url="https://ircv3.net/specs/extensions/channel-rename",
106        standard="draft IRCv3",
107    ),
108    CapDef(
109        identifier="SASL",
110        name="sasl",
111        url="https://ircv3.net/specs/extensions/sasl-3.2.html",
112        standard="IRCv3",
113    ),
114    CapDef(
115        identifier="ServerTime",
116        name="server-time",
117        url="https://ircv3.net/specs/extensions/server-time-3.2.html",
118        standard="IRCv3",
119    ),
120    CapDef(
121        identifier="SetName",
122        name="setname",
123        url="https://ircv3.net/specs/extensions/setname.html",
124        standard="IRCv3",
125    ),
126    CapDef(
127        identifier="STS",
128        name="sts",
129        url="https://ircv3.net/specs/extensions/sts.html",
130        standard="IRCv3",
131    ),
132    CapDef(
133        identifier="UserhostInNames",
134        name="userhost-in-names",
135        url="https://ircv3.net/specs/extensions/userhost-in-names-3.2.html",
136        standard="IRCv3",
137    ),
138    CapDef(
139        identifier="ZNCSelfMessage",
140        name="znc.in/self-message",
141        url="https://wiki.znc.in/Query_buffers",
142        standard="ZNC vendor",
143    ),
144    CapDef(
145        identifier="EventPlayback",
146        name="draft/event-playback",
147        url="https://github.com/ircv3/ircv3-specifications/pull/362",
148        standard="proposed IRCv3",
149    ),
150    CapDef(
151        identifier="ZNCPlayback",
152        name="znc.in/playback",
153        url="https://wiki.znc.in/Playback",
154        standard="ZNC vendor",
155    ),
156    CapDef(
157        identifier="Nope",
158        name="ergo.chat/nope",
159        url="https://ergo.chat/nope",
160        standard="Ergo vendor",
161    ),
162    CapDef(
163        identifier="Multiline",
164        name="draft/multiline",
165        url="https://github.com/ircv3/ircv3-specifications/pull/398",
166        standard="proposed IRCv3",
167    ),
168    CapDef(
169        identifier="Chathistory",
170        name="draft/chathistory",
171        url="https://github.com/ircv3/ircv3-specifications/pull/393",
172        standard="proposed IRCv3",
173    ),
174    CapDef(
175        identifier="AccountRegistration",
176        name="draft/account-registration",
177        url="https://github.com/ircv3/ircv3-specifications/pull/435",
178        standard="draft IRCv3",
179    ),
180    CapDef(
181        identifier="ExtendedMonitor",
182        name="draft/extended-monitor",
183        url="https://github.com/ircv3/ircv3-specifications/pull/466",
184        standard="draft IRCv3",
185    ),
186]
187
188def validate_defs():
189    CAPDEFS.sort(key=lambda d: d.name)
190    numCaps = len(CAPDEFS)
191    numNames = len(set(capdef.name for capdef in CAPDEFS))
192    if numCaps != numNames:
193        raise Exception("defs must have unique names, but found duplicates")
194    numIdentifiers = len(set(capdef.identifier for capdef in CAPDEFS))
195    if numCaps != numIdentifiers:
196        raise Exception("defs must have unique identifiers, but found duplicates")
197
198def main():
199    validate_defs()
200    output = io.StringIO()
201    print("""
202package caps
203
204/*
205	WARNING: this file is autogenerated by `make capdefs`
206	DO NOT EDIT MANUALLY.
207*/
208
209
210    """, file=output)
211
212
213    numCapabs = len(CAPDEFS)
214    bitsetLen = numCapabs // 32
215    if numCapabs % 32 > 0:
216        bitsetLen += 1
217    print ("""
218const (
219	// number of recognized capabilities:
220	numCapabs = %d
221	// length of the uint64 array that represents the bitset:
222	bitsetLen = %d
223)
224    """ % (numCapabs, bitsetLen), file=output)
225
226    print("const (", file=output)
227    for capdef in CAPDEFS:
228        print("// %s is the %s capability named \"%s\":" % (capdef.identifier, capdef.standard, capdef.name), file=output)
229        print("// %s" % (capdef.url,), file=output)
230        print("%s Capability = iota" % (capdef.identifier,), file=output)
231        print(file=output)
232    print(")", file=output)
233
234    print("// `capabilityNames[capab]` is the string name of the capability `capab`", file=output)
235    print("""var ( capabilityNames = [numCapabs]string{""", file=output)
236    for capdef in CAPDEFS:
237        print("\"%s\"," % (capdef.name,), file=output)
238    print("})", file=output)
239
240    # run the generated code through `gofmt -s`, which will print it to stdout
241    gofmt = subprocess.Popen(['gofmt', '-s'], stdin=subprocess.PIPE)
242    gofmt.communicate(input=output.getvalue().encode('utf-8'))
243    if gofmt.poll() != 0:
244        print(output.getvalue())
245        raise Exception("gofmt failed")
246    return 0
247
248if __name__ == '__main__':
249    sys.exit(main())
250