my xfce4 dotfiles
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
11 KiB

3 years ago
  1. #!/usr/bin/env zsh
  2. #
  3. # This script does not have a stable API.
  4. #
  5. # Usage: mbuild [-b git-ref] [kernel-arch]...
  6. #
  7. # Builds a bunch of gitstatusd-* binaries. Without arguments builds binaries
  8. # for all platforms. git-ref defaults to master.
  9. #
  10. # Before using this script you need to set up build servers and list them
  11. # in ~/.ssh/config. There should be a Host entry for every value of `assets`
  12. # association defined below. VMs and cloud instances work as well as physical
  13. # machines, including localhost. As long as the machine has been set up as
  14. # described below and you can SSH to it without password, it should work.
  15. #
  16. # ===[ Build Server Setup ]===
  17. #
  18. # Linux
  19. #
  20. # - Install docker.
  21. # $ apt install docker.io # adjust appropriately if there is no `apt`
  22. # $ usermod -aG docker $USER # not needed if going to build as root
  23. # - Install git.
  24. # $ apt install git # adjust appropriately if there is no `apt`
  25. #
  26. # macOS
  27. #
  28. # - Install compiler tools:
  29. # $ xcode-select --install
  30. # - Install homebrew: https://brew.sh/.
  31. # $ bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
  32. #
  33. # FreeBSD
  34. #
  35. # - Install git.
  36. # $ pkg install git
  37. #
  38. # Windows
  39. #
  40. # - Disable Windows Defender (optional).
  41. # ps> Set-MpPreference -DisableRealtimeMonitoring $true
  42. # - Install 64-bit and 32-bit msys2: https://www.msys2.org/wiki/MSYS2-installation/.
  43. # - Open each of them after installation, type `pacman -Syu --noconfirm` and close the window.
  44. # - Then run in powershell while having no msys2 or cygwin windows open:
  45. # ps> C:\msys32\autorebase.bat
  46. # ps> C:\msys64\autorebase.bat
  47. # - Install 64-bit and 32-bit cygwin: https://cygwin.com/install.html.
  48. # - Choose to install 32-bit to c:/cygwin32 instead of the default c:/cygwin.
  49. # - Select these packages: binutils, cmake, gcc-core, gcc-g++, git, make, perl, wget.
  50. #
  51. # IMPORTANT: Install msys2 and cygwin one at a time.
  52. #
  53. # IMPORTANT: msys2 builder can reboot the build machine.
  54. #
  55. # Option 1: OpenSSH for Windows
  56. #
  57. # - Install OpenSSH: https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse.
  58. # ps> Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
  59. # ps> Start-Service sshd
  60. # ps> Set-Service -Name sshd -StartupType 'Automatic'
  61. # - Enable publickey authentication: https://stackoverflow.com/a/50502015/1095235.
  62. # ps> cd $env:USERPROFILE
  63. # ps> mkdir .ssh
  64. # ps> notepad.exe .ssh/authorized_keys
  65. # - Paste your public key, save, close.
  66. # ps> icacls .ssh/authorized_keys /inheritance:r
  67. # ps> notepad.exe C:\ProgramData\ssh\sshd_config
  68. # - Comment out these two lines, save, close:
  69. # # Match Group administrators
  70. # # AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
  71. # ps> Restart-Service sshd
  72. #
  73. # Option 2: OpenSSH from WSL
  74. #
  75. # - Install WSL.
  76. # - Install Ubuntu.
  77. # - Install sshd.
  78. # $ apt install openssh-server
  79. # $ dpkg-reconfigure openssh-server
  80. # $ cat >/etc/ssh/sshd_config <<\END
  81. # ClientAliveInterval 60
  82. # AcceptEnv TERM LANG LC_*
  83. # PermitRootLogin no
  84. # AllowTcpForwarding no
  85. # AllowAgentForwarding no
  86. # AllowStreamLocalForwarding no
  87. # AuthenticationMethods publickey
  88. # END
  89. # service ssh --full-restart
  90. # - Add your public ssh key to ~/.ssh/authorized_keys.
  91. # - Make `sshd` start when Windows boots.
  92. 'emulate' '-L' 'zsh' '-o' 'no_aliases' '-o' 'err_return'
  93. setopt no_unset extended_glob pipe_fail prompt_percent typeset_silent \
  94. no_prompt_subst no_prompt_bang pushd_silent warn_create_global
  95. autoload -Uz is-at-least
  96. if ! is-at-least 5.1 || [[ $ZSH_VERSION == 5.4.* ]]; then
  97. print -ru2 -- "[error] unsupported zsh version: $ZSH_VERSION"
  98. return 1
  99. fi
  100. zmodload zsh/system
  101. local -r git_url='https://github.com/romkatv/gitstatus.git'
  102. local -rA assets=(
  103. # target kernel-arch hostname of the build machine
  104. cygwin_nt-10.0-i686 build-windows-x86_64
  105. cygwin_nt-10.0-x86_64 build-windows-x86_64
  106. msys_nt-10.0-i686 build-windows-x86_64
  107. msys_nt-10.0-x86_64 build-windows-x86_64
  108. darwin-arm64 build-macos-arm64
  109. darwin-x86_64 build-macos-x86_64
  110. freebsd-amd64 build-freebsd-amd64
  111. linux-aarch64 build-linux-aarch64
  112. linux-armv6l build-linux-armv7l
  113. linux-armv7l build-linux-armv7l
  114. linux-i686 build-linux-x86_64
  115. linux-ppc64le build-linux-ppc64le
  116. linux-x86_64 build-linux-x86_64
  117. )
  118. local -rA protocol=(
  119. 'cygwin_nt-10.0-*' windows
  120. 'msys_nt-10.0-*' windows
  121. 'darwin-*' unix
  122. 'freebsd-*' unix
  123. 'linux-*' unix
  124. )
  125. local -r rootdir=${ZSH_SCRIPT:h}
  126. local -r logs=$rootdir/logs
  127. local -r locks=$rootdir/locks
  128. local -r binaries=$rootdir/usrbin
  129. function usage() {
  130. print -r -- 'usage: mbuild [-b REF] [KERNEL-ARCH]...'
  131. }
  132. local OPTARG opt git_ref=master
  133. local -i OPTIND
  134. while getopts ":b:h" opt; do
  135. case $opt in
  136. h) usage; return 0;;
  137. b) [[ -n $OPTARG ]]; git_ref=$OPTARG;;
  138. \?) print -ru2 -- "mbuild: invalid option: -$OPTARG" ; return 1;;
  139. :) print -ru2 -- "mbuild: missing required argument: -$OPTARG"; return 1;;
  140. *) print -ru2 -- "mbuild: invalid option: -$opt" ; return 1;;
  141. esac
  142. done
  143. shift $((OPTIND - 1))
  144. (( $# )) || set -- ${(ko)assets}
  145. set -- ${(u)@}
  146. local platform
  147. for platform; do
  148. if (( ! $+assets[$platform] )); then
  149. print -ru2 -- "mbuild: invalid platform: $platform"
  150. return 1
  151. fi
  152. done
  153. local build='
  154. rm -rf gitstatus
  155. git clone --recursive --shallow-submodules --depth=1 -b '$git_ref' '$git_url'
  156. cd gitstatus
  157. if command -v zsh >/dev/null 2>&1; then
  158. sh=zsh
  159. elif command -v dash >/dev/null 2>&1; then
  160. sh=dash
  161. elif command -v ash >/dev/null 2>&1; then
  162. sh=ash
  163. else
  164. sh=sh
  165. fi
  166. $sh -x ./build -m '
  167. function build-unix() {
  168. local intro flags=(-sw)
  169. case $2 in
  170. linux-ppc64le) ;;
  171. linux-*) flags+=(-d docker);;
  172. darwin-arm64) intro='PATH="/opt/local/bin:$PATH"';;
  173. darwin-*) intro='PATH="/usr/local/bin:$PATH"';;
  174. esac
  175. ssh $1 -- /bin/sh -uex <<<"
  176. $intro
  177. cd /tmp
  178. $build ${2##*-} ${(j: :)${(@q)flags}}"
  179. scp $1:/tmp/gitstatus/usrbin/gitstatusd $binaries/gitstatusd-$2
  180. }
  181. function build-windows() {
  182. local shell=$(ssh $1 'echo $0')
  183. if [[ $shell == '$0'* ]]; then
  184. local c='c:'
  185. else
  186. local c='/mnt/c'
  187. fi
  188. local tmp env bin intro flags=(-w)
  189. case $2 in
  190. cygwin_nt-10.0-i686) bin='cygwin32/bin' ;|
  191. cygwin_nt-10.0-x86_64) bin='cygwin64/bin' ;|
  192. msys_nt-10.0-i686) bin='msys32/usr/bin';|
  193. msys_nt-10.0-x86_64) bin='msys64/usr/bin';|
  194. cygwin_nt-10.0-*)
  195. tmp='/cygdrive/c/tmp'
  196. ;|
  197. msys_nt-10.0-*)
  198. tmp='/c/tmp'
  199. env='MSYSTEM=MSYS'
  200. # TODO: fix this (some errors about PGP keys).
  201. # flags+=(-s)
  202. # intro='pacman -S --needed --noconfirm git; '
  203. intro+='PATH="$PATH:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl"'
  204. while true; do
  205. # TODO: run autorebase only when getting an error that can be fixed by autorebasing.
  206. break
  207. local out
  208. out="$(ssh $1 cmd.exe "$c/${bin%%/*}/autorebase.bat" 2>&1)"
  209. [[ $out == *"The following DLLs couldn't be rebased"* ]] || break
  210. # Reboot to get rid of whatever is using those DLLs.
  211. ssh $1 powershell.exe <<<'Restart-Computer -Force' || true
  212. sleep 30
  213. while ! ssh $1 <<<''; do sleep 5; done
  214. done
  215. () {
  216. while true; do
  217. # TODO: fix this (some errors about PGP keys).
  218. break
  219. local -i fd
  220. exec {fd}< <(
  221. ssh $1 $c/$bin/env.exe $env c:/$bin/bash.exe -l 2>&1 <<<"
  222. pacman -Syu --noconfirm
  223. exit")
  224. {
  225. local line
  226. while true; do
  227. IFS= read -u $fd -r line || return 0
  228. if [[ $line == *"warning: terminate MSYS2"* ]]; then
  229. # At this point the machine is hosed. A rogue process with a corrupted name
  230. # is eating all CPU. The top SSH connection won't terminate on its own.
  231. ssh $1 powershell.exe <<<'Restart-Computer -Force' || true
  232. sleep 30
  233. while ! ssh $1 <<<''; do sleep 5; done
  234. break
  235. fi
  236. done
  237. } always {
  238. exec {fd}<&-
  239. kill -- -$sysparams[procsubstpid] 2>/dev/null || true
  240. }
  241. done
  242. } "$@"
  243. ;|
  244. esac
  245. ssh $1 $c/$bin/env.exe $env c:/$bin/bash.exe -l <<<"
  246. set -uex
  247. $intro
  248. mkdir -p -- $tmp
  249. cd -- $tmp
  250. $build ${2##*-} ${(j: :)${(@q)flags}}
  251. exit"
  252. scp $1:$c/tmp/gitstatus/usrbin/gitstatusd $binaries/gitstatusd-$2
  253. chmod +x $binaries/gitstatusd-$2
  254. }
  255. function build() (
  256. setopt xtrace
  257. local platform=$1
  258. local machine=$assets[$platform]
  259. print -n >>$locks/$machine
  260. zsystem flock $locks/$machine
  261. build-${protocol[(k)$platform]} $machine $platform
  262. local tmp=gitstatusd-$platform.tmp.$$.tar.gz
  263. ( cd -q -- $binaries; tar --owner=0 --group=0 -I 'gzip -9' -cf $tmp gitstatusd-$platform )
  264. mv -f -- $binaries/$tmp $binaries/gitstatusd-$platform.tar.gz
  265. )
  266. function mbuild() {
  267. local platform pid pids=()
  268. for platform; do
  269. build $platform &>$logs/$platform &
  270. print -r -- "starting build for $platform on $assets[$platform] (pid $!)"
  271. pids+=($platform $!)
  272. done
  273. local failed=()
  274. for platform pid in $pids; do
  275. print -rn -- "$platform => "
  276. if wait $pid; then
  277. print -r -- "ok"
  278. else
  279. print -r -- "error"
  280. failed+=$platform
  281. fi
  282. done
  283. (( $#failed )) || return 0
  284. print
  285. print -r -- "Error logs:"
  286. print
  287. for platform in $failed; do
  288. print -r -- " $platform => $logs/$platform"
  289. done
  290. return 1
  291. }
  292. # Copied from https://github.com/romkatv/run-process-tree.
  293. function run-process-tree() {
  294. zmodload zsh/parameter zsh/param/private || return
  295. local -P opt=(${(kv)options[@]}) || return
  296. local -P pat=(${patchars[@]}) || return
  297. local -P dis_pat=(${dis_patchars[@]}) || return
  298. emulate -L zsh -o err_return || return
  299. setopt monitor traps_async pipe_fail no_unset
  300. zmodload zsh/system
  301. if (( $# == 0 )); then
  302. print -ru2 -- 'usage: run-process-tree command [arg]...'
  303. return 1
  304. fi
  305. local -P stdout REPLY
  306. exec {stdout}>&1
  307. {
  308. {
  309. local -Pi pipe
  310. local -P gid=$sysparams[pid]
  311. local -P sig=(ABRT EXIT HUP ILL INT PIPE QUIT TERM ZERR)
  312. local -P trap=(trap "trap - $sig; kill -- -$sysparams[pid]" $sig)
  313. exec {pipe}>&1 1>&$stdout
  314. $trap
  315. {
  316. $trap
  317. while sleep 1 && print -u $pipe .; do; done
  318. } 2>/dev/null &
  319. local -Pi watchdog=$!
  320. {
  321. trap - ZERR
  322. exec {pipe}>&-
  323. enable -p -- $pat
  324. disable -p -- $dis_pat
  325. options=($opt zle off monitor off)
  326. "$@"
  327. } &
  328. local -Pi ret
  329. wait $! || ret=$?
  330. trap "exit $ret" TERM
  331. kill $watchdog
  332. wait $watchdog
  333. return ret
  334. } | while read; do; done || return
  335. } always {
  336. exec {stdout}>&-
  337. }
  338. }
  339. mkdir -p -- $logs $locks $binaries
  340. run-process-tree mbuild $@