#!/bin/bash ############################################################################### # Copyright 2005 Mike Green # # Distributed under the terms of the GNU General Public License v2 # # # # This emerge wrapper script aims to cut through all of the BS that is caused # # by a lack of basic functionality in emerge command. The basic philosphy # # goes like this: # # # # 1) Toolchain upgrades should rarely happen on a stable system. # # 2) Toolchain upgrades should be performed in the correct order. # # 3) Toolchain upgrades should only happen when you want them to. # # 4) System emerges should not touch toolchain components. # # 5) World emerges should not touch system or toolchain components. # # 6) Bootstrapping from any stage should be possible and done correctly. # # # # With those guidelines in mind, the task is simple. Split packages into # # distinct targets: bootstrap, toolchain, system, world, universe. When # # emerging one of those targets, only emerge packages from within that class, # # no matter what portage thinks! # ############################################################################### VER="20060105-01" # # What is a toolchain? Might be different packages on different o/s's, for # example the bsds might be different. I am not installing bsd, but perhaps # this will provide the functionality to enable someone else to hack this # script for use by other portage based o/s's. The toolchain packages # listed here need to be listed in the correct order that they need to be # merged. This list serves two purposes, a) these package names are # excluded from system/world/universe lists, and b) these package names # will be emerged in the order listed by the bootstrap/toolchain targets. # TOOLCHAIN_PACKAGES="sys-devel/binutils-config sys-devel/binutils sys-devel/gcc-config sys-devel/gcc sys-kernel/linux-headers sys-libs/glibc" # # The list of packages that should never be touched during # a system/world/universe build. These package names will be used to # generate the exclude list during system/world/universe builds. DO NOT # remove ${TOOLCHAIN_PACKAGES} from this list unless you really know what # you are doing. To add extra exclusions just tag them on. For example, # some people don't ever want sys-kernel/gentoo-sources to be upgraded # for no good reason. # SYSTEM_EXCLUDES="${TOOLCHAIN_PACKAGES}" # # Define packages that will always be rebuilt immediately after # any toolchain upgrades/bootstraps. These packages are meant to # bootstrap portage itself. The packages defined here will be rebuilt # immediately after TOOLCHAIN_PACKAGES in the order listed. # As with the toolchain packages, the first pass will be a minimal # bootstrap/build pass, the second pass will be a full pass. # PORTAGE_BOOTSTRAP_PACKAGES="sys-devel/libtool sys-devel/autoconf sys-devel/automake dev-lang/python sys-apps/portage" # # Define the location of progress tracking files. # progressfile="/var/run/nobsmerge-progress" envfile="/var/run/nobsmerge-env" logfile="/var/run/nobsmerge.log" ############################################################################### # Load functions from /etc/init.d/functions.sh and set up pretty formatting of # text. # if [ -e /etc/init.d/functions.sh ] ; then source /etc/init.d/functions.sh esyslog() { echo &> /dev/null; } else eerror() { echo "!!! $*"; } einfo() { echo "* $*"; } fi ############################################################################### # What to do when we bomb or succeed. If you have custom stuff you want to # do after the bootstrap completes, add it here. # cleanup() { rc=$1 stty sane >/dev/null 2>&1 if [ ! "${rc}" == "0" ]; then : # # Add custom stuff to do after a failure here. # eerror eerror "Exiting nonzero" if [ -f "${logfile}" ]; then eerror "Take a gander at ${logfile} if you are wondering why." fi eerror exit ${rc} fi if [[ -n ${DO_ACTUAL_RUN} ]] ; then : # # Add custom stuff to do after a successful run here. # Send an email, add an entry to a log, etc... # fi exit ${rc} } ############################################################################### # do_pause() { einfo "Press any key to continue or control-c to cancel..." read -n 1 -s junk } ############################################################################### # draw_line() { echo echo ------------------------------------------------------------------------------- } ############################################################################### # Generate the envfile, which will contain the lists of packages etc... # generateEnvFile() { if [ -z "${TARGET}" ]; then usage cleanup 0 fi PACKAGE_LIST="" draw_line echo " [[ Initializing Package List ]]" echo if [ -f "${envfile}" ]; then eerror eerror "${envfile} already exists and cannot be overwritten." eerror "To start over, remove ${envfile} and ${progressfile}." eerror cleanup 1 fi # run emerge --info to apply updates emerge --info >/dev/null 2>&1 case ${TARGET} in bootstrap) einfo "target: bootstrap" eerror eerror "ERROR: bootstrap not supported yet" eerror cleanup 0 ;; toolchain) einfo "target: toolchain" eerror eerror "ERROR: toolchain not supported yet" eerror cleanup 0 einfo "target: toolchain" einfo "generate: package list" PACKAGE_LIST="`listToolchain`" if [ -z "${PACKAGE_LIST}" ]; then einfo "detected: 0 packages" cleanup 0 fi einfo "generate: pass1 USE flags" FIRSTPASS_USE="" for opt in `portageq envvar USE` do case "${opt}" in build|bootstrap) eerror eerror "You have 'build' or 'bootstrap' in your USE flags. Please" eerror "remove it before trying to continue, since these USE flags" eerror "are automatically set as needed by this script." eerror cleanup 1 ;; multilib) FIRSTPASS_USE="${FIRSTPASS_USE} multilib" ;; nptl) FIRSTPASS_USE="${FIRSTPASS_USE} nptl" ;; nptlonly) FIRSTPASS_USE="${FIRSTPASS_USE} nptlonly" ;; userlocales) FIRSTPASS_USE="${FIRSTPASS_USE} userlocales" ;; esac done ;; system) einfo "target: system" if [ "${DO_DEEPUPDATE}" == "1" ]; then einfo "generate: deep update package list" PACKAGE_LIST="`listSystemUpdate`" elif [ "${DO_EMPTYTREE}" == "1" ]; then einfo "generate: emptytree package list" PACKAGE_LIST="`listSystemEmpty`" else einfo "generate: package list" PACKAGE_LIST="`listSystem`" fi if [ -z "${PACKAGE_LIST}" ]; then einfo "detected: 0 packages" cleanup 0 fi ;; universe) A_LIST="" B_LIST="" einfo "target: universe" if [ "${DO_DEEPUPDATE}" == "1" ]; then einfo "generate: deep update package list" A_LIST="`listSystemUpdate`" elif [ "${DO_EMPTYTREE}" == "1" ]; then einfo "generate: emptytree package list" A_LIST="`listSystemEmpty`" else einfo "generate: package list" A_LIST="`listSystem`" fi if [ "${DO_DEEPUPDATE}" == "1" ]; then B_LIST="`listWorldUpdate`" elif [ "${DO_EMPTYTREE}" == "1" ]; then B_LIST="`listWorldEmpty`" else B_LIST="`listWorld`" fi PACKAGE_LIST="${A_LIST} ${B_LIST}" if [ -z "${PACKAGE_LIST}" ]; then einfo "detected: 0 packages" cleanup 0 fi ;; world) einfo "target: world" if [ "${DO_DEEPUPDATE}" == "1" ]; then einfo "generate: deep update package list" PACKAGE_LIST="`listWorldUpdate`" elif [ "${DO_EMPTYTREE}" == "1" ]; then einfo "generate: emptytree package list" PACKAGE_LIST="`listWorldEmpty`" else einfo "generate: package list" PACKAGE_LIST="`listWorld`" fi if [ -z "${PACKAGE_LIST}" ]; then einfo "detected: 0 packages" cleanup 0 fi ;; *) usage cleanup 1 ;; esac # count up the packages junk=(${PACKAGE_LIST}) TOTAL_PACKAGES=${#junk[@]} if [ "${TOTAL_PACKAGES}" -lt 1 ]; then einfo einfo "detected: 0 packages" einfo cleanup 0 else einfo "detected: ${TOTAL_PACKAGES} package(s)" fi if [ "${DO_LISTONLY}" == "1" ]; then echo for pkg in ${PACKAGE_LIST} do echo $pkg done echo cleanup 0 fi # # Seed the envfile with all the needed variables. # VARS="DO_BOOTSTRAP DO_SYSTEM DO_TOOLCHAIN DO_WORLD DO_UNIVERSE DO_DEEPUPDATE DO_EMPTYTREE TARGET ACTION PACKAGE_LIST TOTAL_PACKAGES" [[ "${DO_TOOLCHAIN}" == "1" ]] && VARS="${VARS} FIRSTPASS_USE" for var in ${VARS} do val=$(eval echo \$$var) echo "${var}=\"${val}\"" >>${envfile} done set_step 0 einfo "created: ${envfile}" } ############################################################################### # Return a list of what portage sees as the system package list. # listSystem() { if [ -z "${SYSTEM_EXCLUDES}" ]; then eerror eerror "listSystem() failed, SYSTEM_EXCLUDES not set" eerror return fi # construct the regular expression list from SYSTEM_EXCLUDES EXCLUDES="" for pkg in ${SYSTEM_EXCLUDES} do EXCLUDES="${EXCLUDES}|${pkg}" done EXCLUDES="`echo ${EXCLUDES} | cut -b2-`" junk=`emerge -p system | grep '\[ebuild' | \ grep -vE "${EXCLUDES}" | cut -b17- | cut -f1 -d\[` if [ $? -ne 0 ]; then eerror eerror "listSystem() failed" eerror cleanup 1 fi echo ${junk} } ############################################################################### # Return a list of what portage sees as the system package list. # listSystemEmpty() { if [ -z "${SYSTEM_EXCLUDES}" ]; then eerror eerror "listSystemEmpty() failed, SYSTEM_EXCLUDES not set" eerror return fi # construct the regular expression list from SYSTEM_EXCLUDES EXCLUDES="" for pkg in ${SYSTEM_EXCLUDES} do EXCLUDES="${EXCLUDES}|${pkg}" done EXCLUDES="`echo ${EXCLUDES} | cut -b2-`" junk=`emerge -pe system | grep '\[ebuild' | \ grep -vE "${EXCLUDES}" | cut -b17-` if [ $? -ne 0 ]; then eerror eerror "listSystemEmpty() failed" eerror cleanup 1 fi echo ${junk} } ############################################################################### # Return a list of what portage sees as a system update package list. # listSystemUpdate() { if [ -z "${SYSTEM_EXCLUDES}" ]; then eerror eerror "listSystemUpdate() failed, SYSTEM_EXCLUDES not set" eerror return fi # construct the regular expression list from SYSTEM_EXCLUDES EXCLUDES="" for pkg in ${SYSTEM_EXCLUDES} do EXCLUDES="${EXCLUDES}|${pkg}" done EXCLUDES="`echo ${EXCLUDES} | cut -b2-`" junk=`emerge -pDu system | grep '\[ebuild' | \ grep -vE "${EXCLUDES}" | cut -b17- | cut -f1 -d\[` if [ $? -ne 0 ]; then eerror eerror "listSystemUpdate() failed" eerror cleanup 1 fi echo ${junk} } ############################################################################### # Return the entire list of all of the packages that need to be installed # # during a toolchain upgrade, logically handled in sets. # # # # The toolchain packages themselves are compiled twice only. The first pass # # is a minimal bootstrap pass, the second pass is the full compile plus all # # of the dependencies. The packages needed to bootstrap portage are handled # # in the same manner. The end result is that every package on the box ends # # up getting compiled 4 times with the exception of the toolchain packages, # # which only compile against themselves so two passes are all that is needed. # # The toolchain and portage bootstrap packages are also installed in the # # correct order. # # # # This entire convoluted looking process is equivalent to the Rob Moss method # # of upgrading the toolchain: # # emerge -e system && emerge -e system && emerge -e world && emerge -e world # # The exception is that it is done in a more correct order and a little time # # is saved by compiling the toolchain packages only twice. # # # # Set 1) The packages in ${TOOLCHAIN_PACKAGES}, with no dependencies. This # # is a bootstrap pass, so the USE flags will be overridden to make # # this step as short as possible. # # For each package in ${TOOLCHAIN_PACKAGES}, the following will # # happen: # # USE="-* minimal build bootstrap ${TOOLCHAIN_FIRST_PASS_USE}" \ # # emerge --nodeps -1 ${pkg}. # # Set 2) The packages in ${PORTAGE_BOOTSTRAP_PACKAGES}, with no dependencies, # # again a build/bootstrap pass. # # Set 3) Each package from ${TOOLCHAIN_PACKAGES}, along with dependencies. # # The order of how the packages are listed in ${TOOLCHAIN_PACKAGES} # # will be enforced. No alteration to the USE flags or other portage # # environment settings will happen during this pass. # # Set 4) Each package from ${PORTAGE_BOOTSTRAP_PACKAGES}, minus dependencies # # already caught by set 3. The order of how the packages are listed # # in ${PORTAGE_BOOTSTRAP_PACKAGES} will be enforced. No alteration to # # the USE flags or other portage environment settings will happen # # during this pass. # # Set 5) System packages, minus packages in sets 1-4. # # Set 6) System packages, minus packages in sets 1-2. # # Set 7) World packages, minus packages in sets 1-5. # # Set 8) World packages, minus packages in set 1. # ############################################################################### listToolchain() { if [ -z "${TOOLCHAIN_PACKAGES}" ]; then eerror eerror "listToolchain() failed, TOOLCHAIN_PACKAGES not set" eerror return fi if [ -z "${PORTAGE_BOOTSTRAP_PACKAGES}" ]; then eerror eerror "listToolchain() failed, PORTAGE_BOOTSTRAP_PACKAGES not set" eerror return fi # # Generate set 1, just the toolchain packages. # This set will be emerge with USE="-* miminimal build bootstrap" + # the toolchain related use flags nptl, nptlonly, multilib, etc... # INCLUDES="" for pkg in ${TOOLCHAIN_PACKAGES} do INCLUDES="${INCLUDES} ${pkg}" done SET_1=`emerge -pe --nodeps ${INCLUDES} | grep '\[ebuild' | \ cut -b17- | cut -f1 -d\[` if [ $? -ne 0 ]; then eerror eerror "listToolchain() failed to determine SET_1" eerror cleanup 1 fi # # Generate set 2. Same as above, but for the PORTAGE_BOOTSTRAP_PACKAGES # INCLUDES="" for pkg in ${PORTAGE_BOOTSTRAP_PACKAGES} do INCLUDES="${INCLUDES} ${pkg}" done SET_2=`emerge -pe --nodeps ${INCLUDES} | grep '\[ebuild' | \ cut -b17- | cut -f1 -d\[` if [ $? -ne 0 ]; then eerror eerror "listToolchain() failed to determine SET_2" eerror cleanup 1 fi # # Generate set 3, which are the toolchain packages and their dependencies # in the correct order. Starting with set 3 all remaining sets # will use whatever settings are in make.conf and the other # usual portage settings methods. After this set is done, the # toolchain has been compiled against itself, the dependencies # have only been compiled against the new toolchain once. The # 2nd pass for the dependencies will be caught in SET_5 and SET_6. # SET_3="" for pkg in ${SET_1} do junk=`emerge -pe =${pkg} | grep '\[ebuild' | \ cut -b17- | cut -f1 -d\[` if [ $? -ne 0 ]; then eerror eerror "listToolchain() failed to determine SET_3" eerror cleanup 1 fi for pkg_a in ${junk} do [[ "${pkg_a}" == "${pkg}" ]] && continue for pkg_b in ${SET_1} ${SET_3} do [[ "${pkg_a}" == "${pkg_b}" ]] && continue 2 done SET_3="${SET_3} ${pkg_a}" done SET_3="${SET_3} ${pkg}" done # # Generate set 4, same as above but for PORTAGE_BOOTSTRAP_PACKAGES. # Exclude dependencies that have already by compiled by the new # toolchain for the first time in SET_3. # SET_4="" for pkg in ${SET_2} do junk=`emerge -pe =${pkg} | grep '\[ebuild' | \ cut -b17- | cut -f1 -d\[` if [ $? -ne 0 ]; then eerror eerror "listToolchain() failed to determine SET_4" eerror cleanup 1 fi for pkg_a in ${junk} do [[ "${pkg_a}" == "${pkg}" ]] && continue for pkg_b in ${SET_2} ${SET_3} ${SET_4} do [[ "${pkg_a}" == "${pkg_b}" ]] && continue 2 done SET_4="${SET_4} ${pkg_a}" done SET_4="${SET_4} ${pkg}" done # # Generate set 5, system packages minus set_1, set_2, set_3, set_4. # junk=`emerge -pe system | grep '\[ebuild' | \ cut -b17- | cut -f1 -d\[` SET_5="" if [ $? -ne 0 -o -z "${junk}" ]; then eerror eerror "listToolchain() failed to determine SET_5" eerror cleanup 1 fi for pkg_a in ${junk} do for pkg_b in ${SET_1} ${SET_2} ${SET_3} ${SET_4} ${SET_5} do [[ "${pkg_a}" == "${pkg_b}" ]] && continue 2 done SET_5="${SET_5} ${pkg_a}" done if [ -z "${junk}" -o "${junk}" == "" ]; then eerror eerror "listToolchain() generated an empty SET_5" eerror cleanup 1 fi # # Generate set 6, system packages minus set_1, set_2. # junk=`emerge -pe system | grep '\[ebuild' | \ cut -b17- | cut -f1 -d\[` SET_6="" if [ $? -ne 0 -o -z "${junk}" ]; then eerror eerror "listToolchain() failed to determine SET_6" eerror cleanup 1 fi for pkg_a in ${junk} do for pkg_b in ${SET_1} ${SET_2} ${SET_6} do [[ "${pkg_a}" == "${pkg_b}" ]] && continue 2 done SET_6="${SET_6} ${pkg_a}" done if [ -z "${SET_6}" -o "${SET_6}" == "" ]; then eerror eerror "listToolchain() generated an empty SET_6" eerror cleanup 1 fi # # Generate set 7, world packages minus set_1-5 # junk=`emerge -pe world | grep '\[ebuild' | \ cut -b17- | cut -f1 -d\[` SET_7="" if [ $? -ne 0 -o "${junk}" == "" ]; then eerror eerror "listToolchain() failed to determine SET_7" eerror cleanup 1 fi for pkg_a in ${junk} do for pkg_b in ${SET_1} ${SET_2} ${SET_3} ${SET_4} ${SET_5} ${SET_7} do [[ "${pkg_a}" == "${pkg_b}" ]] && continue 2 done SET_7="${SET_7} ${pkg_a}" done if [ -z "${SET_7}" -o "${SET_7}" == "" ]; then eerror eerror "listToolchain() generated an empty SET_7" eerror cleanup 1 fi # # Generate set 8, world packages minus set_1 # junk=`emerge -pe world | grep '\[ebuild' | \ cut -b17- | cut -f1 -d\[` SET_8="" if [ $? -ne 0 -o "${junk}" == "" ]; then eerror eerror "listToolchain() failed to determine SET_8" eerror cleanup 1 fi for pkg_a in ${junk} do for pkg_b in ${SET_1} ${SET_8} do [[ "${pkg_a}" == "${pkg_b}" ]] && continue 2 done SET_8="${SET_8} ${pkg_a}" done if [ -z "${SET_8}" -o "${SET_8}" == "" ]; then eerror eerror "listToolchain() generated an empty SET_8" eerror cleanup 1 fi echo ${SET_1} ${SET_2} ${SET_3} ${SET_4} ${SET_5} ${SET_6} \ ${SET_7} ${SET_8} ${SET_8} } ############################################################################### # Return a list of what portage sees as the world package list. # listWorld() { if [ -z "${SYSTEM_EXCLUDES}" ]; then eerror eerror "listWorld() failed, SYSTEM_EXCLUDES not set" eerror return fi # first get the list of system packages SYS_PACKAGES="`listSystemEmpty`" if [ -z "${SYS_PACKAGES}" ]; then eerror eerror "listWorld() failed, cannot query system packages" eerror return fi # Get world - toolchain EXCLUDES="" for pkg in ${SYSTEM_EXCLUDES} do EXCLUDES="${EXCLUDES}|${pkg}" done EXCLUDES="`echo ${EXCLUDES} | cut -b2-`" world=`emerge -p world | grep '\[ebuild' | \ grep -vE "${EXCLUDES}" | cut -b17- | cut -f1 -d\[` if [ $? -ne 0 ]; then eerror eerror "listWorld() failed" eerror cleanup 1 fi # Exclude system packages junk="" for pkg_a in ${world} do for pkg_b in ${SYS_PACKAGES} do [[ "${pkg_a}" == "${pkg_b}" ]] && continue 2 done junk="${junk} ${pkg_a}" done echo ${junk} } ############################################################################### # Return a list of what portage sees as the world package list. # listWorldEmpty() { if [ -z "${SYSTEM_EXCLUDES}" ]; then eerror eerror "listWorldEmpty() failed, SYSTEM_EXCLUDES not set" eerror return fi # first get the list of system packages SYS_PACKAGES="`listSystemEmpty`" if [ -z "${SYS_PACKAGES}" ]; then eerror eerror "listWorldEmpty() failed, cannot query system packages" eerror return fi # Get world - toolchain EXCLUDES="" for pkg in ${SYSTEM_EXCLUDES} do EXCLUDES="${EXCLUDES}|${pkg}" done EXCLUDES="`echo ${EXCLUDES} | cut -b2-`" world=`emerge -pe world | grep '\[ebuild' | \ grep -vE "${EXCLUDES}" | cut -b17- | cut -f1 -d\[` if [ $? -ne 0 ]; then eerror eerror "listWorldEmpty() failed" eerror cleanup 1 fi # Exclude system packages junk="" for pkg_a in ${world} do for pkg_b in ${SYS_PACKAGES} do [[ "${pkg_a}" == "${pkg_b}" ]] && continue 2 done junk="${junk} ${pkg_a}" done echo ${junk} } ############################################################################### # Return a list of what portage sees as the world package list. # listWorldUpdate() { if [ -z "${SYSTEM_EXCLUDES}" ]; then eerror eerror "listWorldUpdate() failed, SYSTEM_EXCLUDES not set" eerror return fi # first get the list of system packages SYS_PACKAGES="`listSystemEmpty`" if [ -z "${SYS_PACKAGES}" ]; then eerror eerror "listWorldUpdate() failed, cannot query system packages" eerror return fi # Get world - toolchain EXCLUDES="" for pkg in ${SYSTEM_EXCLUDES} do EXCLUDES="${EXCLUDES}|${pkg}" done EXCLUDES="`echo ${EXCLUDES} | cut -b2-`" world=`emerge -pDu world | grep '\[ebuild' | \ grep -vE "${EXCLUDES}" | cut -b17- | cut -f1 -d\[` if [ $? -ne 0 ]; then eerror eerror "listWorldUpdate() failed" eerror cleanup 1 fi # Exclude system packages junk="" for pkg_a in ${world} do for pkg_b in ${SYS_PACKAGES} do [[ "${pkg_a}" == "${pkg_b}" ]] && continue 2 done junk="${junk} ${pkg_a}" done echo ${junk} } ############################################################################### # Determine the current binutils version. Don't rely on what portage reports. # runningBinutilsVersion() { as --version | head -n 1 | cut -f3 -d' ' } ############################################################################### # Parse the current CHOST from the running binutils version. Don't rely on # what portage reports. # runningBinutilsTarget() { as --version | tail -n1 | cut -f2 -d'`' | cut -f1 -d"'" } ############################################################################### # set_step() { export STEP_NUM=$1 [[ -z ${DO_ACTUAL_RUN} ]] && return 0 echo "STEP_NUM=$1" > ${progressfile} } ############################################################################### # show_status() { local num=$1 shift echo " [[ ($num/$TOTAL_PACKAGES) $* ]]" } ############################################################################### # offer_pause() { [[ "${DO_PAUSE}" == "0" ]] && return echo einfo "Press any key within 10 seconds to pause..." read -t 10 -n 1 -s junk if [ $? -eq 0 ]; then do_pause fi } ############################################################################### # usage() { echo -e "Usage: ${HILITE}${0##*/}${NORMAL} ${GOOD}TARGET [ACTION] [OPTIONS]${NORMAL}" echo echo -e " The selected TARGET will persist until completion, to change" echo -e " the TARGET, rm /var/run/nobs*" echo echo -e " TARGETS:" #echo -e " ${GOOD}bootstrap${NORMAL} Bootstrap the system, then system, then world" echo -e " ${GOOD}toolchain${NORMAL} Rebuild the toolchain, then system, then world" echo -e " ${GOOD}system${NORMAL} emerge system, excluding toolchain packages" echo -e " ${GOOD}world${NORMAL} emerge world, excluding toolchain/system packages" echo -e " ${GOOD}universe${NORMAL} emerge system and world, excluding toolchain packages" echo echo -e " The ACTION is optional and will persist until completion, to " echo -e " change the ACTION, rm /var/run/nobs*. If no ACTION is specified," echo -e " it will default to emerge system, emerge world, etc..." echo echo -e " ACTIONS:" echo -e " ${GOOD}--emptytree (-e)${NORMAL} Rebuild all packages in TARGET (emerge -e TARGET)" echo -e " ${GOOD}--update (-u)${NORMAL} Deep update all packages in TARGET (emerge -Du TARGET)" echo echo -e " Options are not persistent, they can be changed on each run and" echo -e " only affect the current run." echo echo -e " OPTIONS:" echo echo -e " ${GOOD}--debug (-d)${NORMAL} Run with debug information turned on" echo -e " ${GOOD}--fetchonly (-f)${NORMAL} Just download all the package source files" #echo -e " ${GOOD}--gccpause (-gp)${NORMAL} Pause after any gcc merge during bootstrap/toolchain" echo -e " ${GOOD}--help (-h)${NORMAL} Display this message" echo -e " ${GOOD}--listonly (-l)${NORMAL} Just list what packages would be emerged and exit" echo -e " ${GOOD}--nopause (-np)${NORMAL} Don't ever pause" echo -e " ${GOOD}--pretend (-p)${NORMAL} Pretend run, i.e. emerge -p. No packages will actually be installed." echo -e " ${GOOD}--verbose (-v)${NORMAL} Be verbose (show packages being compiled)" echo -e " ${GOOD}--version${NORMAL} Show version and exit" } ############################################################################### # v_echo() { cmd="$@" if [ "${DO_DEBUG}" == "1" -o "${DO_VERBOSE}" == "1" ]; then eval ${cmd} else eval ${cmd} >>${logfile} 2>&1 fi } ############################################################################### ## Here is where all of the fun finally starts :) ## ############################################################################### # Trap ctrl-c and stuff. trap "cleanup" TERM KILL INT QUIT ABRT # # display banner # echo -e "\n${GOOD}Gentoo Linux; ${BRACKET}http://www.gentoo.org/${NORMAL}" echo -e "Copyright 2005 badpenguins.com; Distributed under the GPLv2; Version ${VER}" echo # # Catch major showstoppers early on... # MYPROFILEDIR=$(readlink -f /etc/make.profile) if [[ ! -d ${MYPROFILEDIR} ]] ; then eerror "Error: '${MYPROFILEDIR}' does not exist. Exiting." cleanup 1 fi [[ -e /etc/profile ]] && source /etc/profile # Bug #50158 (don't use `which` in a bootstrap). if ! type -path portageq &>/dev/null ; then draw_line eerror eerror "Your portage version is too old. Please use a newer stage1 image." eerror cleanup 1 fi # # Initialize environment settings for current run, will be overwritten # after loading the envfile. # export STEP_NUM=${STEP_NUM:-0} EMERGE_OPTS="--oneshot --nodeps" # # Determines if STEP_NUM is incremented in ${envfile} or # only in the running environment (in case of fetches or pretents). # DO_ACTUAL_RUN="1" # # 4 main targets # DO_BOOTSTRAP="0" DO_SYSTEM="0" DO_TOOLCHAIN="0" DO_WORLD="0" DO_UNIVERSE="0" # # deep update or emptytree? # DO_DEEPUPDATE="0" DO_EMPTYTREE="0" # # Special emerge options # DO_FETCHONLY="0" DO_LISTONLY="0" DO_PRETEND="0" # # pausing/debugging/verbosity # DO_PAUSE="1" #DO_GCC_PAUSE="0" DO_DEBUG="0" DO_VERBOSE="0" # # placeholder for target/action # TARGET="" ACTION="" # # Determine if this is an interrupted run by attempting to load settings # from the envfile. The defaults above will be overwritten. # if [ -e ${envfile} ]; then source ${envfile} einfo einfo "Resuming previous run using target/action from ${envfile}" einfo "To start over from scratch, rm /var/run/nobs* and re-run." einfo offer_pause fi # # Process command line args that can only be set if the ${envfile) has # not been created yet. # if [ ! -e "${envfile}" ]; then for opt in "$@" ; do case ${opt} in --emptytree|-e) if [ "${DO_DEEPUPDATE}" -ne 0 ]; then eerror "Cannot do --update and --emptytree at the same time" usage cleanup 1 fi DO_EMPTYTREE=1 ACTION="emptytree" ;; --help|-h) usage exit 0 ;; --listonly|-l) DO_LISTONLY="1" ;; --update|-u) if [ "${DO_EMPTYTREE}" -ne 0 ]; then eerror "Cannot do --update and --emptytree at the same time" usage cleanup 1 fi DO_DEEPUPDATE="1" ACTION="deep update" ;; --version) einfo "Badpenguins.com nobsmerge ${VER}" exit 0 ;; bootstrap) if [ -n "${TARGET}" ]; then eerror "Target already set: ${TARGET}" usage cleanup 1 fi DO_BOOTSTRAP="1" TARGET="bootstrap" ;; system) if [ -n "${TARGET}" ]; then eerror "Target already set: ${TARGET}" usage cleanup 1 fi DO_SYSTEM="1" TARGET="system" ;; toolchain) if [ -n "${TARGET}" ]; then eerror "Target already set: ${TARGET}" usage cleanup 1 fi DO_TOOLCHAIN="1" TARGET="toolchain" ;; universe) if [ -n "${TARGET}" ]; then eerror "Target already set: ${TARGET}" usage cleanup 1 fi DO_UNIVERSE="1" TARGET="universe" ;; world) if [ -n "${TARGET}" ]; then eerror "Target already set: ${TARGET}" usage cleanup 1 fi DO_WORLD="1" TARGET="world" ;; esac done generateEnvFile || cleanup 1 fi source "${envfile}" || cleanup 1 # # process command line args that can by changed dynamically. # for opt in "$@" ; do case ${opt} in --debug|-d) DO_DEBUG="1" ;; --fetchonly|-f) unset DO_ACTUAL_RUN DO_FETCHONLY="1" ;; #--gccpause|-gp) # DO_GCC_PAUSE="1" #;; --help|-h) usage exit 0 ;; --nopause|-np) DO_PAUSE="0" ;; --pretend|-p) DO_PRETEND="1" DO_VERBOSE="1" unset DO_ACTUAL_RUN ;; --verbose|-v) EMERGE_OPTS="${EMERGE_OPTS} -v" DO_VERBOSE="1" ;; --version) einfo "Badpenguins.com nobsmerge ${VER}" exit 0 ;; esac done # # Verify sanity of command line arguments # if [ -z "${TARGET}" ]; then eerror "You must specify bootstrap, toolchain, system, universe, or world" usage cleanup 1 fi # double check case ${TARGET} in bootstrap) : ;; toolchain) : ;; system) : ;; universe) : ;; world) : ;; *) eerror "You must specify bootstrap, toolchain, system, universe, or world" usage cleanup 1 ;; esac # # Generate EMERGE_OPTS # [[ "${DO_DEBUG}" == "1" ]] && EMERGE_OPTS="${EMERGE_OPTS} --debug" [[ "${DO_FETCHONLY}" == "1" ]] && EMERGE_OPTS="${EMERGE_OPTS} -f" [[ "${DO_PRETEND}" == "1" ]] && EMERGE_OPTS="${EMERGE_OPTS} -p" # # Track progress # [[ -e ${progressfile} ]] && source ${progressfile} # # Generate a warning if the target is bootstrap/toolchain and the # user has done --nopause and --gccpause # #if [ "${TARGET}" == "bootstrap" -o "${TARGET}" == "toolchain" ]; then # if [ "${DO_PAUSE}" == "0" -a "${DO_GCC_PAUSE}" == "1" ]; then # einfo # einfo "Warning - you have set --nopause and --gccpause." # einfo "This script WILL pause after any emerge of gcc , in spite" # einfo "of the --nopause argument." # einfo # DO_PAUSE="1" # offer_pause # DO_PAUSE="0" # fi #fi # # What to do if everything has already been done! # if [[ -n ${DO_ACTUAL_RUN} ]]; then if [ ${STEP_NUM} -ge ${TOTAL_PACKAGES} ] ; then einfo einfo "All actions complete!" einfo einfo "To start completely over, rm -f /var/run/nobs*" einfo cleanup 0 fi fi if [ ${STEP_NUM} -gt 0 ] ; then einfo "Resuming at internal stage #${STEP_NUM} ..." fi if [[ ${EMERGE_OPTS:0:2} = "-f" ]] ; then echo "Fetching all packages ..." fi # Speed things up export CLEAN_DELAY=0 export EBEEP_IGNORE=0 export EMERGE_WARNING_DELAY=0 export EPAUSE_IGNORE=0 ############################################################################### ## Here is where we get down to the real nut cuttin ## ############################################################################### rm -f ${logfile} junk=(${TOOLCHAIN_PACKAGES} ${PORTAGE_BOOTSTRAP_PACKAGES}) NUM_TOOLCHAIN_PACKAGES=${#junk[@]} PACKAGE_LIST=(${PACKAGE_LIST}) # # draw the menu displaying basic stats # draw_line echo " [[ Package Emerge Information ]]" echo einfo "Target: ${TARGET}" einfo "Action: ${ACTION}" einfo "Total Packages: ${TOTAL_PACKAGES}" einfo "Remaining Packages: $(expr ${TOTAL_PACKAGES} - ${STEP_NUM})" if [ "${DO_PAUSE}" == "1" ]; then einfo "Pausing: On" else einfo "Pausing: Off" fi if [ "${DO_FETCHONLY}" == "1" ]; then einfo "Fetch Only: Yes" else einfo "Fetch Only: No" fi if [ "${DO_PRETEND}" == "1" ]; then einfo "Pretend: Yes" else einfo "Pretend: No" fi #if [ "${DO_GCC_PAUSE}" == "1" ]; then # einfo "Pause after GCC? Yes" #else # einfo "Pause after GCC? No" #fi offer_pause if [ ${STEP_NUM} -gt 0 ]; then draw_line echo " [[ Installed Packages ]]" echo ctr=0 while [ $ctr -lt ${STEP_NUM} ]; do einfo ${PACKAGE_LIST[$ctr]} ctr=$((ctr+1)) done offer_pause fi draw_line echo " [[ Remaining Packages ]]" echo ctr=${STEP_NUM} while [ $ctr -lt ${TOTAL_PACKAGES} ] do einfo ${PACKAGE_LIST[$ctr]} ctr=$((ctr+1)) done offer_pause # # Start handling packages here, one at a time. Continue until they are # are all installed. # # Generate special emerge cmds if we are doing a toolchain target. # while [ ${STEP_NUM} -lt ${TOTAL_PACKAGES} ] do pkg=${PACKAGE_LIST[${STEP_NUM}]} echo # Tell the user whats up draw_line show_status $(expr ${STEP_NUM} + 1) Installing ${pkg} echo # # If we are doing a toolchain upgrade and it is the first pass, override # any USE flags set by the user other than what is applicable to the first # pass. This should speed toolchain updates up considerably. # if [ "${DO_TOOLCHAIN}" == "1" -a ${STEP_NUM} -lt ${NUM_TOOLCHAIN_PACKAGES} ] then cmd="AUTOCLEAN=\"yes\"" cmd="${cmd} USE=\"-* build bootstrap minimal ${FIRSTPASS_USE}\"" cmd="${cmd} FEATURES=\"-ccache -distcc noman nodoc noinfo\"" cmd="${cmd} emerge ${EMERGE_OPTS} =${pkg}" else cmd="emerge ${EMERGE_OPTS} =${pkg}" fi # # run the command # if [ -z "${cmd}" ]; then eerror eerror "Cannot determine how to handle package: ${pkg}" eerror cleanup 1 fi einfo "EMERGE: \"${EMERGE_OPTS} =${pkg}\"" if [ "${DO_DEBUG}" == "0" -a "${DO_VERBOSE}" == "0" ]; then einfo "LOG: ${logfile}" fi v_echo ${cmd} if [ $? -ne 0 ]; then eerror eerror "FAILED: ${cmd}" eerror cleanup 1 fi # # skip post-processing if we are fetching or pretending only. # if [[ -z "${DO_ACTUAL_RUN}" ]]; then set_step $((STEP_NUM+1)) continue fi # # Customize the post processing of packages here, particularly in # the case of toolchain/bootstrap. # # Any time gcc is being installed, check for gccpause. if [ "${STEP_NUM}" -lt "${NUM_TOOLCHAIN_PACKAGES}" ]; then if [ "${pkg:0:14}" == "sys-devel/gcc-" -a \ ! "${pkg:0:15}" == "sys-devel/gcc-c" ]; then # # Until the process can be consistently automated within this script, # make the user manually choose which gcc they want... # #if [ "${GCC_PAUSE}" == "1" -a -n "${DO_ACTUAL_RUN}" ]; then echo einfo "An emerge of gcc has just completed. The default behavior" einfo "is to not switch over to using upgraded versions of gcc," einfo "therefore it is next to impossible to automate the " einfo "switchover in case of gcc upgrades." einfo einfo "As a result, you must now manually switch over to the" einfo "upgraded gcc by using the gcc-config command. This is also" einfo "the time to edit make.conf to use new CFLAGS that might be" einfo "available after the gcc upgrade. After using gcc-config to" einfo "switch over to your desired version of gcc and possibly" einfo "editing your compiler options in make.conf, re-run this" einfo "script to continue." echo set_step $((STEP_NUM+1)) #do_pause #continue cleanup 0 #fi fi fi # # Everything went ok! Carry on back at the top of the loop! # set_step $((STEP_NUM+1)) done if [ -n "${DO_ACTUAL_RUN}" ]; then einfo einfo "Your emerges have completed" einfo einfo "To restart: rm /var/run/nobs*" einfo fi cleanup 0