alpar@38: #!/bin/bash alpar@733: # alpar@733: # This file is a part of LEMON, a generic C++ optimization library. alpar@733: # alpar@733: # Copyright (C) 2003-2009 alpar@733: # Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@733: # (Egervary Research Group on Combinatorial Optimization, EGRES). alpar@733: # alpar@733: # Permission to use, modify and distribute this software is granted alpar@733: # provided that this copyright notice appears in all copies. For alpar@733: # precise terms see the accompanying LICENSE file. alpar@733: # alpar@733: # This software is provided "AS IS" with no warranty of any kind, alpar@733: # express or implied, and with no claim as to its suitability for any alpar@733: # purpose. alpar@38: alpar@498: YEAR=`date +%Y` alpar@38: HGROOT=`hg root` alpar@38: alpar@498: function hg_year() { alpar@498: if [ -n "$(hg st $1)" ]; then alpar@498: echo $YEAR alpar@655: else alpar@655: hg log -l 1 --template='{date|isodate}\n' $1 | alpar@655: cut -d '-' -f 1 alpar@655: fi alpar@628: } alpar@628: deba@324: # file enumaration modes deba@324: deba@324: function all_files() { deba@324: hg status -a -m -c | deba@324: cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | deba@324: while read file; do echo $HGROOT/$file; done deba@324: } deba@324: deba@324: function modified_files() { deba@324: hg status -a -m | deba@324: cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | deba@324: while read file; do echo $HGROOT/$file; done deba@324: } deba@324: deba@324: function changed_files() { deba@324: { deba@324: if [ -n "$HG_PARENT1" ] deba@324: then deba@324: hg status --rev $HG_PARENT1:$HG_NODE -a -m deba@324: fi deba@324: if [ -n "$HG_PARENT2" ] deba@324: then deba@324: hg status --rev $HG_PARENT2:$HG_NODE -a -m deba@324: fi deba@324: } | cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | deba@324: sort | uniq | deba@324: while read file; do echo $HGROOT/$file; done deba@324: } deba@324: deba@324: function given_files() { deba@324: for file in $GIVEN_FILES deba@324: do deba@324: echo $file deba@324: done deba@324: } deba@324: deba@324: # actions deba@324: deba@324: function update_action() { deba@324: if ! diff -q $1 $2 >/dev/null deba@324: then deba@324: echo -n " [$3 updated]" deba@324: rm $2 deba@324: mv $1 $2 deba@324: CHANGED=YES alpar@498: fi alpar@498: } alpar@498: deba@324: function update_warning() { deba@324: echo -n " [$2 warning]" deba@324: WARNED=YES deba@324: } deba@324: deba@324: function update_init() { deba@324: echo Update source files... deba@324: TOTAL_FILES=0 deba@324: CHANGED_FILES=0 deba@324: WARNED_FILES=0 deba@324: } deba@324: deba@324: function update_done() { deba@324: echo $CHANGED_FILES out of $TOTAL_FILES files has been changed. alpar@325: echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings. deba@324: } deba@324: deba@324: function update_begin() { deba@324: ((TOTAL_FILES++)) deba@324: CHANGED=NO deba@324: WARNED=NO deba@324: } deba@324: deba@324: function update_end() { deba@324: if [ $CHANGED == YES ] deba@324: then deba@324: ((++CHANGED_FILES)) deba@324: fi deba@324: if [ $WARNED == YES ] deba@324: then deba@324: ((++WARNED_FILES)) deba@324: fi deba@324: } deba@324: deba@324: function check_action() { kpeter@341: if [ "$3" == 'tabs' ] kpeter@341: then kpeter@554: if echo $2 | grep -q -v -E 'Makefile\.am$' kpeter@554: then kpeter@554: PATTERN=$(echo -e '\t') kpeter@554: else kpeter@554: PATTERN=' ' kpeter@554: fi kpeter@341: elif [ "$3" == 'trailing spaces' ] kpeter@341: then kpeter@341: PATTERN='\ +$' kpeter@341: else kpeter@341: PATTERN='*' kpeter@341: fi kpeter@341: deba@324: if ! diff -q $1 $2 >/dev/null deba@324: then kpeter@341: if [ "$PATTERN" == '*' ] kpeter@341: then kpeter@341: diff $1 $2 | grep '^[0-9]' | sed "s|^\(.*\)c.*$|$2:\1: check failed: $3|g" | kpeter@341: sed "s/:\([0-9]*\),\([0-9]*\):\(.*\)$/:\1:\3 (until line \2)/g" kpeter@341: else kpeter@341: grep -n -E "$PATTERN" $2 | sed "s|^\([0-9]*\):.*$|$2:\1: check failed: $3|g" kpeter@341: fi kpeter@341: FAILED=YES deba@324: fi deba@324: } deba@324: deba@324: function check_warning() { kpeter@329: if [ "$2" == 'long lines' ] kpeter@329: then kpeter@341: grep -n -E '.{81,}' $1 | sed "s|^\([0-9]*\):.*$|$1:\1: warning: $2|g" kpeter@329: else kpeter@341: echo "$1: warning: $2" kpeter@329: fi deba@324: WARNED=YES deba@324: } deba@324: deba@324: function check_init() { deba@324: echo Check source files... deba@324: FAILED_FILES=0 deba@324: WARNED_FILES=0 deba@324: TOTAL_FILES=0 deba@324: } deba@324: deba@324: function check_done() { deba@324: echo $FAILED_FILES out of $TOTAL_FILES files has been failed. alpar@325: echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings. deba@324: kpeter@396: if [ $WARNED_FILES -gt 0 -o $FAILED_FILES -gt 0 ] deba@324: then deba@324: if [ "$WARNING" == 'INTERACTIVE' ] deba@324: then kpeter@396: echo -n "Are the files with errors/warnings acceptable? (yes/no) " deba@324: while read answer deba@324: do deba@324: if [ "$answer" == 'yes' ] deba@324: then deba@324: return 0 deba@324: elif [ "$answer" == 'no' ] deba@324: then deba@324: return 1 deba@324: fi kpeter@396: echo -n "Are the files with errors/warnings acceptable? (yes/no) " deba@324: done deba@324: elif [ "$WARNING" == 'WERROR' ] deba@324: then deba@324: return 1 deba@324: fi deba@324: fi deba@324: } deba@324: deba@324: function check_begin() { deba@324: ((TOTAL_FILES++)) deba@324: FAILED=NO deba@324: WARNED=NO deba@324: } deba@324: deba@324: function check_end() { deba@324: if [ $FAILED == YES ] deba@324: then deba@324: ((++FAILED_FILES)) deba@324: fi deba@324: if [ $WARNED == YES ] deba@324: then deba@324: ((++WARNED_FILES)) deba@324: fi deba@324: } deba@324: deba@324: deba@324: deba@324: # checks deba@324: deba@324: function header_check() { deba@324: if echo $1 | grep -q -E 'Makefile\.am$' deba@324: then deba@324: return deba@324: fi deba@324: alpar@38: TMP_FILE=`mktemp` alpar@38: alpar@208: (echo "/* -*- mode: C++; indent-tabs-mode: nil; -*- alpar@38: * alpar@208: * This file is a part of LEMON, a generic C++ optimization library. alpar@38: * alpar@498: * Copyright (C) 2003-"$(hg_year $1)" alpar@38: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@38: * (Egervary Research Group on Combinatorial Optimization, EGRES). alpar@38: * alpar@38: * Permission to use, modify and distribute this software is granted alpar@38: * provided that this copyright notice appears in all copies. For alpar@38: * precise terms see the accompanying LICENSE file. alpar@38: * alpar@38: * This software is provided \"AS IS\" with no warranty of any kind, alpar@38: * express or implied, and with no claim as to its suitability for any alpar@38: * purpose. alpar@38: * alpar@38: */ alpar@38: " deba@324: awk 'BEGIN { pm=0; } alpar@38: pm==3 { print } alpar@38: /\/\* / && pm==0 { pm=1;} alpar@38: /[^:blank:]/ && (pm==0 || pm==2) { pm=3; print;} alpar@38: /\*\// && pm==1 { pm=2;} alpar@38: ' $1 deba@324: ) >$TMP_FILE alpar@208: deba@324: "$ACTION"_action "$TMP_FILE" "$1" header alpar@38: } alpar@38: deba@324: function tabs_check() { deba@324: if echo $1 | grep -q -v -E 'Makefile\.am$' deba@324: then deba@324: OLD_PATTERN=$(echo -e '\t') deba@324: NEW_PATTERN=' ' deba@324: else deba@324: OLD_PATTERN=' ' deba@324: NEW_PATTERN=$(echo -e '\t') deba@324: fi alpar@208: TMP_FILE=`mktemp` deba@324: cat $1 | sed -e "s/$OLD_PATTERN/$NEW_PATTERN/g" >$TMP_FILE alpar@38: deba@324: "$ACTION"_action "$TMP_FILE" "$1" 'tabs' alpar@208: } alpar@208: deba@324: function spaces_check() { alpar@208: TMP_FILE=`mktemp` deba@324: cat $1 | sed -e 's/ \+$//g' >$TMP_FILE alpar@208: kpeter@328: "$ACTION"_action "$TMP_FILE" "$1" 'trailing spaces' alpar@208: } alpar@208: deba@324: function long_lines_check() { deba@324: if cat $1 | grep -q -E '.{81,}' alpar@208: then deba@324: "$ACTION"_warning $1 'long lines' alpar@208: fi alpar@208: } alpar@208: deba@324: # process the file deba@324: deba@324: function process_file() { kpeter@341: if [ "$ACTION" == 'update' ] kpeter@341: then kpeter@341: echo -n " $ACTION $1..." kpeter@341: else kpeter@341: echo " $ACTION $1..." kpeter@341: fi deba@324: deba@324: CHECKING="header tabs spaces long_lines" deba@324: deba@324: "$ACTION"_begin $1 deba@324: for check in $CHECKING alpar@38: do deba@324: "$check"_check $1 alpar@38: done deba@324: "$ACTION"_end $1 kpeter@341: if [ "$ACTION" == 'update' ] kpeter@341: then kpeter@341: echo kpeter@341: fi deba@324: } deba@324: deba@324: function process_all { deba@324: "$ACTION"_init deba@324: while read file alpar@38: do deba@324: process_file $file deba@324: done < <($FILES) deba@324: "$ACTION"_done deba@324: } deba@324: deba@324: while [ $# -gt 0 ] deba@324: do deba@324: deba@324: if [ "$1" == '--help' ] || [ "$1" == '-h' ] deba@324: then deba@324: echo -n \ deba@324: "Usage: deba@324: $0 [OPTIONS] [files] deba@324: Options: deba@324: --dry-run|-n alpar@325: Check the files, but do not modify them. deba@324: --interactive|-i alpar@325: If --dry-run is specified and the checker emits warnings, alpar@325: then the user is asked if the warnings should be considered alpar@325: errors. deba@324: --werror|-w alpar@325: Make all warnings into errors. deba@324: --all|-a kpeter@328: Check all source files in the repository. deba@324: --modified|-m alpar@325: Check only the modified (and new) source files. This option is alpar@325: useful to check the modification before making a commit. deba@324: --changed|-c deba@324: Check only the changed source files compared to the parent(s) of alpar@325: the current hg node. This option is useful as hg hook script. alpar@325: To automatically check all your changes before making a commit, alpar@325: add the following section to the appropriate .hg/hgrc file. deba@324: deba@324: [hooks] deba@324: pretxncommit.checksources = scripts/unify-sources.sh -c -n -i deba@324: deba@324: --help|-h deba@324: Print this help message. deba@324: files kpeter@328: The files to check/unify. If no file names are given, the modified kpeter@328: source files will be checked/unified (just like using the kpeter@328: --modified|-m option). deba@324: " deba@324: exit 0 deba@324: elif [ "$1" == '--dry-run' ] || [ "$1" == '-n' ] deba@324: then kpeter@328: [ -n "$ACTION" ] && echo "Conflicting action options" >&2 && exit 1 deba@324: ACTION=check deba@324: elif [ "$1" == "--all" ] || [ "$1" == '-a' ] deba@324: then kpeter@328: [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1 deba@324: FILES=all_files deba@324: elif [ "$1" == "--changed" ] || [ "$1" == '-c' ] deba@324: then kpeter@328: [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1 deba@324: FILES=changed_files deba@324: elif [ "$1" == "--modified" ] || [ "$1" == '-m' ] deba@324: then kpeter@328: [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1 deba@324: FILES=modified_files deba@324: elif [ "$1" == "--interactive" ] || [ "$1" == "-i" ] deba@324: then kpeter@328: [ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1 deba@324: WARNING='INTERACTIVE' deba@324: elif [ "$1" == "--werror" ] || [ "$1" == "-w" ] deba@324: then kpeter@328: [ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1 deba@324: WARNING='WERROR' kpeter@328: elif [ $(echo x$1 | cut -c 2) == '-' ] deba@324: then deba@324: echo "Invalid option $1" >&2 && exit 1 deba@324: else deba@324: [ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1 deba@324: GIVEN_FILES=$@ deba@324: FILES=given_files deba@324: break deba@324: fi deba@324: deba@324: shift deba@324: done deba@324: deba@324: if [ -z $FILES ] deba@324: then deba@324: FILES=modified_files alpar@38: fi deba@324: deba@324: if [ -z $ACTION ] deba@324: then deba@324: ACTION=update alpar@208: fi deba@324: deba@324: process_all