github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/build/node-run.sh (about) 1 #!/usr/bin/env bash 2 3 # node-run.sh runs a command installed by NPM/Yarn. It looks for COMMAND in 4 # ./node_modules/bin, where NPM/Yarn install commands by default, then invokes 5 # it with the specified ARGS, if any. 6 # 7 # The reason for this script's existence is somewhat arcane. NodeJS strongly 8 # prefers non-blocking I/O, so if it detects that stdout or stderr is a Unix 9 # pipe, it will enable non-blocking I/O on that file descriptor [0]. The 10 # non-blocking I/O mode applies to every process that has a reference to that 11 # open file description [1]. Normally, this is not a problem: if stdout or 12 # stderr is a pipe, it is typically a single-purpose pipe created by a shell 13 # pipeline that is not shared with any other processes. In Docker, however, the 14 # stdout and stderr streams are named FIFOs, which look like anonymous pipes but 15 # are shared by all processes launched by the same shell. Launching a NodeJS 16 # process in Docker will thus make stdout and stderr non-blocking for all other 17 # processes invoked by the same shell. 18 # 19 # In CI, because we run NodeJS and `go test` in the same Docker shell, `go test` 20 # will intermittently drop output on the floor when a write fails with EAGAIN. 21 # `go-test-teamcity` interprets this missing output as an indication that the 22 # test panicked. Note that dropping output is reasonable behavior from `go 23 # test`--most programs simply cannot and should not handle non-blocking stdio 24 # streams [2]--and is arguably a bug in NodeJS [3]. 25 # 26 # As a workaround, this script pipes NodeJS's stdout and stderr through `cat`, 27 # which prevents the actual stdout and stderr streams from being infected with 28 # non-blocking I/O. 29 # 30 # TODO(benesch): see if we can propagate isatty from the true stdout and stderr 31 # so that colors, etc. are supported. 32 33 # [0]: https://nodejs.org/docs/latest-v8.x/api/process.html#process_a_note_on_process_i_o 34 # [1]: See `man 2 open` for details on the difference between a file 35 # descriptor, an open file description, and a file. 36 # [2]: https://jdebp.eu/FGA/dont-set-shared-file-descriptors-to-non-blocking-mode.html 37 # [3]: https://github.com/nodejs/node/issues/14752 38 39 set -euo pipefail 40 41 [[ "${1-}" ]] || { echo "usage: $0 [-C CWD] COMMAND [ARGS...]" >&2; exit 1; } 42 43 while getopts "C:" opt; do 44 case $opt in 45 C) cd "$OPTARG" ;; 46 \?) exit 1; 47 esac 48 done 49 shift $((OPTIND-1)) 50 51 "$@" > >(cat) 2> >(cat >&2)