pthbs

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

pthbs-build (10232B)


      1 #!/bin/sh
      2 if test -n "$pthbs_xtrace"; then set -x; fi
      3 bsh=$(sha256sum $1) || exit $?
      4 bsh=${bsh%% *}
      5 if test -z "$pthbs_workdir"; then
      6     printf '%s\n' >&2 "$0: fatal: pthbs_workdir env var undefined or empty"
      7     exit 100
      8 fi
      9 if test -z "$pthbs_versions"; then
     10     printf '%s\n' >&2 "$0: fatal: pthbs_versions env var undefined or empty"
     11     exit 100
     12 fi
     13 if test -z "$pthbs_pkgdir"; then
     14     printf '%s\n' >&2 "$0: fatal: pthbs_pkgdir env var undefined or empty"
     15     exit 100
     16 fi
     17 if test -z "$pthbs_cache"; then
     18     printf '%s\n' >&2 "$0: fatal: pthbs_cache env var undefined or empty"
     19     exit 100
     20 fi
     21 if test -z "$pthbs_source"; then
     22     printf '%s\n' >&2 "$0: fatal: pthbs_source env var undefined or empty"
     23     exit 100
     24 fi
     25 
     26 mkdir -p "$pthbs_workdir/builddir.$$" || exit $?
     27 workdir=$(realpath "$pthbs_workdir/builddir.$$")
     28 if ! test -d "$workdir"; then
     29 	printf '%s\n' "Error: could not determine workdir"
     30 	exit 1
     31 fi
     32 
     33 script=$(realpath "$1")
     34 if ! test -f "$script"; then
     35 	printf '%s\n' "Error: could not determine script path"
     36 	exit 1
     37 fi
     38 
     39 pthbs_package=${1##*/}
     40 pthbs_package=${pthbs_package%%:*}.$bsh
     41 
     42 printf "BUILDING %s => %s => %s\n" "$1" "$workdir" "$pthbs_package"
     43 
     44 eval "$(
     45     awk '
     46 BEGIN {
     47 	settings["sandbox"] = 1
     48 	settings["set_path"] = 1
     49 	FS=":"
     50 }
     51 /^#@pragma:/ {
     52 	if($2 == "nosandbox") {
     53 		settings["sandbox"] = 0
     54 	} else if($2 == "nopath") {
     55 		settings["set_path"] = 0
     56 	} else {
     57 		fatal("unrecognized @pragma:")
     58 	}
     59 }
     60 END {
     61 	print "setting_sandbox=" (settings["sandbox"]?"true":"false")
     62 	print "setting_set_path=" (settings["set_path"]?"true":"false")
     63 }
     64 ' "$1" )"
     65 
     66 if test -f "$pthbs_cache/make/package.sha256.${bsh}.env"; then
     67 	envfile="$pthbs_cache/make/package.sha256.${bsh}.env"
     68 	envhash=$(pthbs-getenvhash "$envfile") || exit $?
     69 	export pthbs_build_environment=/versions/env.$envhash
     70 	if $setting_set_path; then
     71 		if ! test -x "$pthbs_build_environment/command/pthbs-enter"; then
     72 		  printf >&2 "Error: %s does not exist!" "$pthbs_build_environment/command/pthbs-enter"
     73 		  exit 1
     74 		fi
     75 	fi
     76 fi
     77 
     78 mkdir -p "$workdir"
     79 case $(id -u) in
     80 	(0)
     81 		sandbox_mode=root
     82 		export pthbs_uid=$(id -u pthbs) || exit $?
     83 		export pthbs_gid=$(id -g pthbs) || exit $?
     84 		export pthbs_install_uid=0 || exit $?
     85 		export pthbs_install_gid=$pthbs_gid || exit $?
     86 		;;
     87 	(*)
     88 		sandbox_mode=userns
     89 		;;
     90 esac
     91 
     92 env \
     93     workdir="$workdir" \
     94     script="$script" \
     95     envdir="$pthbs_build_environment" \
     96     awk -v single_quote="'" -v sandbox_mode="$sandbox_mode" >"$workdir/pthbs-setup" '
     97 BEGIN {
     98 	settings["sandbox"] = 1
     99 	settings["set_path"] = 1
    100 	FS=":"
    101 	print "#!/bin/sh -e"
    102 	print "if test -n \"$pthbs_xtrace\"; then pthbs_xtrace=-x; set -x; fi"
    103 	print "cd "q(ENVIRON["workdir"])
    104 	if(ENVIRON["pthbs_uid"]) {
    105 		print "export pthbs_uid=" ENVIRON["pthbs_uid"]
    106 	}
    107 	if(ENVIRON["pthbs_gid"]) {
    108 		print "export pthbs_gid=" ENVIRON["pthbs_gid"]
    109 	}
    110 }
    111 
    112 function q(s) {  # quote string for sh
    113 	gsub(single_quote, single_quote "\\" single_quote single_quote, s)
    114 	return single_quote s single_quote
    115 }
    116 
    117 function dirname(s) {  # strip the last path component
    118 	sub("/[^/]*$", "", s)
    119 	return s
    120 }
    121 
    122 function basename(s) {  # strip the last path component
    123 	sub("^.*/$", "", s)
    124 	return s
    125 }
    126 
    127 function fatal(msg) {
    128 	printf "FATAL: pthbs-build: %s %s:%d: \"%s\"\n", msg, FILENAME, FNR, $0 >"/dev/stderr"
    129 	exit 1
    130 }
    131 
    132 function qlink(rel) {
    133 	return q(ENVIRON["pthbs_cache"] "/link/" rel)
    134 }
    135 
    136 function at_git(commit_id, dstdir){
    137 	print "mkdir -p "q(dstdir)
    138 	print "(cd "qlink("git-commit-sha1/"commit_id)" && git archive --format=tar "q(commit_id)" ) | tar --no-same-owner --no-same-permissions -xC "q(dstdir)
    139 }
    140 
    141 function at_untar(extra_opts, hash_type, file_hash, dstdir){
    142 	print "mkdir -p "q(dstdir)
    143 	print "tar -x "extra_opts" -C "q(dstdir)" -f "qlink("file-"hash_type"/"file_hash)
    144 }
    145 
    146 function at_filehash(hash_type, file_hash, dst,    dstdir){
    147 	if(dst ~ /\//) {
    148 		dstdir = dst
    149 		sub("/[^/]*$", "", dstdir)
    150 		print "mkdir -p "q(dstdir)
    151 	}
    152 	print "cp -Lp "qlink("file-"hash_type"/"file_hash)" "q(dst)
    153 }
    154 
    155 /^#!/ { next }
    156 /^#\+/ {
    157 	if($0 == "#+*") {
    158 		settings["sandbox"] = 0
    159 	} else if(!length(ENVIRON["envdir"])) {
    160 		fatal("dependency specified but no envfile:")
    161 	}
    162 	next
    163 }
    164 /^#@/ {
    165 	if($1 == "#@git") {
    166 		if(match($0, "^#@git:[0-9a-f]+:") == 0) {
    167 			fatal("invalid syntax for @git:")
    168 		}
    169 		at_git($2, substr($0, RLENGTH+1))
    170 	} else if($1 == "#@sha256") {
    171 		if(match($0, "^#@sha256:[0-9a-f]+:") == 0) {
    172 			fatal("invalid syntax for @sha256:")
    173 		}
    174 		at_filehash("sha256", $2, substr($0, RLENGTH+1))
    175 	} else if($1 == "#@untar") {
    176 		if(match($0, "^#@untar:[^:]*:sha256:[0-9a-f]+:") == 0) {
    177 			fatal("invalid syntax for @untar:")
    178 		}
    179 		at_untar($2, $3, $4, substr($0, RLENGTH+1))
    180 	} else if($1 == "#@pragma") {
    181 		if($2 == "nosandbox") {
    182 			settings["sandbox"] = 0
    183 		} else if($2 == "nopath") {
    184 			settings["set_path"] = 0
    185 		} else {
    186 			fatal("unrecognized @pragma:")
    187 		}
    188 	} else {
    189 		fatal("unrecognized @command:")
    190 	}
    191 	next
    192 }
    193 /^$/ {
    194 	if(settings["sandbox"]) {
    195 		if(length(ENVIRON["PTHBS_SYD"])) {
    196 			sandbox_cmd=" SYD_NO_SYSLOG=1 SYD_LOG_FD=3 3>syd.log"
    197 			sandbox_cmd=sandbox_cmd " " ENVIRON["PTHBS_SYD"] " -m sandbox/stat:off -m sandbox/exec:off"
    198 			sandbox_cmd=sandbox_cmd " -m " q("allow/read+"ENVIRON["workdir"]"/***")
    199 			sandbox_cmd=sandbox_cmd " -m " q("allow/write+"ENVIRON["workdir"]"/***")
    200 			sandbox_cmd=sandbox_cmd " -m " q("allow/read+/proc/loadavg")
    201 			sandbox_cmd=sandbox_cmd " -m " q("allow/read+/etc/passwd")
    202 			sandbox_cmd=sandbox_cmd " -m " q("allow/read+/etc/group")
    203 			sandbox_cmd=sandbox_cmd " -m " q("allow/read+/tmp/***")
    204 			sandbox_cmd=sandbox_cmd " -m " q("allow/write+/tmp/***")
    205 			sandbox_cmd=sandbox_cmd " -m " q("allow/read+/dev/***")
    206 			sandbox_cmd=sandbox_cmd " -m " q("allow/write+/dev/***")
    207 			sandbox_cmd=sandbox_cmd " -m " q("allow/read+"ENVIRON["script"])
    208 			sandbox_cmd=sandbox_cmd " -m " q("allow/read+"dirname(ENVIRON["envdir"])"/***")
    209 			sandbox_cmd=sandbox_cmd " -munshare/user:1"
    210 			sandbox_cmd=sandbox_cmd " -munshare/mount:1"
    211 			sandbox_cmd=sandbox_cmd " -mbind+" q(ENVIRON["pthbs_workdir"]"/bin:/bin:ro,nosuid,nodev")
    212 			sandbox_cmd=sandbox_cmd " -m " q("allow/read+/bin/***")
    213 			sandbox_cmd=sandbox_cmd " -munshare/net:1 -munshare/ipc:1"
    214 		} else if(sandbox_mode == "userns") {
    215 			sandbox_cmd=" "q(ENVIRON["pthbs_source"]"/sandbox/ns_sandbox.py")" --mode=userns"
    216 			sandbox_cmd=sandbox_cmd" --versions="q(ENVIRON["pthbs_versions"])
    217 			sandbox_cmd=sandbox_cmd" --extra-mount=tmpfs:"q(ENVIRON["pthbs_workdir"])
    218 			sandbox_cmd=sandbox_cmd" --extra-mount=ro_bind:"q(ENVIRON["pthbs_pkgdir"]":"ENVIRON["pthbs_pkgdir"])
    219 			sandbox_cmd=sandbox_cmd" --extra-mount=rw_bind:"q(ENVIRON["workdir"]":"ENVIRON["workdir"])
    220 			sandbox_cmd=sandbox_cmd" --extra-mount=rw_bind:"q(ENVIRON["workdir"]"/.tmp:/tmp")
    221 			sandbox_cmd=sandbox_cmd" -- "q(ENVIRON["pthbs_workdir"]"/root")
    222 			printf "%s\n", "mkdir -p "q(ENVIRON["workdir"]"/.tmp")" "q(ENVIRON["pthbs_workdir"]"/root")
    223 		} else if(sandbox_mode == "root") {
    224 			sandbox_cmd=" "q(ENVIRON["pthbs_cache"]"/venv/bin/python")" "q(ENVIRON["pthbs_source"]"/sandbox/ns_sandbox.py")" --mode=root"
    225 			sandbox_cmd=sandbox_cmd" --versions="q(ENVIRON["pthbs_versions"])
    226 			sandbox_cmd=sandbox_cmd" --untar="q(ENVIRON["pthbs_source"]"/sandbox/root.tar")
    227 			sandbox_cmd=sandbox_cmd" --chdir="q(ENVIRON["workdir"])
    228 			sandbox_cmd=sandbox_cmd" --extra-mount=tmpfs:"q(ENVIRON["pthbs_workdir"])
    229 			sandbox_cmd=sandbox_cmd" --extra-mount=ro_bind:"q(ENVIRON["pthbs_pkgdir"]":"ENVIRON["pthbs_pkgdir"])
    230 			sandbox_cmd=sandbox_cmd" --extra-mount=rw_bind:"q(ENVIRON["workdir"]":"ENVIRON["workdir"])
    231 			sandbox_cmd=sandbox_cmd" --extra-mount=rw_bind:"q(ENVIRON["workdir"]"/.tmp:/tmp")
    232 			sandbox_cmd=sandbox_cmd" -- "q(ENVIRON["pthbs_workdir"]"/root")
    233 			printf "%s\n", "mkdir -p "q(ENVIRON["workdir"]"/.tmp")" "q(ENVIRON["pthbs_workdir"]"/root")
    234 		} else {
    235 			fatal("unrecognized sanbox_mode " sandbox_mode)
    236 		}
    237 	} else if(ENVIRON["pthbs_uid"]){
    238 		sandbox_cmd="busybox chpst -u \"$pthbs_uid:$pthbs_gid\" --"
    239 	} else {
    240 		sandbox_cmd=""
    241 	}
    242 	if(ENVIRON["pthbs_uid"]) {
    243 		printf "%s\n", "chown -R \"$pthbs_uid:$pthbs_gid\"  "q(ENVIRON["workdir"])
    244 	}
    245 	if(length(ENVIRON["envdir"])){
    246 		cmd="env pthbs_build_environment="q(ENVIRON["envdir"])
    247 		cmd=cmd" "sandbox_cmd
    248 		if(settings["set_path"]) {
    249 			cmd=cmd" "q(ENVIRON["envdir"]"/command/pthbs-enter")
    250 		}
    251 		cmd=cmd" sh -xe "q(ENVIRON["script"])
    252 	} else {
    253 		cmd=sandbox_cmd" sh -xe "q(ENVIRON["script"])
    254 	}
    255 	print "exec >build.log 2>&1 " cmd
    256 	exit 0
    257 }
    258 {
    259 	fatal("unexpected line")
    260 }
    261 ' "$1" || exit $?
    262 
    263 if test -z "$JOBS"; then
    264 	JOBS=$(nproc)
    265 	if test -z "$JOBS"; then
    266 		JOBS=$(grep -ce '^processor' /proc/cpuinfo)
    267 		if test -z "$JOBS"; then
    268 			JOBS=1
    269 		fi
    270 	fi
    271 fi
    272 
    273 logdir=$pthbs_workdir/logs/$(date '+%Y-%m-%d-%H%M%S')-$pthbs_package
    274 ret=0
    275 if test -n "$pthbs_xtrace"; then pthbs_xtrace=-x; set -x; fi
    276 trap 'trap - INT' INT
    277 if env -i \
    278    PATH="$PATH" \
    279    JOBS="$JOBS" \
    280    pthbs_script="$script" \
    281    pthbs_destdir="$workdir/destdir" \
    282    pthbs_package="$pthbs_package" \
    283    sh $pthbs_xtrace -e "$workdir/pthbs-setup" </dev/null; then
    284 	trap - INT
    285 	printf "BUILD SUCCESFUL :: %s\n" "$pthbs_package"
    286 	if ! pthbs-install "$workdir/destdir" "$pthbs_package"; then
    287 		ret=1
    288 		echo "INSTALL FAILED"
    289 	fi
    290 else
    291 	ret=$?
    292 	trap - INT
    293 	if test -n "$pthbs_fail_log_cmd"; then
    294 		$pthbs_fail_log_cmd "$workdir/build.log"
    295 	else
    296 		printf "Errors found in log:\n"
    297 		grep -C 1 -Eie '(error|fatal)[: ]' "$workdir/build.log"
    298 	fi
    299 	printf "BUILD FAILED: exitcode %s :: %s :: %s :: %s\n" "$ret" "$1" "$workdir" "$logdir"
    300 	mkdir -p "$logdir"
    301 	rm -v "$(dirname "$logdir")/last_failed_build"
    302 	ln -v -s -f "$(basename "$logdir")" "$(dirname "$logdir")/last_failed_build"
    303 	find "$workdir" -name config.log -exec cp -v --backup=numbered '{}' "$logdir/config.log" \;
    304 	pthbs-digest-tree >"$logdir/workdir-digest" "$workdir"
    305 fi
    306 
    307 mkdir -p "$logdir"
    308 
    309 if test -e "$workdir/build.log"; then
    310 	mv "$workdir/build.log" "$logdir/log"
    311 	bzip2 "$logdir/log"
    312 fi
    313 
    314 if test -e "$workdir/syd.log"; then
    315 	mv "$workdir/syd.log" "$logdir/syd.log"
    316 	bzip2 "$logdir/syd.log"
    317 fi
    318 
    319 if test -e "$workdir/pthbs-setup"; then
    320 	mv "$workdir/pthbs-setup" "$logdir/"
    321 fi
    322 
    323 if test -n "$pthbs_build_environment"; then
    324 	ln -s "$pthbs_build_environment" "$logdir/env"
    325 fi
    326 
    327 if test -z "$pthbs_skip_cleanup"; then
    328 	rm -rf "$workdir" || ret=$?
    329 fi
    330 exit $ret