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