Skip to content

Instantly share code, notes, and snippets.

@geblanco
Last active May 18, 2023 16:37
Show Gist options
  • Save geblanco/eeaabf983d4d672f581a4a134fb10110 to your computer and use it in GitHub Desktop.
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.
#!/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