Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | |
| 3 | # Copyright (c) 2015 Cisco and/or its affiliates. |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at: |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | |
| 16 | # This aptly-named script verifies and fixes time ordering |
| 17 | # problems with Makefile.{am,in} aclocal.m4 configure* files. |
| 18 | |
| 19 | set -eu |
| 20 | #set -vx |
| 21 | |
| 22 | touch="" |
| 23 | commit="" |
| 24 | comma_v="" |
| 25 | aclocal="" |
| 26 | optimize="" |
| 27 | |
| 28 | # The old autowank scheme used "touch <foo> ; sleep 1" |
| 29 | # to ensure differentiable, ordered timestamps. Worked, but |
| 30 | # took N seconds given N files to fix. We have an example |
| 31 | # which wastes multiple minutes given the old scheme. |
| 32 | # |
| 33 | # This version generates a sequence of timestamps |
| 34 | # starting an hour ago. That gives us |
| 35 | # lots to play with, in case some obnoxious program feels the need |
| 36 | # to complain about timestamps in the future. |
| 37 | |
| 38 | # If we're in UTC+N land, generate UTC+(N+1) |
| 39 | # If we're in UTC-N land, generate UTC-(N-1) |
| 40 | |
| 41 | my_tz=`date +%z` |
| 42 | sign=`echo $my_tz | sed -n -e 's/^\(.\{1\}\).*$/\1/p'` |
| 43 | t=`echo $my_tz | sed -n -e 's/^\(.\{1\}\)//p'` |
| 44 | tz_hour=`echo $t | sed -n -e 's/^\(.\{2\}\).*$/\1/p'` |
| 45 | tz_hour=`echo $tz_hour | sed 's/^0//'` |
| 46 | |
| 47 | if [ $sign = "-" ] ; then |
| 48 | sign="+" |
| 49 | let tz_hour=$tz_hour+1 |
| 50 | if [[ $tz_hour -ge "24" ]] ; then |
| 51 | tz_hour=0 |
| 52 | fi |
| 53 | else |
| 54 | sign="-" |
| 55 | let tz_hour=$tz_hour-1 || true |
| 56 | if [[ $tz_hour -lt "0" ]] ; then |
| 57 | tz_hour=23 |
| 58 | fi |
| 59 | fi |
| 60 | |
| 61 | # Timestamp, an hour ago: |
| 62 | ts_begin=`TZ=UTC${sign}${tz_hour} date +%Y%m%d%H%M.%S` |
| 63 | |
| 64 | # break into constituent parts |
| 65 | year=`echo $ts_begin | sed -n -e 's/^\(.\{4\}\).*$/\1/p'` |
| 66 | t=`echo $ts_begin | sed -n -e 's/^\(.\{4\}\)//p'` |
| 67 | month=`echo $t | sed -n -e 's/^\(.\{2\}\).*$/\1/p'` |
| 68 | t=`echo $t | sed -n -e 's/^\(.\{2\}\)//p'` |
| 69 | day=`echo $t | sed -n -e 's/^\(.\{2\}\).*$/\1/p'` |
| 70 | t=`echo $t | sed -n -e 's/^\(.\{2\}\)//p'` |
| 71 | hour=`echo $t | sed -n -e 's/^\(.\{2\}\).*$/\1/p'` |
| 72 | t=`echo $t | sed -n -e 's/^\(.\{2\}\)//p'` |
| 73 | min=`echo $t | sed -n -e 's/^\(.\{2\}\).*$/\1/p'` |
| 74 | t=`echo $t | sed -n -e 's/^\(.\{2\}\)//p'` |
| 75 | sec=`echo $t | sed -n -e 's/\.//p'` |
| 76 | |
| 77 | # How many days in the current month? |
| 78 | # Good until someone changes the calendar rules |
| 79 | days_in_current_month() { |
| 80 | if [[ $month -eq 9 || $month -eq 4 \ |
| 81 | || $month -eq 6 || $month -eq 11 ]] ; then |
| 82 | return 30; |
| 83 | fi |
| 84 | if [[ $month -eq 2 ]] ; then |
| 85 | let t=($year/400)*400 |
| 86 | if [[ $t -eq $year ]] ; then |
| 87 | return 29; |
| 88 | fi |
| 89 | let t=($year/100)*100 |
| 90 | if [[ $t -eq $year ]] ; then |
| 91 | return 28; |
| 92 | fi |
| 93 | let t=($year/4)*4 |
| 94 | if [[ $t -eq $year ]] ; then |
| 95 | return 29; |
| 96 | fi |
| 97 | return 28; |
| 98 | fi |
| 99 | return 31; |
| 100 | } |
| 101 | |
| 102 | # The next timestamp to issue via touch |
| 103 | # A real hemorrhoid because bash isnt easily convinced |
| 104 | # that 08 is a decimal number |
| 105 | next_ts() { |
| 106 | sec=`echo $sec | sed 's/^0//'` |
| 107 | let sec=$sec+1 |
| 108 | if [[ "$sec" -lt "60" ]] ; then |
| 109 | if [[ "$sec" -lt "10" ]] ; then |
| 110 | sec=0$sec |
| 111 | fi |
| 112 | return 0; |
| 113 | fi |
| 114 | sec="00" |
| 115 | min=`echo $min | sed 's/^0//'` |
| 116 | let min=$min+1 |
| 117 | if [[ "$min" -lt "60" ]] ; then |
| 118 | if [[ "$min" -lt "10" ]] ; then |
| 119 | min=0$min |
| 120 | fi |
| 121 | return 0; |
| 122 | fi |
| 123 | min="00" |
| 124 | hour=`echo $hour | sed 's/^0//'` |
| 125 | let hour=$hour+1 |
| 126 | if [[ "$hour" -lt "24" ]] ; then |
| 127 | if [[ "$hour" -lt "10" ]] ; then |
| 128 | hour=0$hour |
| 129 | fi |
| 130 | return 0; |
| 131 | fi |
| 132 | hour="00" |
| 133 | days_in_current_month |
| 134 | days_in_month=$? |
| 135 | if [[ "$day" -lt "$days_in_month" ]] ; then |
| 136 | day=`echo $day | sed 's/^0//'` |
| 137 | let day=$day+1 |
| 138 | if [[ "$day" -lt "10" ]] ; then |
| 139 | day=0$day |
| 140 | fi |
| 141 | return 0; |
| 142 | fi |
| 143 | day="01" |
| 144 | month=`echo $month | sed 's/^0//'` |
| 145 | let month=$month+1 |
| 146 | if [[ "$month" -lt "13" ]] ; then |
| 147 | if [[ "$month" -lt "10" ]] ; then |
| 148 | month=0$month |
| 149 | fi |
| 150 | return 0; |
| 151 | fi |
| 152 | month="01" |
| 153 | let year=$year+1 |
| 154 | return 0; |
| 155 | } |
| 156 | |
| 157 | while [ $# != 0 ] ; do |
| 158 | case "$1" in |
| 159 | (--commav) comma_v=",v" ;; |
| 160 | (--touch) touch=yes ;; |
| 161 | (--aclocal) aclocal=yes ;; |
| 162 | (--nooptimize) optimize="" ;; |
| 163 | (--commit=*) commit="$1" ;; |
| 164 | (*) echo "$0: usage [--touch|--commit|]" > /dev/stderr |
| 165 | exit 17 ;; |
| 166 | esac |
| 167 | shift |
| 168 | done |
| 169 | |
| 170 | if [ "${aclocal}" != "" ] ; then |
| 171 | if [ -f aclocal.m4 ] ; then |
| 172 | echo touching aclocal.m4 |
| 173 | sleep 1 |
| 174 | touch aclocal.m4 |
| 175 | else |
| 176 | echo aclocal.m4 not found |
| 177 | fi |
| 178 | fi |
| 179 | |
| 180 | if [ "${comma_v}" != "" -a "${commit}" != "" ] ; then |
| 181 | echo "No, you may NOT molest ,v files directly. Go away." > /dev/stderr |
| 182 | exit 1 |
| 183 | fi |
| 184 | |
| 185 | function touchme () |
| 186 | { |
| 187 | local victim="${1}" |
| 188 | shift |
| 189 | local touchmebaby="" |
| 190 | local sein="is" |
| 191 | local newer="no" |
| 192 | local older="no" |
| 193 | |
| 194 | if [ ! -r "$victim" ] ; then |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 195 | return |
| 196 | fi |
| 197 | |
| 198 | while [ $# != 0 ] ; do |
| 199 | if [ "${1}" -nt "${victim}" ] ; then |
| 200 | newer="yes" |
| 201 | fi |
| 202 | if [ "${1}" -ot "${victim}" ] ; then |
| 203 | older="yes" |
| 204 | fi |
| 205 | if [ "${newer}" = "no" -a "${older}" = "no" ] ; then |
| 206 | newer="yes" |
| 207 | fi |
| 208 | |
| 209 | if [ "${newer}" = "yes" ] ; then |
| 210 | if [ "${touchmebaby}" = "" ] ; then |
| 211 | touchmebaby="${1}" |
| 212 | else |
| 213 | sein="are" |
| 214 | touchmebaby="${touchmebaby} ${1}" |
| 215 | fi |
| 216 | fi |
| 217 | shift |
| 218 | done |
| 219 | if [ -n "${touchmebaby}" ] ; then |
| 220 | echo "*** ${touchmebaby} ${sein} newer than ${victim} " |
| 221 | if [ -n "${touch}" ] ; then |
| 222 | # |
| 223 | # This is the old version, in case something backfires... |
| 224 | if [ "${optimize}" != "yes" ] ; then |
| 225 | echo "Fixing " ;touch -c "$victim" ; sleep 1 |
| 226 | else |
| 227 | echo "Fixing " |
| 228 | # echo touch -c -t $year$month$day$hour$min.$sec "$victim" |
| 229 | touch -c -t $year$month$day$hour$min.$sec "$victim" |
| 230 | next_ts |
| 231 | fi |
| 232 | fi |
| 233 | fi |
| 234 | } |
| 235 | |
| 236 | makefileins="`/usr/bin/find . -name Attic -prune -o -name Makefile.in${comma_v}`" |
| 237 | |
| 238 | # aclocal.m4 depends on ***/Makefile.am, configure.ac, acinclude.m4, *.m4 crap |
| 239 | touchme aclocal.m4${comma_v} \ |
| 240 | `/usr/bin/find . -name Attic -prune -o -name Makefile.am${comma_v}` \ |
| 241 | "configure.in${comma_v}" "configure.ac${comma_v}" \ |
| 242 | "acinclude.m4${comma_v}" |
| 243 | |
| 244 | # Makefile.in must be newer than Makefile.am |
| 245 | for f in $makefileins ; do |
| 246 | d="`dirname ${f}`" |
| 247 | touchme "${d}/Makefile.in${comma_v}" "${d}/Makefile.am${comma_v}" |
| 248 | done |
| 249 | |
| 250 | # Makefile.in depends on aclocal.m4 |
| 251 | for f in $makefileins ; do |
| 252 | d="`dirname $f`" |
| 253 | touchme "${d}/Makefile.in${comma_v}" "aclocal.m4${comma_v}" |
| 254 | done |
| 255 | |
| 256 | # config.in must be newer than aclocal.m4 and configure.ac |
| 257 | if [ -f "config.in${comma_v}" ] ; then |
| 258 | touchme "config.in${comma_v}" "aclocal.m4${comma_v}" \ |
| 259 | "configure.ac${comma_v}" \ |
| 260 | "configure.in${comma_v}" |
| 261 | fi |
| 262 | |
| 263 | # config.h.in (or More Thoroughly Modern configh.in) |
| 264 | # must be newer than aclocal.m4 and (obsolete) acconfig.h |
| 265 | for c_h_in in config.h.in configh.in ; do |
| 266 | if [ -f "${c_h_in}${comma_v}" ]; then |
| 267 | touchme "${c_h_in}${comma_v}" "aclocal.m4${comma_v}" "acconfig.h${comma_v}" |
| 268 | #>>>> WTF? Why? This is nonsensical |
| 269 | ## ***/Makefile.in must be newer than config.h.in |
| 270 | #for f in $makefileins ; do |
| 271 | # touchme "$f" "${c_h_in}${comma_v}" |
| 272 | #done |
| 273 | fi |
| 274 | done |
| 275 | |
| 276 | # configure must be newer than everything |
| 277 | # touchme configure $makefileins -- why would this be needed? |
| 278 | touchme "configure${comma_v}" "aclocal.m4${comma_v}" "acconfig.h${comma_v}" \ |
| 279 | "config.in${comma_v}" "config.h.in${comma_v}" \ |
| 280 | "configh.in${comma_v}" |
| 281 | |
| 282 | if [ -n "${commit}" ] ; then |
| 283 | commit="${commit:9}" # strip off "--commit=" |
| 284 | # First ***/Makefile.am, |
| 285 | # configure.in, configure.ac, |
| 286 | # ***/*.m4 |
| 287 | # acconfig.h |
| 288 | cvs commit -m "${commit}" \ |
| 289 | `for f in ${makefileins} ; do \ |
| 290 | [ -f "$${f%.in}.am" ] && echo "$${f%.in}.am" ; \ |
| 291 | done` \ |
| 292 | `[ -f configure.in ] && echo configure.in` \ |
| 293 | `[ -f configure.ac ] && echo configure.ac` \ |
| 294 | `[ -f acconfig.h ] && echo acconfig.h` \ |
| 295 | `/usr/bin/find . -name '*.m4' -mindepth 2` |
| 296 | |
| 297 | # Next aclocal.m4 |
| 298 | [ -f "aclocal.m4" ] && cvs commit -m "${commit}" aclocal.m4 |
| 299 | |
| 300 | # Next config.in, config.h.in, configh.in |
| 301 | [ -f "config.in" ] && cvs commit -m "${commit}" config.in |
| 302 | [ -f "config.h.in" ] && cvs commit -m "${commit}" config.h.in |
| 303 | [ -f "configh.in" ] && cvs commit -m "${commit}" configh.in |
| 304 | |
| 305 | # Last ***/Makefile.in, configure |
| 306 | cvs commit -m "${commit}" ${makefileins} configure |
| 307 | fi |