testpatches.sh (7546B)
1 #!/bin/sh 2 # TODO: 3 # ? build: 4 # - set flags per project? (per version too?). 5 # - add build status (OK, FAIL, unknown), must be secure though. 6 7 projects() { 8 cat <<!__EOF__ 9 dmenu tools.suckless.org/dmenu/patches 10 dwm dwm.suckless.org/patches 11 ii tools.suckless.org/ii/patches 12 sent tools.suckless.org/sent/patches 13 sic tools.suckless.org/sic/patches 14 slock tools.suckless.org/slock/patches 15 st st.suckless.org/patches 16 surf surf.suckless.org/patches 17 tabbed tools.suckless.org/tabbed/patches 18 !__EOF__ 19 } 20 21 wikidir="$(pwd)/sites" 22 repodir="$(pwd)/repos" 23 revdir="$(pwd)/rev" 24 resultsdir="$(pwd)/results" 25 builddir="$(pwd)/build" 26 27 # dryrun patch command (OpenBSD). 28 # must be unified diff (-u, so no ed script), -t and -C are dryrun (non-POSIX). 29 dryrun="patch -u -p1 -t -C" 30 31 # getdateutc() 32 getdateutc() { 33 # date as UTC+0 time. 34 TZ="UTC+0" date 35 } 36 37 # log(s) 38 log() { 39 s="[$(date)] $1" 40 echo "$s" >&2 41 } 42 43 # getprojects() 44 getprojects() { 45 # allow commenting to disable. 46 projects | grep -v '^#' 47 } 48 49 # clone() 50 clone() { 51 getprojects | while read -r -- project dir; do 52 test -d "$repodir/$project" && continue 53 54 git clone --bare "git://git.suckless.org/$project" "$repodir/$project" 55 done 56 } 57 58 # pull() 59 pull() { 60 getprojects | while read -r -- project dir; do 61 test -d "$repodir/$project" || continue 62 63 GIT_DIR="$repodir/$project" git fetch "git://git.suckless.org/$project" 64 done 65 } 66 67 # listpatches() 68 listpatches() { 69 getprojects | while read -r -- project dir; do 70 find "$wikidir/$dir" -name "*.diff" | while read -r p; do 71 test -f "$p" || continue 72 73 b=$(basename "$p") 74 bb="${b%.diff}" 75 bb="${bb#${project}-}" 76 77 # NOTE: historical patches like "r1506" (mercurial) are ignored. 78 v=$(echo "$bb" | sed -En 's@^([0-9a-f\.]+)-.*$@\1@p') 79 if test -z "$v"; then 80 v=$(echo "$bb" | sed -En 's@^.*-([0-9a-f\.]+)$@\1@p') 81 fi 82 83 # version not found, skip. 84 if test -z "$v"; then 85 continue 86 fi 87 88 name="${p%.diff}" 89 name="${name##*/patches/}" 90 name="${name%%/*}" 91 92 printf '%s\t%s\t%s\t%s\t%s\n' "$project" "$v" "$dir" "$name" "$p" 93 done 94 done 95 } 96 97 # checkoutrev(project, version) 98 checkoutrev() { 99 project="$1" 100 v="$2" 101 102 test -f "$revdir/$project/$v/fail" && return 1 103 test -d "$revdir/$project/$v" && return 0 104 105 cur=$(pwd) 106 d="$revdir/$project/$v" 107 mkdir -p "$d" 108 cd "$d" || return 1 109 110 GIT_DIR="$repodir/$project" \ 111 git archive "$v" 2> "$revdir/$project/$v/fail" | \ 112 tar xf - 2>/dev/null 113 status=$? 114 if test x"$status" != x"0"; then 115 status=1 116 else 117 rm -f "$revdir/$project/$v/fail" 118 fi 119 cd "$cur" 120 121 return $status 122 } 123 124 # preparebuilds() 125 preparebuilds() { 126 listpatches | while read -r -- project v dir name p; do 127 test -f "$p" || continue 128 129 # version quirks (wrong tagging). 130 if test x"$project" = x"sent"; then 131 if test x"$v" = x"1.0"; then 132 v="1" 133 test -e "$revdir/$project/1.0" || \ 134 ln -sf "$v" "$revdir/$project/1.0" 135 fi 136 fi 137 if test x"$project" = x"ii"; then 138 if test x"$v" = x"1.7"; then 139 v="v1.7" 140 test -e "$revdir/$project/1.7" || \ 141 ln -sf "$v" "$revdir/$project/1.7" 142 fi 143 fi 144 145 # prepare clean build directory for patch. 146 b=$(basename "$p") 147 b="${b%.diff}" 148 149 # cannot prepare revision for build: skip. 150 if ! checkoutrev "$project" "$v"; then 151 log "CANNOT CHECKOUT REVISION: $project v=$v, name=$name, patch=$b, error=$(cat "$revdir/$project/$v/fail")" 152 continue 153 fi 154 155 # already has clean builddir. 156 test -d "$builddir/$project/$b" && continue 157 cleanbuild "$project" "$v" "$b" 158 done 159 } 160 161 # cleanbuild(project, version, build) 162 cleanbuild() { 163 project="$1" 164 v="$2" 165 b="$3" 166 167 test -d "$builddir/$project/$b" && rm -rf "$builddir/$project/$b" 168 169 mkdir -p "$builddir/$project" 170 cp -r "$revdir/$project/$v" "$builddir/$project/$b" 171 } 172 173 # testpatches() 174 testpatches() { 175 # sort by project, name, version 176 listpatches | sort -k1,1 -k4,4 -k2,2 | \ 177 while read -r -- project v dir name p; do 178 test -f "$p" || continue 179 180 # cannot prepare revision for build: skip. 181 checkoutrev "$project" "$v" || continue 182 183 b=$(basename "$p") 184 b="${b%.diff}" 185 186 test -d "$builddir/$project/$b" || continue 187 cd "$builddir/$project/$b" || continue 188 189 # copy patch file for convenience / debugging. 190 cp "$p" "$builddir/$project/$b/p.diff" 191 192 # lenient: copy config.def.h to config.h if config.h doesn't exist. 193 #rm -f "$builddir/$project/$b/config.h" # DEBUG 194 #if test -f "$builddir/$project/$b/config.def.h"; then 195 # if ! test -f "$builddir/$project/$b/config.h"; then 196 # cp "$builddir/$project/$b/config.def.h" "$builddir/$project/$b/config.h" 197 # fi 198 #fi 199 200 # patch (dryrun). 201 $dryrun < "$p" 2> "$builddir/$project/$b/patch.2.log" >"$builddir/$project/$b/patch.1.log" 202 applystatus=$? 203 204 # write results to metadata file (for creating views). 205 printf "%s\t%s\t%s\t%s\t%s\t%s\n" \ 206 "$project" "$v" "$dir" "$name" "$applystatus" "$b" > "$builddir/$project/$b/metadata" 207 208 log "$p $applystatus" 209 done 210 } 211 212 # outputhtml() 213 outputhtml() { 214 index="$resultsdir/index.html" 215 title="Last updated on $(getdateutc)" 216 217 cat > "$index" <<!__EOF__ 218 <!DOCTYPE html> 219 <html> 220 <head> 221 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 222 <title>$title - Patch applystatus</title> 223 <style type="text/css"> 224 table { border-collapse: collapse; } 225 td { padding: 2px; } 226 thead td { background-color: #eee; } 227 .s-0 td { background-color: #ccffcc; } 228 .s-1 td { background-color: #ffcccc; } 229 .s-2 td { background-color: #ff0000; color: #fff; } 230 </style> 231 </head> 232 <body> 233 <h1>$title</h1> 234 <table> 235 <thead> 236 <tr> 237 <td><b>Project</b></td> 238 <td><b>Version/revision</b></td> 239 <td><b>Patch</b></td> 240 <td><b>Patch</b></td> 241 <td><b>Patch file</b></td> 242 <td><b>Patch stdout</b></td> 243 <td><b>Patch stderr</b></td> 244 <td><b>Exitcode</b></td> 245 <td><b>Status</b></td> 246 </tr> 247 </thead> 248 <tbody> 249 !__EOF__ 250 251 # sort by project, name, version 252 find "$builddir" -name "metadata" -type f -exec cat {} \; | \ 253 sort -k1,1 -k4,4 -k2,2 | \ 254 while read -r -- project v dir name applystatus b; do 255 test -d "$builddir/$project/$b" || continue 256 257 # HTML output test 258 mkdir -p "$resultsdir/$b/" 259 cp \ 260 "$builddir/$project/$b/p.diff"\ 261 "$builddir/$project/$b/patch.2.log"\ 262 "$builddir/$project/$b/patch.1.log"\ 263 "$resultsdir/$b/" 264 265 statustext="OK" 266 pageurl="https://$dir/$name/" 267 268 case "$applystatus" in 269 0) statustext="OK";; 270 1) statustext="FAIL";; 271 2) statustext="CORRUPT";; 272 *) statustext="UNKNOWN";; 273 esac 274 275 cat >> "$index" <<!__EOF__ 276 <tr class="s-$applystatus"> 277 <td><a href="https://git.suckless.org/$project/">$project</a></td> 278 <td>$v</td> 279 <td><a href="$pageurl">$name</a></td> 280 <td><a href="$pageurl">$b</a></td> 281 <td><a href="$b/p.diff">[patch]</a></td> 282 <td><a href="$b/patch.1.log">[stdout]</a></td> 283 <td><a href="$b/patch.2.log">[stderr]</a></td> 284 <td>$applystatus</td> 285 <td>$statustext</td> 286 </tr> 287 !__EOF__ 288 done 289 290 echo "</tbody></table></body></html>" >> "$index" 291 } 292 293 # outputcsv() 294 outputcsv() { 295 index="$resultsdir/index.csv" 296 297 # sort by project, name, version 298 find "$builddir" -name "metadata" -type f -exec cat {} \; | \ 299 sort -k1,1 -k4,4 -k2,2 | \ 300 while read -r -- project v dir name applystatus b; do 301 test -d "$builddir/$project/$b" || continue 302 303 printf '%s\n' "$project $v $name $b $applystatus" >> "$index" 304 done 305 } 306 307 case "$1" in 308 clone|pull) 309 mkdir -p "$repodir" 310 $1 311 ;; 312 clean) 313 rm -rf "$revdir" "$builddir" 314 ;; 315 prepare) 316 mkdir -p "$builddir" "$revdir" 317 preparebuilds 318 ;; 319 test) 320 testpatches 321 ;; 322 results) 323 # output results 324 rm -rf "$resultsdir" 325 mkdir -p "$resultsdir" 326 outputhtml 327 outputcsv 328 ;; 329 *) 330 echo "usage: $0 <clone | pull | clean | prepare | test | results>" >&2 331 exit 1 332 ;; 333 esac