]> granicus.if.org Git - strace/blob - maint/update_copyright_years.sh
nlattr: add UID/GID netlink attribute decoders
[strace] / maint / update_copyright_years.sh
1 #!/bin/sh -efu
2 #
3 # Update copyright notices for source files.
4 #
5 # Copyright (c) 2017 The strace developers.
6 # All rights reserved.
7 #
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions
10 # are met:
11 # 1. Redistributions of source code must retain the above copyright
12 #    notice, this list of conditions and the following disclaimer.
13 # 2. Redistributions in binary form must reproduce the above copyright
14 #    notice, this list of conditions and the following disclaimer in the
15 #    documentation and/or other materials provided with the distribution.
16 # 3. The name of the author may not be used to endorse or promote products
17 #    derived from this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 DEFAULT_GIT_COMMIT_TEMPLATE="Update copyright headers
31
32 Headers updated automatically with
33
34     $0 $*"
35
36 : ${COPYRIGHT_NOTICE='The strace developers.'}
37 : ${COPYRIGHT_MARKER='Copyright'}
38 : ${COPYRIGHT_PREFIX="${COPYRIGHT_MARKER} (c)"}
39 : ${VERBOSE=1}
40 : ${CALL_GIT_ADD=0}
41 : ${CALL_GIT_COMMIT=0}
42 : ${GIT_COMMIT_TEMPLATE=$DEFAULT_GIT_COMMIT_TEMPLATE}
43 LC_TIME=C; export LC_TIME
44
45 # These files are only imported into strace and not changed.
46 # Remove them from the list once they have been changed.
47 IGNORED_FILES="git-set-file-times
48 gitlog-to-changelog
49 ${ADDITIONAL_IGNORED_FILES-}"
50
51 log()   { [ "$VERBOSE" -lt 1 ] || printf '%s\n' "$*"; }
52 debug() { [ "$VERBOSE" -lt 2 ] || printf '%s\n' "$*"; }
53
54 print_help()
55 {
56         cat <<'EOF'
57 Usage: update_copyright_notices [-v]* [-q]* [-a] [-h] [-j JOBS] [FILES]
58
59 If no files provided, process all files in current directory, recursively.
60 Only git-tracked files are processed.
61
62 Script implements hard-coded logic for extracting comments in files:
63   ' *'    *.c, *.h (as part of multiline /* ... */ comment)
64   '.\"'   *.[1-8] (man pages)
65   '#'     Everything else
66
67 Options:
68   -a  Invoke git add for the changed files.
69   -c  Call git commit with message provided in $GIT_COMMIT_TEMPLATE (implies -a).
70   -v  Increase verbosity.
71   -q  Decrease verbosity.
72   -h  Show this help.
73   -b  Overwrite beginning year too on update of existing notice.
74   -j  Maximum concurrent jobs.
75
76 Environment:
77   COPYRIGHT_NOTICE  Copyright ownership string.
78   COPYRIGHT_MARKER  What strings are considered copyright strings.
79   COPYTIGHT_PREFIX  Part of copyright string before the year interval.
80   VERBOSE           Verbosity level.
81   CALL_GIT_ADD      Whether to invoke 'git add' on processed files.
82 EOF
83 }
84
85 # $1 - file name
86 # $2 - return version suitable for using in regular expressions
87 get_comment_prefix()
88 {
89         case "$1" in
90         *.[ch])
91                 printf '%s' ' *'
92                 ;;
93         *.[1-8])
94                 printf '%s' '.\"'
95                 ;;
96         *)
97                 printf '%s' '#'
98                 ;;
99         esac
100 }
101
102 # $1 - file
103 process_file()
104 {
105         local f p r span p_quoted r_quoted year_re start_note
106         local last_commit_year first_commit_year
107         local copyright_year copyright_year_raw copyright_notice
108         local existing_notice_re existing_notice_year
109
110         f="$1"
111
112         p=$(get_comment_prefix "$f")
113         r=$(printf '%s' "$p" | sed 's/[].*&^$[\/]/\\&/g')
114
115         year_re="[12][0-9][0-9][0-9]"
116         copyright_year_raw=$(sed -n \
117                 "/^${r}  *${COPYRIGHT_MARKER}"'/s/.*[- ]\('"${year_re}"'\)\( .*\)\?$/\1/p' \
118                         < "$f")
119
120         if [ -z "$copyright_year_raw" ]; then
121                 debug "Copyright notices haven't been found, skipping: $f"
122                 continue
123         fi
124
125         last_commit_year=$(date -u +%Y -d "$(git log -n1 --format=format:%aD \
126                 -- "$f")")
127         first_commit_year=$(date -u +%Y -d "$(git log --reverse --format=format:%aD \
128                 -- "$f" | head -n 1)")
129         copyright_year=$(printf '%s' "$copyright_year_raw" |
130                 sort -r -n | head -n 1)
131         start_note='from git log'
132
133         existing_notice_re="^\(${r}  *${COPYRIGHT_MARKER}.* \)\(\(${year_re}\)\([-, ]*${year_re}\)*\)\( ${COPYRIGHT_NOTICE}\)$"
134         existing_notice_year=$(sed -n \
135                 "/${existing_notice_re}/s//\\3/p" "$f")
136         # assume copyright notice is still relevant
137         if [ "$last_commit_year" = "$copyright_year" ]; then
138                 debug "Does not need update, skipping: $f"
139                 continue
140         else
141                 debug "Needs update ('$copyright_year' != '$last_commit_year'): $f"
142         fi
143
144         # avoid gaps not covered by copyright
145         [ "$first_commit_year" -lt "$copyright_year" ] || {
146                 start_note='from last copyright year'
147                 first_commit_year="$copyright_year"
148         }
149
150         # if there is existing notice, its starting year takes precedence
151         if [ -n "$existing_notice_year" ]; then
152                 start_note='from existing copyright notice'
153                 first_commit_year="$existing_notice_year"
154         fi
155
156         if [ "$first_commit_year" = "$last_commit_year" ]; then
157                 span="$last_commit_year"
158         else
159                 span="$first_commit_year-$last_commit_year"
160         fi
161
162         copyright_notice="${COPYRIGHT_PREFIX} ${span} ${COPYRIGHT_NOTICE}"
163         p_quoted="$(printf '%s' "$p" | sed 's/\\/\\\\/g')" \
164         r_quoted="$(printf '%s' "$r" | sed 's/\\/\\\\/g')" \
165
166         if [ -n "$existing_notice_year" ]; then
167                 # update existing notice, avoid touching starting date
168                 sed -i "/${existing_notice_re}/s//\\1${span} ${COPYRIGHT_NOTICE}/" "$f" &&
169                         log "Updated copyright notice in $f (start year $start_note)"
170         else
171                 awk \
172                         -v COMMENT_MARKER="$p_quoted" \
173                         -v COMMENT_MARKER_RE="$r_quoted" \
174                         -v COPYRIGHT_NOTICE="$copyright_notice" \
175                         -v COPYRIGHT_MARKER="$COPYRIGHT_MARKER" \
176                         -f $(dirname "$0")/update_copyright_years.awk \
177                         "$f" > "$f.out" && {
178                                 cat "$f.out" > "$f"
179                                 log "Added copyright notice to $f (start year $start_note)"
180                         } || debug "No changes performed (exit code $?), skipping: $f"
181
182                         rm -f "$f.out"
183         fi
184
185         [ "$CALL_GIT_ADD" = 0 ] || git add "$f"
186 }
187
188 MAX_JOBS="$(getconf _NPROCESSORS_ONLN)"
189 : $(( MAX_JOBS *= 2 ))
190
191 while [ -n "${1-}" ]; do
192         case "$1" in
193         "-v")
194                 VERBOSE=$(($VERBOSE + 1))
195                 ;;
196         "-q")
197                 VERBOSE=$(($VERBOSE - 1))
198                 ;;
199         "-h")
200                 print_help
201                 exit 1
202                 ;;
203         "-a")
204                 CALL_GIT_ADD=1
205                 ;;
206         "-c")
207                 CALL_GIT_ADD=1
208                 CALL_GIT_COMMIT=1
209                 ;;
210         "-j")
211                 shift
212                 MAX_JOBS="$1"
213                 ;;
214         *)
215                 break
216                 ;;
217         esac
218
219         shift
220 done
221
222 jobs=0
223 pids=
224 [ 1 -le "${MAX_JOBS}" ] || MAX_JOBS=2
225
226 git ls-files -- "$@" | grep -vFx "$IGNORED_FILES" | while read f; do
227         process_file "$f" &
228         pids="$pids $!"
229         : $(( jobs += 1 ))
230         if [ "${jobs}" -gt "$MAX_JOBS" ]; then
231                 read wait_pid rest
232                 pids="$rest"
233                 wait -n 2>/dev/null || wait "$wait_pid"
234                 : $(( jobs -= 1 ))
235         fi <<- EOF
236         $pids
237         EOF
238 done
239
240 wait
241
242 [ "$CALL_GIT_COMMIT" = 0 ] || git commit -m "$GIT_COMMIT_TEMPLATE"