Kumi
cf25a22641
Added explanatory comments for steps using the Hugo CLI to generate new issues and subsequent file operations, improving code readability and maintainability. No functional changes were made.
177 lines
5.6 KiB
Python
Executable file
177 lines
5.6 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import subprocess
|
|
import pathlib
|
|
import argparse
|
|
import datetime
|
|
import tempfile
|
|
import tomllib
|
|
|
|
|
|
def get_period_string(
|
|
start: datetime.datetime,
|
|
end: datetime.datetime,
|
|
year: bool = False,
|
|
) -> str:
|
|
"""Get a string representation of the period
|
|
|
|
Args:
|
|
start (datetime.datetime): The start of the period
|
|
end (datetime.datetime): The end of the period
|
|
year (bool, optional): Include the year in the string. Defaults to False.
|
|
|
|
Returns:
|
|
str: The period string
|
|
"""
|
|
if period_start.year == period_end.year:
|
|
if period_start.month == period_end.month:
|
|
period_string = (
|
|
f"{period_start.strftime('%B %d')} - {period_end.strftime('%d')}"
|
|
)
|
|
else:
|
|
period_string = (
|
|
f"{period_start.strftime('%B %d')} - {period_end.strftime('%B %d')}"
|
|
)
|
|
|
|
if year:
|
|
period_string += f", {period_start.year}"
|
|
|
|
else:
|
|
period_string = (
|
|
f"{period_start.strftime('%B %d, %Y')} - {period_end.strftime('%B %d, %Y')}"
|
|
)
|
|
|
|
return period_string
|
|
|
|
|
|
def create_issue(
|
|
issue_number: int, period_start: datetime.datetime, period_end: datetime.datetime
|
|
) -> None:
|
|
"""Create a new issue
|
|
|
|
Args:
|
|
issue_number (int): The issue number
|
|
period_start (datetime.datetime): The start of the period
|
|
period_end (datetime.datetime): The end of the period
|
|
|
|
Raises:
|
|
subprocess.CalledProcessError: If the Hugo command fails
|
|
IOError: If any of the Python file operations fail
|
|
"""
|
|
# Use the Hugo CLI to create a new issue
|
|
subprocess.run(
|
|
["hugo", "new", f"weekly/issue-{issue_number}/_index.md"], check=True
|
|
)
|
|
|
|
# Read the content of the new file
|
|
with open(f"content/weekly/issue-{issue_number}/_index.md", "r") as f:
|
|
content = f.read()
|
|
|
|
# Get line that starts with "title" and replace it with the new title
|
|
lines = content.split("\n")
|
|
|
|
period_string = get_period_string(period_start, period_end, True)
|
|
|
|
for i, line in enumerate(lines):
|
|
if line.startswith("title:"):
|
|
lines[i] = f"title: Issue {issue_number} - {period_string}"
|
|
|
|
content = "\n".join(lines)
|
|
|
|
# Overwrite the file with the new content
|
|
with open(f"content/weekly/issue-{issue_number}/_index.md", "w") as f:
|
|
f.write(content)
|
|
|
|
|
|
def create_issue_image(
|
|
site_title: str,
|
|
issue_number: int,
|
|
period_start: datetime.datetime,
|
|
period_end: datetime.datetime,
|
|
) -> None:
|
|
"""Create a cover image for the issue
|
|
|
|
Args:
|
|
site_title (str): The title of the site
|
|
issue_number (int): The issue number
|
|
period_start (datetime.datetime): The start of the period
|
|
period_end (datetime.datetime): The end of the period
|
|
|
|
Raises:
|
|
FileNotFoundError: If the cover template is not found
|
|
IOError: If any of the file operations fail
|
|
"""
|
|
with open("assets/img/cover-template.svg") as f:
|
|
cover_template = f.read()
|
|
|
|
period_string = get_period_string(period_start, period_end)
|
|
|
|
cover_template = cover_template.replace("__SITE__", site_title)
|
|
cover_template = cover_template.replace("__TITLE__", f"Issue {issue_number}")
|
|
cover_template = cover_template.replace("__DATE__", period_string)
|
|
|
|
with tempfile.TemporaryDirectory() as tempdir:
|
|
cover_path = pathlib.Path(tempdir) / "cover.svg"
|
|
with open(cover_path, "w") as f:
|
|
f.write(cover_template)
|
|
|
|
subprocess.run(
|
|
[
|
|
"inkscape",
|
|
str(cover_path),
|
|
"--export-filename",
|
|
f"content/weekly/issue-{issue_number}/cover.png",
|
|
]
|
|
)
|
|
|
|
|
|
def get_latest_issue() -> int:
|
|
"""Get the latest issue number from the weekly directory
|
|
|
|
Returns:
|
|
int: The latest issue number
|
|
"""
|
|
issues = list(pathlib.Path("content/weekly").iterdir())
|
|
latest_issue = max(issues, key=lambda x: int(x.name.split("-")[1]))
|
|
return int(latest_issue.name.split("-")[1])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
with open("hugo.toml", "rb") as f:
|
|
hugo_config = tomllib.load(f)
|
|
|
|
parser = argparse.ArgumentParser(description="Create a new issue")
|
|
parser.add_argument("--issue", type=int, help="Issue number")
|
|
parser.add_argument("--period-start", type=str, help="Period start")
|
|
parser.add_argument("--period-end", type=str, help="Period end")
|
|
parser.add_argument("--quiet", "-q", action="store_true", help="Quiet mode")
|
|
args = parser.parse_args()
|
|
|
|
if not (args.period_start and args.period_end):
|
|
if not args.quiet:
|
|
# Query the user for the period start and end
|
|
today = datetime.datetime.now().strftime("%Y-%m-%d")
|
|
|
|
period_start_str = input(f"Period start [{today}]: ") or today
|
|
period_start = datetime.datetime.strptime(period_start_str, "%Y-%m-%d")
|
|
|
|
seven_days = (period_start + datetime.timedelta(days=7)).strftime(
|
|
"%Y-%m-%d"
|
|
)
|
|
|
|
period_end_str = input(f"Period end [{seven_days}]: ") or seven_days
|
|
period_end = datetime.datetime.strptime(period_end_str, "%Y-%m-%d")
|
|
|
|
else:
|
|
# Assume the period is the next 7 days - # TODO: Check if this is correct
|
|
period_start = datetime.datetime.now()
|
|
period_end = datetime.datetime.now() + datetime.timedelta(days=7)
|
|
|
|
if args.issue:
|
|
new_issue = args.issue
|
|
else:
|
|
latest_issue = get_latest_issue()
|
|
new_issue = int(latest_issue) + 1
|
|
|
|
create_issue(new_issue, period_start, period_end)
|
|
create_issue_image(hugo_config["title"], new_issue, period_start, period_end)
|