7
7
import os
8
8
import json
9
9
10
+ from difflib import unified_diff
10
11
from pathlib import Path
11
12
from typing import Optional , Dict
12
13
from copy import deepcopy
21
22
22
23
23
24
def prepare_scanner (doc_gen : DocGen ) -> Optional [Scanner ]:
25
+ """
26
+ Processes the metadata for the scanner.
27
+ :param doc_gen: The documentation generator
28
+ :return: The populated scanner.
29
+ """
24
30
for path in (doc_gen .root / ".doc_gen/metadata" ).glob ("*_metadata.yaml" ):
25
31
doc_gen .process_metadata (path )
26
32
doc_gen .collect_snippets ()
@@ -32,20 +38,22 @@ def prepare_scanner(doc_gen: DocGen) -> Optional[Scanner]:
32
38
return None
33
39
34
40
scanner = Scanner (doc_gen )
35
-
36
41
# Preload cross-content examples
37
42
scanner .load_crosses ()
38
-
39
43
return scanner
40
44
41
45
42
46
def main ():
43
- # Load all examples immediately for cross references. Trades correctness for speed.
47
+ """
48
+ Main entry point of the catalog generation.
49
+ """
50
+ # Load all examples immediately for cross-references. Trades correctness for speed.
44
51
doc_gen = DocGen .from_root (Path (__file__ ).parent .parent .parent , incremental = True )
45
52
# To get the complete list, fill the missing fields.
46
53
doc_gen .fill_missing_fields ()
47
54
48
- languages = ['Python:3' ] # Currently enabled only for Python version 3.
55
+ # Currently enabled only for Python version 3. Add more languages to enable catalog generation.
56
+ languages = ['Python:3' ]
49
57
parser = argparse .ArgumentParser ()
50
58
parser .add_argument (
51
59
"--languages" ,
@@ -111,20 +119,24 @@ def main():
111
119
id = f"{ language } :{ version } :{ service } "
112
120
try :
113
121
renderer .set_example (service , language , int (version ), False )
114
- service_folder_path = renderer .lang_config ["service_folder" ]
115
- logging .debug ("Cataloging %s" , id )
116
- catalog_status = write_catalog_json (doc_gen , service , language , service_folder_path , args .dry_run )
117
- logging .debug ("Status %s" , catalog_status )
118
-
119
- if catalog_status == RenderStatus .UPDATED :
120
- if args .dry_run :
121
- diff = None
122
- failed .append ((id , diff ))
123
- else :
124
- written .append (id )
125
- elif catalog_status == RenderStatus .UNCHANGED :
122
+ # Ignore folders that are duplicates due to service folder overrides.
123
+ if service in renderer .lang_config ["service_folder_ignores" ]:
124
+ logging .debug ("Ignoring %s" , id )
126
125
unchanged .append (id )
127
- pass
126
+ else :
127
+ service_folder_path = renderer .lang_config ["service_folder" ]
128
+ logging .debug ("Cataloging %s" , id )
129
+ catalog_status = write_catalog_json (doc_gen , service , language , service_folder_path , args .dry_run )
130
+ logging .debug ("Status %s" , catalog_status )
131
+
132
+ if catalog_status == RenderStatus .UPDATED :
133
+ if args .dry_run :
134
+ failed .append (id )
135
+ else :
136
+ written .append (id )
137
+ elif catalog_status == RenderStatus .UNCHANGED :
138
+ unchanged .append (id )
139
+ pass
128
140
except FileNotFoundError as fnfe :
129
141
logging .debug (fnfe , exc_info = True )
130
142
skipped .append (id )
@@ -144,23 +156,27 @@ def main():
144
156
done_list = "\n " .join (f"Wrote { f } " for f in sorted (written ))
145
157
print (done_list or "(None Written)" )
146
158
if failed :
147
- if args .diff :
148
- failed_list = "\n " .join (
149
- f"Diff: { f [1 ]} " for f in sorted (failed , key = lambda f : f [0 ])
150
- )
151
- else :
152
- failed_list = "\n " .join (f"Incorrect: { f [0 ]} " for f in sorted (failed ))
159
+ failed_list = "\n " .join (f"Incorrect: { f } " for f in sorted (failed ))
153
160
print (failed_list )
154
161
print ("Rerun catalog.py to update the example catalog list." )
155
162
print ("Catalog Run completed." )
156
163
return len (failed )
157
164
158
165
159
166
def write_catalog_json (doc_gen , service_name , language_name , folder_path , is_dry_run ):
167
+ """
168
+ Writes or checks the catalog json file for the language/service combination.
169
+ :param doc_gen: The documentation generator.
170
+ :param service_name: Service name for the catalog.
171
+ :param language_name: Language name for the catalog.
172
+ :param folder_path: Folder path for the resulting file.
173
+ :param is_dry_run: True to compare only.
174
+ :return: A render status of UNCHANGED, or UPDATED.
175
+ """
160
176
filepath = (
161
177
Path (__file__ ).parent .parent .parent
162
178
/ folder_path
163
- / 'examples_catalog.json'
179
+ / config . catalog_filename
164
180
)
165
181
166
182
language_examples = []
@@ -194,7 +210,10 @@ def write_catalog_json(doc_gen, service_name, language_name, folder_path, is_dry
194
210
with open (filepath , "r" , encoding = "utf-8" ) as example_meta :
195
211
old_catalog = example_meta .read ()
196
212
except FileNotFoundError :
197
- old_catalog = ""
213
+ old_catalog = ''
214
+ # If the list is empty or the folder does not exist do not expect a file.
215
+ if len (language_examples ) == 0 or not os .path .exists (folder_path ):
216
+ return RenderStatus .UNCHANGED
198
217
199
218
if old_catalog == new_catalog :
200
219
return RenderStatus .UNCHANGED
@@ -203,11 +222,34 @@ def write_catalog_json(doc_gen, service_name, language_name, folder_path, is_dry
203
222
print (f"Writing serialized versions of DocGen to { filepath } " )
204
223
with open (filepath , "w" , encoding = "utf-8" ) as example_meta :
205
224
example_meta .write (new_catalog )
225
+ else :
226
+ diff = make_catalog_diff (new_catalog , old_catalog , service_name )
227
+ print ('diff:' )
228
+ print (diff )
206
229
return RenderStatus .UPDATED
207
230
208
231
232
+ def make_catalog_diff (new_catalog , current_catalog , service ):
233
+ """
234
+ Generate a diff text for the old and new catalogs.
235
+ :param new_catalog: The newly updated catalog.
236
+ :param current_catalog: The current catalog file contents.
237
+ :param service: The service to catalog.
238
+ :return: The diff text.
239
+ """
240
+ current = current_catalog .split ("\n " )
241
+ expected = new_catalog .split ("\n " )
242
+ diff = unified_diff (current , expected , f"{ service } /current" , f"{ service } /expected" )
243
+ return "\n " .join (diff )
244
+
245
+
209
246
def sanitize_example_title (example , service ) -> [str , None ]:
210
- """Clean up the text in an example."""
247
+ """
248
+ Clean up the title text for an example.
249
+ :param example: The example to update.
250
+ :param service: The service name.
251
+ :return: The cleaned title string.
252
+ """
211
253
# API examples use the API name.
212
254
if example .category == 'Api' :
213
255
return sorted (example .services [service ])[0 ]
0 commit comments