From 7d462ce38d078faa7547df834ee184ea861c645a Mon Sep 17 00:00:00 2001 From: Johannes Batzill Date: Tue, 26 Sep 2023 01:07:31 +0000 Subject: [PATCH] [MISC] Adding script for license header generation (#610) --- scripts/license/.license-extensions.txt | 24 ++ scripts/license/README.md | 8 + scripts/license/insert-license-headers.sh | 297 ++++++++++++++++++++++ scripts/license/license-header.txt | 13 + 4 files changed, 342 insertions(+) create mode 100644 scripts/license/.license-extensions.txt create mode 100644 scripts/license/README.md create mode 100755 scripts/license/insert-license-headers.sh create mode 100644 scripts/license/license-header.txt diff --git a/scripts/license/.license-extensions.txt b/scripts/license/.license-extensions.txt new file mode 100644 index 000000000..39a23e0d2 --- /dev/null +++ b/scripts/license/.license-extensions.txt @@ -0,0 +1,24 @@ +EXTENSION , COMMENT_STYLE +cjs , slash_star +css , slash_star +go , double_slash +graphql , hash +groovy , slash_star +gql , hash +java , slash_star +js , slash_star +jsx , slash_star +mjs , slash_star +pl , hash +proto , double_slash +ps1 , hash +py , hash +rs , double_slash +scss , slash_star +sh , hash +sql , double_hyphen +ts , slash_star +tsx , slash_star +bazel , hash +bzl , hash +tf , slash_star diff --git a/scripts/license/README.md b/scripts/license/README.md new file mode 100644 index 000000000..1594d7f58 --- /dev/null +++ b/scripts/license/README.md @@ -0,0 +1,8 @@ +# Backfil license headers +The script in this folder can be used to backfill license headers on existing files. +To run the script, execute: +```bash +./insert-license-headers.sh -l license-header.txt -f "$PATH_TO_CODE_FILE" +``` + +Alternatively, one can also provide `-s "$PATH_TO_LIST_FILE"` parameter to a file that contains a list of files (or path prefixes) \ No newline at end of file diff --git a/scripts/license/insert-license-headers.sh b/scripts/license/insert-license-headers.sh new file mode 100755 index 000000000..f7524774a --- /dev/null +++ b/scripts/license/insert-license-headers.sh @@ -0,0 +1,297 @@ +#!/usr/bin/env bash +# Copyright 2023 Harness, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +function usage { + echo "Script to add license header to files" + echo + echo "./$(basename $0) -l [-s ] [-f ]" + echo "Options" + echo " -h prints usage" + echo " -l path to file containing license text" + echo " -s path to file containing source files to process" + echo " -f path to a single file to process" +} + +function error { + usage + echo + echo "$1" +} + +function error_missing_file { + error "ERROR: $1 file is required!" + exit 3 +} + +function error_cannot_read_file { + error "ERROR: Cannot open file for reading $1" + exit 4 +} + +while getopts ":df:hl:s:v" arg; do + case ${arg} in + f) SOURCE_FILES=${OPTARG} ;; + h) usage ; exit 0 ;; + l) PATH_TO_LICENSE=${OPTARG} ;; + s) PATH_TO_INPUT=${OPTARG} ;; + v) VERBOSE="ON" ;; + :) + echo "$0: Must supply an argument to -$OPTARG." >&2 + exit 1 ;; + ?) + echo "Invalid option: -${OPTARG}." + exit 2 ;; + esac +done + +if [ -z $PATH_TO_LICENSE ]; then + error_missing_file "License" +fi + +if [ -z "$SOURCE_FILES" -a -z "$PATH_TO_INPUT" ]; then + error_missing_file "Source" +fi + +if [ ! -r $PATH_TO_LICENSE ]; then + error_cannot_read_file "$PATH_TO_LICENSE" +fi + +if [ -z "$SOURCE_FILES" -a ! -r "$PATH_TO_INPUT" ]; then + error_cannot_read_file "$PATH_TO_INPUT" +fi + +############################ +## Common Functions ## +############################ + +function debug { + if [ "$VERBOSE" = "ON" ]; then + echo $1 + fi +} + +function create_output_file { + FILE_COUNT=$(( FILE_COUNT + 1 )) + LINE_COUNT=$(( LINE_COUNT + $(wc -l "$FILE" | awk '{print $1}') )) + cp -p "$FILE" "$NEW_FILE" + : > "$NEW_FILE" +} + +function add_header_if_required { + HEADER_WITHOUT_YEAR=$(sed 's/ 20[0-9][0-9] / /' <<< "$HEADER_WITHOUT_COMMENT_SYMBOL") + if [ "$HEADER_WITHOUT_YEAR" = "$LICENSE_TEXT" ]; then + debug "File has correct license header: $FILE" + elif [ $(grep -m1 -ciE "(copyright|license)" <<<"$EXISTING_HEADER") -eq 1 ]; then + debug "Skipping file with alternate license header: $FILE" + else + $1 + fi +} + +function write_file_header { + FILE_DATE=$(git log -1 --format="%ad" --date=format:%Y -- "$FILE") + FILE_DATE=${FILE_DATE:-$(date +'%Y')} + while IFS='' read -r license_line; do + if [ -z "$license_line" ]; then + echo "$SYMBOL" >> "$NEW_FILE" + else + echo "$SYMBOL $license_line" | sed "s//${FILE_DATE}/" >> "$NEW_FILE" + fi + done <"$PATH_TO_LICENSE" +} + +function write_remaining_file_content { + if [ ! -z "$(head -1 <<<"$FILE_CONTENT")" ]; then + echo >> "$NEW_FILE" + fi + echo "$FILE_CONTENT" >> "$NEW_FILE" + mv "$NEW_FILE" "$FILE" +} + +############################ +## Double Slash ## +############################ + +function handle_double_slash { + EXISTING_HEADER=$(read_header_double_slash) + if [ -z "$EXISTING_HEADER" ]; then + write_file_double_slash + else + HEADER_WITHOUT_COMMENT_SYMBOL=$(cut -c 4- <<<"$EXISTING_HEADER") + add_header_if_required "write_file_double_slash" + fi +} + +function read_header_double_slash { + awk '{ if (/^\/\//) {print} else {exit} }' "$FILE" +} + +function write_file_double_slash { + debug "Adding license header: $FILE" + NEW_FILE="$FILE.new" + SYMBOL="//" + create_output_file + write_file_header + write_remaining_file_content +} + +############################ +## Slash Star ## +############################ + +function handle_slash_star { + EXISTING_HEADER=$(read_header_slash_star) + if [ -z "$EXISTING_HEADER" ]; then + write_file_slash_star + else + HEADER_WITHOUT_COMMENT_SYMBOL=$(cut -c 4- <<<"$EXISTING_HEADER" | awk 'NR > 1') + add_header_if_required "write_file_slash_star" + fi +} + +function read_header_slash_star { + awk '/\/\*/ {isHeader=1}; isHeader == 1 {print}; /\*\// {exit}' "$FILE" +} + +function write_file_slash_star { + debug "Adding license header: $FILE" + NEW_FILE="$FILE.new" + SYMBOL=" *" + create_output_file + echo "/*" > "$NEW_FILE" + write_file_header + echo " */" >> "$NEW_FILE" + write_remaining_file_content +} + +############################ +## Hash ## +############################ + +function handle_hash { + RAW_HEADER=$(read_header_hash) + EXISTING_HEADER=$(grep -v "^#!" <<<"$RAW_HEADER") + IS_MISSING_SHE_BANG=$(test "$RAW_HEADER" = "$EXISTING_HEADER" && echo "TRUE") + + if [ -z "$EXISTING_HEADER" ]; then + write_file_hash + else + HEADER_WITHOUT_COMMENT_SYMBOL=$(cut -c 3- <<<"$EXISTING_HEADER") + add_header_if_required "write_file_hash" + fi +} + +function read_header_hash { + awk '{ if (/^#/) {print} else {exit} }' "$FILE" +} + +function write_file_hash { + debug "Adding license header: $FILE" + NEW_FILE="$FILE.new" + SYMBOL="#" + create_output_file + if [ "$IS_MISSING_SHE_BANG" != "TRUE" ]; then + head -1 <<<"$FILE_CONTENT" > "$NEW_FILE" + fi + write_file_header + if [ "$IS_MISSING_SHE_BANG" != "TRUE" ]; then + FILE_CONTENT=$(echo "$FILE_CONTENT" | awk "NR > 1") + fi + write_remaining_file_content +} + +############################ +## Double Hyphen ## +############################ + +function handle_double_hyphen { + EXISTING_HEADER=$(read_header_double_hyphen) + if [ -z "$EXISTING_HEADER" ]; then + write_file_double_hyphen + else + HEADER_WITHOUT_COMMENT_SYMBOL=$(cut -c 4- <<<"$EXISTING_HEADER") + add_header_if_required "write_file_double_hyphen" + fi +} + +function read_header_double_hyphen { + awk '{ if (/^--/) {print} else {exit} }' "$FILE" +} + +function write_file_double_hyphen { + debug "Adding license header: $FILE" + NEW_FILE="$FILE.new" + SYMBOL="--" + create_output_file + write_file_header + write_remaining_file_content +} + +############################ +## Execution Functions ## +############################ + +function handle_directory { + FILE_EXTENSIONS=$(awk 'NR>1 {print $1}' "$SUPPORTED_EXTENSIONS_FILE" | paste -s -d '|' -) + FILES_IN_DIR=$(find "$FILE" -type f | grep -E "\.($FILE_EXTENSIONS)$") + while read -r FILE; do + handle_file_based_on_extension + done <<< "$FILES_IN_DIR" +} + +function handle_file_based_on_extension { + FILE_TYPE=$(basename "$FILE" | awk '{gsub(/.*\./, ""); print}' <<<"$FILE") + FILE_CONTENT=$(cat "$FILE") + FILE_TYPE_HANDLER=$(grep "$FILE_TYPE " "$SUPPORTED_EXTENSIONS_FILE" | awk '{print $3}') + + if [ -z "$FILE_TYPE_HANDLER" ]; then + debug "Skipping file with extension '$FILE_TYPE' as it is not a supported filetype, file is $FILE" + else + handle_${FILE_TYPE_HANDLER} + fi +} + +############################ +## Execution ## +############################ + +FILE_COUNT=0 +LINE_COUNT=0 +SCRIPT_DIR=$(dirname "$0") +SUPPORTED_EXTENSIONS_FILE="$SCRIPT_DIR/.license-extensions.txt" +LICENSE_TEXT=$(cat $PATH_TO_LICENSE) +if [ ! -z "$PATH_TO_INPUT" ]; then + SOURCE_FILES=$(cat $PATH_TO_INPUT) +fi +PREVIOUSLY_OVERWRITTEN_HEADER="" + +while read -r FILE; do + if [ ! -e "$FILE" ]; then + debug "Skipping file as it does not exist $FILE" + continue + elif [ -d "$FILE" ]; then + handle_directory + continue + elif [ ! -w "$FILE" ]; then + echo "ERROR: Skipping file as it is not writable $FILE" + continue + fi + + handle_file_based_on_extension +done <<< "$SOURCE_FILES" + +if [ "$FILE_COUNT" -gt 0 ]; then + echo "License added to $FILE_COUNT files with a total line count of $LINE_COUNT" +fi \ No newline at end of file diff --git a/scripts/license/license-header.txt b/scripts/license/license-header.txt new file mode 100644 index 000000000..852608e9a --- /dev/null +++ b/scripts/license/license-header.txt @@ -0,0 +1,13 @@ +Copyright 2023 Harness, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.