scripts/unify-sources.sh
changeset 784 1a7fe3bef514
parent 655 c706534d4740
     1.1 --- a/scripts/unify-sources.sh	Fri Oct 16 10:21:37 2009 +0200
     1.2 +++ b/scripts/unify-sources.sh	Thu Nov 05 15:50:01 2009 +0100
     1.3 @@ -1,17 +1,220 @@
     1.4  #!/bin/bash
     1.5 +#
     1.6 +# This file is a part of LEMON, a generic C++ optimization library.
     1.7 +#
     1.8 +# Copyright (C) 2003-2009
     1.9 +# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    1.10 +# (Egervary Research Group on Combinatorial Optimization, EGRES).
    1.11 +#
    1.12 +# Permission to use, modify and distribute this software is granted
    1.13 +# provided that this copyright notice appears in all copies. For
    1.14 +# precise terms see the accompanying LICENSE file.
    1.15 +#
    1.16 +# This software is provided "AS IS" with no warranty of any kind,
    1.17 +# express or implied, and with no claim as to its suitability for any
    1.18 +# purpose.
    1.19  
    1.20 -YEAR=`date +2003-%Y`
    1.21 +YEAR=`date +%Y`
    1.22  HGROOT=`hg root`
    1.23  
    1.24 -function update_header() {
    1.25 +function hg_year() {
    1.26 +    if [ -n "$(hg st $1)" ]; then
    1.27 +        echo $YEAR
    1.28 +    else
    1.29 +        hg log -l 1 --template='{date|isodate}\n' $1 |
    1.30 +        cut -d '-' -f 1
    1.31 +    fi
    1.32 +}
    1.33 +
    1.34 +# file enumaration modes
    1.35 +
    1.36 +function all_files() {
    1.37 +    hg status -a -m -c |
    1.38 +    cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' |
    1.39 +    while read file; do echo $HGROOT/$file; done
    1.40 +}
    1.41 +
    1.42 +function modified_files() {
    1.43 +    hg status -a -m |
    1.44 +    cut -d ' ' -f 2 | grep -E  '(\.(cc|h|dox)$|Makefile\.am$)' |
    1.45 +    while read file; do echo $HGROOT/$file; done
    1.46 +}
    1.47 +
    1.48 +function changed_files() {
    1.49 +    {
    1.50 +        if [ -n "$HG_PARENT1" ]
    1.51 +        then
    1.52 +            hg status --rev $HG_PARENT1:$HG_NODE -a -m
    1.53 +        fi
    1.54 +        if [ -n "$HG_PARENT2" ]
    1.55 +        then
    1.56 +            hg status --rev $HG_PARENT2:$HG_NODE -a -m
    1.57 +        fi
    1.58 +    } | cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | 
    1.59 +    sort | uniq |
    1.60 +    while read file; do echo $HGROOT/$file; done
    1.61 +}
    1.62 +
    1.63 +function given_files() {
    1.64 +    for file in $GIVEN_FILES
    1.65 +    do
    1.66 +	echo $file
    1.67 +    done
    1.68 +}
    1.69 +
    1.70 +# actions
    1.71 +
    1.72 +function update_action() {
    1.73 +    if ! diff -q $1 $2 >/dev/null
    1.74 +    then
    1.75 +	echo -n " [$3 updated]"
    1.76 +	rm $2
    1.77 +	mv $1 $2
    1.78 +	CHANGED=YES
    1.79 +    fi
    1.80 +}
    1.81 +
    1.82 +function update_warning() {
    1.83 +    echo -n " [$2 warning]"
    1.84 +    WARNED=YES
    1.85 +}
    1.86 +
    1.87 +function update_init() {
    1.88 +    echo Update source files...
    1.89 +    TOTAL_FILES=0
    1.90 +    CHANGED_FILES=0
    1.91 +    WARNED_FILES=0
    1.92 +}
    1.93 +
    1.94 +function update_done() {
    1.95 +    echo $CHANGED_FILES out of $TOTAL_FILES files has been changed.
    1.96 +    echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings.
    1.97 +}
    1.98 +
    1.99 +function update_begin() {
   1.100 +    ((TOTAL_FILES++))
   1.101 +    CHANGED=NO
   1.102 +    WARNED=NO
   1.103 +}
   1.104 +
   1.105 +function update_end() {
   1.106 +    if [ $CHANGED == YES ]
   1.107 +    then
   1.108 +	((++CHANGED_FILES))
   1.109 +    fi
   1.110 +    if [ $WARNED == YES ]
   1.111 +    then
   1.112 +	((++WARNED_FILES))
   1.113 +    fi
   1.114 +}
   1.115 +
   1.116 +function check_action() {
   1.117 +    if [ "$3" == 'tabs' ]
   1.118 +    then
   1.119 +        if echo $2 | grep -q -v -E 'Makefile\.am$'
   1.120 +        then
   1.121 +            PATTERN=$(echo -e '\t')
   1.122 +        else
   1.123 +            PATTERN='        '
   1.124 +        fi
   1.125 +    elif [ "$3" == 'trailing spaces' ]
   1.126 +    then
   1.127 +        PATTERN='\ +$'
   1.128 +    else
   1.129 +        PATTERN='*'
   1.130 +    fi
   1.131 +
   1.132 +    if ! diff -q $1 $2 >/dev/null
   1.133 +    then
   1.134 +        if [ "$PATTERN" == '*' ]
   1.135 +        then
   1.136 +            diff $1 $2 | grep '^[0-9]' | sed "s|^\(.*\)c.*$|$2:\1: check failed: $3|g" |
   1.137 +              sed "s/:\([0-9]*\),\([0-9]*\):\(.*\)$/:\1:\3 (until line \2)/g"
   1.138 +        else
   1.139 +            grep -n -E "$PATTERN" $2 | sed "s|^\([0-9]*\):.*$|$2:\1: check failed: $3|g"
   1.140 +        fi
   1.141 +        FAILED=YES
   1.142 +    fi
   1.143 +}
   1.144 +
   1.145 +function check_warning() {
   1.146 +    if [ "$2" == 'long lines' ]
   1.147 +    then
   1.148 +        grep -n -E '.{81,}' $1 | sed "s|^\([0-9]*\):.*$|$1:\1: warning: $2|g"
   1.149 +    else
   1.150 +        echo "$1: warning: $2"
   1.151 +    fi
   1.152 +    WARNED=YES
   1.153 +}
   1.154 +
   1.155 +function check_init() {
   1.156 +    echo Check source files...
   1.157 +    FAILED_FILES=0
   1.158 +    WARNED_FILES=0
   1.159 +    TOTAL_FILES=0
   1.160 +}
   1.161 +
   1.162 +function check_done() {
   1.163 +    echo $FAILED_FILES out of $TOTAL_FILES files has been failed.
   1.164 +    echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings.
   1.165 +
   1.166 +    if [ $WARNED_FILES -gt 0 -o $FAILED_FILES -gt 0 ]
   1.167 +    then
   1.168 +	if [ "$WARNING" == 'INTERACTIVE' ]
   1.169 +	then
   1.170 +	    echo -n "Are the files with errors/warnings acceptable? (yes/no) "
   1.171 +	    while read answer
   1.172 +	    do
   1.173 +		if [ "$answer" == 'yes' ]
   1.174 +		then
   1.175 +		    return 0
   1.176 +		elif [ "$answer" == 'no' ]
   1.177 +		then
   1.178 +		    return 1
   1.179 +		fi
   1.180 +		echo -n "Are the files with errors/warnings acceptable? (yes/no) "
   1.181 +	    done
   1.182 +	elif [ "$WARNING" == 'WERROR' ]
   1.183 +	then
   1.184 +	    return 1
   1.185 +	fi
   1.186 +    fi
   1.187 +}
   1.188 +
   1.189 +function check_begin() {
   1.190 +    ((TOTAL_FILES++))
   1.191 +    FAILED=NO
   1.192 +    WARNED=NO
   1.193 +}
   1.194 +
   1.195 +function check_end() {
   1.196 +    if [ $FAILED == YES ]
   1.197 +    then
   1.198 +	((++FAILED_FILES))
   1.199 +    fi
   1.200 +    if [ $WARNED == YES ]
   1.201 +    then
   1.202 +	((++WARNED_FILES))
   1.203 +    fi
   1.204 +}
   1.205 +
   1.206 +
   1.207 +
   1.208 +# checks
   1.209 +
   1.210 +function header_check() {
   1.211 +    if echo $1 | grep -q -E 'Makefile\.am$'
   1.212 +    then
   1.213 +	return
   1.214 +    fi
   1.215 +
   1.216      TMP_FILE=`mktemp`
   1.217 -    FILE_NAME=$1
   1.218  
   1.219      (echo "/* -*- mode: C++; indent-tabs-mode: nil; -*-
   1.220   *
   1.221   * This file is a part of LEMON, a generic C++ optimization library.
   1.222   *
   1.223 - * Copyright (C) "$YEAR"
   1.224 + * Copyright (C) 2003-"$(hg_year $1)"
   1.225   * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
   1.226   * (Egervary Research Group on Combinatorial Optimization, EGRES).
   1.227   *
   1.228 @@ -25,110 +228,163 @@
   1.229   *
   1.230   */
   1.231  "
   1.232 -	awk 'BEGIN { pm=0; }
   1.233 +    awk 'BEGIN { pm=0; }
   1.234       pm==3 { print }
   1.235       /\/\* / && pm==0 { pm=1;}
   1.236       /[^:blank:]/ && (pm==0 || pm==2) { pm=3; print;}
   1.237       /\*\// && pm==1 { pm=2;}
   1.238      ' $1
   1.239 -	) >$TMP_FILE
   1.240 +    ) >$TMP_FILE
   1.241  
   1.242 -    HEADER_CH=`diff -q $TMP_FILE $FILE_NAME >/dev/null&&echo NO||echo YES`
   1.243 -
   1.244 -    rm $FILE_NAME
   1.245 -    mv $TMP_FILE $FILE_NAME
   1.246 +    "$ACTION"_action "$TMP_FILE" "$1" header
   1.247  }
   1.248  
   1.249 -function update_tabs() {
   1.250 +function tabs_check() {
   1.251 +    if echo $1 | grep -q -v -E 'Makefile\.am$'
   1.252 +    then
   1.253 +        OLD_PATTERN=$(echo -e '\t')
   1.254 +        NEW_PATTERN='        '
   1.255 +    else
   1.256 +        OLD_PATTERN='        '
   1.257 +        NEW_PATTERN=$(echo -e '\t')
   1.258 +    fi
   1.259      TMP_FILE=`mktemp`
   1.260 -    FILE_NAME=$1
   1.261 +    cat $1 | sed -e "s/$OLD_PATTERN/$NEW_PATTERN/g" >$TMP_FILE
   1.262  
   1.263 -    cat $1 |
   1.264 -    sed -e 's/\t/        /g' >$TMP_FILE
   1.265 -
   1.266 -    TABS_CH=`diff -q $TMP_FILE $FILE_NAME >/dev/null&&echo NO||echo YES`
   1.267 -
   1.268 -    rm $FILE_NAME
   1.269 -    mv $TMP_FILE $FILE_NAME
   1.270 +    "$ACTION"_action "$TMP_FILE" "$1" 'tabs'
   1.271  }
   1.272  
   1.273 -function remove_trailing_space() {
   1.274 +function spaces_check() {
   1.275      TMP_FILE=`mktemp`
   1.276 -    FILE_NAME=$1
   1.277 +    cat $1 | sed -e 's/ \+$//g' >$TMP_FILE
   1.278  
   1.279 -    cat $1 |
   1.280 -    sed -e 's/ \+$//g' >$TMP_FILE
   1.281 -
   1.282 -    SPACES_CH=`diff -q $TMP_FILE $FILE_NAME >/dev/null&&echo NO||echo YES`
   1.283 -
   1.284 -    rm $FILE_NAME
   1.285 -    mv $TMP_FILE $FILE_NAME
   1.286 +    "$ACTION"_action "$TMP_FILE" "$1" 'trailing spaces'
   1.287  }
   1.288  
   1.289 -function long_line_test() {
   1.290 -    cat $1 |grep -q -E '.{81,}'
   1.291 -}
   1.292 -
   1.293 -function update_file() {
   1.294 -    echo -n '    update' $i ...
   1.295 -
   1.296 -    update_header $1
   1.297 -    update_tabs $1
   1.298 -    remove_trailing_space $1
   1.299 -
   1.300 -    CHANGED=NO;
   1.301 -    if [[ $HEADER_CH = YES ]];
   1.302 +function long_lines_check() {
   1.303 +    if cat $1 | grep -q -E '.{81,}'
   1.304      then
   1.305 -	echo -n '  [header updated]'
   1.306 -	CHANGED=YES;
   1.307 -    fi
   1.308 -    if [[ $TABS_CH = YES ]];
   1.309 -    then
   1.310 -	echo -n ' [tabs removed]'
   1.311 -	CHANGED=YES;
   1.312 -    fi
   1.313 -    if [[ $SPACES_CH = YES ]];
   1.314 -    then
   1.315 -	echo -n ' [trailing spaces removed]'
   1.316 -	CHANGED=YES;
   1.317 -    fi
   1.318 -    if long_line_test $1 ;
   1.319 -    then
   1.320 -	echo -n ' [LONG LINES]'
   1.321 -	((LONG_LINE_FILES++))
   1.322 -    fi
   1.323 -    echo
   1.324 -    if [[ $CHANGED = YES ]];
   1.325 -    then
   1.326 -	((CHANGED_FILES++))
   1.327 +	"$ACTION"_warning $1 'long lines'
   1.328      fi
   1.329  }
   1.330  
   1.331 -CHANGED_FILES=0
   1.332 -TOTAL_FILES=0
   1.333 -LONG_LINE_FILES=0
   1.334 -if [ $# == 0 ]; then
   1.335 -    echo Update all source files...
   1.336 -    for i in `hg manifest|grep -E  '\.(cc|h|dox)$'`
   1.337 +# process the file
   1.338 +
   1.339 +function process_file() {
   1.340 +    if [ "$ACTION" == 'update' ]
   1.341 +    then
   1.342 +        echo -n "    $ACTION $1..."
   1.343 +    else
   1.344 +        echo "	  $ACTION $1..."
   1.345 +    fi
   1.346 +
   1.347 +    CHECKING="header tabs spaces long_lines"
   1.348 +
   1.349 +    "$ACTION"_begin $1
   1.350 +    for check in $CHECKING
   1.351      do
   1.352 -	update_file $HGROOT/$i
   1.353 -	((TOTAL_FILES++))
   1.354 +	"$check"_check $1
   1.355      done
   1.356 -    echo '  done.'
   1.357 -else
   1.358 -    for i in $*
   1.359 +    "$ACTION"_end $1
   1.360 +    if [ "$ACTION" == 'update' ]
   1.361 +    then
   1.362 +        echo
   1.363 +    fi
   1.364 +}
   1.365 +
   1.366 +function process_all {
   1.367 +    "$ACTION"_init
   1.368 +    while read file
   1.369      do
   1.370 -	update_file $i
   1.371 -	((TOTAL_FILES++))
   1.372 -    done
   1.373 +	process_file $file
   1.374 +    done < <($FILES)
   1.375 +    "$ACTION"_done
   1.376 +}
   1.377 +
   1.378 +while [ $# -gt 0 ]
   1.379 +do
   1.380 +    
   1.381 +    if [ "$1" == '--help' ] || [ "$1" == '-h' ]
   1.382 +    then
   1.383 +	echo -n \
   1.384 +"Usage:
   1.385 +  $0 [OPTIONS] [files]
   1.386 +Options:
   1.387 +  --dry-run|-n
   1.388 +     Check the files, but do not modify them.
   1.389 +  --interactive|-i
   1.390 +     If --dry-run is specified and the checker emits warnings,
   1.391 +     then the user is asked if the warnings should be considered
   1.392 +     errors.
   1.393 +  --werror|-w
   1.394 +     Make all warnings into errors.
   1.395 +  --all|-a
   1.396 +     Check all source files in the repository.
   1.397 +  --modified|-m
   1.398 +     Check only the modified (and new) source files. This option is
   1.399 +     useful to check the modification before making a commit.
   1.400 +  --changed|-c
   1.401 +     Check only the changed source files compared to the parent(s) of
   1.402 +     the current hg node.  This option is useful as hg hook script.
   1.403 +     To automatically check all your changes before making a commit,
   1.404 +     add the following section to the appropriate .hg/hgrc file.
   1.405 +
   1.406 +       [hooks]
   1.407 +       pretxncommit.checksources = scripts/unify-sources.sh -c -n -i
   1.408 +
   1.409 +  --help|-h
   1.410 +     Print this help message.
   1.411 +  files
   1.412 +     The files to check/unify. If no file names are given, the modified
   1.413 +     source files will be checked/unified (just like using the
   1.414 +     --modified|-m option).
   1.415 +"
   1.416 +        exit 0
   1.417 +    elif [ "$1" == '--dry-run' ] || [ "$1" == '-n' ]
   1.418 +    then
   1.419 +	[ -n "$ACTION" ] && echo "Conflicting action options" >&2 && exit 1
   1.420 +	ACTION=check
   1.421 +    elif [ "$1" == "--all" ] || [ "$1" == '-a' ]
   1.422 +    then
   1.423 +	[ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
   1.424 +	FILES=all_files
   1.425 +    elif [ "$1" == "--changed" ] || [ "$1" == '-c' ]
   1.426 +    then
   1.427 +	[ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
   1.428 +	FILES=changed_files
   1.429 +    elif [ "$1" == "--modified" ] || [ "$1" == '-m' ]
   1.430 +    then
   1.431 +	[ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
   1.432 +	FILES=modified_files
   1.433 +    elif [ "$1" == "--interactive" ] || [ "$1" == "-i" ]
   1.434 +    then
   1.435 +	[ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1
   1.436 +	WARNING='INTERACTIVE'
   1.437 +    elif [ "$1" == "--werror" ] || [ "$1" == "-w" ]
   1.438 +    then
   1.439 +	[ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1
   1.440 +	WARNING='WERROR'
   1.441 +    elif [ $(echo x$1 | cut -c 2) == '-' ]
   1.442 +    then
   1.443 +	echo "Invalid option $1" >&2 && exit 1
   1.444 +    else
   1.445 +	[ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1
   1.446 +	GIVEN_FILES=$@
   1.447 +	FILES=given_files
   1.448 +	break
   1.449 +    fi
   1.450 +    
   1.451 +    shift
   1.452 +done
   1.453 +
   1.454 +if [ -z $FILES ]
   1.455 +then
   1.456 +    FILES=modified_files
   1.457  fi
   1.458 -echo $CHANGED_FILES out of $TOTAL_FILES files has been changed.
   1.459 -if [[ $LONG_LINE_FILES -gt 1 ]]; then
   1.460 -    echo
   1.461 -    echo WARNING: $LONG_LINE_FILES files contains long lines!    
   1.462 -    echo
   1.463 -elif [[ $LONG_LINE_FILES -gt 0 ]]; then
   1.464 -    echo
   1.465 -    echo WARNING: a file contains long lines!
   1.466 -    echo
   1.467 +
   1.468 +if [ -z $ACTION ]
   1.469 +then
   1.470 +    ACTION=update
   1.471  fi
   1.472 +
   1.473 +process_all