Skip to content
Snippets Groups Projects
check-license 2.88 KiB
#!/usr/bin/env bash
set -euo pipefail

# Pretty fancy method to get reliable the absolute path of a shell
# script, *even if it is sourced*. Credits go to GreenFox on
# stackoverflow: http://stackoverflow.com/a/12197518/194894
pushd . > /dev/null
SCRIPTDIR="${BASH_SOURCE[0]}";
while([ -h "${SCRIPTDIR}" ]); do
    cd "`dirname "${SCRIPTDIR}"`"
    SCRIPTDIR="$(readlink "`basename "${SCRIPTDIR}"`")";
done
cd "`dirname "${SCRIPTDIR}"`" > /dev/null
SCRIPTDIR="`pwd`";
popd  > /dev/null

echoerr() { echo "$@" 1>&2; }

AUTOFIX=false
VERBOSE=false

while getopts :dfv OPT; do
	case $OPT in
		d)
			set -x
			;;
		f)
			AUTOFIX=true
			;;
		v)
			VERBOSE=true
			;;
		*)
			echo "usage: ${0##*/} [-d]"
			exit 2
	esac
done
shift $(( OPTIND - 1 ))
OPTIND=1

export ROOTDIR
ROOTDIR=$(readlink -f "${SCRIPTDIR}/..")

export CHECKED_FILES_FILE
CHECKED_FILES_FILE=$(mktemp)
export INVALID_LICENSE_FILES_FILE
INVALID_LICENSE_FILES_FILE=$(mktemp)

function cleanup() {
	rm "${CHECKED_FILES_FILE}"
	rm "${INVALID_LICENSE_FILES_FILE}"
}
trap cleanup EXIT

# Safely call bash function from xargs
# https://stackoverflow.com/questions/11003418/calling-shell-functions-with-xargs/11003457#11003457
check_license() {
	echo "${1}" >> "${CHECKED_FILES_FILE}"

	local license_identifier=".*SPDX-License-Identifier: LGPL-3.0-or-later"
	local copyright_regex=".*Copyright (© )?[0-9]{4}(-[0-9]{4})?( \w)+.*"
	local sed_cmd="{N; N; /^${license_identifier}\n${copyright_regex}\n.+$/!{q1}}"

	local full_path="${ROOTDIR}/${1}"
	if ! head --lines=3 "${full_path}" |\
			sed --regexp-extended --quiet "${sed_cmd}" >/dev/null
	then
		echo "${1}" >> "${INVALID_LICENSE_FILES_FILE}"
		return 1
	fi
}
export -f check_license


MAX_PROCS=$(nproc)

cd "${ROOTDIR}"

set +e
find . \( -path '*/\.*' -o -path "./build*" -o -path "./test/3rd-party*" \) -prune -o \
	-type f -regextype posix-extended -regex '.*\.(c|h|cpp|hpp)' -print0 |\
	xargs --null --max-args=1 --max-procs="${MAX_PROCS}" -I {} \
		  bash -c 'check_license "$@"' _ "{}"
readonly CHECK_RETURN_VALUE="$?"
set -e

if [[ $CHECK_RETURN_VALUE -ne 0 ]]; then
	mapfile -t < "${INVALID_LICENSE_FILES_FILE}"
	echoerr "The following ${#MAPFILE[@]} files have a missing or invalid license header:"
	for INVALID_LICENSE_FILE in "${MAPFILE[@]}"; do
		echoerr "- ${INVALID_LICENSE_FILE}"
	done

	if $AUTOFIX; then
		echo "Autofixing enabled, prepending default header to those files"
		for INVALID_LICENSE_FILE in "${MAPFILE[@]}"; do
			TMPFILE=$(mktemp)

			cat <<EOF > "${TMPFILE}"
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright © 2020 Florian Schmaus
EOF
			cat "${INVALID_LICENSE_FILE}" >> "${TMPFILE}"
			mv "${TMPFILE}" "${INVALID_LICENSE_FILE}"
		done
	fi
	exit "${CHECK_RETURN_VALUE}"
fi

FILE_COUNT=$(<"${CHECKED_FILES_FILE}" wc -l)
echo "Checked ${FILE_COUNT} files for license headers"
if $VERBOSE; then
	mapfile -t < "${CHECKED_FILES_FILE}"
	for FILE in "${MAPFILE[@]}"; do
		echo "- ${FILE}"
	done
fi