1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
import dataclasses
from enum import Enum
from textwrap import dedent
from typing import ClassVar, NamedTuple
from common import cxx_literal, generate_file, load_data, get_argument_parser
class FeatureTypeNames(NamedTuple):
code_tag: str
doc_tag: str
class TimelineEvent(NamedTuple):
date: str
release: str
message: str
cls: list[int]
class FeatureType(FeatureTypeNames, Enum):
experimental = FeatureTypeNames("Xp", "xp")
deprecated = FeatureTypeNames("Dep", "dp")
@dataclasses.dataclass
class ExtraFeature:
name: str
internal_name: str
documentation: str
timeline: list[TimelineEvent] = dataclasses.field(default_factory=list)
type: ClassVar[FeatureType]
@property
def code(self) -> str:
return dedent(f"""
{{
.tag = {ExtraFeature.type.code_tag}::{self.internal_name},
.name = {cxx_literal(self.name)},
.description = {cxx_literal(self.documentation)},
}},
""")
@property
def docs(self) -> str:
timeline = (
f"""
### Timeline
{
"\n ".join(
[
f"- {event.date}, {event.release}: {event.message} [{", ".join([f'[CL {cl}](https://gerrit.lix.systems/c/lix/+/{cl})' for cl in event.cls])}]"
for event in self.timeline
]
)
}
"""
if self.timeline
else ""
)
return dedent(f"""
## [`{self.name}`]{{#{ExtraFeature.type.doc_tag}-feature-{self.name}}}
{self.documentation.replace("\n", f"\n{' ' * 3}")}
{timeline}
""")
@property
def short_docs(self) -> str:
return f" - [`{self.name}`](@docroot@/contributing/{ExtraFeature.type.name}-features.md#{ExtraFeature.type.doc_tag}-feature-{self.name})\n"
def main():
ap = get_argument_parser()
ap.add_argument("--deprecated", action="store_true", help="Generate deprecated features")
ap.add_argument("--impl-header", help="Path of the implementation header to generate")
ap.add_argument("--shortlist", help="Path of the shortlist file to generate")
args = ap.parse_args()
ExtraFeature.type = FeatureType.deprecated if args.deprecated else FeatureType.experimental
def load(**kwargs) -> ExtraFeature:
kwargs["timeline"] = [TimelineEvent(**args) for args in kwargs.get("timeline", [])]
return ExtraFeature(**kwargs)
features = load_data(args.defs, load)
generate_file(
args.header,
features,
lambda feature: feature.name,
lambda feature: f" {feature.internal_name},\n",
)
generate_file(args.impl_header, features, lambda feature: feature.name, lambda f: f.code)
generate_file(args.docs, features, lambda feature: feature.name, lambda f: f.docs)
generate_file(args.shortlist, features, lambda feature: feature.name, lambda f: f.short_docs)
if __name__ == "__main__":
main()
|