[Buildroot] [PATCH 4/5] support/graphs: real-time build status on graph-depends
Yann E. MORIN
yann.morin.1998 at free.fr
Sun Aug 9 22:38:19 UTC 2015
Currently, following the state of the build is not easily done. One may
want to see at a glance where the build has progressed so far, which
package are built, what dependency chains are finished, why a certain
package is not yet built.
We add a new make target, rt-graph-depends, that takes the exisiting
dependency graph (graph-depends) and overlays the build status for each
package, with colors and the current action being done on the package.
The new scritps loops forever, each time parsing the build-time.log file
to extract the status for each package; it then uses that to replace the
color and label in the .dot script and eventually re-renders the graph.
Also add the <pkg>-rt-graph-depends to limit tracking the build to that
specific package's dependencies.
Signed-off-by: "Yann E. MORIN" <yann.morin.1998 at free.fr>
Cc: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
---
Note: the script should be able to handle the full-parallel build once
it lands in the tree.
---
Makefile | 7 ++
package/pkg-generic.mk | 7 ++
support/scripts/rt-graph-depends | 175 +++++++++++++++++++++++++++++++++++++++
3 files changed, 189 insertions(+)
create mode 100755 support/scripts/rt-graph-depends
diff --git a/Makefile b/Makefile
index e70bbd6..014e95a 100644
--- a/Makefile
+++ b/Makefile
@@ -688,6 +688,13 @@ graph-depends: graph-depends-requirements
|tee $(GRAPHS_DIR)/$(@).dot \
|dot $(BR2_GRAPH_DOT_OPTS) -T$(BR_GRAPH_OUT) -o $(GRAPHS_DIR)/$(@).$(BR_GRAPH_OUT)
+rt-graph-depends:
+ @cd "$(CONFIG_DIR)"; \
+ $(TOPDIR)/support/scripts/rt-graph-depends \
+ -l $(BUILD_DIR)/build-time.log -d $(GRAPHS_DIR) \
+ -g graph-depends -T$(BR_GRAPH_OUT) -- \
+ $(BR2_GRAPH_DOT_OPTS)
+
else # ifeq ($(BR2_HAVE_DOT_CONFIG),y)
all: menuconfig
diff --git a/package/pkg-generic.mk b/package/pkg-generic.mk
index d0d580a..fe752b2 100644
--- a/package/pkg-generic.mk
+++ b/package/pkg-generic.mk
@@ -623,6 +623,13 @@ $(1)-graph-depends: graph-depends-requirements
|tee $$(GRAPHS_DIR)/$$(@).dot \
|dot $$(BR2_GRAPH_DOT_OPTS) -T$$(BR_GRAPH_OUT) -o $$(GRAPHS_DIR)/$$(@).$$(BR_GRAPH_OUT)
+$(1)-rt-graph-depends:
+ @cd "$(CONFIG_DIR)"; \
+ $(TOPDIR)/support/scripts/rt-graph-depends \
+ -l $(BUILD_DIR)/build-time.log -d $(GRAPHS_DIR) \
+ -g $(1)-graph-depends -T$(BR_GRAPH_OUT) -- \
+ $(BR2_GRAPH_DOT_OPTS)
+
$(1)-all-source: $(1)-source
$(1)-all-source: $$(foreach p,$$($(2)_FINAL_ALL_DEPENDENCIES),$$(p)-all-source)
diff --git a/support/scripts/rt-graph-depends b/support/scripts/rt-graph-depends
new file mode 100755
index 0000000..752f56b
--- /dev/null
+++ b/support/scripts/rt-graph-depends
@@ -0,0 +1,175 @@
+#!/bin/bash
+
+declare -A COLORS
+COLORS=(
+ ["start:extract"]="coral"
+ ["end:extract"]="coral"
+ ["start:patch"]="coral"
+ ["end:patch"]="coral"
+ ["start:configure"]="orange"
+ ["end:configure"]="orange"
+ ["start:build"]="orange"
+ ["end:build"]="orange"
+ ["start:install-staging"]="green"
+ ["end:install-staging"]="green"
+ ["start:install-target"]="green"
+ ["end:install-target"]="green"
+ ["start:install-image"]="green"
+ ["end:install-image"]="green"
+ ["start:install-host"]="green"
+ ["end:install-host"]="green"
+ ["start:assemble"]="green"
+ ["end:assemble"]="green"
+)
+
+# The label to print under the package name when there is an action
+# being done on that package. Empty means to not add an action label,
+# and is used when the package reaches a terminal state (e.g. installed
+# for packages, assembled for rootfs images).
+#
+# Note: some packages have only one of the target/staging/image install
+# commands, so we don't know which will be the last to be done. So, we
+# just consider each to be terminal.
+declare -A TRANSLATE
+TRANSLATE=(
+ ["start:extract"]="extracting"
+ ["end:extract"]="extracted"
+ ["start:patch"]="patching"
+ ["end:patch"]="patched"
+ ["start:configure"]="configuring"
+ ["end:configure"]="configured"
+ ["start:build"]="building"
+ ["end:build"]="built"
+ ["start:install-staging"]="installing staging"
+ ["end:install-staging"]=""
+ ["start:install-target"]="installing target"
+ ["end:install-target"]=""
+ ["start:install-image"]="installing image"
+ ["end:install-image"]=""
+ ["start:install-host"]="installing host"
+ ["end:install-host"]=""
+ ["start:assemble"]="assembling"
+ ["end:assemble"]=""
+)
+
+main() {
+ local OPT OPTARG
+ local log gdir gname dot_type
+ local infile outfile outgraph
+ local -A pkg_status
+ local -a sed_expr
+ local _ step stat pkg last_pkg color h _h _r _s _t
+
+ while getopts :hl:d:g:T: OPT; do
+ case "${OPT}" in
+ h) help; exit 0;;
+ l) log="${OPTARG}";;
+ d) gdir="${OPTARG}";;
+ g) gname="${OPTARG}";;
+ T) dot_type="${OPTARG}";;
+ :) error "option '%s' expects a mandatory argument\n" "${OPTARG}";;
+ \?) error "unknown option '%s'\n" "${OPTARG}";;
+ esac
+ done
+ # Forget our options, and keep only the ones for 'dot'
+ shift $((OPTIND-1))
+
+ if [ -z "${log}" ]; then
+ error "no build-time.log file specified\n"
+ fi
+
+ if [ -z "${gdir}" ]; then
+ error "no graph directory specified\n"
+ fi
+
+ if [ -z "${gname}" ]; then
+ error "no graph name specified\n"
+ fi
+
+ if [ -z "${dot_type}" ]; then
+ error "no output type specified\n"
+ fi
+
+ if [ ! -f "${gdir}/${gname}.${dot_type}" ]; then
+ make ${gname} || exit $?
+ fi
+
+ infile="${gdir}/${gname}.dot"
+ outfile="$(sed -r -e 's/(graph-depends)/rt-\1/' <<<${gname})"
+ outgraph="${gdir}/${outfile}.${dot_type}"
+ cp "${gdir}/${gname}.${dot_type}" "${outgraph}"
+
+ printf "Realtime graph is at: %s\n" "${outgraph}"
+ printf "Now rendering realtime status... (Ctrl-C to interrupt)"
+
+ _h=""
+ while true; do
+ pkg_status=()
+ sed_expr=()
+ while read _ step stat pkg; do
+ pkg_status["${pkg}"]="${step}:${stat}"
+ done < <( sed -r -e 's/:/ /g; s/ +/ /g;' "${log}" 2>/dev/null )
+ h="$( printf "%s\n" "${pkg_status[@]}" |sort |md5sum )"
+ if [ "${h}" = "${_h}" ]; then
+ inotifywait -t 1 -e modify -qq "${log}" >/dev/null 2>&1
+ [ -f "${log}" ] || sleep 0.1
+ continue
+ fi
+ _h="${h}"
+ for pkg in "${!pkg_status[@]}"; do
+ stat="${pkg_status["${pkg}"]}"
+ color="${COLORS["${stat}"]}"
+ [ -n "${color}" ] || continue
+ _s="^(${pkg//-/}\>.*color=)[^,]+(.*)\$"
+ _r="\\1${color}\\2"
+ sed_expr+=( "s/${_s}/${_r}/;" )
+ _t="${TRANSLATE["${stat}"]}"
+ if [ -n "${_t}" ]; then
+ _s="^(${pkg//-/}\>.*label = \"[^\"]+)(.*)\$"
+ _r="\\1\n[${_t}]\\2"
+ sed_expr+=( "s/${_s}/${_r}/;" )
+ fi
+ done
+ sed -r -e "${sed_expr[*]}" "${infile}" \
+ |dot "${@}" -T${dot_type} -o"${outgraph}.tmp"
+ mv -f "${outgraph}.tmp" "${outgraph}"
+ done
+}
+
+help() {
+cat <<_EOF_
+NAME
+ ${my_name} - draw the dependency graph with packages status
+
+SYNOPSIS
+ ${my_name} [OPTION...]
+
+DESCRIPTION
+ ${my_name} displays the dependency graph and colors each package
+ depending on their build status. The graph is refreshed every time
+ the status of a package changes, so that it is possible to follow
+ the status of the build in near-realtime.
+
+ -l full-path to the build-time.log file
+
+ -d base directory with the existing dependency graph, in 'dot'
+ format.
+
+ -g base name of the dependency graph
+
+ -T output type, anything acepted by the 'dot' program (which uses
+ the same option)
+
+EXIT STATUS
+ Unless there is an error, ${my_name} never exits on its own, you
+ must interrupt it (Ctrl-C).
+_EOF_
+}
+
+trace() { local msg="${1}"; shift; printf "%s: ${msg}" "${my_name}" "${@}"; }
+warn() { trace "${@}" >&2; }
+errorN() { local ret="${1}"; shift; warn "${@}"; exit ${ret}; }
+error() { errorN 1 "${@}"; }
+
+my_name="${0##*/}"
+main "${@}"
--
1.9.1
More information about the buildroot
mailing list