From 0e13849b20795e560e38793e6f6a09043dbffb34 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 19 Oct 2025 00:50:33 -0400 Subject: [PATCH] [license-header] refactor: excludes, updating, better logic Rewrite of license-header.sh. Lots of new goodies: - Fully POSIX compliant - supports dash arguments (-u/--update, -c/--commit, -uc for both) - can update year or malformed headers in-place now - accounts for shell scripts - exclusion of external files (e.g. sse2neon, my CMake modules/scripts) - better, more extensible logic all around Signed-off-by: crueter --- .ci/license-header.sh | 257 ++++++++++++++++++++++++++--------------- tools/cpm-fetch-all.sh | 0 2 files changed, 166 insertions(+), 91 deletions(-) mode change 100644 => 100755 tools/cpm-fetch-all.sh diff --git a/.ci/license-header.sh b/.ci/license-header.sh index 3d4929d1c1..6a9b4dfa2b 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -1,74 +1,122 @@ #!/bin/sh -e -HEADER="$(cat "$PWD/.ci/license/header.txt")" -HEADER_HASH="$(cat "$PWD/.ci/license/header-hash.txt")" +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later -echo "Getting branch changes" +# argparse -# BRANCH=`git rev-parse --abbrev-ref HEAD` -# COMMITS=`git log ${BRANCH} --not master --pretty=format:"%h"` -# RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}" -# FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` +usage() { + cat << EOF +$0: Check license headers compared to this branch's merge base with master. +Usage: $0 [uc] + -u, --update Fix license headers, if applicable + -c, --commit Commit changes to Git (requires --update) +EOF +} -BASE=`git merge-base master HEAD` -FILES=`git diff --name-only $BASE` +while true; do + case "$1" in + (-uc) UPDATE=true; COMMIT=true ;; + (-u|--update) UPDATE=true ;; + (-c|--commit) COMMIT=true ;; + ("$0") break ;; + ("") break ;; + (*) usage ;; + esac + + shift +done -#FILES=$(git diff --name-only master) +# specify full path if dupes may exist +EXCLUDE_FILES="CPM.cmake CPMUtil.cmake GetSCMRev.cmake sse2neon.h" +EXCLUDE_FILES=$(echo "$EXCLUDE_FILES" | sed 's/ /|/g') -echo "Done" +# license header constants, please change when needed :)))) +YEAR=2025 +HOLDER="Eden Emulator Project" +LICENSE="GPL-3.0-or-later" -check_header() { - CONTENT="`head -n3 < $1`" - case "$CONTENT" in - "$HEADER"*) ;; - *) BAD_FILES="$BAD_FILES $1" ;; - esac +# human-readable header string +header() { + header_line1 "$1" + header_line2 "$1" } -check_cmake_header() { - CONTENT="`head -n3 < $1`" +header_line1() { + echo "$1 SPDX-FileCopyrightText: Copyright $YEAR $HOLDER" +} - case "$CONTENT" in - "$HEADER_HASH"*) ;; - *) - BAD_CMAKE="$BAD_CMAKE $1" ;; - esac +header_line2() { + echo "$1 SPDX-License-Identifier: $LICENSE" +} + +# PCRE header string +pcre_header() { + begin="$1" + echo "(?s)$(header_line1 "$begin").*$(header_line2 "$begin")" +} + +check_header() { + begin="$1" + file="$2" + content="$(head -n5 < "$2")" + + header="$(pcre_header "$begin")" + + if ! echo "$content" | grep -Pzo "$header" > /dev/null; then + # SRC_FILES is Kotlin/C++ + # OTHER_FILES is sh, CMake + case "$begin" in + "//") + SRC_FILES="$SRC_FILES $file" + ;; + "#") + OTHER_FILES="$OTHER_FILES $file" + ;; + esac + fi } + +BASE=$(git merge-base master HEAD) +FILES=$(git diff --name-only "$BASE") + for file in $FILES; do [ -f "$file" ] || continue - if [ `basename -- "$file"` = "CMakeLists.txt" ]; then - check_cmake_header "$file" - continue - fi - - EXTENSION="${file##*.}" - case "$EXTENSION" in - kts|kt|cpp|h) - check_header "$file" - ;; - cmake) - check_cmake_header "$file" + case $(basename -- "$file") in + "$EXCLUDE_FILES") + # skip files that are third party (crueter's CMake modules, sse2neon, etc) + continue ;; + *.cmake|*.sh|CMakeLists.txt) + begin="#" + ;; + *.kt*|*.cpp|*.h) + begin="//" + ;; esac + + check_header "$begin" "$file" done -if [ "$BAD_FILES" = "" ] && [ "$BAD_CMAKE" = "" ]; then - echo - echo "All good." +if [ -z "$SRC_FILES" ] && [ -z "$OTHER_FILES" ]; then + echo "-- All good." exit fi -if [ "$BAD_FILES" != "" ]; then - echo "The following source files have incorrect license headers:" - echo +echo + +if [ "$SRC_FILES" != "" ]; then + echo "-- The following source files have incorrect license headers:" - for file in $BAD_FILES; do echo $file; done + HEADER=$(header "//") + + for file in $SRC_FILES; do echo "-- * $file"; done cat << EOF -The following license header should be added to the start of all offending SOURCE files: +-- The following license header should be added to the start of these offending files: === BEGIN === $HEADER @@ -78,18 +126,19 @@ EOF fi -if [ "$BAD_CMAKE" != "" ]; then - echo "The following CMake files have incorrect license headers:" - echo +if [ "$OTHER_FILES" != "" ]; then + echo "-- The following CMake and shell scripts have incorrect license headers:" + + HEADER=$(header "#") - for file in $BAD_CMAKE; do echo $file; done + for file in $OTHER_FILES; do echo "-- * $file"; done cat << EOF -The following license header should be added to the start of all offending CMake files: +-- The following license header should be added to the start of these offending files: === BEGIN === -$HEADER_HASH +$HEADER === END === EOF @@ -97,50 +146,76 @@ EOF fi cat << EOF -If some of the code in this PR is not being contributed by the original author, -the files which have been exclusively changed by that code can be ignored. -If this happens, this PR requirement can be bypassed once all other files are addressed. -EOF - -if [ "$FIX" = "true" ]; then - echo - echo "FIX set to true. Fixing headers." - echo - - for file in $BAD_FILES; do - cat $file > $file.bak + If some of the code in this PR is not being contributed by the original author, + the files which have been exclusively changed by that code can be ignored. + If this happens, this PR requirement can be bypassed once all other files are addressed. - cat .ci/license/header.txt > $file - echo >> $file - cat $file.bak >> $file - - rm $file.bak - - git add $file - done - - for file in $BAD_CMAKE; do - cat $file > $file.bak - - cat .ci/license/header-hash.txt > $file - echo >> $file - cat $file.bak >> $file - - rm $file.bak +EOF - git add $file - done - echo "License headers fixed." +if [ "$UPDATE" = "true" ]; then + TMP_DIR=$(mktemp -d) + echo "-- Fixing headers..." + + for file in $SRC_FILES $OTHER_FILES; do + case $(basename -- "$file") in + *.cmake|CMakeLists.txt) + begin="#" + shell="false" + ;; + *.sh) + begin="#" + shell=true + ;; + *.kt*|*.cpp|*.h) + begin="//" + shell="false" + ;; + esac + + # This is fun + match="$begin SPDX-FileCopyrightText.*$HOLDER" + + # basically if the copyright holder is already defined we can just replace the year + if head -n5 < "$file" | grep -e "$match" >/dev/null; then + replace=$(header_line1 "$begin") + sed "s|$match|$replace|" "$file" > "$file".bak + mv "$file".bak "$file" + else + header "$begin" > "$TMP_DIR"/header + + if [ "$shell" = "true" ]; then + # grab shebang + head -n1 "$file" > "$TMP_DIR/shebang" + echo >> "$TMP_DIR/shebang" + + # remove shebang + sed '1d' "$file" > "$file".bak + mv "$file".bak "$file" + + # add to header + cat "$TMP_DIR"/shebang "$TMP_DIR"/header > "$TMP_DIR"/new-header + mv "$TMP_DIR"/new-header "$TMP_DIR"/header + else + echo >> "$TMP_DIR/header" + fi + + cat "$TMP_DIR"/header "$file" > "$file".bak + mv "$file".bak "$file" + fi + + [ "$shell" = "true" ] && chmod a+x "$file" + [ "$COMMIT" = "true" ] && git add "$file" + done + + echo "-- Done" +fi - if [ "$COMMIT" = "true" ]; then - echo - echo "COMMIT set to true. Committing changes." - echo +if [ "$COMMIT" = "true" ]; then + echo "-- Committing changes" - git commit -m "Fix license headers" + git commit -m "Fix license headers" - echo "Changes committed. You may now push." - fi -else - exit 1 + echo "-- Changes committed. You may now push." fi + +[ -d "$TMP_DIR" ] && rm -rf "$TMP_DIR" \ No newline at end of file diff --git a/tools/cpm-fetch-all.sh b/tools/cpm-fetch-all.sh old mode 100644 new mode 100755