diff --git a/.gitignore b/.gitignore index d5fbbf8..78b9616 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ pkg/ src/ *.tar.xz +*.tar.zst +tests/*.out diff --git a/Bash/header b/Bash/header index 0d7c300..065cc3d 100644 --- a/Bash/header +++ b/Bash/header @@ -250,17 +250,18 @@ function getmagnetlink { fi } -### AniNIX Foundation help ### +### AniNIX/Foundation help ### function findaninixcheckouts { - find /usr/local/src/ -type f -name config -exec egrep -l 'url[[:space:]]=[[:space:]]/srv/foundation|url[[:space:]]=[[:space:]]https://aninix.net|url[[:space:]]=[[:space:]]([a-zA-Z0-9])+@aninix.net' {} \; 2>/dev/null | sed 's#.git/config$##' + ### Find git checkouts in $pwd that are from AniNIX/Foundation + find . -type f -name config -exec egrep -l 'url[[:space:]]=[[:space:]]/srv/foundation|url[[:space:]]=[[:space:]]https://(foundation.)aninix.net|url[[:space:]]=[[:space:]]([a-zA-Z0-9])+@(foundation.)aninix.net' {} \; 2>/dev/null | sed 's#.git/config$##' } function aninixgitstatus { for i in `findaninixcheckouts`; do - infoheader BEGIN REPORT for "$i" - git -C "$i" status - infoheader END REPORT - echo + status="$(git -C "$i" status)" + if [ -n "$status" ]; then + echo "$i" has work in flight. + fi done } diff --git a/Hooks/pre-commit b/Hooks/pre-commit new file mode 100755 index 0000000..b36ea79 --- /dev/null +++ b/Hooks/pre-commit @@ -0,0 +1,18 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +# Run all our checking scripts. +for script in $(find `dirname "$0"`/scripts.d -type f); do + "$script" + if [ $? -ne 0 ]; then + echo "$script" failed checks. + exit 1; + fi +done +echo "Pre-commit checks passed." diff --git a/Hooks/pre-receive b/Hooks/pre-receive new file mode 100755 index 0000000..c66fc9a --- /dev/null +++ b/Hooks/pre-receive @@ -0,0 +1,17 @@ +#!/bin/bash + +# Check each commit +while read oldrev newrev refname; do + + # Thanks to https://blog.developer.atlassian.com/stop-foxtrots-now/ for the inspiration + if [ "$refname" == "refs/heads/main" ]; then + match=`git log --first-parent --pretty='%H %P' $oldrev..$newrev | + grep $oldrev | + awk '{ print $2 }'` + if [ "$oldrev" != "$match" ]; then + echo "Foxtrot detected. Please `git rebase origin/main`." + exit 1 + fi + fi + +done diff --git a/Hooks/scripts.d/nonascii b/Hooks/scripts.d/nonascii new file mode 100755 index 0000000..e8bd335 --- /dev/null +++ b/Hooks/scripts.d/nonascii @@ -0,0 +1,30 @@ +#!/bin/bash + +# Sourced from https://github.com/git/git/blob/master/templates/hooks--pre-commit.sample + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi diff --git a/Hooks/scripts.d/pytest b/Hooks/scripts.d/pytest new file mode 100755 index 0000000..b8c6062 --- /dev/null +++ b/Hooks/scripts.d/pytest @@ -0,0 +1,8 @@ +#!/bin/bash + +# Run python3 tests + +if [ -d venv ]; then + source venv/bin/activate +fi +python3 -m pytest diff --git a/Hooks/scripts.d/stop-foxtrots b/Hooks/scripts.d/stop-foxtrots new file mode 100755 index 0000000..09bb25e --- /dev/null +++ b/Hooks/scripts.d/stop-foxtrots @@ -0,0 +1,20 @@ +#!/bin/bash + +# Borrowing from https://github.com/syncier/pre-commit-hooks-jumanjihouse/blob/master/pre_commit_hooks/protect-first-parent + +# Find the correct reference, or fallback to HEAD's abbrev-ref +base="$( + git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null \ + || git branch -avv | awk '/->/ {print $NF}' 2>/dev/null \ + || : +)" +if [ -z "$base" ]; then base="$(git rev-parse --abbrev-ref HEAD)"; fi + +firstParent="$(git show-ref -s "${base}")" + +if git rev-list --first-parent "${base}^".. | grep -q "^${firstParent}$"; then + exit 0 +else + echo Foxtrot detected -- please either rebase or '`git reset --soft`' to recreate your commit. + exit 1 +fi diff --git a/Hooks/scripts.d/whitespace b/Hooks/scripts.d/whitespace new file mode 100755 index 0000000..afe00b5 --- /dev/null +++ b/Hooks/scripts.d/whitespace @@ -0,0 +1,23 @@ +#!/bin/bash + +# Sourced from https://github.com/git/git/blob/master/templates/hooks--pre-commit.sample + +if egrep -irl '\s\+$' .; then + echo The above lines have trailing whitespace. Run "sed -i 's/\s\+$//'" on the affected files. + exit 1 +fi + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# Redirect output to stderr. +exec 1>&2 + + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/Makefile b/Makefile index c9b8c58..4e61442 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ installdir = ${pkgdir}/opt/aninix/Uniglot/ -targets = Bash C CSharp +targets = Bash C CSharp Hooks compile: @echo Nothing to compile. @@ -7,6 +7,8 @@ compile: install: compile mkdir -p ${installdir} for target in ${targets}; do rsync -avzzl "$$target" ${installdir}; done + mkdir -p ${pkgdir}/usr/local/bin + install -m 0755 -o root -g root bin/uniglot-clone ${pkgdir}/usr/local/bin make checkperm clean: @@ -16,11 +18,11 @@ uninstall: rm -Rf ${installdir} test: - @echo Nothing to do. + python3 -m pytest checkperm: - chmod -R 0755 ${installdir} - chown root:root ${installdir} + chmod -R 0755 ${installdir} ${pkgdir}/usr/local/bin/uniglot-clone + chown root:root ${installdir} ${pkgdir}/usr/local/bin/uniglot-clone diff: ${INSTALLFIR} diff -rc . ${installdir} diff --git a/PKGBUILD b/PKGBUILD index 735f131..98f7d94 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,5 +1,5 @@ depends=('bash>=4.4') -makedepends=('make>=4.2') +makedepends=('make>=4.2','gcc','mono') checkdepends=() optdepends=() pkgname="$(git config remote.origin.url | rev | cut -f 1 -d '/' | rev | sed 's/.git$//')" diff --git a/bin/uniglot-clone b/bin/uniglot-clone new file mode 100755 index 0000000..661a135 --- /dev/null +++ b/bin/uniglot-clone @@ -0,0 +1,53 @@ +#!/bin/bash + +# File: uniglot-clone +# +# Description: This is a convenience script to ensure our hooks are standardized. +# +# Package: AniNIX/Uniglot +# Copyright: WTFPL +# +# Author: DarkFeather + +function uniglotClone() { + target="$1" + git-clone "$target" + clone="$(basename "$1" | sed 's/.git$//')" + cd "$clone" +} + + +### usage +### param retcode: what to return +function usage() { + retcode="$1" + echo "Usage: $0 # Update the current clone" + echo " $0 -t target # Clone the target and set hooks" + echo " $0 -h # Help" + echo Add -v for verbosity. +} + +### Main +if [ `basename "$0"` == "uniglot-clone" ]; then + while getopts 'ht:v' OPTION; do + case "$OPTION" in + h) echo AniNIX/Uniglot git-clone standardization; usage 0 ;; + t) target="$OPTARG" ;; + v) set -x ;; + *) usage 1 ;; + esac + done + + # Sanity + if [ ! -d .git ]; then + echo "This should be run from the root of the clone." + exit 2 + fi + + # Standardizations + if git config remote.origin.url | grep -q AniNIX/Uniglot; then + git config core.hooksPath $PWD/Hooks + else + git config core.hooksPath /opt/aninix/Uniglot/Hooks + fi +fi diff --git a/tests/__pycache__/test_bashlib.cpython-310-pytest-7.1.2.pyc b/tests/__pycache__/test_bashlib.cpython-310-pytest-7.1.2.pyc new file mode 100644 index 0000000..4d54c8e Binary files /dev/null and b/tests/__pycache__/test_bashlib.cpython-310-pytest-7.1.2.pyc differ diff --git a/tests/__pycache__/test_hooks.cpython-310-pytest-7.1.2.pyc b/tests/__pycache__/test_hooks.cpython-310-pytest-7.1.2.pyc new file mode 100644 index 0000000..9e7be56 Binary files /dev/null and b/tests/__pycache__/test_hooks.cpython-310-pytest-7.1.2.pyc differ diff --git a/tests/__pycache__/test_imports.cpython-310-pytest-7.1.2.pyc b/tests/__pycache__/test_imports.cpython-310-pytest-7.1.2.pyc new file mode 100644 index 0000000..c007c7b Binary files /dev/null and b/tests/__pycache__/test_imports.cpython-310-pytest-7.1.2.pyc differ diff --git a/tests/test.csharp b/tests/test.csharp new file mode 100644 index 0000000..e083e7b --- /dev/null +++ b/tests/test.csharp @@ -0,0 +1,15 @@ +using AniNIX.Shared; + +namespace AniNIX.Uniglot { + + /// Test class + public class Test { + + /// + /// The default function + /// + static int Main(string[] args) { + return 0; + } + } +} diff --git a/tests/test_hooks.py b/tests/test_hooks.py new file mode 100644 index 0000000..e2edb2a --- /dev/null +++ b/tests/test_hooks.py @@ -0,0 +1,8 @@ +import os +import pytest + +def test_hooks_exec(): + fh = os.popen("find Hooks -type f -exec ls -l {} \\; | egrep ^-rw-") + output = fh.read() + retcode = fh.close() + assert retcode == 256 and output == '' diff --git a/tests/test_imports.py b/tests/test_imports.py new file mode 100644 index 0000000..b61b290 --- /dev/null +++ b/tests/test_imports.py @@ -0,0 +1,26 @@ +import os +import pytest + +def test_bash_import(): + fh = os.popen("/bin/bash -c 'source Bash/header; [ `declare -F | wc -l` -eq `egrep -c ^function\\ Bash/header` ]'", mode='r', buffering=-1) + output = fh.read() + retcode = fh.close() + assert retcode == None + +def test_c_import(): + fh = os.popen("gcc -o tests/c.out C/ll.h", mode='r', buffering=-1) + output = fh.read() + retcode = fh.close() + assert retcode == None and os.path.isfile('tests/c.out') + +def test_csharp_import(): + fh = os.popen("/bin/bash -c 'mcs -out:tests/csharp.out CSharp/*.csharp tests/test.csharp'", mode='r', buffering=-1) + output = fh.read() + retcode = fh.close() + assert retcode == None and os.path.isfile('tests/csharp.out') + +def test_remove_outs(): + fh = os.popen("/bin/bash -c 'rm -Rf tests/*.out'", mode='r', buffering=-1) + output = fh.read() + retcode = fh.close() + assert retcode == None