pthbs

Packaging Through Hashed Build Scripts
git clone https://ccx.te2000.cz/git/pthbs
Log | Files | Refs | Submodules | README

_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 }