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()
 |