|
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