@@ -28,12 +28,15 @@ class ExitCode(IntFlag):
28
28
NORMAL = 0
29
29
INVALID_UPDATES = 1 << 4
30
30
MISSING_UPDATES = 1 << 5
31
+ NON_UNIQUE_DIRECTIONS = 1 << 6
31
32
32
33
33
34
THIS_SCRIPT_PATH = Path (__file__ )
34
35
RELATIVE_SCRIPT_PATH = THIS_SCRIPT_PATH .relative_to (THIS_SCRIPT_PATH .parent .parent )
35
36
36
37
REDIRECTION_DELAY = 6 # in seconds. Note: at least 6s for accessibility
38
+ REDIRECTION_TITLE = "xkbcommon: Page Redirection"
39
+ OPTIONAL_ENTRY = "__optional__"
37
40
38
41
# NOTE: The redirection works with the HTML tag: <meta http-equiv="refresh">.
39
42
# See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta#http-equiv
@@ -50,7 +53,7 @@ class ExitCode(IntFlag):
50
53
<meta http-equiv="refresh" content="${delay}; url=${canonical}">
51
54
<link href="doxygen.css" rel="stylesheet" type="text/css">
52
55
<link href="doxygen-extra.css" rel="stylesheet" type="text/css">
53
- <title>xkbcommon: Page Redirection </title>
56
+ <title>${title} </title>
54
57
</head>
55
58
<body>
56
59
<div id="top">
@@ -87,6 +90,14 @@ def parse_page_update(update: str) -> Update:
87
90
return updateʹ
88
91
89
92
93
+ def is_page_redirection (path : Path ):
94
+ with path .open ("rt" , encoding = "utf-8" ) as fd :
95
+ for line in fd :
96
+ if REDIRECTION_TITLE in line :
97
+ return True
98
+ return False
99
+
100
+
90
101
def update_registry (registry_path : Path , doc_dir : Path , updates : Sequence [str ]):
91
102
"""
92
103
Update the URL registry by:
@@ -95,21 +106,35 @@ def update_registry(registry_path: Path, doc_dir: Path, updates: Sequence[str]):
95
106
"""
96
107
# Parse updates
97
108
updates_ = dict (map (parse_page_update , updates ))
109
+ # Update
110
+ invalid_updates = set (updates_ )
98
111
# Load previous registry
99
112
with registry_path .open ("rt" , encoding = "utf-8" ) as fd :
100
- registry = yaml .safe_load (fd ) or {}
113
+ registry : dict [str , list [str ]] = yaml .safe_load (fd ) or {}
114
+ registryʹ = dict (
115
+ (canonical , aliases )
116
+ for canonical , aliases in registry .items ()
117
+ if canonical != OPTIONAL_ENTRY
118
+ )
101
119
# Expected updates
102
- missing_updates = set (file for file in registry if not (doc_dir / file ).is_file ())
103
- # Update
104
- invalid_updates = set (updates_ )
105
- redirections = frozenset (chain (* registry .values ()))
120
+ missing_updates = set (
121
+ canonical for canonical in registryʹ if not (doc_dir / canonical ).is_file ()
122
+ )
123
+ # Ensure each page is unique
124
+ for d , rs in registryʹ .items ():
125
+ if clashes := frozenset (rs ).intersection (registry ):
126
+ print (
127
+ f"[ERROR] The following redirections of “{ d } ”" ,
128
+ f"clash with canonical directions: { clashes } " ,
129
+ )
130
+ exit (ExitCode .NON_UNIQUE_DIRECTIONS )
131
+ redirections = frozenset (chain .from_iterable (registryʹ .values ()))
106
132
for file in glob .iglob ("**/*.html" , root_dir = doc_dir , recursive = True ):
107
133
# Skip redirection pages
108
134
if file in redirections :
109
135
continue
110
136
# Get previous entry and potential update
111
- old = updates_ .get (file )
112
- if old :
137
+ if old := updates_ .get (file ):
113
138
# Update old entry
114
139
invalid_updates .remove (file )
115
140
entry = registry .get (old )
@@ -137,19 +162,36 @@ def update_registry(registry_path: Path, doc_dir: Path, updates: Sequence[str]):
137
162
exit_code |= ExitCode .INVALID_UPDATES
138
163
if missing_updates :
139
164
for old in missing_updates :
140
- print (f"[ERROR] “{ old } ” not found and has no update." )
141
- exit_code |= ExitCode .MISSING_UPDATES
165
+ # Handle older Doxygen versions
166
+ if old in registry .get (OPTIONAL_ENTRY , []):
167
+ print (
168
+ "[WARNING] Handling old Doxygen version:" ,
169
+ f"skip optional “{ old } ”" ,
170
+ )
171
+ missing_updates .remove (old )
172
+ continue
173
+ old_redirections = registry [old ]
174
+ for r in old_redirections :
175
+ path = doc_dir / r
176
+ if path .is_file () and not is_page_redirection (path ):
177
+ print (
178
+ "[WARNING] Handling old Doxygen version:" ,
179
+ f"use “{ r } ” instead of “{ old } ” for the canonical direction" ,
180
+ )
181
+ missing_updates .remove (old )
182
+ break
183
+ else :
184
+ print (f"[ERROR] “{ old } ” not found and has no update." )
185
+ if missing_updates :
186
+ exit_code |= ExitCode .MISSING_UPDATES
142
187
if exit_code :
143
188
print ("[ERROR] Processing interrupted: please fix the errors above." )
144
189
exit (exit_code .value )
145
190
# Write changes
146
191
with registry_path .open ("wt" , encoding = "utf-8" ) as fd :
147
192
fd .write (f"# WARNING: This file is autogenerated by: { RELATIVE_SCRIPT_PATH } \n " )
148
193
fd .write ("# Do not edit manually.\n " )
149
- yaml .dump (
150
- registry ,
151
- fd ,
152
- )
194
+ yaml .dump (registry , fd )
153
195
154
196
155
197
def generate_redirections (registry_path : Path , doc_dir : Path ):
@@ -159,22 +201,47 @@ def generate_redirections(registry_path: Path, doc_dir: Path):
159
201
cool = True
160
202
# Load registry
161
203
with registry_path .open ("rt" , encoding = "utf-8" ) as fd :
162
- registry = yaml .safe_load (fd ) or {}
163
- for canonical , aliases in registry .items ():
204
+ registry : dict [str , list [str ]] = yaml .safe_load (fd ) or {}
205
+ registryʹ = dict (
206
+ (canonical , aliases )
207
+ for canonical , aliases in registry .items ()
208
+ if canonical != OPTIONAL_ENTRY
209
+ )
210
+ for canonical , aliases in registryʹ .items ():
164
211
# Check canonical path is up-to-date
165
212
if not (doc_dir / canonical ).is_file ():
166
- cool = False
167
- print (
168
- f"ERROR: missing canonical documentation page “{ canonical } ”. "
169
- f"Please update “{ registry_path } ” using { RELATIVE_SCRIPT_PATH } ”."
170
- )
213
+ # Handle older Doxygen versions
214
+ if canonical in registry .get (OPTIONAL_ENTRY , []):
215
+ print (
216
+ "[WARNING] Handling old Doxygen version:" ,
217
+ f"skip optional “{ canonical } ”" ,
218
+ )
219
+ continue
220
+ for r in aliases :
221
+ path = doc_dir / r
222
+ if path .is_file () and not is_page_redirection (path ):
223
+ print (
224
+ "[WARNING] Handling old Doxygen version:" ,
225
+ f"use “{ r } ” instead of “{ canonical } ” for the canonical direction" ,
226
+ )
227
+ canonical = r
228
+ aliases .remove (r )
229
+ break
230
+ else :
231
+ cool = False
232
+ print (
233
+ f"ERROR: missing canonical documentation page “{ canonical } ”. "
234
+ f"Please update “{ registry_path } ” using { RELATIVE_SCRIPT_PATH } ”."
235
+ )
171
236
# Add a redirection page
172
237
for alias in aliases :
173
238
path = doc_dir / alias
174
239
with path .open ("wt" , encoding = "utf-8" ) as fd :
175
240
fd .write (
176
241
REDIRECTION_PAGE_TEMPLATE .substitute (
177
- canonical = canonical , delay = REDIRECTION_DELAY
242
+ canonical = canonical ,
243
+ delay = REDIRECTION_DELAY ,
244
+ title = REDIRECTION_TITLE ,
178
245
)
179
246
)
180
247
if not cool :
0 commit comments