scripts/unify-sources.sh
author Peter Kovacs <kpeter@inf.elte.hu>
Sun, 30 Nov 2008 22:06:36 +0100
changeset 396 c5f010a5647a
parent 341 f8832dc16d45
child 554 6b9c1f6eb1e5
permissions -rwxr-xr-x
Improve unify-sources.sh (#186)
Errors can also be accepted when the script is used as a hg hook.
Sometimes it is useful (e.g. if someone else made the errors).
     1 #!/bin/bash
     2 
     3 YEAR=`date +2003-%Y`
     4 HGROOT=`hg root`
     5 
     6 # file enumaration modes
     7 
     8 function all_files() {
     9     hg status -a -m -c |
    10     cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' |
    11     while read file; do echo $HGROOT/$file; done
    12 }
    13 
    14 function modified_files() {
    15     hg status -a -m |
    16     cut -d ' ' -f 2 | grep -E  '(\.(cc|h|dox)$|Makefile\.am$)' |
    17     while read file; do echo $HGROOT/$file; done
    18 }
    19 
    20 function changed_files() {
    21     {
    22         if [ -n "$HG_PARENT1" ]
    23         then
    24             hg status --rev $HG_PARENT1:$HG_NODE -a -m
    25         fi
    26         if [ -n "$HG_PARENT2" ]
    27         then
    28             hg status --rev $HG_PARENT2:$HG_NODE -a -m
    29         fi
    30     } | cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | 
    31     sort | uniq |
    32     while read file; do echo $HGROOT/$file; done
    33 }
    34 
    35 function given_files() {
    36     for file in $GIVEN_FILES
    37     do
    38 	echo $file
    39     done
    40 }
    41 
    42 # actions
    43 
    44 function update_action() {
    45     if ! diff -q $1 $2 >/dev/null
    46     then
    47 	echo -n " [$3 updated]"
    48 	rm $2
    49 	mv $1 $2
    50 	CHANGED=YES
    51     fi
    52 }
    53 
    54 function update_warning() {
    55     echo -n " [$2 warning]"
    56     WARNED=YES
    57 }
    58 
    59 function update_init() {
    60     echo Update source files...
    61     TOTAL_FILES=0
    62     CHANGED_FILES=0
    63     WARNED_FILES=0
    64 }
    65 
    66 function update_done() {
    67     echo $CHANGED_FILES out of $TOTAL_FILES files has been changed.
    68     echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings.
    69 }
    70 
    71 function update_begin() {
    72     ((TOTAL_FILES++))
    73     CHANGED=NO
    74     WARNED=NO
    75 }
    76 
    77 function update_end() {
    78     if [ $CHANGED == YES ]
    79     then
    80 	((++CHANGED_FILES))
    81     fi
    82     if [ $WARNED == YES ]
    83     then
    84 	((++WARNED_FILES))
    85     fi
    86 }
    87 
    88 function check_action() {
    89     if [ "$3" == 'tabs' ]
    90     then
    91         PATTERN=$(echo -e '\t')
    92     elif [ "$3" == 'trailing spaces' ]
    93     then
    94         PATTERN='\ +$'
    95     else
    96         PATTERN='*'
    97     fi
    98 
    99     if ! diff -q $1 $2 >/dev/null
   100     then
   101         if [ "$PATTERN" == '*' ]
   102         then
   103             diff $1 $2 | grep '^[0-9]' | sed "s|^\(.*\)c.*$|$2:\1: check failed: $3|g" |
   104               sed "s/:\([0-9]*\),\([0-9]*\):\(.*\)$/:\1:\3 (until line \2)/g"
   105         else
   106             grep -n -E "$PATTERN" $2 | sed "s|^\([0-9]*\):.*$|$2:\1: check failed: $3|g"
   107         fi
   108         FAILED=YES
   109     fi
   110 }
   111 
   112 function check_warning() {
   113     if [ "$2" == 'long lines' ]
   114     then
   115         grep -n -E '.{81,}' $1 | sed "s|^\([0-9]*\):.*$|$1:\1: warning: $2|g"
   116     else
   117         echo "$1: warning: $2"
   118     fi
   119     WARNED=YES
   120 }
   121 
   122 function check_init() {
   123     echo Check source files...
   124     FAILED_FILES=0
   125     WARNED_FILES=0
   126     TOTAL_FILES=0
   127 }
   128 
   129 function check_done() {
   130     echo $FAILED_FILES out of $TOTAL_FILES files has been failed.
   131     echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings.
   132 
   133     if [ $WARNED_FILES -gt 0 -o $FAILED_FILES -gt 0 ]
   134     then
   135 	if [ "$WARNING" == 'INTERACTIVE' ]
   136 	then
   137 	    echo -n "Are the files with errors/warnings acceptable? (yes/no) "
   138 	    while read answer
   139 	    do
   140 		if [ "$answer" == 'yes' ]
   141 		then
   142 		    return 0
   143 		elif [ "$answer" == 'no' ]
   144 		then
   145 		    return 1
   146 		fi
   147 		echo -n "Are the files with errors/warnings acceptable? (yes/no) "
   148 	    done
   149 	elif [ "$WARNING" == 'WERROR' ]
   150 	then
   151 	    return 1
   152 	fi
   153     fi
   154 }
   155 
   156 function check_begin() {
   157     ((TOTAL_FILES++))
   158     FAILED=NO
   159     WARNED=NO
   160 }
   161 
   162 function check_end() {
   163     if [ $FAILED == YES ]
   164     then
   165 	((++FAILED_FILES))
   166     fi
   167     if [ $WARNED == YES ]
   168     then
   169 	((++WARNED_FILES))
   170     fi
   171 }
   172 
   173 
   174 
   175 # checks
   176 
   177 function header_check() {
   178     if echo $1 | grep -q -E 'Makefile\.am$'
   179     then
   180 	return
   181     fi
   182 
   183     TMP_FILE=`mktemp`
   184 
   185     (echo "/* -*- mode: C++; indent-tabs-mode: nil; -*-
   186  *
   187  * This file is a part of LEMON, a generic C++ optimization library.
   188  *
   189  * Copyright (C) "$YEAR"
   190  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
   191  * (Egervary Research Group on Combinatorial Optimization, EGRES).
   192  *
   193  * Permission to use, modify and distribute this software is granted
   194  * provided that this copyright notice appears in all copies. For
   195  * precise terms see the accompanying LICENSE file.
   196  *
   197  * This software is provided \"AS IS\" with no warranty of any kind,
   198  * express or implied, and with no claim as to its suitability for any
   199  * purpose.
   200  *
   201  */
   202 "
   203     awk 'BEGIN { pm=0; }
   204      pm==3 { print }
   205      /\/\* / && pm==0 { pm=1;}
   206      /[^:blank:]/ && (pm==0 || pm==2) { pm=3; print;}
   207      /\*\// && pm==1 { pm=2;}
   208     ' $1
   209     ) >$TMP_FILE
   210 
   211     "$ACTION"_action "$TMP_FILE" "$1" header
   212 }
   213 
   214 function tabs_check() {
   215     if echo $1 | grep -q -v -E 'Makefile\.am$'
   216     then
   217         OLD_PATTERN=$(echo -e '\t')
   218         NEW_PATTERN='        '
   219     else
   220         OLD_PATTERN='        '
   221         NEW_PATTERN=$(echo -e '\t')
   222     fi
   223     TMP_FILE=`mktemp`
   224     cat $1 | sed -e "s/$OLD_PATTERN/$NEW_PATTERN/g" >$TMP_FILE
   225 
   226     "$ACTION"_action "$TMP_FILE" "$1" 'tabs'
   227 }
   228 
   229 function spaces_check() {
   230     TMP_FILE=`mktemp`
   231     cat $1 | sed -e 's/ \+$//g' >$TMP_FILE
   232 
   233     "$ACTION"_action "$TMP_FILE" "$1" 'trailing spaces'
   234 }
   235 
   236 function long_lines_check() {
   237     if cat $1 | grep -q -E '.{81,}'
   238     then
   239 	"$ACTION"_warning $1 'long lines'
   240     fi
   241 }
   242 
   243 # process the file
   244 
   245 function process_file() {
   246     if [ "$ACTION" == 'update' ]
   247     then
   248         echo -n "    $ACTION $1..."
   249     else
   250         echo "	  $ACTION $1..."
   251     fi
   252 
   253     CHECKING="header tabs spaces long_lines"
   254 
   255     "$ACTION"_begin $1
   256     for check in $CHECKING
   257     do
   258 	"$check"_check $1
   259     done
   260     "$ACTION"_end $1
   261     if [ "$ACTION" == 'update' ]
   262     then
   263         echo
   264     fi
   265 }
   266 
   267 function process_all {
   268     "$ACTION"_init
   269     while read file
   270     do
   271 	process_file $file
   272     done < <($FILES)
   273     "$ACTION"_done
   274 }
   275 
   276 while [ $# -gt 0 ]
   277 do
   278     
   279     if [ "$1" == '--help' ] || [ "$1" == '-h' ]
   280     then
   281 	echo -n \
   282 "Usage:
   283   $0 [OPTIONS] [files]
   284 Options:
   285   --dry-run|-n
   286      Check the files, but do not modify them.
   287   --interactive|-i
   288      If --dry-run is specified and the checker emits warnings,
   289      then the user is asked if the warnings should be considered
   290      errors.
   291   --werror|-w
   292      Make all warnings into errors.
   293   --all|-a
   294      Check all source files in the repository.
   295   --modified|-m
   296      Check only the modified (and new) source files. This option is
   297      useful to check the modification before making a commit.
   298   --changed|-c
   299      Check only the changed source files compared to the parent(s) of
   300      the current hg node.  This option is useful as hg hook script.
   301      To automatically check all your changes before making a commit,
   302      add the following section to the appropriate .hg/hgrc file.
   303 
   304        [hooks]
   305        pretxncommit.checksources = scripts/unify-sources.sh -c -n -i
   306 
   307   --help|-h
   308      Print this help message.
   309   files
   310      The files to check/unify. If no file names are given, the modified
   311      source files will be checked/unified (just like using the
   312      --modified|-m option).
   313 "
   314         exit 0
   315     elif [ "$1" == '--dry-run' ] || [ "$1" == '-n' ]
   316     then
   317 	[ -n "$ACTION" ] && echo "Conflicting action options" >&2 && exit 1
   318 	ACTION=check
   319     elif [ "$1" == "--all" ] || [ "$1" == '-a' ]
   320     then
   321 	[ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
   322 	FILES=all_files
   323     elif [ "$1" == "--changed" ] || [ "$1" == '-c' ]
   324     then
   325 	[ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
   326 	FILES=changed_files
   327     elif [ "$1" == "--modified" ] || [ "$1" == '-m' ]
   328     then
   329 	[ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
   330 	FILES=modified_files
   331     elif [ "$1" == "--interactive" ] || [ "$1" == "-i" ]
   332     then
   333 	[ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1
   334 	WARNING='INTERACTIVE'
   335     elif [ "$1" == "--werror" ] || [ "$1" == "-w" ]
   336     then
   337 	[ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1
   338 	WARNING='WERROR'
   339     elif [ $(echo x$1 | cut -c 2) == '-' ]
   340     then
   341 	echo "Invalid option $1" >&2 && exit 1
   342     else
   343 	[ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1
   344 	GIVEN_FILES=$@
   345 	FILES=given_files
   346 	break
   347     fi
   348     
   349     shift
   350 done
   351 
   352 if [ -z $FILES ]
   353 then
   354     FILES=modified_files
   355 fi
   356 
   357 if [ -z $ACTION ]
   358 then
   359     ACTION=update
   360 fi
   361 
   362 process_all