--- /usr/bin/euse 2009-02-06 08:35:58.893794000 -0600 +++ euse 2009-02-24 16:16:27.491596733 -0600 @@ -14,6 +14,7 @@ MAKE_GLOBALS_PATH=/etc/make.globals MAKE_PROFILE_PATH=/etc/make.profile MAKE_CONF_BACKUP_PATH=/etc/make.conf.euse_backup +PACKAGE_USE_PATH=/etc/portage/package.use [ -z "${MODE}" ] && MODE="showhelp" # available operation modes: showhelp, showversion, showdesc, showflags, modify @@ -56,6 +57,10 @@ exit 1 } +warn() { + echo "WARNING: ${1}" +} + get_real_path() { set -P cd "$1" @@ -83,6 +88,7 @@ done # [ ! -r "$(get_make_defaults)" ] && error "$(get_make_defaults) is not readable" [ "${MODE}" == "modify" -a ! -w "${MAKE_CONF_PATH}" ] && error ""${MAKE_CONF_PATH}" is not writable" + [ "${MODE}" == "modify" -a -s "${PACKAGE_USE_PATH}" -a ! -w "${PACKAGE_USE_PATH}" ] && error ""${PACKAGE_USE_PATH}" is not writable" } showhelp() { @@ -148,9 +154,36 @@ print ' '.join(r)" } +# Similar to reduce_incrementals except converts lines from package atoms +# in /etc/portage/package.use files to lines of "pkg [-]flag" +reduce_package_use() { + echo "${@}" | python -c "import sys,re +h={}; getflags=re.compile(r'(-?[\w*-]+)') +for x in sys.stdin.read().split('\n'): + if not x: continue + parts = x.lstrip().split(' ',1) + if len(parts)==1: continue + pkg = parts[0] + flags = getflags.findall(parts[1]) + if not pkg in h: h[pkg]=[] + r=h[pkg] + for x in flags: + if x[0] == '-' and x[1:] in r: + r.remove(x[1:]) + r.append(x) + elif x[0] != '-' and '-'+x in r: + r.remove('-'+x) + r.append(x) + elif x == '-*': + r = h[pkg] = ['-*'] + elif x not in r: + r.append(x) +print '\n'.join([' %s %s ' % (pkg,' '.join(flgs)) for pkg,flgs in h.iteritems() if len(flgs)])" +} + # the following function creates a bash array ACTIVE_FLAGS that contains the # global use flags, indexed by origin: 0: environment, 1: make.conf, -# 2: make.defaults, 3: make.globals +# 2: make.defaults, 3: make.globals, 4: package.use get_useflags() { # only calculate once as calling emerge is painfully slow [ -n "${USE_FLAGS_CALCULATED}" ] && return @@ -175,6 +208,15 @@ USE="${ACTIVE_FLAGS[0]}" PORTDIR="${portdir_backup}" + # Parse through /etc/portage/package.use + if [[ -d ${PACKAGE_USE_PATH} ]]; then + ACTIVE_FLAGS[4]=$( find ${PACKAGE_USE_PATH} -type f | xargs cat ) + elif [[ -e ${PACKAGE_USE_PATH} ]]; then + ACTIVE_FLAGS[4]=$( cat ${PACKAGE_USE_PATH} ) + fi + # Simplify ACTIVE_FLAGS[4] to be lines of pkg [-]flag + ACTIVE_FLAGS[4]=$(reduce_package_use "${ACTIVE_FLAGS[4]}"); + # get the currently active USE flags as seen by portage, this has to be after # restoring USE or portage won't see the original environment ACTIVE_FLAGS[9]="$(emerge --info | grep 'USE=' | cut -b 5- | sed -e 's:"::g')" #' @@ -239,13 +281,16 @@ # 3: echo value for positive (and as lowercase for negative) test result, # 4 (optional): echo value for "missing" test result, defaults to blank get_flagstatus_helper() { - if echo " ${ACTIVE_FLAGS[${2}]} " | grep " ${1} " > /dev/null; then + if echo " ${ACTIVE_FLAGS[${2}]} " | grep " ${1} " | grep "${5} " > /dev/null; then echo -n "${3}" - elif echo " ${ACTIVE_FLAGS[${2}]} " | grep " -${1} " > /dev/null; then - echo -n "$(echo ${3} | tr [[:upper:]] [[:lower:]])" + return 0 + elif echo " ${ACTIVE_FLAGS[${2}]} " | grep " -${1} " | grep "${5} " > /dev/null; then + echo -n "$(echo ${3} | tr [:upper:]+ [:lower:]-)" + return 0 else echo -n "${4:- }" fi + return 1 } # prints a status string for the given flag, each column indicating the presence @@ -256,7 +301,14 @@ get_useflags echo -n '[' - get_flagstatus_helper "${1}" 9 "+" "-" + if [ "${SCOPE}" == "local" ]; then + if ! get_flagstatus_helper "${1}" 4 "+" "-" "${2}" ; then + echo -n -e "\b" + get_flagstatus_helper "${1}" 9 "+" "-" + fi + else + get_flagstatus_helper "${1}" 9 "+" "-" + fi get_flagstatus_helper "${1}" 0 "E" get_flagstatus_helper "${1}" 1 "C" get_flagstatus_helper "${1}" 2 "D" @@ -328,7 +380,7 @@ pkg="$(echo $line | cut -d\| -f 1)" flag="$(echo $line | cut -d\| -f 2)" desc="$(echo $line | cut -d\| -f 3)" - get_flagstatus "${flag}" + get_flagstatus "${flag}" "${pkg}" printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc}" done fi @@ -397,7 +449,7 @@ # exit status of equery instead of a subshell and pipe to wc -l if [ $(equery -q -C list -i -e "${pkg}" | wc -l) -gt 0 ]; then foundone=1 - get_flagstatus "${flag}" + get_flagstatus "${flag}" "${pkg}" printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc#- }" fi done < <(grep ":${1} *-" "${descdir}/use.local.desc") @@ -431,6 +483,14 @@ get_flagstatus ${1} echo fi + if echo " ${ACTIVE_FLAGS[4]} " | egrep -e " -?${1} " > /dev/null; then + for pkg in $( echo "${ACTIVE_FLAGS[4]}" | \ + egrep " -?${1} " | cut -d " " -f 2); do + printf "%-20s" ${1} + SCOPE="local" get_flagstatus ${1} "${pkg}" + printf "(%s)\n" ${pkg} + done; + fi shift done } @@ -444,9 +504,102 @@ NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE// ${1} / }" } +modify_package() { + get_useflags + + local flag=${1} + local pkg=${2} + local content + # + # --- Sanity checks + # (1) make sure ${pkg} exists in portdir + if [[ ! -d "$(get_portdir)/${pkg}" ]]; then + error "Package ""${pkg}"" does not exist" + # + # (2) make sure ${flag} is defined in get_useflaglist + elif [[ ! -n $(echo " $(get_useflaglist) " | grep "${flag}") ]]; then + warn "USE flag ""${flag}"" does not exist" + # Don't bail just because of this, just warn + fi; + # + # If flag is enabled in portage USE flags (emerge --info), + # then "remove"ing the flag should be replaced with adding + # the negative flag instead + if [[ "${ACTION}" == "remove" && -n $( echo " ${ACTIVE_FLAGS[9]} " | \ + grep " ${flag} " ) ]]; then + ACTION="add" + flag="-${flag}" + fi; + case "${ACTION}" in + "add") + local filename + if [[ -d ${PACKAGE_USE_PATH} ]]; then + # Use naming convention of package.use/package + filename="${PACKAGE_USE_PATH}/${pkg#*/}" + if [[ ! -s "${filename}" ]]; then + # Create new file to contain flag + echo "${pkg} ${flag}" > ${filename} + echo "Adding ""${pkg}:${flag}"" use flag to new file ""${filename}""" + return + fi; + else + # Add to package.use file instead + filename=${PACKAGE_USE_PATH} + # Create as necessary + touch "${filename}" + fi; + local flags=$( grep "${pkg} " "${filename}" || echo "${pkg} ") + flags=$( reduce_package_use "${flags} ${flag}" ) + # Remove current flags of app in file and add + # new line which include the addition of the new flag + echo "Enabling ""${pkg}:${flag}"" use flag in ""${filename}""" + content=$(cat "${filename}" | grep -v "${pkg} " | sort) + echo -n "${content}" > "${filename}" + echo -n "${flags}" | cut -d " " -f 2- >> "${filename}" + ;; + "remove") + local filename + if [[ -d ${PACKAGE_USE_PATH} ]]; then + # Scan for file containing named package and use flag + filename=$( egrep -rle "${pkg}.*[^-]${flag}( |$)" "${PACKAGE_USE_PATH}") + if [[ -z "${filename}" ]]; then + error ""${flag}" is not defined for package "${pkg}"" + return + fi; + else + # Remove from package.use instead + filename=${PACKAGE_USE_PATH} + # Create as necessary + touch "${filename}" + fi; + # Remove flag from line of file containing package + local flags=$( grep "${pkg} " "${filename}" | sed "s/ ${flag}//") + flags=$( reduce_package_use ${flags} ) + # Remove current flags of app in file and add + # new line which include the addition of the new flag + echo "Disabling ""${pkg}:${flag}"" use flag in ""${filename}""" + content=$(cat "${filename}" | grep -v "${pkg} " | sort) + echo -n "${content}" > "${filename}" + echo -n "${flags}" | cut -d " " -f 2- >> "${filename}" + # Remove empty files + if [[ -d ${PACKAGE_USE_PATH} ]]; then + for f in $(find ${PACKAGE_USE_PATH} -size 0); do + echo "Removing empty file ""${f}""" + rm ${f} + done; + fi;; + esac; +} + # USE flag modification function. Mainly a loop with calls to add_flag and # remove_flag to create a new USE string which is then inserted into make.conf. modify() { + if [ -n "${2}" ]; then + # Add flag to specified package + modify_package "${@}" + return + fi; + if [ -z "${*}" ]; then if [ "${ACTION}" != "prune" ]; then echo "WARNING: no USE flags listed for modification, do you really"