#!/bin/bash shopt -s nocasematch SMITHY_NAME=$(readlink -f "$0") cd "$(dirname "$0")" VERBOSE="${VERBOSE:-0}" PY2RPM_CMD="$PWD/tools/py2rpm" YUM_OPTS="--assumeyes --nogpgcheck" PIP_CMD="" PIP_OPTS="" RPM_OPTS="" CURL_OPTS="" PACKAGES="" PACKAGE_NAMES="" CONFLICTS="" if [ "$VERBOSE" == "0" ]; then YUM_OPTS="$YUM_OPTS -q" PIP_OPTS="-q" RPM_OPTS="-q" CURL_OPTS="-s" fi # Source in our variables (or overrides) source ".anvilrc" if [ -n "$SUDO_USER" ]; then USER_HOME=$(getent passwd $SUDO_USER | cut -d: -f6) if [ -n "$USER_HOME" ]; then HOME_RC="${USER_HOME}/.anvilrc" if [ -f "$HOME_RC" ]; then source "$HOME_RC" fi fi fi if [ -z "$BOOT_FILES" ]; then BOOT_FN=".anvil_bootstrapped" BOOT_FILES="${PWD}/$BOOT_FN" fi conflicts() { local rpm_name=$1 if [ -n "$rpm_name" ]; then CONFLICTS="$CONFLICTS $rpm_name" fi } remove_conflicts() { if [ -z "$CONFLICTS" ]; then return 0 fi echo "Removing conflicting packages: $CONFLICTS" for rpm_name in $CONFLICTS; do if [ -n $rpm_name ]; then yum erase $YUM_OPTS $rpm_name fi done } find_pip() { if [ -n "$PIP_CMD" ]; then return fi # Handle how RHEL likes to rename it. PIP_CMD="" for name in pip pip-python; do if which "$name" &>/dev/null; then PIP_CMD=$name break fi done if [ -z "$PIP_CMD" ]; then echo "pip or pip-python not found" exit 1 fi } rpm_is_installed() { local name="$(basename "$1")" rpm $RPM_OPTS "${name%.rpm}" &>/dev/null } cache_and_install_rpm_url() { url=${1:?"Error: rpm uri is undefined!"} cachedir=${RPM_CACHEDIR:-'/tmp'} rpm=$(basename $url) if rpm_is_installed "$rpm"; then return fi if [ ! -f "$cachedir/$rpm" ]; then echo "Downloading $rpm to $cachedir..." curl $CURL_OPTS $url -o "$cachedir/$rpm" || return 1 fi install_rpm "$cachedir/$rpm" return $? } yum_install() { local rpm_path=$1 output=$(yum install $YUM_OPTS "$rpm_path" 2>&1) rc=$? if [ -n "$output" ]; then if [[ ! "$output" =~ "Nothing to do" ]]; then echo $output fi fi if [ "$rc" != "0" ]; then if [[ "$output" =~ "Nothing to do" ]]; then # Not really a problem. return 0 fi fi return $rc } install_rpm() { local rpm_path=$1 local py_name=$2 local always_build=$3 if [ -n "$rpm_path" -a -z "$always_build" ]; then yum_install "$rpm_path" if rpm_is_installed "$rpm_path"; then return 0 fi fi if [ -z "$py_name" ]; then return 1 fi # RPM is not available. Try to build it on fly # First download it. pip_tmp_dir=$(mktemp -d) find_pip pip_opts="$PIP_OPTS -U -I" $PIP_CMD install $pip_opts "$py_name" --download "$pip_tmp_dir" # Now build it echo "Building RPM for $py_name" rpm_names=$("$PY2RPM_CMD" "$pip_tmp_dir/"* 2>/dev/null | awk '/^Wrote: /{ print $2 }' | grep -v '.src.rpm' | sort -u | grep -v "python-distribute") rm -rf "$pip_tmp_dir" if [ -z "$rpm_names" ]; then echo "No binary RPM was built for $py_name" return 1 fi for pkg in $rpm_names; do echo "Installing RPM $pkg" if [ -f "$pkg" ]; then yum_install "$pkg" fi done } bootstrap_epel() { [ -z "$EPEL_RPM_URL" ] && return 0 cache_and_install_rpm_url $EPEL_RPM_URL return $? } bootstrap_packages() { [ -z "$PACKAGES" ] && return 0 for pkg in $PACKAGES; do local rpm_name=$(echo $pkg | cut -d: -f1) local py_name=$(echo $pkg | cut -d: -f2) local always_build=$(echo $pkg | cut -d: -f3) install_rpm "$rpm_name" "$py_name" "$always_build" install_status=$? if [ "$install_status" != 0 ]; then echo "Error: Installation of package '$rpm_name' failed!" return "$install_status" fi done } require() { local rpm_name=$1 local py_name=$2 local always_build=$3 if [ -z "$rpm_name" -a -z "$py_name" ]; then echo "Please specify at RPM or Python package name" exit 1 fi PACKAGES="$PACKAGES $rpm_name:$py_name:$always_build" PACKAGE_NAMES="$PACKAGE_NAMES $rpm_name" } needs_bootstrap() { $BOOTSTRAP && return 0 checksums=$(get_checksums) for i in $BOOT_FILES; do if [ -f $i ]; then contents=`cat $i` [ "$contents" = "$checksums" ] && return 1 fi done return 0 } get_checksums() { if [ ! -f "$BSCONF_FILE" ]; then return 1 fi # Used to tell if the file have changed echo $(md5sum "$BSCONF_FILE") } run_smithy() { PYTHON=`which python` exec $PYTHON anvil $ARGS } puke() { cleaned_force=$(echo $FORCE | sed -e 's/\([A-Z]\)/\L\1/g;s/\s//g') if [[ "$cleaned_force" == "yes" ]]; then run_smithy else echo "To run anyway set FORCE=yes and rerun." >&2 exit 1 fi } ## Identify which bootstrap configuration file to use: either set ## explicitly (BSCONF_FILE) or determined based on the os distribution: BSCONF_DIR=${BSCONF_DIR:-$(dirname $(readlink -f "$0"))/tools/bootstrap} get_os_info(){ OS=`uname` if [ "${OS}" = "Linux" ] ; then if [ -f /etc/redhat-release ] ; then PKG="rpm" OSNAME=`cat /etc/redhat-release` OSDIST=`cat /etc/redhat-release | sed -e 's/release.*$//g;s/\s//g'` PSUEDONAME=`cat /etc/redhat-release | sed s/.*\(// | sed s/\)//` RELEASE=`cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//` elif [ -f /etc/debian_version ] ; then PKG="deb" OSDIST=`cat /etc/lsb-release | grep '^DISTRIB_ID' | awk -F= '{ print $2 }'` PSUEDONAME=`cat /etc/lsb-release | grep '^DISTRIB_CODENAME' | awk -F= '{ print $2 }'` RELEASE=`cat /etc/lsb-release | grep '^DISTRIB_RELEASE' | awk -F= '{ print $2 }'` OSNAME="$OSDIST $RELEASE ($PSUEDONAME)" fi fi } get_os_info if [ -z "$BSCONF_FILE" ]; then BSCONF_FILE="$BSCONF_DIR/$OSDIST" fi ARGS="" BOOTSTRAP=false if [ -f "$BSCONF_FILE" ]; then source $BSCONF_FILE fi # Export these immediatly so that anvil can know about them and it will # avoid removing them. export REQUIRED_PACKAGES="$PACKAGE_NAMES" export CONFLICTING_PACKAGES="$CONFLICTS" # Ad-hoc getopt to handle long opts. # # Smithy opts are consumed while those to anvil are copied through. while [ ! -z $1 ]; do case "$1" in '--bootstrap') BOOTSTRAP=true shift ;; '--force') FORCE=yes shift ;; *) ARGS="$ARGS $1" shift ;; esac done if ! needs_bootstrap; then run_smithy elif ! $BOOTSTRAP; then echo "This system needs to be updated in order to run anvil!" >&2 echo "Running 'sudo $SMITHY_NAME --bootstrap' will attempt to do so." >&2 exit 1 fi ## Bootstrap smithy if [ "$(id -u)" != "0" ]; then echo "You must run '$SMITHY_NAME --bootstrap' with root privileges!" >&2 exit 1 fi if [ ! -f "$BSCONF_FILE" ]; then echo "Anvil has not been tested on distribution '$OSNAME'" >&2 puke fi MIN_RELEASE=${MIN_RELEASE:?"Error: MIN_RELEASE is undefined!"} SHORTNAME=${SHORTNAME:?"Error: SHORTNAME is undefined!"} BC_OK=$(echo "$RELEASE < $MIN_RELEASE" | bc) if [ "$BC_OK" == "1" ]; then echo "This script must be run on $SHORTNAME $MIN_RELEASE+ and not $SHORTNAME $RELEASE." >&2 puke fi echo "Bootstrapping $SHORTNAME $RELEASE" echo "Please wait..." remove_conflicts for step in ${STEPS:?"Error: STEPS is undefined!"}; do bootstrap_${step} if [ $? != 0 ]; then echo "Bootstrapping $SHORTNAME $RELEASE failed." >&2 exit 1 fi done # Write the checksums of the bootstrap file # which if new requirements are added will cause new checksums # and a new dependency install... checksum=$(get_checksums) for i in $BOOT_FILES; do echo -e $checksum > $i done mkdir -p -v /etc/anvil /usr/share/anvil if [ -n "$SUDO_UID" -a -n "SUDO_GID" ]; then chown -c "$SUDO_UID:$SUDO_GID" /etc/anvil /usr/share/anvil fi echo "Success! Bootstrapped for $SHORTNAME $RELEASE" exit 0