diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/etc/poudriere.conf.sample | 26 | ||||
-rw-r--r-- | src/poudriere-sh/mapfile.c | 6 | ||||
-rwxr-xr-x | src/share/poudriere/common.sh | 235 | ||||
-rw-r--r-- | src/share/poudriere/image_zfs.sh | 2 | ||||
-rw-r--r-- | src/share/poudriere/include/colors.pre.sh | 58 | ||||
-rw-r--r-- | src/share/poudriere/include/display.sh | 37 | ||||
-rw-r--r-- | src/share/poudriere/include/fs.sh | 1 | ||||
-rw-r--r-- | src/share/poudriere/include/pkgqueue.sh | 2 | ||||
-rw-r--r-- | src/share/poudriere/include/util.sh | 31 | ||||
-rwxr-xr-x | src/share/poudriere/jail.sh | 4 | ||||
-rwxr-xr-x | src/share/poudriere/ports.sh | 4 | ||||
-rwxr-xr-x | src/share/poudriere/status.sh | 2 |
12 files changed, 313 insertions, 95 deletions
diff --git a/src/etc/poudriere.conf.sample b/src/etc/poudriere.conf.sample index 71b5b897..ccba4989 100644 --- a/src/etc/poudriere.conf.sample +++ b/src/etc/poudriere.conf.sample @@ -62,6 +62,15 @@ USE_TMPFS=yes # (default: none) #TMPFS_LIMIT=8 +# List of package globs that are not allowed to use tmpfs for their WRKDIR +# Note that you *must* set TMPFS_BLACKLIST_TMPDIR +# EXAMPLE: TMPFS_BLACKLIST="rust" + +# The host path where tmpfs-blacklisted packages can be built in. +# A temporary directory will be generated here and be null-mounted as the +# WRKDIR for any packages listed in TMPFS_BLACKLIST. +# EXAMPLE: TMPFS_BLACKLIST_TMPDIR=${BASEFS}/data/cache/tmp + # How much memory to limit jail processes to for *each builder* # in GiB (default: none) #MAX_MEMORY=8 @@ -223,12 +232,6 @@ DISTFILES_CACHE=/usr/ports/distfiles # Default: no #TIMESTAMP_LOGS=no -# URL where your POUDRIERE_DATA/logs are hosted -# This will be used for giving URL hints to the HTML output when -# scheduling and starting builds -#URL_BASE=http://yourdomain.com/poudriere/ - - # This defines the max time (in seconds) that a command may run for a build # before it is killed for taking too long. Default: 86400 #MAX_EXECUTION_TIME=86400 @@ -237,7 +240,6 @@ DISTFILES_CACHE=/usr/ports/distfiles # be in a runaway state for having no output on stdout. Default: 7200 #NOHANG_TIME=7200 - # The repository is updated atomically if set yes. This leaves the # repository untouched until the build completes. This involves using # hardlinks and symlinks. The operations are fast, but can be intrusive @@ -338,6 +340,11 @@ DISTFILES_CACHE=/usr/ports/distfiles # Default: none #LOCAL_MTREE_EXCLUDES="/usr/obj /var/tmp/ccache" +# URL where your POUDRIERE_DATA/logs are hosted +# This will be used for giving URL hints to the HTML output when +# scheduling and starting builds +#URL_BASE=http://yourdomain.com/poudriere/ + # Set to hosted to use the /data directory instead of inline style HTML # Default: inline #HTML_TYPE="hosted" @@ -347,6 +354,11 @@ DISTFILES_CACHE=/usr/ports/distfiles # Default: no #HTML_TRACK_REMAINING=yes +# Grep build logs to determine a possible build failure reason. This is +# only shown on the web interface. +# Default: yes +#DETERMINE_BUILD_FAILURE_REASON=yes + # Set to pass arguments to buildworld. # Default: #MAKEWORLDARGS="WITHOUT_LLVM_ASSERTIONS=yes WITH_MALLOC_PRODUCTION=yes -DMALLOC_PRODUCTION" diff --git a/src/poudriere-sh/mapfile.c b/src/poudriere-sh/mapfile.c index 33cd358a..fe14009d 100644 --- a/src/poudriere-sh/mapfile.c +++ b/src/poudriere-sh/mapfile.c @@ -543,8 +543,12 @@ mapfile_writecmd(int argc, char **argv) * XXX: Using shell mapfile_cat until some changes from * copool branch make it in to avoid massive conflicts */ - const char *cmd = "__mapfile_write_cat=$(mapfile_cat)"; + /* Avoid adding our own newline by keeping any read. */ + const char *cmd = + "__mapfile_write_cat=\"$(mapfile_cat; echo .)\";" + "__mapfile_write_cat=\"${__mapfile_write_cat%.}\""; + nflag = 1; evalstring(cmd, 0); if (exitstatus != 0) { ret = exitstatus; diff --git a/src/share/poudriere/common.sh b/src/share/poudriere/common.sh index de70e425..af13d175 100755 --- a/src/share/poudriere/common.sh +++ b/src/share/poudriere/common.sh @@ -28,6 +28,8 @@ BSDPLATFORM=`uname -s | tr '[:upper:]' '[:lower:]'` . ${SCRIPTPREFIX}/include/common.sh.${BSDPLATFORM} +. ${SCRIPTPREFIX}/include/hash.sh +. ${SCRIPTPREFIX}/include/util.sh EX_USAGE=64 EX_DATAERR=65 EX_SOFTWARE=70 @@ -112,7 +114,8 @@ _err() { if [ ${ERRORS_ARE_FATAL:-1} -eq 1 ]; then if was_a_bulk_run && [ -n "${POUDRIERE_BUILD_TYPE-}" ] && - [ "${PARALLEL_CHILD:-0}" -eq 0 ]; then + [ "${PARALLEL_CHILD:-0}" -eq 0 ] && + [ "$(getpid)" = "$$" ]; then show_build_summary >&2 show_log_info >&2 fi @@ -145,11 +148,14 @@ _msg_n() { unset elapsed arrow="=>>" fi - if [ -n "${COLOR_ARROW-}" ] || [ -z "${1##*\033[*}" ]; then - printf "${COLOR_ARROW}${elapsed}${DRY_MODE-}${arrow:+${COLOR_ARROW}${arrow} }${COLOR_RESET}%b${COLOR_RESET}${NL}" "$*" - else - printf "${elapsed}${DRY_MODE-}${arrow:+${arrow} }%b${NL}" "$*" - fi + case "${COLOR_ARROW-}${1}" in + *$'\033'"["*) + printf "${COLOR_ARROW}${elapsed}${DRY_MODE-}${arrow:+${COLOR_ARROW}${arrow} }${COLOR_RESET}%s${COLOR_RESET}${NL}" "$*" + ;; + *) + printf "${elapsed}${DRY_MODE-}${arrow:+${arrow} }%s${NL}" "$*" + ;; + esac } msg_n() { @@ -1374,7 +1380,7 @@ log_url() { show_log_info() { local log build_url - if ! was_a_bulk_run; then + if ! was_a_bulk_run && ! [ "${SCRIPTNAME}" = "status.sh" ]; then return 0 fi _log_path log @@ -1483,7 +1489,8 @@ siginfo_handler() { local now local j elapsed elapsed_phase job_id_color local pkgname origin phase buildtime buildtime_phase started - local started_phase format_origin_phase format_phase + local started_phase format_origin_phase format_phase sep + local tmpfs cpu mem local - set +e @@ -1502,14 +1509,75 @@ siginfo_handler() { return 0 fi - show_build_summary + show_build_summary >&2 now=$(clock -monotonic) + # Some of the \b and empty field hacks here are for adding [] in + # the output but not the header for historical and consistency + # reasons. + format_origin_phase="%%c \b%%s \b%%-%ds${COLOR_RESET} \b%%c %%-%ds ${COLOR_PORT}%%%ds %%c %%-%ds${COLOR_RESET} ${COLOR_PHASE}%%%ds${COLOR_RESET} %%-%ds %%-%ds %%%ds %%%ds" + display_setup "${format_origin_phase}" + display_add " " "" "ID" " " "TOTAL" "ORIGIN" " " "PKGNAME" "PHASE" \ + "PHASE" "TMPFS" "CPU%" "MEM%" + # Skip if stopping or starting jobs or stopped. if [ -n "${JOBS}" -a "${status#starting_jobs:}" = "${status}" \ -a "${status}" != "stopping_jobs:" -a -n "${MASTERMNT}" ] && \ ! status_is_stopped "${status}"; then + while mapfile_read_loop_redir j cpu mem; do + j="${j#*-job-}" + hash_set siginfo_cpu "${j}" "${cpu}" + hash_set siginfo_mem "${j}" "${mem}" + done <<-EOF + $(ps -ax -o jail,%cpu,%mem | + awk -v MASTERNAME="${MASTERNAME}" '\ + $1 ~ "^" MASTERNAME "(-job-[0-9]+)?(-n)?$" \ + { \ + gsub(/-n$/, "", $1); \ + cpu[$1] += $2; \ + mem[$1] += $3; \ + } \ + END { \ + for (jail in cpu) { \ + print jail, cpu[jail], mem[jail]; \ + } \ + } \ + ') + EOF + while mapfile_read_loop_redir j tmpfs; do + hash_set siginfo_tmpfs "${j}" "${tmpfs}" + done <<-EOF + $(env BLOCKSIZE=512 df -t tmpfs | \ + awk -v MASTERMNTROOT="${MASTERMNTROOT}" ' \ + function humanize(number) { \ + hum[1024**4]="TiB"; \ + hum[1024**3]="GiB"; \ + hum[1024**2]="MiB"; \ + hum[1024]="KiB"; \ + hum[0]="B"; \ + for (x=1024**4; x>=1024; x/=1024) { \ + if (number >= x) { \ + printf "%.2f %s", number/x, hum[x]; \ + return; \ + } \ + } \ + } \ + $6 ~ "^" MASTERMNTROOT "/" { \ + sub(MASTERMNTROOT "/", "", $6); \ + slash = match($6, "/"); \ + if (RLENGTH == -1) \ + id = substr($6, 0); \ + else \ + id = substr($6, 0, slash-1); \ + totals[id] += $3; \ + } \ + END { \ + for (id in totals) { \ + print id, humanize(totals[id]*512); \ + } \ + }') + EOF for j in ${JOBS}; do # Ignore error here as the zfs dataset may not be cloned yet. _bget status ${j} status || : @@ -1518,9 +1586,9 @@ siginfo_handler() { continue fi # Hide idle workers - if [ "${status}" = "idle:" ]; then - continue - fi + case "${status}" in + idle:|done:) continue ;; + esac phase="${status%%:*}" status="${status#*:}" origin="${status%%:*}" @@ -1533,25 +1601,37 @@ siginfo_handler() { colorize_job_id job_id_color "${j}" - # Must put colors in format - format_origin_phase="\t[${job_id_color}%s${COLOR_RESET}]: ${COLOR_PORT}%-25s | %-25s ${COLOR_PHASE}%-15s${COLOR_RESET} (%s / %s)\n" - format_phase="\t[${job_id_color}%s${COLOR_RESET}]: %53s ${COLOR_PHASE}%-15s${COLOR_RESET}\n" if [ -n "${pkgname}" ]; then elapsed=$((now - started)) calculate_duration buildtime "${elapsed}" elapsed_phase=$((now - started_phase)) calculate_duration buildtime_phase \ "${elapsed_phase}" - printf "${format_origin_phase}" "${j}" \ - "${origin}" "${pkgname}" "${phase}" \ - "${buildtime_phase}" "${buildtime}" + sep="|" + hash_remove siginfo_cpu "${j}" cpu || cpu= + hash_remove siginfo_mem "${j}" mem || mem= + hash_remove siginfo_tmpfs "${j}" tmpfs || tmpfs= else - printf "${format_phase}" "${j}" '' "${phase}" + buildtime= + buildtime_phase= + sep= + tmpfs= + cpu= + mem= fi + display_add \ + "[" "${job_id_color}" "${j}" "]" \ + "${buildtime-}" \ + "${origin-}" "${sep:- }" "${pkgname-}" "${phase-}" \ + "${buildtime_phase-}" \ + "${tmpfs}" \ + "${cpu:+${cpu}%}" \ + "${mem:+${mem}%}" done fi + display_output >&2 - show_log_info + show_log_info >&2 enable_siginfo_handler } @@ -1863,11 +1943,13 @@ cd() { local ret ret=0 + critical_start command cd "$@" || ret=$? # Handle fixing relative paths if [ "${OLDPWD}" != "${PWD}" ]; then _update_relpaths "${OLDPWD}" "${PWD}" || : fi + critical_end return ${ret} } @@ -4528,11 +4610,16 @@ start_builder() { local jname="$2" local ptname="$3" local setname="$4" - local mnt MY_JOBID + local mnt MY_JOBID NO_ELAPSED_IN_MSG TIME_START_JOB COLOR_JOBID MY_JOBID=${id} _my_path mnt + NO_ELAPSED_IN_MSG=1 + TIME_START_JOB=$(clock -monotonic) + colorize_job_id COLOR_JOBID "${MY_JOBID}" + job_msg "Builder starting" + # Jail might be lingering from previous build. Already recursively # destroyed all the builder datasets, so just try stopping the jail # and ignore any errors @@ -4544,7 +4631,26 @@ start_builder() { do_portbuild_mounts "${mnt}" "${jname}" "${ptname}" "${setname}" jstart bset ${id} status "idle:" + shash_set builder_active "${id}" 1 run_hook builder start "${id}" "${mnt}" + + job_msg "Builder started" +} + +maybe_start_builder() { + [ $# -ge 5 ] || eargs maybe_start_builder MY_JOBID jname ptname \ + setname cmd [args] + local jobid="$1" + local jname="$2" + local ptname="$3" + local setname="$4" + shift 4 + + if ! shash_exists builder_active "${jobid}"; then + start_builder "${jobid}" "${jname}" "${ptname}" \ + "${setname}" || return "$?" + fi + "$@" } start_builders() { @@ -4579,6 +4685,7 @@ stop_builder() { run_hook builder stop "${jobid}" "${mnt}" jstop destroyfs "${mnt}" jail + shash_unset builder_active "${jobid}" } stop_builders() { @@ -4586,9 +4693,11 @@ stop_builders() { # wait for the last running processes # the pidfiles may not contain an EOF newline so awk fixes that - find "${MASTER_DATADIR}/var/run/" -name "*.pid" -exec \ - awk '{print}' {} + | - xargs pwait -t 20 2>/dev/null || : + if [ -n "${MASTER_DATADIR}" ]; then + find "${MASTER_DATADIR}/var/run/" -name "*.pid" -exec \ + awk '{print}' {} + | + xargs pwait -t 20 2>/dev/null || : + fi if [ ${PARALLEL_JOBS} -ne 0 ]; then msg "Stopping ${PARALLEL_JOBS} builders" @@ -4603,6 +4712,16 @@ stop_builders() { parallel_run stop_builder "${j}" done parallel_stop + + if [ -n "${TMPFS_BLACKLIST_TMPDIR-}" ] && + [ -d "${TMPFS_BLACKLIST_TMPDIR}/wrkdirs" ]; then + if ! rm -rf "${TMPFS_BLACKLIST_TMPDIR}/wrkdirs/"*; then + chflags -R 0 \ + "${TMPFS_BLACKLIST_TMPDIR}/wkrdirs"/* || : + rm -rf "${TMPFS_BLACKLIST_TMPDIR}/wrkdirs"/* || + : + fi + fi fi # No builders running, unset JOBS @@ -4631,7 +4750,11 @@ job_done() { } build_queue() { + [ $# -eq 3 ] || eargs build_queue jname ptname setname required_env build_queue PWD "${MASTER_DATADIR_ABS}/pool" + local jname="$1" + local ptname="$2" + local setname="$3" local j jobid pid pkgname builders_active queue_empty local builders_idle idle_only timeout log porttesting @@ -4685,7 +4808,10 @@ build_queue() { continue fi builders_active=1 + # Opportunistically start the builder in a subproc MY_JOBID="${j}" spawn_job \ + maybe_start_builder "${j}" "${jname}" \ + "${ptname}" "${setname}" \ build_pkg "${pkgname}" "${porttesting}" pid=$! echo "${pid}" > "${MASTER_DATADIR}/var/run/${j}.pid" @@ -4804,11 +4930,9 @@ parallel_build() { # Minimize PARALLEL_JOBS to queue size [ ${PARALLEL_JOBS} -gt ${nremaining} ] && PARALLEL_JOBS=${nremaining##* } - msg "Building ${nremaining} packages using ${PARALLEL_JOBS} builders" + msg "Building ${nremaining} packages using up to ${PARALLEL_JOBS} builders" JOBS="$(jot -w %02d ${PARALLEL_JOBS})" - start_builders "${jname}" "${ptname}" "${setname}" - # Ensure rollback for builders doesn't copy schg files. if schg_immutable_base; then chflags noschg \ @@ -4844,12 +4968,13 @@ parallel_build() { coprocess_start pkg_cacher + bset builders "${JOBS}" bset status "parallel_build:" [ ! -d "${MASTER_DATADIR}/pool" ] && err 1 "Build pool is missing" cd "${MASTER_DATADIR}/pool" - build_queue + build_queue "${jname}" "${ptname}" "${setname}" cd "${MASTER_DATADIR}" @@ -4968,8 +5093,9 @@ build_pkg() { local failed_status failed_phase local clean_rdepends local log - local errortype + local errortype="???" local ret=0 + local tmpfs_blacklist_dir local elapsed now pkgname_varname jpkg originspec _my_path mnt @@ -5016,11 +5142,30 @@ build_pkg() { :> "${mnt}/${LOCALBASE:-/usr/local}/.mounted" fi + if [ -f "${mnt}/.tmpfs_blacklist_dir" ]; then + umount "${mnt}/wrkdirs" + rm -rf $(cat "${mnt}/.tmpfs_blacklist_dir") + fi [ -f ${mnt}/.need_rollback ] && rollbackfs prepkg ${mnt} [ -f ${mnt}/.need_rollback ] && \ err 1 "Failed to rollback ${mnt} to prepkg" :> ${mnt}/.need_rollback + for jpkg in ${TMPFS_BLACKLIST-}; do + case "${pkgname%-*}" in + ${jpkg}) + mkdir -p "${TMPFS_BLACKLIST_TMPDIR:?}/wrkdirs" + tmpfs_blacklist_dir=$(\ + TMPDIR="${TMPFS_BLACKLIST_TMPDIR:?}/wrkdirs" \ + mktemp -dt "${pkgname}") + ${NULLMOUNT} "${tmpfs_blacklist_dir}" "${mnt}/wrkdirs" + echo "${tmpfs_blacklist_dir}" \ + > "${mnt}/.tmpfs_blacklist_dir" + break + ;; + esac + done + rm -rfx ${mnt}/wrkdirs/* || : log_start "${pkgname}" 0 @@ -5078,9 +5223,11 @@ build_pkg() { # Symlink the buildlog into errors/ ln -s "../${pkgname}.log" \ "${log}/logs/errors/${pkgname}.log" - errortype=$(/bin/sh ${SCRIPTPREFIX}/processonelog.sh \ - "${log}/logs/errors/${pkgname}.log" \ - 2> /dev/null) + if [ "${DETERMINE_BUILD_FAILURE_REASON}" = "yes" ]; then + errortype=$(/bin/sh ${SCRIPTPREFIX}/processonelog.sh \ + "${log}/logs/errors/${pkgname}.log" \ + 2> /dev/null) + fi badd ports.failed "${originspec} ${pkgname} ${failed_phase} ${errortype} ${elapsed}" COLOR_ARROW="${COLOR_FAIL}" job_msg "${COLOR_FAIL}Finished ${COLOR_PORT}${port}${FLAVOR:+@${FLAVOR}} | ${pkgname}${COLOR_FAIL}: Failed: ${COLOR_PHASE}${failed_phase}" run_hook pkgbuild failed "${port}" "${pkgname}" "${failed_phase}" \ @@ -5099,6 +5246,12 @@ build_pkg() { -DNOCLEANDEPENDS clean ${MAKE_ARGS} || : rm -rfx ${mnt}/wrkdirs/* || : + if [ -n "${tmpfs_blacklist_dir}" ]; then + umount "${mnt}/wrkdirs" + rm -f "${mnt}/.tmpfs_blacklist_dir" + rm -rf "${tmpfs_blacklist_dir}" + fi + clean_pool "${pkgname}" "${originspec}" "${clean_rdepends}" stop_build "${pkgname}" "${originspec}" ${build_failed} @@ -7689,10 +7842,17 @@ trim_ignored() { bset status "trimming_ignore:" msg "Trimming IGNORED and blacklisted ports" - ignored_packages | while mapfile_read_loop_redir pkgname originspec \ - _rdep ignore; do - trim_ignored_pkg "${pkgname}" "${originspec}" "${ignore}" - done + parallel_start + while mapfile_read_loop_redir pkgname originspec _rdep ignore; do + if [ -z "${pkgname}" ]; then + break + fi + parallel_run trim_ignored_pkg "${pkgname}" "${originspec}" \ + "${ignore}" + done <<-EOF + $(ignored_packages) + EOF + parallel_stop || err "$?" "trim_ignored" # Update ignored/skipped stats update_stats 2>/dev/null || : update_stats_queued @@ -8755,6 +8915,7 @@ fi : ${FORCE_MOUNT_HASH:=no} : ${DELETE_UNQUEUED_PACKAGES:=no} : ${DELETE_UNKNOWN_FILES:=yes} +: ${DETERMINE_BUILD_FAILURE_REASON:=yes} DRY_RUN=0 INTERACTIVE_MODE=0 @@ -8816,12 +8977,10 @@ fi TIME_START=$(clock -monotonic) EPOCH_START=$(clock -epoch) -. ${SCRIPTPREFIX}/include/util.sh . ${SCRIPTPREFIX}/include/colors.sh . ${SCRIPTPREFIX}/include/display.sh . ${SCRIPTPREFIX}/include/html.sh . ${SCRIPTPREFIX}/include/parallel.sh -. ${SCRIPTPREFIX}/include/hash.sh . ${SCRIPTPREFIX}/include/shared_hash.sh . ${SCRIPTPREFIX}/include/cache.sh . ${SCRIPTPREFIX}/include/fs.sh diff --git a/src/share/poudriere/image_zfs.sh b/src/share/poudriere/image_zfs.sh index cd55c00e..d788f088 100644 --- a/src/share/poudriere/image_zfs.sh +++ b/src/share/poudriere/image_zfs.sh @@ -41,7 +41,7 @@ zfs_check() [ -n "${IMAGESIZE}" ] || err 1 "Please specify the imagesize" [ -n "${ZFS_POOL_NAME}" ] || err 1 "Please specify a pool name" - zpool list -Ho name ${ZFS_POOL_NAME} >/dev/null 2>&1 || \ + zpool list -Ho name ${ZFS_POOL_NAME} >/dev/null 2>&1 && \ err 1 "Target pool name already exists" case "${IMAGENAME}" in ''|*[!A-Za-z0-9]*) diff --git a/src/share/poudriere/include/colors.pre.sh b/src/share/poudriere/include/colors.pre.sh index b1d7d013..2847d942 100644 --- a/src/share/poudriere/include/colors.pre.sh +++ b/src/share/poudriere/include/colors.pre.sh @@ -24,35 +24,35 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. -COLOR_RESET="\033[0;0m" -COLOR_BOLD="\033[1m" -COLOR_UNDER="\033[4m" -COLOR_BLINK="\033[5m" -COLOR_INVERSE="\033[7m" +COLOR_RESET=$'\033'"[0;0m" +COLOR_BOLD=$'\033'"[1m" +COLOR_UNDER=$'\033'"[4m" +COLOR_BLINK=$'\033'"[5m" +COLOR_INVERSE=$'\033'"[7m" -COLOR_BLACK="\033[0;30m" -COLOR_RED="\033[0;31m" -COLOR_GREEN="\033[0;32m" -COLOR_BROWN="\033[0;33m" -COLOR_BLUE="\033[0;34m" -COLOR_MAGENTA="\033[0;35m" -COLOR_CYAN="\033[0;36m" -COLOR_LIGHT_GRAY="\033[0;37m" +COLOR_BLACK=$'\033'"[0;30m" +COLOR_RED=$'\033'"[0;31m" +COLOR_GREEN=$'\033'"[0;32m" +COLOR_BROWN=$'\033'"[0;33m" +COLOR_BLUE=$'\033'"[0;34m" +COLOR_MAGENTA=$'\033'"[0;35m" +COLOR_CYAN=$'\033'"[0;36m" +COLOR_LIGHT_GRAY=$'\033'"[0;37m" -COLOR_DARK_GRAY="\033[1;30m" -COLOR_LIGHT_RED="\033[1;31m" -COLOR_LIGHT_GREEN="\033[1;32m" -COLOR_YELLOW="\033[1;33m" -COLOR_LIGHT_BLUE="\033[1;34m" -COLOR_LIGHT_MAGENTA="\033[1;35m" -COLOR_LIGHT_CYAN="\033[1;36m" -COLOR_WHITE="\033[1;37m" +COLOR_DARK_GRAY=$'\033'"[1;30m" +COLOR_LIGHT_RED=$'\033'"[1;31m" +COLOR_LIGHT_GREEN=$'\033'"[1;32m" +COLOR_YELLOW=$'\033'"[1;33m" +COLOR_LIGHT_BLUE=$'\033'"[1;34m" +COLOR_LIGHT_MAGENTA=$'\033'"[1;35m" +COLOR_LIGHT_CYAN=$'\033'"[1;36m" +COLOR_WHITE=$'\033'"[1;37m" -COLOR_BG_BLACK="\033[40m" -COLOR_BG_RED="\033[41m" -COLOR_BG_GREEN="\033[42m" -COLOR_BG_BROWN="\033[43m" -COLOR_BG_BLUE="\033[44m" -COLOR_BG_MAGENTA="\033[45m" -COLOR_BG_CYAN="\033[46m" -COLOR_BG_LIGHT_GRAY="\033[47m" +COLOR_BG_BLACK=$'\033'"[40m" +COLOR_BG_RED=$'\033'"[41m" +COLOR_BG_GREEN=$'\033'"[42m" +COLOR_BG_BROWN=$'\033'"[43m" +COLOR_BG_BLUE=$'\033'"[44m" +COLOR_BG_MAGENTA=$'\033'"[45m" +COLOR_BG_CYAN=$'\033'"[46m" +COLOR_BG_LIGHT_GRAY=$'\033'"[47m" diff --git a/src/share/poudriere/include/display.sh b/src/share/poudriere/include/display.sh index 8e761c93..d4009e9c 100644 --- a/src/share/poudriere/include/display.sh +++ b/src/share/poudriere/include/display.sh @@ -25,11 +25,10 @@ # SUCH DAMAGE. display_setup() { - [ $# -ge 2 ] || eargs display_setup format columns [column_sort] + [ $# -ge 1 ] || eargs display_setup format [column_sort] _DISPLAY_DATA= _DISPLAY_FORMAT="$1" - _DISPLAY_COLUMNS="$2" - _DISPLAY_COLUMN_SORT="$3" + _DISPLAY_COLUMN_SORT="${3-}" } display_add() { @@ -48,6 +47,8 @@ display_add() { display_output() { local cnt lengths length format arg flag quiet line n + local header header_format + local OPTIND=1 quiet=0 @@ -67,11 +68,20 @@ display_output() { format="${_DISPLAY_FORMAT}" # Determine optimal format + n=0 while mapfile_read_loop_redir line; do + n=$((n + 1)) + if [ "${n}" -eq 1 ]; then + if [ "${quiet}" -eq 1 ]; then + continue + fi + header="${line}" + fi eval "set -- ${line}" cnt=0 for arg in "$@"; do hash_get lengths ${cnt} max_length || max_length=0 + stripansi "${arg}" arg if [ ${#arg} -gt ${max_length} ]; then # Keep the hash var local to this function _hash_var_name "lengths" "${cnt}" @@ -86,11 +96,17 @@ display_output() { EOF # Set format lengths if format is dynamic width - if [ "${format##*%%*}" != "${format}" ]; then + case "${format}" in + *%%*) set -- ${format} lengths= n=0 for arg in "$@"; do + # Check if this is a format argument + case "${arg}" in + *%*) ;; + *) continue ;; + esac case ${arg} in *%d*) hash_get lengths ${n} length @@ -100,14 +116,15 @@ display_output() { n=$((n + 1)) done format=$(printf "${format}" ${lengths}) - fi + ;; + esac # Show header separately so it is not sorted if [ "${quiet}" -eq 0 ]; then - echo "${_DISPLAY_DATA}"| head -n 1 | while read line; do - eval "set -- ${line}" - printf "${format}\n" "$@" - done + stripansi "${header}" header + stripansi "${format}" header_format + eval "set -- ${header}" + printf "${header_format}\n" "$@" fi # Sort as configured in display_setup() @@ -118,6 +135,6 @@ display_output() { printf "${format}\n" "$@" done - unset _DISPLAY_DATA _DISPLAY_FORMAT _DISPLAY_COLUMNS \ + unset _DISPLAY_DATA _DISPLAY_FORMAT \ _DISPLAY_COLUMN_SORT } diff --git a/src/share/poudriere/include/fs.sh b/src/share/poudriere/include/fs.sh index 9b85a9cd..b3f60c62 100644 --- a/src/share/poudriere/include/fs.sh +++ b/src/share/poudriere/include/fs.sh @@ -81,6 +81,7 @@ _do_clone() { local rflags="$1" shift local src dst common relative cpignore FLAG + local OPTIND=1 relative=0 cpignore="" diff --git a/src/share/poudriere/include/pkgqueue.sh b/src/share/poudriere/include/pkgqueue.sh index a8079331..db8ce4bc 100644 --- a/src/share/poudriere/include/pkgqueue.sh +++ b/src/share/poudriere/include/pkgqueue.sh @@ -310,7 +310,7 @@ pkgqueue_remaining() { # Find items in queue not ready-to-build. ( cd "${MASTER_DATADIR}"; pkgqueue_list ) | \ sed -e 's,$, waiting-on-dependency,' - } | sed -e 's,.*/,,' + } 2>/dev/null | sed -e 's,.*/,,' } # Return directory name for given job diff --git a/src/share/poudriere/include/util.sh b/src/share/poudriere/include/util.sh index cf5e2d43..e8873acc 100644 --- a/src/share/poudriere/include/util.sh +++ b/src/share/poudriere/include/util.sh @@ -701,12 +701,14 @@ _mapfile_write_from_stdin() { [ $# -eq 1 ] || eargs _mapfile_write_from_stdin handle local data - data="$(cat)" - _mapfile_write "$@" "${data}" + # . is to preserve newline + data="$(cat; echo .)" + data="${data%.}" + _mapfile_write "$@" -n "${data}" } _mapfile_write() { - [ $# -eq 2 ] || eargs mapfile_write handle data + [ $# -ge 2 ] || eargs mapfile_write handle [-n] data local handle="$1" shift local fd @@ -1316,3 +1318,26 @@ globmatch() { return 0 done } + +stripansi() { + [ $# -eq 2 ] || eargs stripansi input output_var + local _input="$1" + local _output_var="$2" + local _gsub + + case "${_input}" in + *$'\033'"["*) ;; + *) + setvar "${_output_var}" "${_input}" + return 0 + ;; + esac + + _gsub="${_input}" + _gsub "${_gsub}" $'\033'"[?m" "" + _gsub "${_gsub}" $'\033'"[??m" "" + _gsub "${_gsub}" $'\033'"[?;?m" "" + _gsub "${_gsub}" $'\033'"[?;??m" "" + + setvar "${_output_var}" "${_gsub}" +} diff --git a/src/share/poudriere/jail.sh b/src/share/poudriere/jail.sh index ba521246..3374bb86 100755 --- a/src/share/poudriere/jail.sh +++ b/src/share/poudriere/jail.sh @@ -94,12 +94,12 @@ list_jail() { if [ ${NAMEONLY} -eq 0 ]; then format='%%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%s' - display_setup "${format}" 6 "-d -k2,2 -k3,3 -k1,1" + display_setup "${format}" "-d -k2,2 -k3,3 -k1,1" display_add "JAILNAME" "VERSION" "ARCH" "METHOD" \ "TIMESTAMP" "PATH" else format='%s' - display_setup "${format}" 1 "-d" + display_setup "${format}" "-d" display_add JAILNAME fi [ -d ${POUDRIERED}/jails ] || return 0 diff --git a/src/share/poudriere/ports.sh b/src/share/poudriere/ports.sh index bd2a21ec..0ee72948 100755 --- a/src/share/poudriere/ports.sh +++ b/src/share/poudriere/ports.sh @@ -194,11 +194,11 @@ case $COMMAND in list) if [ ${NAMEONLY} -eq 0 ]; then format='%%-%ds %%-%ds %%-%ds %%s\n' - display_setup "${format}" 4 "-d" + display_setup "${format}" "-d" display_add "PORTSTREE" "METHOD" "TIMESTAMP" "PATH" else format='%s' - display_setup "${format}" 1 "-d" + display_setup "${format}" "-d" display_add "PORTSTREE" fi while read ptname ptmethod ptpath; do diff --git a/src/share/poudriere/status.sh b/src/share/poudriere/status.sh index 18e4e655..dff47d8e 100755 --- a/src/share/poudriere/status.sh +++ b/src/share/poudriere/status.sh @@ -191,7 +191,7 @@ show_summary() { [ ${COMPACT} -eq 0 ] && format="${format}\t%s" fi - display_setup "${format}" "${columns}" "-d -k1,1 -k2,2 -k3,3n -k4,4n" + display_setup "${format}" "-d -k1,1 -k2,2 -k3,3n -k4,4n" if [ ${COMPACT} -eq 0 ]; then if [ -n "${URL_BASE}" ] && [ ${URL} -eq 1 ]; then |