_verify-external-resources.awk (7416B)
1 #!/bin/awk -f 2 BEGIN { 3 load_indexes() 4 5 dep_count = 0 6 env_count = 0 7 FS="[ /]" 8 } 9 10 function fatal(msg) { 11 if(pline) { 12 printf "FATAL: pthbs-verifypkg: %s %s:%d\n", msg, pfile, pline >"/dev/stderr" 13 } else { 14 printf "FATAL: pthbs-verifypkg: %s %s:%d: \"%s\"\n", msg, FILENAME, FNR, $0 >"/dev/stderr" 15 } 16 exit 1 17 } 18 19 function q(s) { 20 return "'" s "'" 21 } 22 function dbgprint(msg) { 23 if(length(ENVIRON["pthbs_debug"])) { 24 printf "DBG: %s\n", msg >"/dev/stderr" 25 } 26 } 27 function dbgprint_count(n) { 28 if(length(ENVIRON["pthbs_debug"])) { 29 printf "DBG: %d entries\n", n >"/dev/stderr" 30 } 31 } 32 function dbgprint_dep(dep_type, dep_value) { 33 dbgprint(pfile" -> ["dep_type"]"dep_value) 34 } 35 function dbgprint_pkg() { 36 dbgprint(q(pfile)" => "q(pname)) 37 } 38 39 function vprint(msg) { 40 printf "%s\n", msg 41 } 42 43 function load_indexes() { 44 if(!length(ENVIRON["pthbs_indexdir"])) { 45 fatal("variable 'pthbs_indexdir' not defined") 46 } 47 load_downloadlist(ENVIRON["pthbs_indexdir"]"/downloadlist.sha256") 48 load_filelist(ENVIRON["pthbs_indexdir"]"/filelist.sha256") 49 load_commitlist(ENVIRON["pthbs_indexdir"]"/commitlist.sha1") 50 } 51 52 function load_downloadlist(downloadlist_path, n) { 53 dbgprint("reading downloadlist: "q(downloadlist_path)) 54 n = 0 55 while(getline <downloadlist_path) { 56 if(/^$/ || /^#/) { 57 continue 58 } 59 downloadable_hashes["sha256:"$1] = 0 60 hash_info["sha256:"$1] = downloadlist_path ":" FNR substr($0, length($1 + 2)) 61 n += 1 62 } 63 close(downloadlist_path) 64 dbgprint_count(n) 65 } 66 67 function load_filelist(filelist_path, n) { 68 dbgprint("reading filelist: "q(filelist_path)) 69 n = 0 70 while(getline <filelist_path) { 71 linkable_hashes["sha256:"$1] = 0 72 hash_info["sha256:"$1] = filelist_path ":" FNR substr($0, length($1 + 2)) 73 n += 1 74 } 75 close(filelist_path) 76 dbgprint_count(n) 77 } 78 79 function load_commitlist(commitlist_path, n) { 80 dbgprint("reading commitlist: "q(commitlist_path)) 81 n = 0 82 while(getline <commitlist_path) { 83 commits[$1] = 0 84 n += 1 85 } 86 close(filelist_path) 87 dbgprint_count(n) 88 } 89 90 /^[0-9a-f]+ .*\/[-_:.0-9a-zA-Z]+\/[-_:.0-9a-zA-Z]+/ { 91 pfile = substr($0, length($1) + 3) 92 pvariant = $(NF-1) 93 pname = $NF 94 sub(/:.*/, "", pname) 95 if(pname ~ /\.environment$/) { 96 namedenv_name[pfile] = pvariant"/"pname 97 pname = "env" 98 } 99 pname = $(NF-1)"/"pname"."$1 100 101 dbgprint_pkg() 102 package_names[pname] = 0 103 package_files[pname] = pfile 104 package_variants[pfile] = pvariant 105 next 106 } 107 108 { 109 fatal("unexpected line") 110 } 111 function record_failure(dep_type, dep_value, msg) { 112 if(!pline) { 113 fatal("internal error: record_failure() called without pline") 114 } 115 failed[pfile] = failed[pfile] pfile ":" pline " [" dep_type "] '" dep_value "'\t" msg "\n" 116 } 117 118 function find_namedenvs(pfile, rdeps, rdep_count, n, result) { 119 if (pfile ~ /\.environment$/) { 120 return pfile 121 } 122 rdep_count = split(package_rdeps[pfile], rdeps, " ") 123 for(n=1; n<=rdep_count; n++) { 124 result = spacemerge(result, find_namedenvs(rdeps[n])) 125 } 126 return result 127 } 128 129 END { 130 pname="" 131 for(pfile in package_variants) { 132 read_package(pfile) 133 } 134 count = 0 135 unused = 0 136 for(commit_id in commits) { 137 count += 1 138 unused += commits[commit_id] ? 0 : 1 139 } 140 printf "commit ids: %4d unused: %4d\n", count, unused 141 142 count = 0 143 unused = 0 144 for(i in linkable_hashes) { 145 count += 1 146 unused += linkable_hashes[i] ? 0 : 1 147 if(!linkable_hashes[i]) { 148 vprint(i " unused local file " hash_info[i]) 149 } 150 } 151 printf "local files: %4d unused: %4d\n", count, unused 152 153 count = 0 154 unused = 0 155 for(i in downloadable_hashes) { 156 count += 1 157 unused += downloadable_hashes[i] ? 0 : 1 158 if(!downloadable_hashes[i]) { 159 vprint(i " unused download " hash_info[i]) 160 } 161 } 162 printf "downloads: %4d unused: %4d\n", count, unused 163 164 # for(pfile in package_rdeps) { 165 for(pfile in package_variants) { 166 dbgprint("'" pfile "' <- '" package_rdeps[pfile] "'") 167 nes = find_namedenvs(pfile) 168 if(length(nes)){ 169 dbgprint("'" pfile "' <= '" nes "'") 170 } else { 171 vprint("unused package: " pfile) 172 } 173 } 174 175 failed_files = 0 176 for(pfile in failed) { 177 failed_files += 1 178 printf "errors in file %s:\n%s\n", pfile, failed[pfile] 179 } 180 exit failed_files ? 1 : 0 181 } 182 183 function read_package(f, line, seen_shebang) { 184 dbgprint("reading package: "q(f)) 185 pvariant = package_variants[f] 186 seen_shebang = 0 187 pline = 0 188 while(getline line <f) { 189 pline += 1 190 if(line == "") { 191 break 192 } 193 if(pline == 1 && line ~ /^#!.*pthbs-build/) { 194 seen_shebang = 1 195 continue 196 } 197 if(line ~ /^#\+/) { 198 hash_plus(line) 199 continue 200 } 201 if(line ~ /^#@/) { 202 hash_at(line) 203 continue 204 } 205 fatal("unexpected line") 206 } 207 close(f) 208 if(pline == 0) { 209 fatal("error reading file: '"f"'") 210 } 211 if(!seen_shebang) { 212 fatal("did not encounter expected shebang line in package") 213 } 214 pline="" 215 } 216 217 function depend_git(commit_id) { 218 dbgprint_dep("git-sha1", commit_id) 219 if(commit_id in commits) { 220 commits[commit_id] += 1 221 } else { 222 #dbgprint("!!! could not resolve '"commit_id"' to repository file in "pfile) 223 record_failure("git-sha1", commit_id, "could not resolve '"commit_id"' to git repository") 224 } 225 } 226 227 function depend_file(hash_type, file_hash) { 228 dbgprint_dep(hash_type, file_hash) 229 if((hash_type":"file_hash) in linkable_hashes) { 230 dbgprint("local") 231 linkable_hashes[hash_type":"file_hash] += 1 232 } else if((hash_type":"file_hash) in downloadable_hashes) { 233 dbgprint("download") 234 downloadable_hashes[hash_type":"file_hash] += 1 235 } else { 236 #dbgprint("!!! could not resolve how to get file with "q(hash_type":"file_hash)" in") 237 record_failure(hash_type, file_hash, "could not resolve how to get file with "q(hash_type":"file_hash)) 238 } 239 } 240 241 function at_git(commit_id, dstdir){ 242 depend_git(commit_id) 243 } 244 245 function at_untar(extra_opts, hash_type, file_hash, dstdir){ 246 depend_file(hash_type, file_hash) 247 } 248 249 function at_filehash(hash_type, file_hash, dst, dstdir){ 250 depend_file(hash_type, file_hash) 251 } 252 253 function spacejoin(a, b) { 254 return (length(a) ? a " " : "") b 255 } 256 257 function spacemerge(a, b, arr, cnt, n, marr, merged) { 258 cnt = split(a, arr, " ") 259 for(n=1; n<=cnt; n++) { 260 marr[arr[n]]=1 261 } 262 cnt = split(b, arr, " ") 263 for(n=1; n<=cnt; n++) { 264 marr[arr[n]]=1 265 } 266 for(n in marr) { 267 merged = spacejoin(merged, n) 268 } 269 return merged 270 } 271 272 function hash_plus(line, dep, depfile) { 273 if(line == "#+*") { 274 # settings["sandbox"] = 0 275 } else { 276 dep = pvariant "/" substr(line, 3) 277 if(!(dep in package_names)) { 278 fatal("could not resolve '"dep"' to package file in") 279 } else { 280 dbgprint_dep("pkg", dep) 281 package_names[dep] += 1 282 depfile = package_files[dep] 283 package_deps[pfile] = spacejoin(package_deps[pfile], depfile) 284 package_rdeps[depfile] = spacejoin(package_rdeps[depfile], pfile) 285 } 286 } 287 } 288 289 function hash_at(line, a){ 290 split(line, a, ":") 291 if(a[1] == "#@git") { 292 if(match(line, "^#@git:[0-9a-f]+:") == 0) { 293 fatal("invalid syntax for @git:") 294 } 295 at_git(a[2], substr(line, RLENGTH+1)) 296 } else if(a[1] == "#@sha256") { 297 if(match(line, "^#@sha256:[0-9a-f]+:") == 0) { 298 fatal("invalid syntax for @sha256:") 299 } 300 at_filehash("sha256", a[2], substr(line, RLENGTH+1)) 301 } else if(a[1] == "#@untar") { 302 if(match(line, "^#@untar:[^:]*:sha256:[0-9a-f]+:") == 0) { 303 fatal("invalid syntax for @untar:") 304 } 305 at_untar(a[2], a[3], a[4], substr(line, RLENGTH+1)) 306 } else if(a[1] == "#@pragma") { 307 if(a[2] == "nosandbox") { 308 # settings["sandbox"] = 0 309 } else if(a[2] == "nopath") { 310 # settings["set_path"] = 0 311 } else { 312 fatal("unrecognized @pragma:") 313 } 314 } else { 315 fatal("unrecognized @command:") 316 } 317 }