1# -*- mode: makefile-gmake -*- 2# 3# Contains rules that are shared between SLEPc and PETSc 4# 5# This file is not included by rules, or rules_doc.mk. In PETSc it is only included by the toplevel makefile 6 7# ********* Rules for printing PETSc library properties useful for building applications *********************************************************** 8 9getversion: 10 -@${PETSC_DIR}/lib/petsc/bin/petscversion 11 12getmpilinklibs: 13 -@echo ${MPI_LIB} 14 15getmpiincludedirs: 16 -@echo ${MPI_INCLUDE} 17 18getmpiexec: 19 -@echo ${MPIEXEC} 20 21getccompiler: 22 -@echo ${CC} 23 24getfortrancompiler: 25 -@echo ${FC} 26 27getcxxcompiler: 28 -@echo ${CXX} 29 30getlinklibs: 31 -@echo ${C_SH_LIB_PATH} ${PETSC_TS_LIB} 32 33getincludedirs: 34 -@echo ${PETSC_CC_INCLUDES} 35 36getcflags: 37 -@echo ${CC_FLAGS} 38 39getcxxflags: 40 -@echo ${CXX_FLAGS} 41 42getfortranflags: 43 -@echo ${FC_FLAGS} 44 45getblaslapacklibs: 46 -@echo ${BLASLAPACK_LIB} 47 48getautoconfargs: 49 -@echo CC='"${CC}"' CXX='"${CXX}"' FC='"${FC}"' CFLAGS='"${CC_FLAGS}"' CXXFLAGS='"${CXX_FLAGS}"' FCFLAGS='"${FC_FLAGS}"' LIBS='"${C_SH_LIB_PATH} ${PETSC_TS_LIB}"' 50 51#********* Rules for checking the PETSc source code, and comments do not violate PETSc standards. And for properly formatting source code and manual pages 52PETSCCLANGFORMAT ?= clang-format 53# Check the version of clang-format matches PETSc requirement 54checkclangformatversion: 55 @version=`${PETSCCLANGFORMAT} --version | cut -d" " -f3 | cut -d"." -f 1` ;\ 56 if [ "$$version" = "version" ]; then version=`${PETSCCLANGFORMAT} --version | cut -d" " -f4 | cut -d"." -f 1`; fi;\ 57 if [ $$version != 21 ]; then echo "Require clang-format version 21! Currently used ${PETSCCLANGFORMAT} version is $$version" ;false ; fi 58 59# Format all the source code in the given directory and down according to the file $PETSC_DIR/.clang_format 60clangformat: checkclangformatversion 61 -@git --no-pager ls-files -z ${GITCFSRC} | xargs -0 -P $(MAKE_NP) -L 10 ${PETSCCLANGFORMAT} -i 62 63GITFSRC = '*.[hF]90' '*/finclude/*.h' 64GITSRC = '*.[ch]' '*.hpp' '*.cxx' '*.cu' ${GITFSRC} ${GITSRCEXCL} 65GITMAKE = '*[Mm]akefile*' 'lib/petsc/conf/*' 'lib/slepc/conf/*' 66GITSRCEXCL = \ 67':!*khash/*' \ 68':!*valgrind/*' \ 69':!*yaml/*' \ 70':!*perfstubs/*' 71GITCFSRC = '*.[ch]' '*.hpp' '*.cxx' '*.cu' ${GITSRCEXCL} ${GITCFSRCEXCL} 72GITCFSRCEXCL = \ 73':!*petscversion.h' \ 74':!*mpiunifdef.h' \ 75':!*finclude/*' \ 76':!systems/*' \ 77':!*binding/*' 78 79# Check that copies of external source code that live in the PETSc repository have not been changed by developer 80checkbadFileChange: 81 @git diff --stat --exit-code `lib/petsc/bin/maint/check-merge-branch.sh`..HEAD -- src/sys/yaml/include src/sys/yaml/License include/petsc/private/valgrind include/petsc/private/kash 82 83vermin: 84 @vermin --violations -t=3.4- ${VERMIN_OPTIONS} ${PETSC_DIR}/config 85 @vermin --violations -t=3.6- --exclude-regex '\.pyi$$' ${VERMIN_OPTIONS} ${PETSC_DIR}/src/binding/petsc4py 86 87# Check that source code does not violate basic PETSc coding standards 88checkbadsource: checkbadSource 89 90checkbadSource: 91 @git --no-pager grep -n -P 'self\.gitcommit' -- config/BuildSystem/config/packages | grep 'origin/' ; if [[ "$$?" == "0" ]]; then echo "Error: Do not use a branch name in a configure package file"; false; fi 92 -@${RM} -f checkbadSource.out 93 -@touch checkbadSource.out 94 -@${PYTHON} ${PETSC_DIR}/lib/petsc/bin/maint/check_header_guard.py --action=check --kind=pragma_once -- ./src ./include >> checkbadSource.out 95 -@echo "----- Double blank lines in file -----------------------------------" >> checkbadSource.out 96 -@git --no-pager grep -n -P '^$$' -- ${GITSRC} ${GITMAKE} 'config/*' > doublelinecheck.out 97 -@${PYTHON} ${PETSC_DIR}/lib/petsc/bin/maint/doublelinecheck.py doublelinecheck.out >> checkbadSource.out 98 -@${RM} -f doublelinecheck.out 99 -@echo "----- Tabs in file -------------------------------------------------" >> checkbadSource.out 100 -@git --no-pager grep -n -P '\t' -- ${GITSRC} >> checkbadSource.out;true 101 -@echo "----- Tabs in makefiles --------------------------------------------" >> checkbadSource.out 102 -@git --no-pager grep -n -P '^[^#][ ]*[#A-Za-z0-9][ :=_A-Za-z0-9]*\t' -- ${GITMAKE} >> checkbadSource.out;true 103 -@echo "----- White space at end of line -----------------------------------" >> checkbadSource.out 104 -@git --no-pager grep -n -P ' $$' -- ${GITSRC} ${GITMAKE} 'config/*' >> checkbadSource.out;true 105 -@echo "----- Two ;; -------------------------------------------------------" >> checkbadSource.out 106 -@git --no-pager grep -n -P -e ';;' -- ${GITSRC} | grep -v ' for (' >> checkbadSource.out;true 107 -@echo "----- PetscCall for an MPI error code ------------------------------" >> checkbadSource.out 108 -@git --no-pager grep -n -P -e 'PetscCall\(MPI[U]*_\w*\(.*\)\);' -- ${GITSRC} | grep -Ev 'MPIU_File' >> checkbadSource.out;true 109 -@echo "----- DOS file (with DOS newlines) ---------------------------------" >> checkbadSource.out 110 -@git --no-pager grep -n -P '\r' -- ${GITSRC} ${GITMAKE} 'config/*' >> checkbadSource.out;true 111 -@echo "----- { before SETERRQ ---------------------------------------------" >> checkbadSource.out 112 -@git --no-pager grep -n -P '{SETERRQ' -- ${GITSRC} >> checkbadSource.out;true 113 -@echo "----- PetscCall following SETERRQ ----------------------------------" >> checkbadSource.out 114 -@git --no-pager grep -n -P 'SETERRQ' -- ${GITSRC} | grep ";PetscCall" >> checkbadSource.out;true 115 -@echo "----- SETERRQ() without defined error code -------------------------" >> checkbadSource.out 116 -@git --no-pager grep -n -P 'SETERRQ\((?!\))' -- ${GITSRC} | grep -v PETSC_ERR | grep " if " | grep -v "__VA_ARGS__" | grep -v "then;" | grep -v flow.c >> checkbadSource.out;true 117 -@echo "----- SETERRQ() with trailing newline ------------------------------" >> checkbadSource.out 118 -@git --no-pager grep -n -P "SETERRQ[1-9]?.*\\\n\"" -- ${GITSRC} >> checkbadSource.out;true 119 -@echo "----- Define keyword used in test definition -----------------------" >> checkbadSource.out 120 -@git --no-pager grep -n -P -e 'requires:.*define\(' -- ${GITSRC} >> checkbadSource.out;true 121 -@echo "----- Using if (condition) SETERRQ(...) instead of PetscCheck() ----" >> checkbadSource.out 122 -@git --no-pager grep -n -P ' if +(.*) *SETERRQ' -- ${GITSRC} | grep -v 'PetscUnlikelyDebug' | grep -v 'petscerror.h' | grep -v "then;" | grep -v "__VA_ARGS__" >> checkbadSource.out;true 123 -@echo "----- Using if (PetscUnlikelyDebug(condition)) SETERRQ(...) instead of PetscAssert()" >> checkbadSource.out 124 -@git --no-pager grep -n -P -E ' if +\(PetscUnlikelyDebug.*\) *SETERRQ' -- ${GITSRC} | grep -v petscerror.h >> checkbadSource.out;true 125 -@echo "----- Using PetscFunctionReturn(ierr) ------------------------------" >> checkbadSource.out 126 -@git --no-pager grep -n -P 'PetscFunctionReturn(ierr)' -- ${GITSRC} >> checkbadSource.out;true 127 -@echo "----- .seealso with leading white spaces ---------------------------" >> checkbadSource.out 128 -@git --no-pager grep -n -P -E '^[ ]+.seealso:' -- ${GITSRC} ':!src/sys/tests/linter/*' >> checkbadSource.out;true 129 -@echo "----- .seealso with double backticks -------------------------------" >> checkbadSource.out 130 -@git --no-pager grep -n -P -E '^.seealso:.*``' -- ${GITSRC} >> checkbadSource.out;true 131 -@echo "----- Defining a returning macro without PetscMacroReturns() -------" >> checkbadSource.out 132 -@git --no-pager grep -n -P 'define .*\w+;\s+do' -- ${GITSRC} | grep -E -v '(PetscMacroReturns|PetscDrawCollectiveBegin|MatPreallocateBegin|PetscOptionsBegin|PetscObjectOptionsBegin|PetscOptionsHeadEnd)' >> checkbadSource.out;true 133 -@echo "----- Defining an error checking macro using CHKERR style ----------" >> checkbadSource.out 134 -@git --no-pager grep -n -P 'define\s+CHKERR\w*\(.*\)\s*do\s+{' -- ${GITSRC} >> checkbadSource.out;true 135 -@echo "----- Using Petsc[Array|Mem]cpy() for ops instead of assignment ----" >> checkbadSource.out 136 -@git --no-pager grep -n -P 'cpy\(.*(.|->)ops, .*\)' -- ${GITSRC} >> checkbadSource.out;true 137 -@echo "----- Extra spaces in test harness rules ---------------------------" >> checkbadSource.out 138 -@git --no-pager grep -n -P -E '^(\!){0,1}[ ]*(suffix|output_file|nsize|requires|args):.* .*' -- ${GITSRC} >> checkbadSource.out;true 139 -@echo "----- Extra comma in test harness rules ----------------------------" >> checkbadSource.out 140 -@git --no-pager grep -n -P -E '^(\!){0,1}[ ]*requires:.*,' -- ${GITSRC} >> checkbadSource.out;true 141 -@echo "----- Using PetscInfo() without carriage return --------------------" >> checkbadSource.out 142 -@git --no-pager grep -n -P 'PetscCall\(PetscInfo\(' -- ${GITSRC} | grep -v '\\n' >> checkbadSource.out;true 143 -@echo "----- Using Petsc(Assert|Check)() with carriage return -------------" >> checkbadSource.out 144 -@git --no-pager grep -n -P -E 'Petsc(Assert|Check)\(.*[^\]\\\n' -- ${GITSRC} >> checkbadSource.out;true 145 -@echo "----- Extra \"\" after format specifier ending a string --------------" >> checkbadSource.out 146 -@git --no-pager grep -n -P -E '_FMT \"\",' -- ${GITSRC} >> checkbadSource.out;true 147 -@echo "----- First blank line ---------------------------------------------" >> checkbadSource.out 148 -@git --no-pager grep -n -P \^\$$ -- ${GITSRC} ${GITMAKE} 'config/*' | grep ':1:' >> checkbadSource.out;true 149 -@echo "----- Last blank line ----------------------------------------------" >> checkbadSource.out 150 -@git ls-files ${GITFSRC} ${GITMAKE} 'config/*' ':!*petscdm.h90' ':!*petscts.h90' ':!*/__init__.py' | xargs -I{} sh -c 'tail -n1 "{}" | grep -q . || echo "{}"' >> checkbadSource.out;true 151 -@echo "----- Blank line after PetscFunctionBegin and derivatives ----------" >> checkbadSource.out 152 -@git --no-pager grep -n -E -A 1 ' PetscFunctionBegin(User|Hot){0,1};' -- ${GITSRC} | grep -E '\-[0-9]+-$$' | grep -v '^--$$' >> checkbadSource.out;true 153 -@echo "----- Blank line before PetscFunctionReturn ------------------------" >> checkbadSource.out 154 -@git --no-pager grep -n -E -B 1 ' PetscFunctionReturn' -- ${GITSRC} | grep -E '\-[0-9]+-$$' | grep -v '^--$$' >> checkbadSource.out;true 155 -@echo "----- No blank line before PetscFunctionBegin and derivatives ------" >> checkbadSource.out 156 -@git --no-pager grep -n -E -B 1 ' PetscFunctionBegin(User|Hot){0,1};' -- ${GITSRC} ':!src/sys/tests/*' ':!src/sys/tutorials/*' | grep -E '\-[0-9]+-.*;' | grep -v '^--$$' | grep -v '\\' >> checkbadSource.out;true 157 -@echo "----- Unneeded parentheses [!&~*](foo[->|.]bar) --------------------" >> checkbadSource.out 158 -@git --no-pager grep -n -P -E '([\!\&\~\*\(]|\-\-|\+\+|\)\)|\([^,\*\(]+\**\))\(([a-zA-Z0-9_]+((\.|->)[a-zA-Z0-9_]+|\[[a-zA-Z0-9_ \%\+\*\-]+\])+)\)' -- ${GITSRC} >> checkbadSource.out;true 159 -@echo "----- Use PetscSafePointerPlusOffset(ptr, n) instead of ptr ? ptr + n : NULL" >> checkbadSource.out 160 -@git --no-pager grep -n -Po ' ([^()\ ]+) \? (?1) \+ (.)* : NULL' -- ${GITSRC} >> checkbadSource.out;true 161 -@echo "----- Wrong PETSc capitalization -----------------------------------" >> checkbadSource.out 162 -@git --no-pager grep -n -P -E '[^a-zA-Z_*>{.]petsc [^+=]' -- ${GITSRC} | grep -v 'mat_solver_type petsc' | grep -v ' PETSc ' >> checkbadSource.out;true 163 -@echo "----- Fortran: Semi-colon at end of line ---------------------------" >> checkbadSource.out 164 -@git --no-pager grep -n -P -E ";$$" -- ${GITFSRC} >> checkbadSource.out;true 165 -@echo "----- Empty test harness output_file not named output/empty.out ----" >> checkbadSource.out 166 -@git --no-pager grep -L . -- '*.out' | grep -Ev '(/empty|/[a-zA-Z0-9_-]+_alt).out' >> checkbadSource.out;true 167 -@echo "----- Unnecessary braces around one-liners -------------------------" >> checkbadSource.out 168 -@git --no-pager grep -n -P -E '[ ]*(if|for|while|do|else) \(.*\) \{[^;]*;[^;]*\}( \\)?$$' -- ${GITSRC} >> checkbadSource.out;true 169 -@echo "----- MPI_(Allreduce|Irecv|Isend) instead of MPIU_(Allreduce|Irecv|Isend)" >> checkbadSource.out 170 -@git --no-pager grep -n -P -E '\(MPI_(Allreduce|Irecv|Isend)\([^\)]' -- ${GITSRC} ':!*/tests/*' ':!*/tutorials/*' ':!src/sys/objects/pinit.c' >> checkbadSource.out;true 171 -@echo "----- Fortran: #include <petsc/finclude/...> not 1st line (examples/tutorials)" >> checkbadSource.out 172 -@git --no-pager grep -H -B9999 '#include <petsc/finclude/.*>' -- '*/tutorials/*.F90' '*/tests/*.F90' | grep -v -e '!' -e 'F90-$$' -e '#include <petsc/finclude/.*>' -e '--' >> checkbadSource.out;true 173 -@echo "----- Fortran: labeled do loop -------------------------------------" >> checkbadSource.out 174 -@git --no-pager grep -n "[[:space:]]*do[[:space:]]*[0-9]" -- ${GITFSRC} >> checkbadSource.out;true 175 -@echo "----- Duplicate CUDA/Kokkos file names -----------------------------" >> checkbadSource.out 176 -@git ls-files *.cu *.kokkos.cxx | xargs -I{} sh -c 'basename "{}"' | sort | uniq -d >> checkbadSource.out;true 177 -@echo "----- #if [!]defined with a trailing white space -------------------" >> checkbadSource.out 178 -@git --no-pager grep -n "#if [!]defined " -- ${GITFSRC} ${GITSRC} >> checkbadSource.out;true 179 -@echo "----- #if[n]def should use #if [!]defined()-------------------------" >> checkbadSource.out 180 -@git --no-pager grep -n "#if[n]def " -- ${GITFSRC} ${GITSRC} >> checkbadSource.out;true 181 -@echo "----- Use of the .cpp file extension instead of .cxx ---------------" >> checkbadSource.out 182 -@git ls-files *.cpp >> checkbadSource.out;true 183 @a=`cat checkbadSource.out | wc -l`; l=`expr $$a - 43` ;\ 184 if [ $$l -gt 0 ] ; then \ 185 echo $$l " files with errors detected in source code formatting" ;\ 186 cat checkbadSource.out ;\ 187 else \ 188 ${RM} -f checkbadSource.out;\ 189 fi;\ 190 test ! $$l -gt 0 191 -@git --no-pager grep -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" -- ${GITSRC} > badSourceChar.out;true 192 -@w=`cat badSourceChar.out | wc -l`;\ 193 if [ $$w -gt 0 ] ; then \ 194 echo "Source files with non-ASCII characters ----------------" ;\ 195 cat badSourceChar.out ;\ 196 else \ 197 ${RM} -f badSourceChar.out;\ 198 fi 199 @test ! -s badSourceChar.out 200 201# Run a linter in a Python virtual environment to check (and fix) the formatting of PETSc manual pages 202# V=1 verbose 203# REPLACE=1 replace ill-formatted docs with correctly formatted docs 204env-lint: 205 @if [[ `which llvm-config` == "" ]]; then echo "llvm-config for version 14 must be in your path"; exit 1; fi 206 @if [ `llvm-config --version | cut -f1 -d"."` != 14 ]; then echo "llvm-config for version 14 must be in your path"; exit 1; fi 207 @python3 -m venv petsc-lint-env 208 @source petsc-lint-env/bin/activate && python3 -m pip install --quiet -r lib/petsc/bin/maint/petsclinter/requirements.txt && \ 209 python3 ${PETSC_DIR}/lib/petsc/bin/maint/petsclinter --verbose=${V} --apply-patches=${REPLACE} --clang_lib=`llvm-config --libdir`/libclang.dylib --werror 1 ./src ; deactivate 210 211# Run a linter to check (and fix) the formatting of PETSc manual pages 212lint: 213 ${PYTHON} ${PETSC_DIR}/lib/petsc/bin/maint/petsclinter --verbose=${V} --apply-patches=${REPLACE} $(LINTER_OPTIONS) ${DIRECTORY} 214 215help-lint: 216 @${PYTHON} ${PETSC_DIR}/lib/petsc/bin/maint/petsclinter --help 217 -@echo "Basic usage:" 218 -@echo " make lint <options> [DIRECTORY=directory]" 219 -@echo " make test-lint <options> <test only options>" 220 -@echo 221 -@echo "Options:" 222 -@echo " V=[0, 1, 2, 3] Enable increasingly verbose output" 223 -@echo " LINTER_OPTIONS=\"--opt1 --opt2 ...\" See above for available options" 224 -@echo 225 -@echo "Test Only Options:" 226 -@echo " LINTER_SKIP_MYPY=[1, 0] Enable or disable mypy checks" 227 -@echo " REPLACE=[1, 0] Enable or disable replacing test output" 228 -@echo 229 230checkvermin_exist: 231 @ret=`which vermin > /dev/null`; \ 232 if [ $$? -ne 0 ]; then \ 233 echo "vermin is required, please install: python3 -m pip install vermin"; \ 234 false; \ 235 fi 236 237checkmypy_exist: 238 @ret=`which mypy > /dev/null`; \ 239 if [ $$? -ne 0 ]; then \ 240 echo "MyPy is required, please install: python3 -m pip install mypy"; \ 241 false; \ 242 fi 243 244LINTER_SKIP_MYPY ?= 0 245 246test-lint: checkvermin_exist checkmypy_exist 247 vermin --config-file ${PETSC_DIR}/lib/petsc/bin/maint/petsclinter/pyproject.toml -- ${PETSC_DIR}/lib/petsc/bin/maint/petsclinter 248 if [[ "$(LINTER_SKIP_MYPY)" == "0" ]]; then \ 249 cd ${PETSC_DIR}/lib/petsc/bin/maint/petsclinter && mypy . ; \ 250 fi 251 ${PYTHON} ${PETSC_DIR}/lib/petsc/bin/maint/petsclinter/petsclinter/pkg_consistency_checks.py 252 ${PYTHON} ${PETSC_DIR}/lib/petsc/bin/maint/petsclinter ${PETSC_DIR}/src/sys/tests/linter --test -j0 --werror --replace=${REPLACE} --verbose=${V} $(LINTER_OPTIONS) 253 254# Lists all the URLs in the PETSc repository that are unaccessible, nonexistent, or permanently moved (301) 255# REPLACE=1 locations marked as permanently moved (301) are replaced in the repository 256# This code is fragile; always check the changes after a use of REPLACE=1 before committing the changes 257# 258# Notes: 259# The first tr in the line is split lines for the cases where multiple URLs are in the same line 260# The first sed handles the case (http[s]*://xxx) 261# The list is sorted by length so that if REPLACE is used the longer apply before the shorter 262# The code recursively follows the permanently moved (301) redirections until it reaches the final URL 263# For DropBox we need to check the validity of the new URL but do not want to return to user the internal "raw" URL 264checkbadURLS: 265 -@x=`git grep "http[s]*://" -- '*.[chF]' '*.html' '*.cxx' '*.cu' '*.F90' '*.py' '*.tex' | grep -E -v "(config/packages|HandsOnExercises)" | tr '[[:blank:]]' '\n' | grep 'http[s]*://' | sed 's!.*(\(http[s]*://[-a-zA-Z0-9_./()?=&+%~]*\))!\1!g' | sed 's!.*\(http[s]*://[-a-zA-Z0-9_./()?=&+%~]*\).*!\1!g' | sed 's/\.$$//g' | sort | uniq| awk '{ print length, $$0 }' | sort -r -n -s | cut -d" " -f2` ; \ 266 for i in $$x; do \ 267 url=$$i; \ 268 msg=''; \ 269 while [[ "$${msg}D" == "D" ]] ; do \ 270 y1=`curl --connect-timeout 5 --head --silent $${url} | head -n 1`; \ 271 y2=`echo $${y1} | grep ' 4[0-9]* '`; \ 272 y3=`echo $${y1} | grep ' 301 '`; \ 273 if [[ "$${y1}D" == "D" ]] ; then \ 274 msg="Unable to reach site" ; \ 275 elif [[ "$${y2}D" != "D" ]] ; then \ 276 msg=$${y1} ; \ 277 elif [[ "$${y3}D" != "D" ]] ; then \ 278 l=`curl --connect-timeout 5 --head --silent $${url} | grep ocation | sed 's/.*ocation:[[:blank:]]\(.*\)/\1/g' | tr -d '\r'` ; \ 279 w=`echo $$l | grep 'http'` ; \ 280 if [[ "$${w}D" != "D" ]] ; then \ 281 url=$$l ; \ 282 else \ 283 ws=`echo $${url} | sed 's!\(http[s]*://[-a-zA-Z0-9_.]*\)/.*!\1!g'` ; \ 284 dp=`echo $${ws}$${l} | grep "dropbox.com/s/raw"` ; \ 285 if [[ "$${dp}D" != "D" ]] ; then \ 286 b=`curl --connect-timeout 5 --head --silent $${ws}$$l | head -n 1` ; \ 287 c=`echo $${b} | grep -E "( 2[0-9]* | 302 )"` ; \ 288 if [[ "$${c}D" == "D" ]] ; then \ 289 msg=`echo "dropbox file doesn't exist" $${c}` ; \ 290 else \ 291 break ; \ 292 fi; \ 293 else \ 294 url="$${ws}$$l" ; \ 295 fi; \ 296 fi; \ 297 else \ 298 break; \ 299 fi; \ 300 done;\ 301 if [[ "$${msg}D" == "D" && "$${url}" != "$$i" ]] ; then \ 302 echo "URL" $$i "has moved to valid final location:" $${url} ; \ 303 if [[ "$${REPLACE}D" != "D" ]] ; then \ 304 git psed $$i $$l ;\ 305 fi; \ 306 elif [[ "$${msg}D" != "D" && "$${url}" != "$$i" ]] ; then \ 307 echo "ERROR: URL" $$i "has moved to invalid final location:" $${url} $${msg} ; \ 308 elif [[ "$${msg}D" != "D" ]] ; then \ 309 echo "ERROR: URL" $$i "invalid:" $${msg} ; \ 310 fi; \ 311 done 312