Last active
May 18, 2023 16:37
-
-
Save geblanco/eeaabf983d4d672f581a4a134fb10110 to your computer and use it in GitHub Desktop.
Project scaffold for Obsidian. It is a simple structure containing a Readme, Meetings, Todo and Index files.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python | |
import argparse | |
from pathlib import Path | |
from shutil import rmtree | |
from typing import Any, List, Optional | |
# You must override this value! | |
PROJS_BASE = None | |
DEF_FILES = ["index", "readme", "todo", "meetings"] | |
FILES_W_CONTEXT = ["todo", "meetings"] | |
class parse_files(argparse.Action): | |
def __call__( | |
self, _: Any, args: argparse.Namespace, | |
values: Optional[List[str]], option_string: Optional[str] = None | |
): | |
if values is not None: | |
ret = [] | |
append = any([file.startswith("+") for file in values]) | |
if append: | |
ret.extend(DEF_FILES) | |
ret.extend([file.removeprefix("+") for file in values]) | |
setattr(args, self.dest, list(set(ret))) | |
def parse_flags(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument("proj_name", type=str, help="Project name") | |
parser.add_argument( | |
"--projects_base", required=False, type=str, default=PROJS_BASE, | |
help=f"Projects base directory (default: {PROJS_BASE}" | |
) | |
parser.add_argument( | |
"--files", required=False, nargs="*", default=DEF_FILES, | |
action=parse_files, help="Files to create, use +file to append file to" | |
" the list of default files instead of just create the resquested file" | |
f" (default files: [{', '.join(DEF_FILES)}])" | |
) | |
parser.add_argument( | |
"--overwrite", action="store_true", | |
help="Whether to overwrite the project if it already exists" | |
) | |
return parser.parse_args() | |
def generate_index_content(proj_name: str, files: List[str]): | |
# Index order: ToDo, Meetings, the rest | |
sorted_files = sorted( | |
files, key=lambda el: DEF_FILES.index(el) if el in DEF_FILES else len(DEF_FILES) | |
) | |
sorted_files = [file for file in sorted_files if file.lower() not in ["index"]] | |
files_w_content = [file for file in sorted_files if file.lower() in FILES_W_CONTEXT] | |
content = "----\nFiles:\n" | |
for file in sorted_files: | |
fname = file.strip().capitalize() | |
content += f"- [[{proj_name} {fname}|{fname}]]\n" | |
content += "----\n" | |
for file in files_w_content: | |
fname = file.strip().capitalize() | |
content += f"\n## {fname}\n---\n![[{proj_name} {fname}]]" | |
return content | |
def generate_file_content(proj_name: str, file: str, files: List[str]): | |
# By now, everything except the index are empty | |
content = generate_index_content(proj_name, files) if file == "index" else "" | |
return content | |
def create_file(file_path: Path, content: str): | |
with open(file_path, "w") as fout: | |
fout.write(content) | |
def main( | |
proj_name: str, projects_base: str, files: List[str], overwrite: bool | |
): | |
proj_name = proj_name.strip().capitalize() | |
project_dir = Path(projects_base).joinpath(proj_name) | |
if project_dir.exists() and not overwrite: | |
raise RuntimeError( | |
f"Project directory '{project_dir}' already exists! " | |
"Either pass `--overwrite` to overcome this behaviour or rename " | |
"your project!" | |
) | |
elif project_dir.exists(): | |
rmtree(project_dir) | |
project_dir.mkdir(parents=True) | |
files = [file.strip().lower() for file in files] | |
for file in files: | |
content = generate_file_content(proj_name, file, files) | |
file_name = file.strip().capitalize() + ".md" | |
file_path = project_dir.joinpath(f"{proj_name} {file_name}") | |
create_file(file_path, content) | |
if __name__ == "__main__": | |
main(**vars(parse_flags())) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment