Skip to content

Commit 21e5f62

Browse files
committed
Fix edge cases of duplicated services.
1 parent fe9f3a6 commit 21e5f62

File tree

3 files changed

+74
-27
lines changed

3 files changed

+74
-27
lines changed

.github/workflows/catalog.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ jobs:
3030
- name: Install dependencies
3131
run: >-
3232
python3 -m pip install -r .tools/scanners/requirements.txt
33-
- name: Check WRITEMEs
33+
- name: Check Catalogs
3434
run: >-
3535
python3 .tools/scanners/catalog.py --check --diff

.tools/scanners/catalog_runner.py

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import os
88
import json
99

10+
from difflib import unified_diff
1011
from pathlib import Path
1112
from typing import Optional, Dict
1213
from copy import deepcopy
@@ -21,6 +22,11 @@
2122

2223

2324
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+
"""
2430
for path in (doc_gen.root / ".doc_gen/metadata").glob("*_metadata.yaml"):
2531
doc_gen.process_metadata(path)
2632
doc_gen.collect_snippets()
@@ -32,20 +38,22 @@ def prepare_scanner(doc_gen: DocGen) -> Optional[Scanner]:
3238
return None
3339

3440
scanner = Scanner(doc_gen)
35-
3641
# Preload cross-content examples
3742
scanner.load_crosses()
38-
3943
return scanner
4044

4145

4246
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.
4451
doc_gen = DocGen.from_root(Path(__file__).parent.parent.parent, incremental=True)
4552
# To get the complete list, fill the missing fields.
4653
doc_gen.fill_missing_fields()
4754

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']
4957
parser = argparse.ArgumentParser()
5058
parser.add_argument(
5159
"--languages",
@@ -111,20 +119,24 @@ def main():
111119
id = f"{language}:{version}:{service}"
112120
try:
113121
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)
126125
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
128140
except FileNotFoundError as fnfe:
129141
logging.debug(fnfe, exc_info=True)
130142
skipped.append(id)
@@ -144,23 +156,27 @@ def main():
144156
done_list = "\n".join(f"Wrote {f}" for f in sorted(written))
145157
print(done_list or "(None Written)")
146158
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))
153160
print(failed_list)
154161
print("Rerun catalog.py to update the example catalog list.")
155162
print("Catalog Run completed.")
156163
return len(failed)
157164

158165

159166
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+
"""
160176
filepath = (
161177
Path(__file__).parent.parent.parent
162178
/ folder_path
163-
/ 'examples_catalog.json'
179+
/ config.catalog_filename
164180
)
165181

166182
language_examples = []
@@ -194,7 +210,10 @@ def write_catalog_json(doc_gen, service_name, language_name, folder_path, is_dry
194210
with open(filepath, "r", encoding="utf-8") as example_meta:
195211
old_catalog = example_meta.read()
196212
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
198217

199218
if old_catalog == new_catalog:
200219
return RenderStatus.UNCHANGED
@@ -203,11 +222,34 @@ def write_catalog_json(doc_gen, service_name, language_name, folder_path, is_dry
203222
print(f"Writing serialized versions of DocGen to {filepath}")
204223
with open(filepath, "w", encoding="utf-8") as example_meta:
205224
example_meta.write(new_catalog)
225+
else:
226+
diff = make_catalog_diff(new_catalog, old_catalog, service_name)
227+
print('diff:')
228+
print(diff)
206229
return RenderStatus.UPDATED
207230

208231

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+
209246
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+
"""
211253
# API examples use the API name.
212254
if example.category == 'Api':
213255
return sorted(example.services[service])[0]

.tools/scanners/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
readme = "README.md"
55
saved_readme = "README.old.md"
6+
catalog_filename = "examples_catalog.json"
67
doc_base_url = "https://docs.aws.amazon.com"
78
categories = {
89
"hello": "Hello",
@@ -153,6 +154,10 @@
153154
"secrets-manager": "python/example_code/secretsmanager",
154155
"dynamodb": "python/example_code/dynamodb",
155156
},
157+
"service_folder_ignores": [
158+
"cognito",
159+
"elastic-load-balancing",
160+
]
156161
}
157162
},
158163
"Ruby": {

0 commit comments

Comments
 (0)