#!/bin/sh set -e #set -x prog_NAME=$(basename "${0}") warn() { echo "${prog_NAME}: WARN: $*" } info() { echo "${prog_NAME}: INFO: $*" } err() { echo "${prog_NAME}: ERROR: $*" 1>&2 } die() { echo "${prog_NAME}: ERROR: $*" 1>&2 exit 1 } usage() { cat <&2 usage: ${prog_NAME} [ OPTIONS ] Generates visualizations Options: --uuid=STRING UUID of build. --data-dir=STRING Path to the data directory. --cache-dir=STRING Path to the cache directory. EOM exit 1 } UUID= CACHE_DIR= DATA_DIR= while [ $# -gt 0 ]; do OPT="$1" case "${OPT}" in --uuid=*) UUID="${OPT##*=}" ;; --cache-dir=*) CACHE_DIR="${OPT##*=}" ;; --data-dir=*) DATA_DIR="${OPT##*=}" ;; *) warn "Ignoring unknown option: '${OPT}' (Note that this script reads DB)" ;; esac shift done [ -z "${UUID}" ] && die "The --uuid option must be specified" [ -z "${CACHE_DIR}" ] && die "The --cache-dir option must be specified" [ -z "${DATA_DIR}" ] && die "The --data-dir option must be specified" info "processing UUID '$UUID'" DB="${DATA_DIR}/builder.sqlite3" get_main_binary () { sqlite3 "${DB}" "SELECT ba.localpath FROM build AS b JOIN build_artifact AS ba ON ba.build = b.id AND b.main_binary = ba.id WHERE uuid = '$UUID';" } BIN="${DATA_DIR}/$(get_main_binary)" || die "Failed to get main binary from database" [ -z "${BIN}" ] && die "No main-binary found in db '$DB' for build '$UUID'" get_debug_binary () { sqlite3 "${DB}" "SELECT ba.localpath FROM build AS b JOIN build_artifact AS ba ON ba.build = b.id WHERE uuid = '$UUID' AND ba.localpath LIKE '%.debug';" } DEBUG_BIN_RELATIVE="$(get_debug_binary)" || die "Failed to get debug binary from database" get_opam_switch () { sqlite3 "${DB}" "SELECT ba.localpath FROM build AS b JOIN build_artifact AS ba ON ba.build = b.id WHERE uuid = '$UUID' AND ba.filepath = 'opam-switch';" } OPAM_SWITCH="$(get_opam_switch)" || die "Failed to get opam switch from database" [ -z "${OPAM_SWITCH}" ] && die "No 'opam-switch' found in db '$DB' for build '$UUID'" OPAM_SWITCH="${DATA_DIR}/${OPAM_SWITCH}" OPAM_GRAPH="opam-graph" MODULECTOMY="modulectomy" LATEST_TREEMAPVIZ_VERSION="$($MODULECTOMY --version)" || die "Failed to get modulectomy version" LATEST_DEPENDENCIESVIZ_VERSION="$($OPAM_GRAPH --version)" || die "Failed to get opam-graph version" TREEMAP_CACHE_DIR="${CACHE_DIR}/treemap_${LATEST_TREEMAPVIZ_VERSION}" DEPENDENCIES_CACHE_DIR="${CACHE_DIR}/dependencies_${LATEST_DEPENDENCIESVIZ_VERSION}" mktemp_aux () { if [ "$(uname)" = "Linux" ]; then mktemp -t "$1.XXX" elif [ "$(uname)" = "FreeBSD" ]; then mktemp -t "$1" else die 'Unsupported platform' fi } TMPTREE=$(mktemp_aux viz_treemap) TMPDEPENDENCIES=$(mktemp_aux viz_dependencies) cleanup () { rm -rf "${TMPTREE}" "${TMPDEPENDENCIES}" } trap cleanup EXIT # /// Dependencies viz if [ ! -d "${DEPENDENCIES_CACHE_DIR}" ]; then mkdir "${DEPENDENCIES_CACHE_DIR}" || die "Failed to create directory '$DEPENDENCIES_CACHE_DIR'" fi OPAM_SWITCH_FILEPATH='opam-switch' get_opam_switch_hash () { sqlite3 "${DB}" "SELECT lower(hex(ba.sha256)) FROM build AS b JOIN build_artifact AS ba ON ba.build = b.id WHERE uuid = '$UUID' AND ba.filepath = '$OPAM_SWITCH_FILEPATH';" } DEPENDENCIES_INPUT_HASH="$(get_opam_switch_hash)" || die "Failed to get opam-switch hash from database" DEPENDENCIES_VIZ_FILENAME="${DEPENDENCIES_CACHE_DIR}/${DEPENDENCIES_INPUT_HASH}.html" if [ -e "${DEPENDENCIES_VIZ_FILENAME}" ]; then info "Dependency visualization already exists: '${DEPENDENCIES_VIZ_FILENAME}'" else if ${OPAM_GRAPH} --output-format=html "${OPAM_SWITCH}" > "${TMPDEPENDENCIES}"; then cp "${TMPDEPENDENCIES}" "${DEPENDENCIES_VIZ_FILENAME}" rm "$TMPDEPENDENCIES" else die "opam-graph failed to generate visualization" fi fi # /// Treemap viz stat_aux () { if [ "$(uname)" = "Linux" ]; then stat -c "%s" "$1" elif [ "$(uname)" = "FreeBSD" ]; then stat -f "%z" "$1" else die 'Unsupported platform' fi } SIZE="$(stat_aux "$BIN")" if [ ! -d "${TREEMAP_CACHE_DIR}" ]; then mkdir "${TREEMAP_CACHE_DIR}" || die "Failed to create directory '$TREEMAP_CACHE_DIR'" fi get_debug_bin_hash () { sqlite3 "${DB}" "SELECT lower(hex(ba.sha256)) FROM build AS b JOIN build_artifact AS ba ON ba.build = b.id WHERE uuid = '$UUID' AND ba.filepath LIKE '%.debug';" } TREEMAP_INPUT_HASH="$(get_debug_bin_hash)" || die "Failed to get treemap input hash from database" TREEMAP_VIZ_FILENAME="${TREEMAP_CACHE_DIR}/${TREEMAP_INPUT_HASH}.html" if [ -n "${DEBUG_BIN_RELATIVE}" ]; then DEBUG_BIN="${DATA_DIR}/$(get_debug_binary)" if [ -e "${TREEMAP_VIZ_FILENAME}" ]; then info "Treemap visualization already exists: '${TREEMAP_VIZ_FILENAME}'" else if ${MODULECTOMY} \ --robur-defaults \ --with-scale="${SIZE}" \ "${DEBUG_BIN}" \ > "${TMPTREE}" then cp "${TMPTREE}" "${TREEMAP_VIZ_FILENAME}" rm "$TMPTREE" else die "modulectomy failed to generate visualization" fi fi else info "No --debug-binary provided, not producing any treemap" fi