151 lines
4.1 KiB
Python
Executable file
151 lines
4.1 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import datetime
|
|
from hashlib import sha1
|
|
from pathlib import Path
|
|
import subprocess
|
|
import shutil
|
|
from textwrap import fill
|
|
import tempfile
|
|
|
|
from git import Repo
|
|
import pytz
|
|
import sarge
|
|
from slugify import slugify
|
|
import yaml
|
|
|
|
|
|
def is_jekyll_root(path: Path):
|
|
return (path / "_config.yml").exists()
|
|
|
|
|
|
def hash_file(filename: Path) -> str:
|
|
|
|
# Git-like SHA1 hashing
|
|
|
|
filesize = filename.stat().st_size
|
|
|
|
with filename.open() as handle:
|
|
data = handle.read()
|
|
|
|
contents = "blob " + str(filesize) + "\0" + data
|
|
file_hash = sha1(contents.encode())
|
|
|
|
return file_hash.hexdigest()
|
|
|
|
|
|
def perform_commit(filepath: Path, title: str=None,
|
|
draft: bool=False) -> None:
|
|
|
|
import os
|
|
repo = Repo(os.curdir) # FIXME
|
|
repo.index.add(str(filepath))
|
|
|
|
if not draft:
|
|
message = "New post: {}".format(title)
|
|
else:
|
|
message = "New draft: {}".format(title)
|
|
|
|
message = fill(message, width=78)
|
|
|
|
repo.commit(message)
|
|
repo.remotes.origin.push()
|
|
|
|
|
|
def create_new_post(title: str, categories: list=None, tags: list=None,
|
|
post_metadata: dict=None, comments: bool=True,
|
|
draft: bool=False) -> Path:
|
|
|
|
title_slug = slugify(title)
|
|
current_time = datetime.datetime.now(pytz.timezone("Europe/Rome"))
|
|
date_slug = current_time.date().isoformat()
|
|
formatted_date = current_time.strftime("%Y-%m-%d %H:%M:%S%z")
|
|
|
|
metadata = dict(title=title, comments=comments, layout="page")
|
|
|
|
if not draft:
|
|
metadata["date"] = formatted_date
|
|
filename = "{0}-{1}.markdown".format(date_slug, title_slug)
|
|
else:
|
|
filename = "{0}.markdown".format(title_slug)
|
|
|
|
if categories is not None:
|
|
metadata["categories"] = categories
|
|
else:
|
|
metadata["categories"] = ["General"]
|
|
|
|
if tags is not None:
|
|
metadata["tags"] = tags
|
|
|
|
if post_metadata is not None:
|
|
for key, value in post_metadata.items():
|
|
metadata[key] = value
|
|
|
|
if not draft:
|
|
final_path = Path("_posts") / filename
|
|
else:
|
|
final_path = Path("_drafts") / filename
|
|
|
|
with tempfile.NamedTemporaryFile(mode="wt", suffix=".md") as temp:
|
|
|
|
temp_path = Path(temp.name)
|
|
|
|
temp.write("---\n")
|
|
yaml.safe_dump(metadata, temp, default_flow_style=False)
|
|
temp.write("---\n")
|
|
temp.flush()
|
|
|
|
pre_edit_hash = hash_file(temp_path)
|
|
print("Save and close the editor after writing the post.")
|
|
subprocess.check_call("/usr/bin/kate {}".format(temp.name),
|
|
shell=True)
|
|
post_edit_hash = hash_file(temp_path)
|
|
|
|
if pre_edit_hash == post_edit_hash:
|
|
print("No post content. Aborting.")
|
|
return
|
|
|
|
shutil.copy(temp.name, str(final_path))
|
|
|
|
return (final_path)
|
|
|
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("-t", "--tags", nargs="+",
|
|
help="Post tags (space separated)")
|
|
parser.add_argument("-c", "--categories", nargs="+",
|
|
help="Post categories (space separated)")
|
|
parser.add_argument("--disable_comments", action="store_false",
|
|
help="Disable comments for the post")
|
|
parser.add_argument("--commit", action="store_true",
|
|
help="Commit and push to the remote repository")
|
|
parser.add_argument("--draft", action="store_true",
|
|
help="Create the post as draft")
|
|
parser.add_argument("title", help="Title of the new post")
|
|
|
|
options = parser.parse_args()
|
|
|
|
if not is_jekyll_root(Path("./")):
|
|
raise FileNotFoundError("Jekyll root not found.")
|
|
|
|
path = create_new_post(options.title, options.categories, options.tags,
|
|
comments=options.disable_comments,
|
|
draft=options.draft)
|
|
|
|
if path is None:
|
|
exit(1)
|
|
|
|
print("Created new post {}.".format(path.name))
|
|
|
|
if options.commit:
|
|
print("Committing to upstream repository...")
|
|
perform_commit(path, options.title, options.draft)
|
|
|
|
print("Done.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|