|
11 | 11 | from multiprocessing import Pool
|
12 | 12 | import json
|
13 | 13 | import os
|
14 |
| -import traceback |
15 | 14 |
|
| 15 | +import click |
16 | 16 | from PIL import Image, ImageDraw, ImageFont
|
17 | 17 |
|
18 | 18 | from get_imports import (
|
19 | 19 | get_libs_for_project,
|
20 | 20 | get_files_for_project,
|
| 21 | + get_libs_for_example, |
| 22 | + get_files_for_example, |
21 | 23 | get_learn_guide_cp_projects,
|
22 | 24 | )
|
23 | 25 |
|
|
40 | 42 | bundle_data = json.load(f)
|
41 | 43 | f.close()
|
42 | 44 |
|
43 |
| -font = ImageFont.truetype("Roboto-Regular.ttf", 24) |
44 |
| -right_triangle = Image.open("img/right_triangle.png") |
45 |
| -down_triangle = Image.open("img/down_triangle.png") |
46 | 45 |
|
47 |
| -folder_icon = Image.open("img/folder.png") |
48 |
| -folder_hidden_icon = Image.open("img/folder_hidden.png") |
49 |
| -file_icon = Image.open("img/file.png") |
50 |
| -file_hidden_icon = Image.open("img/file_hidden.png") |
51 |
| -file_empty_icon = Image.open("img/file_empty.png") |
52 |
| -file_empty_hidden_icon = Image.open("img/file_empty_hidden.png") |
| 46 | +def asset_path(asset_name): |
| 47 | + """Return the location of a file shipped with the screenshot maker""" |
| 48 | + return os.path.join(os.path.dirname(__file__), asset_name) |
53 | 49 |
|
54 |
| -file_image_icon = Image.open("img/file_image.png") |
55 |
| -file_music_icon = Image.open("img/file_music.png") |
56 |
| -file_font_icon = Image.open("img/file_font.png") |
| 50 | + |
| 51 | +font = ImageFont.truetype(asset_path("Roboto-Regular.ttf"), 24) |
| 52 | +right_triangle = Image.open(asset_path("img/right_triangle.png")) |
| 53 | +down_triangle = Image.open(asset_path("img/down_triangle.png")) |
| 54 | + |
| 55 | +folder_icon = Image.open(asset_path("img/folder.png")) |
| 56 | +folder_hidden_icon = Image.open(asset_path("img/folder_hidden.png")) |
| 57 | +file_icon = Image.open(asset_path("img/file.png")) |
| 58 | +file_hidden_icon = Image.open(asset_path("img/file_hidden.png")) |
| 59 | +file_empty_icon = Image.open(asset_path("img/file_empty.png")) |
| 60 | +file_empty_hidden_icon = Image.open(asset_path("img/file_empty_hidden.png")) |
| 61 | + |
| 62 | +file_image_icon = Image.open(asset_path("img/file_image.png")) |
| 63 | +file_music_icon = Image.open(asset_path("img/file_music.png")) |
| 64 | +file_font_icon = Image.open(asset_path("img/file_font.png")) |
57 | 65 |
|
58 | 66 | FILE_TYPE_ICON_MAP = {
|
59 | 67 | "py": file_icon,
|
|
73 | 81 |
|
74 | 82 |
|
75 | 83 | def generate_requirement_image(
|
76 |
| - learn_guide_project, |
| 84 | + project_files, libs, image_name |
77 | 85 | ): # pylint: disable=too-many-statements
|
78 | 86 | """Generate a single requirement image"""
|
79 | 87 |
|
@@ -149,7 +157,7 @@ def make_line(
|
149 | 157 | font=font,
|
150 | 158 | )
|
151 | 159 |
|
152 |
| - def make_header(position, learn_guide_project): |
| 160 | + def make_header(position, project_files): |
153 | 161 | # Static files
|
154 | 162 | make_line("CIRCUITPY", position)
|
155 | 163 | make_line(
|
@@ -181,24 +189,17 @@ def make_header(position, learn_guide_project):
|
181 | 189 | )
|
182 | 190 |
|
183 | 191 | # dynamic files from project dir in learn guide repo
|
184 |
| - project_files = get_files_for_project(learn_guide_project) |
185 | 192 | rows_added = 0
|
186 | 193 | project_files_to_draw = []
|
187 | 194 | project_folders_to_draw = []
|
188 | 195 | for cur_file in project_files:
|
189 | 196 | if "." in cur_file[-5:]:
|
190 | 197 | cur_extension = cur_file.split(".")[-1]
|
191 | 198 | if cur_extension in SHOWN_FILETYPES:
|
192 |
| - if cur_file != "main.py": |
193 |
| - project_files_to_draw.append(cur_file) |
| 199 | + project_files_to_draw.append(cur_file) |
194 | 200 | else:
|
195 | 201 | project_folders_to_draw.append(cur_file)
|
196 | 202 |
|
197 |
| - try: |
198 |
| - project_files_to_draw.remove("code.py") |
199 |
| - except ValueError: |
200 |
| - pass |
201 |
| - |
202 | 203 | for i, file in enumerate(sorted(project_files_to_draw)):
|
203 | 204 | cur_file_extension = file.split(".")[-1]
|
204 | 205 |
|
@@ -291,50 +292,87 @@ def make_libraries(libraries, position):
|
291 | 292 | triangle_icon=triangle_icon,
|
292 | 293 | )
|
293 | 294 |
|
294 |
| - try: |
295 |
| - libs = get_libs_for_project(learn_guide_project) |
296 |
| - final_list_to_render = sort_libraries(libs) |
| 295 | + final_list_to_render = sort_libraries(libs) |
297 | 296 |
|
298 |
| - project_file_list = get_files_for_project(learn_guide_project) |
| 297 | + if "code.py" in project_files: |
| 298 | + project_files.remove("code.py") |
299 | 299 |
|
300 |
| - project_files_count = len(project_file_list) |
| 300 | + if "main.py" in project_files: |
| 301 | + project_files.remove("main.py") |
301 | 302 |
|
302 |
| - if "code.py" in project_file_list: |
303 |
| - project_files_count -= 1 |
| 303 | + project_files_count = len(project_files) |
304 | 304 |
|
305 |
| - if "main.py" in project_file_list: |
306 |
| - project_files_count -= 1 |
| 305 | + image_height = ( |
| 306 | + PADDING * 2 |
| 307 | + + 7 * LINE_SPACING |
| 308 | + + len(final_list_to_render) * LINE_SPACING |
| 309 | + + (project_files_count) * LINE_SPACING |
| 310 | + ) |
| 311 | + img = Image.new("RGB", (OUT_WIDTH, image_height), "#303030") |
| 312 | + draw = ImageDraw.Draw(img) |
307 | 313 |
|
308 |
| - image_height = ( |
309 |
| - PADDING * 2 |
310 |
| - + 7 * LINE_SPACING |
311 |
| - + len(final_list_to_render) * LINE_SPACING |
312 |
| - + (project_files_count) * LINE_SPACING |
313 |
| - ) |
314 |
| - img = Image.new("RGB", (OUT_WIDTH, image_height), "#303030") |
315 |
| - draw = ImageDraw.Draw(img) |
| 314 | + make_background_highlights( |
| 315 | + 7 + len(final_list_to_render) + project_files_count, |
| 316 | + offset=(PADDING, PADDING), |
| 317 | + ) |
316 | 318 |
|
317 |
| - make_background_highlights( |
318 |
| - 7 + len(final_list_to_render) + project_files_count, |
319 |
| - offset=(PADDING, PADDING), |
320 |
| - ) |
| 319 | + make_header((PADDING, PADDING), project_files) |
| 320 | + make_libraries( |
| 321 | + final_list_to_render, |
| 322 | + (PADDING, PADDING + (LINE_SPACING * (7 + project_files_count))), |
| 323 | + ) |
321 | 324 |
|
322 |
| - make_header((PADDING, PADDING), learn_guide_project) |
323 |
| - make_libraries( |
324 |
| - final_list_to_render, |
325 |
| - (PADDING, PADDING + (LINE_SPACING * (7 + project_files_count))), |
326 |
| - ) |
| 325 | + img.save("generated_images/{}.png".format(image_name)) |
327 | 326 |
|
328 |
| - img.save( |
329 |
| - "generated_images/{}.png".format(learn_guide_project.replace("/", "_")) |
330 |
| - ) |
331 |
| - except SyntaxError as exc: |
332 |
| - print(exc) |
333 |
| - traceback.print_exc() |
334 |
| - print("SyntaxError finding imports for {}".format(learn_guide_project)) |
335 | 327 |
|
| 328 | +def generate_learn_requirement_image( # pylint: disable=invalid-name |
| 329 | + learn_guide_project, |
| 330 | +): |
| 331 | + """Generate an image for a single learn project""" |
| 332 | + image_name = learn_guide_project.replace("/", "_") |
| 333 | + libs = get_libs_for_project(learn_guide_project) |
| 334 | + project_files = get_files_for_project(learn_guide_project) |
| 335 | + generate_requirement_image(project_files, libs, image_name) |
| 336 | + |
| 337 | + |
| 338 | +def generate_example_requirement_image(example_path): # pylint: disable=invalid-name |
| 339 | + """Generate an image for a library example""" |
| 340 | + image_name = "_".join( |
| 341 | + element |
| 342 | + for element in example_path.split("/") |
| 343 | + if element not in ("libraries", "drivers", "helpers", "examples") |
| 344 | + ) |
| 345 | + libs = get_libs_for_example(example_path) |
| 346 | + project_files = get_files_for_example(example_path) |
| 347 | + generate_requirement_image(project_files, libs, image_name) |
| 348 | + |
| 349 | + |
| 350 | +@click.group(invoke_without_command=True) |
| 351 | +@click.pass_context |
| 352 | +def cli(ctx): |
| 353 | + """Main entry point; invokes the learn subcommand if nothing is specified""" |
| 354 | + if ctx.invoked_subcommand is None: |
| 355 | + learn() |
| 356 | + |
| 357 | + |
| 358 | +@cli.command() |
| 359 | +def learn(): |
| 360 | + """Generate images for a learn-style repo""" |
| 361 | + with Pool() as pool: |
| 362 | + for _ in pool.imap( |
| 363 | + generate_learn_requirement_image, get_learn_guide_cp_projects() |
| 364 | + ): |
| 365 | + pass |
336 | 366 |
|
337 |
| -if __name__ == "__main__": |
338 |
| - with Pool() as p: |
339 |
| - for _ in p.imap(generate_requirement_image, get_learn_guide_cp_projects()): |
| 367 | + |
| 368 | +@cli.command() |
| 369 | +@click.argument("paths", nargs=-1) |
| 370 | +def bundle(paths): |
| 371 | + """Generate images for a bundle-style repo""" |
| 372 | + with Pool() as pool: |
| 373 | + for _ in pool.imap(generate_example_requirement_image, paths): |
340 | 374 | pass
|
| 375 | + |
| 376 | + |
| 377 | +if __name__ == "__main__": |
| 378 | + cli() # pylint: disable=no-value-for-parameter |
0 commit comments