]> git.ipfire.org Git - thirdparty/squid.git/blame_incremental - scripts/source-maintenance.sh
Simplify appending SBuf to String (#2108)
[thirdparty/squid.git] / scripts / source-maintenance.sh
... / ...
CommitLineData
1#!/bin/sh
2#
3## Copyright (C) 1996-2025 The Squid Software Foundation and contributors
4##
5## Squid software is distributed under GPLv2+ license and includes
6## contributions from numerous individuals and organizations.
7## Please see the COPYING and CONTRIBUTORS files for details.
8##
9
10#
11# This script contains the code run to perform automatic source maintenance
12# on Squid
13#
14
15# whether to continue execution after a failure
16# TODO: Expand the subset of failures covered by this feature; see run_().
17KeepGoing="no"
18# the actual name of the directive that enabled keep-going mode
19KeepGoingDirective=""
20
21#
22# The script checks that the version of astyle is TargetAstyleVersion.
23# if it isn't, the default behaviour is to not perform the formatting stage
24# in order to avoid unexpected massive changes if the behaviour of astyle
25# has changed in different releases.
26# if --with-astyle /path/to/astyle is used, the check is still performed
27# and a warning is printed, but the sources are reformatted
28TargetAstyleVersion="3.1"
29ASTYLE='astyle'
30
31# whether to check and, if necessary, update boilerplate copyright years
32CheckAndUpdateCopyright=yes
33
34# How to sync CONTRIBUTORS with the current git branch commits:
35# * never: Do not update CONTRIBUTORS at all.
36# * auto: Check commits added since the last similar update.
37# * SHA1/etc: Check commits added after the specified git commit.
38UpdateContributorsSince=auto
39
40# --only-changed-since point
41OnlyChangedSince=""
42
43printUsage () {
44cat <<USAGE_
45Usage: $0 [option...]
46options:
47--check-and-update-copyright <yes|no> (default: yes)
48--help|-h
49--keep-going|-k (default: stop on error)
50--only-changed-since <fork|commit> (default: apply to all files)
51--update-contributors-since <never|auto|revision> (default: auto)
52--with-astyle </path/to/astyle/executable> (default: astyle-${TargetAstyleVersion} or astyle)
53
54USAGE_
55}
56
57printHelp () {
58
59cat <<HELP_INTRO_
60This script applies Squid mandatory code style guidelines and generates
61various files derived from Squid sources.
62HELP_INTRO_
63
64printUsage
65
66cat <<HELP_MAIN_
67--help, -h
68
69Print this information and exit.
70
71--only-changed-since <"fork"|commit>
72
73When specifieid, the script only examines for formatting changes those
74files that have changed since the specified git reference point. The
75argument is either a git commit (fed to "git diff") or a special keyword
76"fork". Common commit values include HEAD^, master, origin/master, and the
77branch the current one was forked off. When "fork" is specified, the
78script will look for files changed since the current branch was forked off
79upstream/master (according to "git merge-base --fork-point").
80
81This option does not disable some repository-wide file generation and
82repository-wide non-formatting checks/adjustments.
83
84--update-contributors-since <never|auto|revision>
85
86Configures how to sync CONTRIBUTORS with the current git branch commits:
87* never: Do not update CONTRIBUTORS at all.
88* auto: Check commits added since the last similar update.
89* SHA1/etc: Check commits added after the specified git commit.
90
91--with-astyle </path/to/astyle/executable>
92
93Squid code style guidelines require astyle version $TargetAstyleVersion.
94The path to the astyle binary can be specified using this command line
95option or by exporting the ASTYLE environment variable. If both are
96specified, the command-line option wins.
97
98External dependencies:
99
100* Astyle. See the --with-astyle command line option above.
101* gperf (if you modify certain source files)
102
103HELP_MAIN_
104}
105
106# command-line options
107while [ $# -ge 1 ]; do
108 case "$1" in
109 --keep-going|-k)
110 KeepGoing=yes
111 KeepGoingDirective=$1
112 shift
113 ;;
114 --check-and-update-copyright)
115 if test "x$2" != xyes -a "x$2" != xno
116 then
117 printUsage
118 echo "Error: Option $1 expects a yes or no argument but got $2"
119 exit 1
120 fi
121 CheckAndUpdateCopyright=$2
122 shift 2
123 ;;
124 --update-contributors-since)
125 if test "x$2" = x
126 then
127 printUsage
128 echo "Error: Option $1 expects an argument."
129 exit 1
130 fi
131 UpdateContributorsSince="$2"
132 shift 2
133 ;;
134 --help|-h)
135 printHelp
136 exit 0
137 ;;
138 --with-astyle)
139 ASTYLE=$2
140 shift 2
141 ;;
142 --only-changed-since)
143 OnlyChangedSince="$2"
144 shift 2
145 ;;
146 *)
147 printUsage
148 echo "Unsupported command-line option: $1"
149 exit 1
150 ;;
151 esac
152done
153
154# an error code seen by a KeepGoing-aware command (or zero)
155SeenErrors=0
156
157if ! git diff --quiet; then
158 echo "There are unstaged changes. This script may modify sources."
159 echo "Stage changes to avoid permanent losses when things go bad."
160 exit 1
161fi
162
163# usage: <well-known program name> <program argument(s)> <candidate name>...
164# Finds the first working program among the given candidate program names.
165# The found program name is returned via the $FoundProgram global:
166FoundProgram=""
167findProgram ()
168{
169 wellKnown="$1"
170 shift
171 options="$1"
172 shift
173
174 for candidate in $*
175 do
176 if "$candidate" $options < /dev/null > /dev/null 2> /dev/null
177 then
178 echo "Found ${wellKnown}-like program: $candidate"
179 FoundProgram="$candidate"
180 return 0
181 fi
182 done
183
184 echo "ERROR: Failed to find a ${wellKnown}-like program; tried: $*"
185 FoundProgram=""
186 return 1
187}
188
189made="generated" # a hack: prevents $GeneratedByMe searches matching this file
190GeneratedByMe="This file is $made by scripts/source-maintenance.sh."
191
192if [ "x$ASTYLE" != "x" ] ; then
193 if ! "${ASTYLE}" --version > /dev/null 2> /dev/null ; then
194 echo "ERROR: Cannot run user-supplied astyle: ${ASTYLE}"
195 exit 1
196 fi
197else
198 findProgram astyle --version astyle-${TargetAstyleVersion} astyle || exit $?
199 ASTYLE=$FoundProgram
200fi
201
202ASVER=`"${ASTYLE}" --version 2>&1 | grep -o -E "[0-9.]+"`
203if test "${ASVER}" != "${TargetAstyleVersion}" ; then
204 if test "${ASTYLE}" = "astyle" ; then
205 echo "Astyle version problem. You have ${ASVER} instead of ${TargetAstyleVersion}"
206 echo "Formatting step skipped due to version mismatch"
207 ASVER=""
208 else
209 echo "WARNING: ${ASTYLE} is version ${ASVER} instead of ${TargetAstyleVersion}"
210 echo "Formatting anyway, please double check output before submitting"
211 fi
212else
213 echo "Detected expected astyle version: ${ASVER}"
214fi
215CppFormatter=''
216if test "${ASVER}"; then
217 CppFormatter="./scripts/format-cpp.pl --with-astyle ${ASTYLE}"
218fi
219
220if test "x$OnlyChangedSince" = "xfork" ; then
221 ForkPoint=`git merge-base --fork-point upstream/master`
222 if test "x$ForkPoint" = "x" ; then
223 echo "Could not identify fork point - sometimes it happens"
224 echo "Please specify commit-id explicitly"
225 exit 1
226 fi
227 OnlyChangedSince="$ForkPoint"
228fi
229
230if test $CheckAndUpdateCopyright = yes
231then
232 COPYRIGHT_YEARS=`date +"1996-%Y"`
233 echo "s/1996-2[0-9]+ The Squid Software Foundation and contributors/${COPYRIGHT_YEARS} The Squid Software Foundation and contributors/g" >> boilerplate_fix.sed
234fi
235
236# executes the specified command
237# in KeepGoing mode, remembers errors and hides them from callers
238run_ ()
239{
240 "$@" && return 0 # return on success
241 error=$?
242
243 if test $KeepGoing = no; then
244 return $error
245 fi
246
247 echo "ERROR: Continuing after a failure ($error) due to $KeepGoingDirective"
248 SeenErrors=$error # TODO: Remember the _first_ error instead
249 return 0 # hide error from the caller
250}
251
252updateIfChanged ()
253{
254 original="$1"
255 updated="$2"
256 message="$3"
257
258 if ! cmp -s "${original}" "${updated}"; then
259 echo "NOTICE: File ${original} changed: ${message}"
260 run_ mv "${updated}" "${original}" || return
261 else
262 run_ rm -f "${updated}" || exit $?
263 fi
264}
265
266# uses the given script to update the given source file
267applyPlugin ()
268{
269 script="$1"
270 source="$2"
271
272 new="$source.new"
273 $script "$source" > "$new" &&
274 updateIfChanged "$source" "$new" "by $script"
275}
276
277# updates the given source file using the given script(s)
278applyPluginsTo ()
279{
280 source="$1"
281 shift
282
283 for script in `git ls-files "$@"`; do
284 run_ applyPlugin $script $source || return
285 done
286}
287
288# succeeds if all MakeNamedErrorDetail() names are unique
289checkMakeNamedErrorDetails ()
290{
291 problems=1 # assume there are problems until proven otherwise
292
293 options='-h --only-matching --extended-regexp'
294 git grep $options 'MakeNamedErrorDetail[(]"[^"]*"[)]' src |
295 sort |
296 uniq --count > \
297 MakeNamedErrorDetail.tmp
298
299 if grep --quiet --word-regexp 1 MakeNamedErrorDetail.tmp; then
300 if grep --invert-match --word-regexp 1 MakeNamedErrorDetail.tmp; then
301 echo "ERROR: Duplicated MakeNamedErrorDetail names (see above)."
302 else
303 problems=0
304 fi
305 else
306 echo "ERROR: Cannot find or process MakeNamedErrorDetail calls."
307 fi
308
309 rm MakeNamedErrorDetail.tmp # ignore (unexpected) cleanup failures
310 return $problems
311}
312
313# extract IDs and gists of cache_log_message debugs() in the given source file
314collectDebugMessagesFrom ()
315{
316 source="$1"
317 destination="doc/debug-messages.tmp"
318
319 if test "x$OnlyChangedSince" != "x"; then
320 # Skipping collection due to --only-changed-since.
321 # processDebugMessages() will warn.
322 return 0
323 fi
324
325 # Merge multi-line debugs() into one-liners and remove '//...' comments.
326 awk 'BEGIN { found=0; dbgLine=""; } {
327 if ($0 ~ /[ \t]debugs[ \t]*\(/)
328 found = 1;
329 if (found) {
330 commented = match($0, /\);[ \t]*\/\//);
331 if (commented)
332 $0 = substr($0, 1, RSTART+1);
333 dbgLine = dbgLine $0;
334 }
335 if ($0 ~ /\);/) {
336 if (found) {
337 found = 0;
338 print dbgLine;
339 dbgLine = "";
340 }
341 }
342 }' $source > doc/debug-messages.tmp2
343
344 # sed expressions:
345 # - replace debugs() prefix with the message ID contained in it
346 # - remove simple parenthesized non-"string" items like (a ? b : c)
347 # - replace any remaining non-"string" items with ...
348 # - remove quotes around "strings"
349 # - remove excessive whitespace
350 # - remove debugs() statement termination sugar
351 grep -o -E '\bdebugs[^,]*,[^,]*(Critical|Important)[(][0-9]+.*' doc/debug-messages.tmp2 | \
352 sed -r \
353 -e 's/.*(Critical|Important)[(]([0-9]+)[)][^,]*,\s*/\2 /' \
354 -e 's/<<\s*[(].*[)]\s*(<<|[)];)/<< ... \1/g' \
355 -e 's/<<\s*[^"]*/.../g' \
356 -e 's@([^\\])"@\1@g' \
357 -e 's/\s\s*/ /g' \
358 -e 's/[)];$//g' \
359 >> $destination
360
361 rm -f doc/debug-messages.tmp2
362}
363
364# make doc/debug-messages.dox from aggregate collectDebugMessagesFrom results
365processDebugMessages ()
366{
367 source="doc/debug-messages.tmp"
368 destination="doc/debug-messages.dox"
369
370 if test "x$OnlyChangedSince" != "x"; then
371 echo "WARNING: Skipping update of $destination due to --only-changed-since"
372 return 0
373 fi
374
375 if test '!' -s "$source"; then
376 echo "ERROR: Failed to find debugs() message IDs"
377 return 1
378 fi
379
380 repeatedIds=`awk '{print $1}' $source | sort -n | uniq -d`
381 if test "x$repeatedIds" != "x"; then
382 echo "ERROR: Repeated debugs() message IDs:"
383 echo "$repeatedIds"
384 echo ""
385 return 1
386 fi
387
388 repeatedGists=`awk '{$1=""; print substr($0,2)}' $source | sort | uniq -d`
389 if test "x$repeatedGists" != "x"; then
390 echo "ERROR: Repeated debugs() message gists:"
391 echo "$repeatedGists"
392 echo ""
393 return 1
394 fi
395
396 cat scripts/boilerplate.h > $destination
397 printf '/**\n' >> $destination
398 printf '\\page ControlledCacheLogMessages Message IDs and gists for cache_log_message\n' >> $destination
399 printf '\\verbatim\n' >> $destination
400 printf 'ID Message gist\n' >> $destination
401 printf '== ============\n' >> $destination
402 sort -n < $source >> $destination
403 printf '\\endverbatim\n' >> $destination
404 printf '*/\n' >> $destination
405
406 rm -f $source
407}
408
409# make doc/debug-sections.txt from aggregated by srcFormat extracts
410processDebugSections ()
411{
412 destination="doc/debug-sections.txt"
413
414 if test "x$OnlyChangedSince" != "x"; then
415 echo "WARNING: Skipping update of $destination due to --only-changed-since"
416 return 0
417 fi
418
419 LC_ALL=C sort -u < doc/debug-sections.tmp > doc/debug-sections.tmp2
420
421 cat scripts/boilerplate.h > $destination
422 echo "" >> $destination
423 cat doc/debug-sections.tmp2 >> $destination
424
425 rm -f doc/debug-sections.tmp*
426}
427
428srcFormat ()
429{
430 # remove stale temporary files that accumulate info extracted below
431 rm -f doc/debug-messages.tmp*
432 rm -f doc/debug-sections.tmp*
433
434#
435# Scan for incorrect use of #ifdef/#ifndef
436#
437git grep "ifn?def .*_SQUID_" |
438 grep -v -E "_H$" |
439 grep -v "scripts/source-maintenance.sh" |
440 while read f; do echo "PROBLEM?: ${f}"; done
441
442#
443# Scan for file-specific actions
444#
445
446 # The two git commands below will also list any files modified during the
447 # current run (e.g., src/http/RegisteredHeadersHash.cci or icons/icon.am).
448 FilesToOperateOn=""
449 if test "x$OnlyChangedSince" != "x" ; then
450 FilesToOperateOn=`git diff --name-only $OnlyChangedSince`
451 gitResult=$?
452 if test $gitResult -ne 0 ; then
453 echo "ERROR: Cannot use --only-changed-since reference point: $OnlyChangedSince"
454 echo "Consider using a git commit SHA (from git log) instead"
455 return $gitResult
456 fi
457 else
458 FilesToOperateOn=`git ls-files`
459 gitResult=$?
460 # a bit paranoid but protects the empty $FilesToOperateOn check below
461 if test $gitResult -ne 0 ; then
462 echo "ERROR: Cannot find source code file names"
463 return $gitResult
464 fi
465 fi
466 if test "x$FilesToOperateOn" = "x"; then
467 echo "WARNING: No files to scan and format"
468 return 0
469 fi
470
471for FILENAME in $FilesToOperateOn; do
472 skip_copyright_check=""
473
474 # skip subdirectories, git ls-files is recursive
475 test -d $FILENAME && continue
476
477 # generated files are formatted during their generation
478 if grep -q -F "$GeneratedByMe" ${FILENAME}; then
479 continue
480 fi
481
482 case ${FILENAME} in
483
484 *.h|*.c|*.cc|*.cci)
485
486 #
487 # Code Style formatting maintenance
488 #
489 applyPluginsTo ${FILENAME} scripts/maintenance/ || return
490 if test "$CppFormatter"; then
491 if $CppFormatter $FILENAME > $FILENAME.new; then
492 updateIfChanged $FILENAME $FILENAME.new 'by astyle'
493 else
494 rm $FILENAME.new
495 fi
496 fi
497
498 #
499 # REQUIRE squid.h first #include
500 #
501 case ${FILENAME} in
502 src/cf_gen.cc)
503 # ignore, this is a build tool.
504 ;;
505 *.c|*.cc)
506 FI=`grep "#include" ${FILENAME} | head -1`;
507 if test "${FI}" != "#include \"squid.h\"" -a "${FILENAME}" != "cf_gen.cc"; then
508 echo "ERROR: ${FILENAME} does not include squid.h first!"
509 fi
510 ;;
511 *.h|*.cci)
512 FI=`grep "#include \"squid.h\"" ${FILENAME}`;
513 if test "x${FI}" != "x" ; then
514 echo "ERROR: ${FILENAME} duplicate include of squid.h"
515 fi
516 ;;
517 esac
518
519 #
520 # If a file includes openssl headers, then it must include compat/openssl.h
521 #
522 if test "${FILENAME}" != "compat/openssl.h"; then
523 FA=`grep "#include.*openssl/" "${FILENAME}" 2>/dev/null | head -1`;
524 FB=`grep '#include.*compat/openssl[.]h' "${FILENAME}" 2>/dev/null | head -1`;
525 if test "x${FA}" != "x" -a "x${FB}" = "x"; then
526 echo "ERROR: ${FILENAME} includes openssl headers without including \"compat/openssl.h\""
527 fi
528 fi
529
530 #
531 # forward.h means different things to Squid code depending on the path
532 # require the full path is explicit for every include
533 #
534 FI=`grep "#include \"forward.h\"" ${FILENAME}`;
535 if test "x${FI}" != "x" ; then
536 echo "ERROR: ${FILENAME} contains reference to forward.h without path"
537 fi
538
539 #
540 # detect functions unsafe for use within Squid.
541 # strdup() - only allowed in compat/xstring.h which defines a safe replacement.
542 # sprintf() - not allowed anywhere.
543 #
544 STRDUP=`grep -e "[^x]strdup(" ${FILENAME}`;
545 if test "x${STRDUP}" != "x" -a "${FILENAME}" != "compat/xstring.h"; then
546 echo "ERROR: ${FILENAME} contains unprotected use of strdup()"
547 fi
548 SPRINTF=`grep -e "[^v]sprintf(" ${FILENAME}`;
549 if test "x${SPRINTF}" != "x" ; then
550 echo "ERROR: ${FILENAME} contains unsafe use of sprintf()"
551 fi
552
553 collectDebugMessagesFrom ${FILENAME}
554
555 #
556 # DEBUG Section list maintenance
557 #
558 grep " DEBUG: section" <${FILENAME} | sed -e 's/ \* DEBUG: //' -e 's%/\* DEBUG: %%' -e 's% \*/%%' >> doc/debug-sections.tmp
559
560 #
561 # File permissions maintenance.
562 #
563 chmod 644 ${FILENAME}
564 ;;
565
566 *.pl|*.sh)
567 #
568 # File permissions maintenance.
569 #
570 chmod 755 ${FILENAME}
571 ;;
572
573 *.am)
574 applyPluginsTo ${FILENAME} scripts/format-makefile-am.pl || return
575 ;;
576
577 ChangeLog|CREDITS|CONTRIBUTORS|COPYING|*.png|*.po|*.pot|rfcs/|*.txt|test-suite/squidconf/empty|.bzrignore)
578 # we do not enforce copyright blurbs in:
579 #
580 # Squid Project contributor attribution file
581 # third-party copyright attribution file
582 # images,
583 # translation PO/POT
584 # license documentation files
585 # (imported) plain-text documentation files and ChangeLogs
586 # VCS internal files
587 #
588 skip_copyright_check=1
589 ;;
590 esac
591
592 # check for Foundation copyright blurb
593 if test $CheckAndUpdateCopyright = yes -a -f ${FILENAME} -a "x$skip_copyright_check" = "x"; then
594 BLURB=`grep -o "${COPYRIGHT_YEARS} The Squid Software Foundation and contributors" ${FILENAME}`;
595 if test "x${BLURB}" = "x"; then
596 BOILER=`grep -o -E "1996-2[0-9]+ The Squid Software Foundation and contributors" ${FILENAME}`;
597 if test "x${BOILER}" != "x"; then
598 echo "UPDATE COPYRIGHT for ${FILENAME}"
599 sed --in-place -r -f boilerplate_fix.sed ${FILENAME}
600 else
601 echo "CHECK COPYRIGHT for ${FILENAME}"
602 fi
603 fi
604 fi
605
606done
607
608 run_ processDebugSections || return
609 run_ processDebugMessages || return
610}
611
612printRawAmFile ()
613{
614 sed -e 's%\ \*%##%; s%/\*%##%; s%##/%##%' < scripts/boilerplate.h
615
616 echo "## $GeneratedByMe"
617 echo
618
619 printf "%s =" "$1"
620 # Only some files are formed from *.po filenames, but all such files
621 # should list *.lang filenames instead.
622 git ls-files $2$3 | sed -e s%$2%%g -e 's%\.po%\.lang%g' | while read f; do
623 printf ' \\\n\t%s' "${f}"
624 done
625 printf '\n'
626}
627
628generateAmFile ()
629{
630 amFile="$1"
631 shift
632
633 # format immediately/here instead of in srcFormat to avoid misleading
634 # "NOTICE: File ... changed by scripts/format-makefile-am.pl" in srcFormat
635 printRawAmFile "$@" | scripts/format-makefile-am.pl > $amFile.new
636
637 # Distinguishing generation-only changes from formatting-only changes is
638 # difficult, so we only check/report cumulative changes. Most interesting
639 # changes are triggered by printRawAmFile() finding new entries.
640 updateIfChanged $amFile $amFile.new 'by generateAmFile()'
641}
642
643# Build icons install include from current icons available
644generateAmFile icons/icon.am ICONS "icons/" "silk/*"
645
646# Build templates install include from current templates available
647generateAmFile errors/template.am ERROR_TEMPLATES "errors/" "templates/ERR_*"
648
649# Build errors translation install include from current .PO available
650generateAmFile errors/language.am LANGUAGE_FILES "errors/" "*.po"
651
652# Build manuals translation install include from current .PO available
653generateAmFile doc/manuals/language.am LANGUAGE_FILES "doc/manuals/" "*.po"
654
655# Build STUB framework include from current stub_* available
656generateAmFile src/tests/Stub.am STUB_SOURCE "src/" "tests/stub_*.cc"
657
658generateRawGperfFile ()
659{
660 gperfFile="$1"
661
662 echo "/* $GeneratedByMe */"
663 echo
664
665 if test `gperf --version | head -1 | cut -d ' ' -f 3 | cut -d. -f '-2' | sed -e 's/\.//'` -lt 32 ; then
666 # We configure C++ compilers to complain about missing '[[fallthrough]]' attribute
667 # where old gperf versions use a '/*FALLTHROUGH*/' code comment.
668 (cd `dirname $gperfFile` && gperf -m 100000 `basename $gperfFile`) | \
669 sed -e 's@/[*]FALLTHROUGH[*]/@[[fallthrough]];@g'
670 else
671 # gperf 3.2+ provide fallthrough attributes
672 (cd `dirname $gperfFile` && gperf -m 100000 `basename $gperfFile`)
673 fi
674}
675
676generateGperfFile ()
677{
678 gperfFile="$1"
679 cciFile=`echo $gperfFile | sed 's/[.]gperf$/.cci/'`
680
681 if test $gperfFile -ot $cciFile; then
682 return 0
683 fi
684
685 generateRawGperfFile $gperfFile > $cciFile.unformatted || return
686
687 if test "$CppFormatter"; then
688 # generateAmFile() explains why we format immediately/here
689 $CppFormatter $cciFile.unformatted > $cciFile.new || return
690 rm $cciFile.unformatted
691 else
692 echo "ERROR: Source code formatting disabled, but regenerated $cciFile needs formatting"
693 mv $cciFile.unformatted $cciFile.new || return
694 fi
695
696 # generateAmFile() explains why we only check/report cumulative changes
697 updateIfChanged $cciFile $cciFile.new 'by generateGperfFile()'
698}
699
700run_ generateGperfFile src/http/RegisteredHeadersHash.gperf || exit 1
701
702run_ checkMakeNamedErrorDetails || exit 1
703
704# This function updates CONTRIBUTORS based on the recent[1] branch commit log.
705# Fresh contributor entries are filtered using the latest vetted CONTRIBOTORS
706# file on the current branch. The following CONTRIBUTORS commits are
707# considered vetted:
708#
709# * authored (in "git log --author" sense) by squidadm,
710# * matching (in "git log --grep" sense) $vettedCommitPhraseRegex set below.
711#
712# A human authoring an official GitHub pull request containing a new
713# CONTRIBUTORS version (that they want to be used as a new vetting point)
714# should add a phrase matching $vettedCommitPhraseRegex to the PR description.
715#
716# [1] As defined by the --update-contributors-since script parameter.
717collectAuthors ()
718{
719 if test "x$UpdateContributorsSince" = xnever
720 then
721 return 0 # successfully did nothing, as requested
722 fi
723
724 vettedCommitPhraseRegex='[Rr]eference point for automated CONTRIBUTORS updates'
725
726 since="$UpdateContributorsSince"
727 if test "x$UpdateContributorsSince" = xauto
728 then
729 # find the last CONTRIBUTORS commit vetted by a human
730 humanSha=`git log -n1 --format='%H' --grep="$vettedCommitPhraseRegex" CONTRIBUTORS`
731 # find the last CONTRIBUTORS commit attributed to this script
732 botSha=`git log -n1 --format='%H' --author=squidadm CONTRIBUTORS`
733 if test "x$humanSha" = x && test "x$botSha" = x
734 then
735 echo "ERROR: Unable to determine the commit to start contributors extraction from"
736 return 1
737 fi
738
739 # find the latest commit among the above one or two commits
740 if test "x$humanSha" = x
741 then
742 since=$botSha
743 elif test "x$botSha" = x
744 then
745 since=$humanSha
746 elif git merge-base --is-ancestor $humanSha $botSha
747 then
748 since=$botSha
749 else
750 since=$humanSha
751 fi
752 echo "Collecting contributors since $since"
753 fi
754 range="$since..HEAD"
755
756 # We add four leading spaces below to mimic CONTRIBUTORS entry style.
757 # add commit authors:
758 git log --format=' %an <%ae>' $range > authors.tmp
759 # add commit co-authors:
760 git log $range | \
761 grep -Ei '^[[:space:]]*Co-authored-by:' | \
762 sed -r 's/^\s*Co-authored-by:\s*/ /i' >> authors.tmp
763 # but do not add committers (--format=' %cn <%ce>').
764
765 # add collected new (co-)authors, if any, to CONTRIBUTORS
766 if ./scripts/update-contributors.pl --quiet < authors.tmp > CONTRIBUTORS.new
767 then
768 updateIfChanged CONTRIBUTORS CONTRIBUTORS.new \
769 "A human PR description should match: $vettedCommitPhraseRegex"
770 fi
771 result=$?
772
773 rm -f authors.tmp
774 return $result
775}
776
777# Update CONTRIBUTORS content
778run_ collectAuthors || exit 1
779
780# Run formatting
781srcFormat || exit 1
782
783test -e boilerplate_fix.sed && rm -f boilerplate_fix.sed
784
785exit $SeenErrors