From 02c548880ee628daab05aff518509bed38ab9b21 Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Thu, 13 Mar 2025 19:28:51 -0500 Subject: [PATCH] static site generator part 3 Signed-off-by: Brian S. Stephan --- incorporealcms/ssg.py | 113 ++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 43 deletions(-) diff --git a/incorporealcms/ssg.py b/incorporealcms/ssg.py index 5016ef2..4f01c9c 100644 --- a/incorporealcms/ssg.py +++ b/incorporealcms/ssg.py @@ -37,7 +37,6 @@ def build(): output_dir = os.path.abspath(args.output_dir) instance_dir = os.path.abspath(args.instance_dir) - pages_dir = os.path.join(instance_dir, 'pages') # initialize configuration with the path to the instance init_instance(instance_dir) @@ -47,50 +46,22 @@ def build(): cprint(f"creating temporary directory '{tmp_output_dir}' for writing", 'green') # CORE CONTENT - # render and/or copy into the output dir after changing into the instance dir (to simplify paths) - os.chdir(pages_dir) - for base_dir, subdirs, files in os.walk(pages_dir): - # remove the absolute path of the pages directory from the base_dir - base_dir = os.path.relpath(base_dir, pages_dir) - # create subdirs seen here for subsequent depth - for subdir in subdirs: - dst = os.path.join(tmp_output_dir, base_dir, subdir) - if os.path.islink(os.path.join(base_dir, subdir)): - # keep the link relative to the output directory - src = symlink_to_relative_dest(pages_dir, os.path.join(base_dir, subdir)) - print(f"creating directory symlink '{dst}' -> '{src}'") - os.symlink(src, dst, target_is_directory=True) - else: - print(f"creating directory '{dst}'") - os.mkdir(dst) + pages_dir = os.path.join(instance_dir, 'pages') + copy_to_destination(pages_dir, tmp_output_dir) - # process and copy files - for file_ in files: - dst = os.path.join(tmp_output_dir, base_dir, file_) - if os.path.islink(os.path.join(base_dir, file_)): - # keep the link relative to the output directory - src = symlink_to_relative_dest(pages_dir, os.path.join(base_dir, file_)) - print(f"creating symlink '{dst}' -> '{src}'") - os.symlink(src, dst, target_is_directory=False) - else: - src = os.path.join(base_dir, file_) - print(f"copying file '{src}' -> '{dst}'") - shutil.copy2(src, dst) + # STATIC DIR + program_static_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static') + static_output_dir = os.path.join(tmp_output_dir, 'static') + try: + os.mkdir(static_output_dir) + except FileExistsError: + # already exists + pass + copy_to_destination(program_static_dir, static_output_dir, convert_markdown=False) - # render markdown as HTML - if src.endswith('.md'): - rendered_file = dst.removesuffix('.md') + '.html' - try: - content = handle_markdown_file_path(src) - except UnicodeDecodeError: - # perhaps this isn't a markdown file at all for some reason; we - # copied it above so stick with tha - cprint(f"{src} has invalid bytes! skipping", 'yellow') - continue - with open(rendered_file, 'w') as dst_file: - dst_file.write(content) - - # TODO: STATIC DIR + # INSTANCE STATIC DIR + custom_static_dir = os.path.join(instance_dir, 'custom-static') + copy_to_destination(custom_static_dir, static_output_dir, convert_markdown=False) # move temporary dir to the destination old_output_dir = f'{output_dir}-old-{os.path.basename(tmp_output_dir)}' @@ -105,6 +76,62 @@ def build(): # TODO: unlink old dir above? arg flag? +def copy_to_destination(source_dir: str, dest_dir: str, convert_markdown: bool = True) -> None: + """Walk the source directory and copy and/or convert its contents into the destination. + + Args: + source_dir: the directory to copy into the destination + dest_dir: the directory to place copied/converted files into + convert_markdown: whether or not to convert Markdown files (or simply copy them) + """ + cprint(f"copying files from '{source_dir}' to '{dest_dir}'", 'green') + os.chdir(source_dir) + for base_dir, subdirs, files in os.walk(source_dir): + # remove the absolute path of the pages directory from the base_dir + base_dir = os.path.relpath(base_dir, source_dir) + # create subdirs seen here for subsequent depth + for subdir in subdirs: + dst = os.path.join(dest_dir, base_dir, subdir) + if os.path.islink(os.path.join(base_dir, subdir)): + # keep the link relative to the output directory + src = symlink_to_relative_dest(source_dir, os.path.join(base_dir, subdir)) + print(f"creating directory symlink '{dst}' -> '{src}'") + os.symlink(src, dst, target_is_directory=True) + else: + print(f"creating directory '{dst}'") + try: + os.mkdir(dst) + except FileExistsError: + # already exists + pass + + # process and copy files + for file_ in files: + dst = os.path.join(dest_dir, base_dir, file_) + if os.path.islink(os.path.join(base_dir, file_)): + # keep the link relative to the output directory + src = symlink_to_relative_dest(source_dir, os.path.join(base_dir, file_)) + print(f"creating symlink '{dst}' -> '{src}'") + os.symlink(src, dst, target_is_directory=False) + else: + src = os.path.join(base_dir, file_) + print(f"copying file '{src}' -> '{dst}'") + shutil.copy2(src, dst) + + # render markdown as HTML + if src.endswith('.md') and convert_markdown: + rendered_file = dst.removesuffix('.md') + '.html' + try: + content = handle_markdown_file_path(src) + except UnicodeDecodeError: + # perhaps this isn't a markdown file at all for some reason; we + # copied it above so stick with tha + cprint(f"{src} has invalid bytes! skipping", 'yellow') + continue + with open(rendered_file, 'w') as dst_file: + dst_file.write(content) + + def symlink_to_relative_dest(base_dir: str, source: str) -> str: """Given a symlink, make sure it points to something inside the instance and provide its real destination.