From 9344b91d0f08d0cd4b06a044df590f9be8dc388b Mon Sep 17 00:00:00 2001 From: Sean Dockray Date: Sat, 5 Sep 2020 23:33:06 +1000 Subject: [PATCH] Python implementation of the post-commit hook script --- custom_syadmin/git_hooks_post-receive.py | 162 +++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 custom_syadmin/git_hooks_post-receive.py diff --git a/custom_syadmin/git_hooks_post-receive.py b/custom_syadmin/git_hooks_post-receive.py new file mode 100644 index 0000000..28fcef9 --- /dev/null +++ b/custom_syadmin/git_hooks_post-receive.py @@ -0,0 +1,162 @@ +#! python +""" +This is an alternative to `git_hooks_post-receive.sh` +The post commit hook in Gitea would include something like the following to ensure this script is called. + +#!/bin/sh +read oldrev newrev ref +python "D:\dev\websites\sandpoints-dev\custom_syadmin\git_hooks_post-receive.py" \ +--git_repo "D:\dev\websites\pirate-care-syllabus\gitea\gitea-repositories\gitea\pirate-care-syllabus.git" \ +--website "D:\dev\websites\testing-ground\sandpoints" \ +--website_preview "D:\dev\websites\testing-ground\sandpoints\_preview" \ +--hugo_preview_url https://syllabus.pirate.care/_preview/ \ +--library "D:\dev\websites\pirate-care-syllabus\_library" \ +--tmp_dir "D:\tmp\tmp" +--oldrev $oldrev \ +--newrev $newrev \ +--ref $ref + +To test this script from the command line without relying on a commit hook being triggered, use: + +python "D:\dev\websites\sandpoints-dev\custom_syadmin\git_hooks_post-receive.py" --ref refs/heads/master --git_repo "D:\dev\websites\pirate-care-syllabus\gitea\gitea-repositories\gitea\pirate-care-syllabus.git" --website D:\\dev\\websites\\testing-ground\\sandpoints --website_preview D:\\dev\\websites\\testing-ground\\sandpoints\\_preview --tmp_dir D:\\tmp\\tmp --git_url "http://localhost:3000/gitea/pirate-care-syllabus" --base_url "http://localhost:8000" + +""" +import os +import argparse +import random +import string +import subprocess +import shutil +import stat +from datetime import datetime + +# format for dates +date_format = "%m/%d/%Y, %H:%M:%S" + +# Set the variables we'll be allowing for (as CL arg or environment variable) +vars = { + 'oldrev': False, # set programmatically by git hook + 'newrev': False, # set programmatically by git hook + 'ref': False, # set programmatically by git hook + 'library': '_library', + 'website': '_website', + 'website_preview': '_websitepreview', + 'git_repo': False, + 'base_url': False, #override the site's base + 'git_url': False, + 'git_path': 'git', + 'hugo_path': 'hugo', + 'tmp_dir': '/tmp', + 'force': False, +} + +# logging time +start_time = datetime.now().strftime(date_format) + +def random_string(length=3): + """ Generates a random string """ + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for i in range(length)) + + +def get_value(name, default=False): + """ Variables can be set as environment variable or in command line """ + if hasattr(args, name.lower()) and getattr(args, name.lower()) is not None: + print('CLI:', name, getattr(args, name.lower())) + return getattr(args, name.lower()) + elif name.upper() in os.environ: + print('env:', name, os.environ[name.upper()]) + return os.environ[name.upper()] + else: + print('default:', name, default) + return default + + +def cmd(parts, cwd=None, env=None): + """ Executes a shell command and returns the output """ + print(f"Command: {' '.join(parts)} ({cwd})") + return subprocess.check_output(parts, cwd=cwd, env=env, universal_newlines=True).strip() + + +def rmrf(path): + """ Use safe-rm for recursive removal """ + """ @TODO: make it safer """ + def remove_readonly(func, path, excinfo): + os.chmod(path, stat.S_IWRITE) + func(path) + # Try removal + if os.path.exists(path) and len(os.path.realpath(path)) > 1: + shutil.rmtree(path, onerror=remove_readonly) + else: + print("Either the path doesn't exist or you are trying to delete the root directory(?!):", path) + + +def clobber(filepath, data, append=False): + """ Equivalent of > or >> when append is True """ + mode = 'a' if append else 'w' + with open(filepath, mode) as f: + f.write(data) + + +def build_site(dest, tmp, hugo_environment='gitea'): + """ builds the website to "dest" using "tmp" as an intermediate location """ + global GIT_PATH, GIT_REPO, HUGO_PATH + cmd([GIT_PATH, 'clone', '.', tmp], cwd=GIT_REPO) + rmrf(dest) + try: + os.makedirs(dest, exist_ok=True) + except: + print(f"Error creating the directory: {dest}") + lcl = f'{tmp}/last-commit-log.txt' + # overriding hugo config for development environments + env = os.environ.copy() + if BASE_URL: + env["HUGO_PARAMS_BASEURL"] = BASE_URL + if GIT_URL: + env["HUGO_PARAMS_GITURL"] = GIT_URL + # run the hugo command + hugo_output = cmd([HUGO_PATH, '-e', hugo_environment, '-d', dest], cwd=tmp, env=env) + clobber(lcl, hugo_output) + now_time = datetime.now().strftime(date_format) + clobber(lcl, f"\n{start_time}\n{now_time}", append=True) + shutil.move(lcl, dest) + rmrf(tmp) + + +# Parsing command line arguments +parser = argparse.ArgumentParser() +for v in vars: + parser.add_argument(f"--{v.lower()}") +args = parser.parse_args() + +# Load all variables from command line arguments or environment variables +for v in vars: + globals()[v.upper()] = get_value(v.lower(), vars[v]) + +# set up directories +os.makedirs(WEBSITE, exist_ok=True) +os.makedirs(WEBSITE_PREVIEW, exist_ok=True) +TMP_WEBSITE = os.path.join(TMP_DIR, 'website', random_string()) +TMP_WEBSITE_PREVIEW = os.path.join(TMP_DIR, 'websitepreview', random_string()) +os.makedirs(TMP_WEBSITE, exist_ok=True) +os.makedirs(TMP_WEBSITE_PREVIEW, exist_ok=True) + +# start working +# Check if someone edited the publish trigger +published = False +refs = cmd([GIT_PATH, 'diff-tree', '--no-commit-id', '--name-only', REF], cwd=GIT_REPO).split("\n") +for r in refs: + if FORCE or r == "PUBLISH.trigger.md": + build_site(WEBSITE, TMP_WEBSITE) + published = True +# Check if there is a !publish! +if not published: + refs = cmd([GIT_PATH, 'show', '--format="%s"', '-s'], cwd=GIT_REPO).split(' ') + for r in refs: + if r == "!publish!": + build_site(WEBSITE, TMP_WEBSITE) + published = True +# create preview version +build_site(WEBSITE_PREVIEW, TMP_WEBSITE_PREVIEW, hugo_environment='preview') + +# @TODO: link the library \ No newline at end of file