1+ #! /usr/bin/env bash
2+ # Copyright (C) 2024 Intel Corporation
3+ # Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
4+ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
6+ # check-headers.sh - check copyright and license in source files
7+
8+ SELF=$0
9+
10+ function usage() {
11+ echo " Usage: $SELF <source_root_path> <license_tag> [-h|-v|-a]"
12+ echo " -h, --help this help message"
13+ echo " -v, --verbose verbose mode"
14+ echo " -a, --all check all files (only modified files are checked by default)"
15+ echo " -d, --update_dates change Copyright dates in all analyzed files (rather not use with -a)"
16+ }
17+
18+ if [ " $# " -lt 2 ]; then
19+ usage >&2
20+ exit 2
21+ fi
22+
23+ SOURCE_ROOT=$1
24+ shift
25+ LICENSE=$1
26+ shift
27+
28+ PATTERN=` mktemp`
29+ TMP=` mktemp`
30+ TMP2=` mktemp`
31+ TEMPFILE=` mktemp`
32+ rm -f $PATTERN $TMP $TMP2
33+
34+ if [ " $1 " == " -h" -o " $1 " == " --help" ]; then
35+ usage
36+ exit 0
37+ fi
38+
39+ export GIT=" git -C ${SOURCE_ROOT} "
40+ $GIT rev-parse || exit 1
41+
42+ if [ -f $SOURCE_ROOT /.git/shallow ]; then
43+ SHALLOW_CLONE=1
44+ echo
45+ echo " Warning: This is a shallow clone. Checking dates in copyright headers"
46+ echo " will be skipped in case of files that have no history."
47+ echo
48+ else
49+ SHALLOW_CLONE=0
50+ fi
51+
52+ VERBOSE=0
53+ CHECK_ALL=0
54+ UPDATE_DATES=0
55+ while [ " $1 " != " " ]; do
56+ case $1 in
57+ -v|--verbose)
58+ VERBOSE=1
59+ ;;
60+ -a|--all)
61+ CHECK_ALL=1
62+ ;;
63+ -d|--update_dates)
64+ UPDATE_DATES=1
65+ ;;
66+ esac
67+ shift
68+ done
69+
70+ if [ $CHECK_ALL -eq 0 ]; then
71+ CURRENT_COMMIT=$( $GIT log --pretty=%H -1)
72+ MERGE_BASE=$( $GIT merge-base HEAD origin/master 2> /dev/null)
73+ [ -z $MERGE_BASE ] && \
74+ MERGE_BASE=$( $GIT log --pretty=" %cN:%H" | grep GitHub | head -n1 | cut -d: -f2)
75+ [ -z $MERGE_BASE -o " $CURRENT_COMMIT " = " $MERGE_BASE " ] && \
76+ CHECK_ALL=1
77+ fi
78+
79+ if [ $CHECK_ALL -eq 1 ]; then
80+ echo " INFO: Checking copyright headers of all files..."
81+ GIT_COMMAND=" ls-tree -r --name-only HEAD"
82+ else
83+ echo " INFO: Checking copyright headers of modified files only..."
84+ GIT_COMMAND=" diff --name-only $MERGE_BASE $CURRENT_COMMIT "
85+ fi
86+
87+ chmod +x " ${SOURCE_ROOT} /check_license/file-exceptions.sh"
88+
89+ FILES=$( $GIT $GIT_COMMAND | ${SOURCE_ROOT} /check_license/file-exceptions.sh | \
90+ grep -E -e ' *\.[chs]$' -e ' *\.[ch]pp$' -e ' *\.sh$' -e ' *\.py$' \
91+ -e ' TEST*' -e ' Makefile*' -e ' CMakeLists.txt$' -e ' *\.cmake$' \
92+ -e ' *\.link$' -e ' *\.map$' -e ' *\.Dockerfile$' -e ' LICENSE$' \
93+ -e ' /common.inc$' -e ' /match$' -e ' /check_whitespace$' -e ' /cppstyle$' | \
94+ xargs)
95+
96+ RV=0
97+ for file in $FILES ; do
98+ if [ $VERBOSE -eq 1 ]; then
99+ echo " Checking file: $file "
100+ fi
101+ # The src_path is a path which should be used in every command except git.
102+ # git is called with -C flag so filepaths should be relative to SOURCE_ROOT
103+ src_path=" ${SOURCE_ROOT} /$file "
104+ [ ! -f $src_path ] && continue
105+ # ensure that file is UTF-8 encoded
106+ ENCODING=` file -b --mime-encoding $src_path `
107+ iconv -f $ENCODING -t " UTF-8" $src_path > $TEMPFILE
108+
109+ if ! grep -q " SPDX-License-Identifier: $LICENSE " $src_path ; then
110+ echo >&2 " error: no $LICENSE SPDX tag in file: $src_path "
111+ RV=1
112+ fi
113+
114+ if [ $SHALLOW_CLONE -eq 0 ]; then
115+ $GIT log --no-merges --format=" %ai %aE" -- $file | sort > $TMP
116+ else
117+ # mark the grafted commits (commits with no parents)
118+ $GIT log --no-merges --format=" %ai %aE grafted-%p-commit" -- $file | sort > $TMP
119+ fi
120+
121+ # skip checking dates for non-Intel commits
122+ [[ ! $( tail -n1 $TMP ) =~ " @intel.com" ]] && continue
123+
124+ # skip checking dates for new files
125+ [ $( cat $TMP | wc -l) -le 1 ] && continue
126+
127+ # grep out the grafted commits (commits with no parents)
128+ # and skip checking dates for non-Intel commits
129+ grep -v -e " grafted--commit" $TMP | grep -e " @intel.com" > $TMP2
130+
131+ [ $( cat $TMP2 | wc -l) -eq 0 ] && continue
132+
133+ FIRST=` head -n1 $TMP2 `
134+ LAST=` tail -n1 $TMP2 `
135+
136+ YEARS=$( sed '
137+ /.*Copyright (C) \+.*[0-9-]\+ Intel Corporation/!d
138+ s/.*Copyright (C) \([0-9]\+\)-\([0-9]\+\).*/\1-\2/
139+ s/.*Copyright (C) \([0-9]\+\).*/\1/' " $src_path " )
140+ if [ -z " $YEARS " ]; then
141+ echo >&2 " No copyright years in $src_path "
142+ RV=1
143+ continue
144+ fi
145+
146+ HEADER_FIRST=` echo $YEARS | cut -d" -" -f1`
147+ HEADER_LAST=` echo $YEARS | cut -d" -" -f2`
148+
149+ COMMIT_FIRST=` echo $FIRST | cut -d" -" -f1`
150+ COMMIT_LAST=` echo $LAST | cut -d" -" -f1`
151+ if [ " $COMMIT_FIRST " != " " -a " $COMMIT_LAST " != " " ]; then
152+ if [[ -n " $COMMIT_FIRST " && -n " $COMMIT_LAST " ]]; then
153+ if [[ $HEADER_FIRST -lt $COMMIT_FIRST ]]; then
154+ HEADER_FIRST=$COMMIT_FIRST
155+ fi
156+ COMMIT_LAST=` date +%G`
157+ if [[ $COMMIT_FIRST -eq $COMMIT_LAST ]]; then
158+ NEW=$COMMIT_LAST
159+ else
160+ NEW=$COMMIT_FIRST -$COMMIT_LAST
161+ fi
162+ if [[ " $YEARS " == " $NEW " ]]; then
163+ echo " No change needed: $YEARS "
164+ else
165+ if [[ ${UPDATE_DATES} -eq 1 ]]; then
166+ sed -i " s/Copyright ${YEARS} /Copyright ${NEW} /g" " ${src_path} "
167+ else
168+ echo " $file :1: error: wrong copyright date: (is: $YEARS , should be: $NEW )" >&2
169+ RV=1
170+ fi
171+ fi
172+ fi
173+ else
174+ echo " error: unknown commit dates in file: $file " >&2
175+ RV=1
176+ fi
177+ done
178+ rm -f $TMP $TMP2 $TEMPFILE
179+
180+ # check if error found
181+ if [ $RV -eq 0 ]; then
182+ echo " Copyright headers are OK."
183+ else
184+ echo " Error(s) in copyright headers found!" >&2
185+ fi
186+ exit $RV
0 commit comments