diff --git a/custom_syadmin/git_hooks_post-receive.py b/custom_syadmin/git_hooks_post-receive.py new file mode 100644 index 0000000..52f7542 --- /dev/null +++ b/custom_syadmin/git_hooks_post-receive.py @@ -0,0 +1,197 @@ +#! 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" \ +--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" + +Just a mental note to read refs from the post-receive hook like this: + +oldrev,newrev,refname = sys.stdin.readline().strip().split(' ') + +""" +import os +import argparse +import random +import string +import subprocess +import shutil +import stat +from datetime import datetime +import logging + +logging.basicConfig(level = logging.DEBUG, filename = "/tmp/git_hooks.log") + +logging.info("WTF!") + + +# 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, + 'branch': None, + 'preview_branch': None, +} + +# 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, keep_dir=False): + """ 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 keep_dir and os.path.exists(path) and len(os.path.realpath(path)) > 1: + for root, dirs, files in os.walk(path): + for f in files: + os.unlink(os.path.join(root, f)) + for d in dirs: + shutil.rmtree(os.path.join(root, d), onerror=remove_readonly) + elif 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, branch=None, hugo_environment='gitea'): + """ builds the website to "dest" using "tmp" as an intermediate location """ + global GIT_PATH, GIT_REPO, HUGO_PATH + if branch: + print("Cloning branch: ", branch) + cmd([GIT_PATH, 'clone', '--branch', branch, '.', tmp], cwd=GIT_REPO) + #print(' '.join([GIT_PATH, 'archive', '--format', 'tar', branch, '|', 'tar', '-x', '-C', tmp])) + #subprocess.call(' '.join([GIT_PATH, 'archive', '--format', 'tar', branch, '|', 'tar', '-x', '-C', tmp]), shell=True, cwd=GIT_REPO) + else: + cmd([GIT_PATH, 'clone', '.', tmp], cwd=GIT_REPO) + rmrf(os.path.join(tmp, '.git')) + rmrf(dest, keep_dir=True) + try: + if not os.path.exists(dest): + os.makedirs(dest) + print("Build destination created: ", dest) + else: + print("Build destination exists: ", dest) + except: + print(f"Error creating the directory: {dest}") + lcl = f'{tmp}/last-commit-log.html' + clobber(lcl, '
')
+    # 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, '--templateMetrics', '-e', hugo_environment, '-d', dest], cwd=tmp, env=env)
+    clobber(lcl, hugo_output, append=True)
+    now_time = datetime.now().strftime(date_format)
+    clobber(lcl, f"\n{start_time}\n{now_time}", append=True)
+    clobber(lcl, f"
", append=True) + shutil.move(lcl, dest) + + +# Parsing command line arguments +parser = argparse.ArgumentParser() +for v in vars: + parser.add_argument(f"--{v.lower()}") +args = parser.parse_args() +logging.info(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, branch=BRANCH) + 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, branch=BRANCH) + published = True +# Let the world know if there hasn't been a publish +if not published: + print("The site wasn't build because there was no publish trigger, nor was it forced.") +# create preview version +build_site(WEBSITE_PREVIEW, TMP_WEBSITE_PREVIEW, branch=PREVIEW_BRANCH, hugo_environment='preview') + +# Clean up temp directories +rmrf(TMP_WEBSITE) +rmrf(TMP_WEBSITE_PREVIEW) diff --git a/custom_syadmin/git_hooks_post-receive.sh b/custom_syadmin/git_hooks_post-receive.sh new file mode 100644 index 0000000..634d23c --- /dev/null +++ b/custom_syadmin/git_hooks_post-receive.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +set -e + +LIBRARY=/var/www/html/library + +WEBSITE=/var/www/html/hugopiratecare +[ -d $WEBSITE ] || mkdir -p $WEBSITE + +WEBSITEPREVIEW=/var/www/html/hugopiratecare/_preview/ +[ -d $WEBSITEPREVIEW ] || mkdir -p $WEBSITEPREVIEW + +GIT_URL="https://git.memoryoftheworld.org/PirateCare/Syllabus" +HUGO_PREVIEW_URL="https://syllabus.pirate.care/_preview/" + +GIT_PATH="git" +HUGO_PATH="hugo" + +BRK="krb" +SAVEIFS=$IFS + +TMP_WEBSITE=/tmp/website$RANDOM +TMP_WEBSITEPREVIEW=/tmp/websitepreview$RANDOM + +d=`date` +CWD=`pwd` + +while read oldrev newrev ref +do + refs=`$GIT_PATH diff-tree --no-commit-id --name-only $ref` + IFS=$'\n' + r=($refs) + + for (( i=0; i<${#r[@]}; i++ )) + do + if [ ${r[$i]} = "PUBLISH.trigger.md" ]; then + cd $CWD + $GIT_PATH clone . $TMP_WEBSITE + cd $TMP_WEBSITE + [ -d $WEBSITE ] || mkdir -p $WEBSITE + + if [ -d $WEBSITE ]; then + safe-rm -rf ${WEBSITE}* + fi + + $HUGO_PATH -e gitea -d $WEBSITE > ${TMP_WEBSITE}/last-commit-log.txt + printf "\n>> $d\n>> `date`" >> ${TMP_WEBSITE}/last-commit-log.txt + mv ${TMP_WEBSITE}/last-commit-log.txt $WEBSITE + cd /tmp/ + + if [ -d $TMP_WEBSITE ] + then + safe-rm -rf $TMP_WEBSITE + fi + BRK="brk" + break + fi + done + + if [ $BRK = "brk" ]; then + break + fi + + cd $CWD + refs=`$GIT_PATH show --format="%s" -s` + IFS=$' ' + r=($refs) + for (( i=0; i<${#r[@]}; i++ )) + do + if [ ${r[$i]} = "!publish!" ]; then + $GIT_PATH clone . $TMP_WEBSITE + cd $TMP_WEBSITE + + [ -d $WEBSITE ] || mkdir -p $WEBSITE + + if [ -d $WEBSITE ]; then + safe-rm -rf ${WEBSITE}* + fi + + $HUGO_PATH -e gitea -d $WEBSITE > ${TMP_WEBSITE}/last-commit-log.txt + printf "\n>> $d\n>> `date`" >> ${TMP_WEBSITE}/last-commit-log.txt + mv $TMP_WEBSITE/last-commit-log.txt $WEBSITE + cd /tmp/ + + if [ -d $TMP_WEBSITE ]; then + safe-rm -rf $TMP_WEBSITE + fi + + break + fi + done +done + +cd $CWD +$GIT_PATH clone . $TMP_WEBSITEPREVIEW +cd $TMP_WEBSITEPREVIEW + +[ -d $WEBSITEPREVIEW ] || mkdir -p $WEBSITEPREVIEW +[ -d data ] || mkdir -p data + +echo 'edit = true' > data/myvars.toml +echo 'giturl="'${GIT_URL}'"' >> data/myvars.toml + +if [ -d $WEBSITEPREVIEW ]; then + safe-rm -rf $WEBSITEPREVIEW +fi + + +$HUGO_PATH -e gitea -d $WEBSITEPREVIEW > ${TMP_WEBSITEPREVIEW}/last-commit-log.txt +printf "\n>> $d\n>> `date`" >> ${TMP_WEBSITEPREVIEW}/last-commit-log.txt +mv ${TMP_WEBSITEPREVIEW}/last-commit-log.txt $WEBSITEPREVIEW + +if [ -d $TMP_WEBSITEPREVIEW ]; then + safe-rm -rf $TMP_WEBSITEPREVIEW +fi + +ln -sf $LIBRARY $WEBSITE +ln -sf $LIBRARY $WEBSITEPREVIEW + +IFS=$SAVEIFS