aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'gentoolkit/bin/euse')
-rwxr-xr-xgentoolkit/bin/euse551
1 files changed, 551 insertions, 0 deletions
diff --git a/gentoolkit/bin/euse b/gentoolkit/bin/euse
new file mode 100755
index 0000000..80e488b
--- /dev/null
+++ b/gentoolkit/bin/euse
@@ -0,0 +1,551 @@
+#!/bin/bash
+
+# $Header$
+
+# bash replacement for the original euse by Arun Bhanu
+# Author: Marius Mauch <genone@gentoo.org>
+# Licensed under the GPL v2
+
+PROGRAM_NAME=euse
+VERSION="svn"
+
+MAKE_CONF_PATH=/etc/make.conf
+MAKE_GLOBALS_PATH=/etc/make.globals
+MAKE_PROFILE_PATH=/etc/make.profile
+MAKE_CONF_BACKUP_PATH=/etc/make.conf.euse_backup
+
+[ -z "${MODE}" ] && MODE="showhelp" # available operation modes: showhelp, showversion, showdesc, showflags, modify
+
+parse_arguments() {
+ if [ -z "${1}" ]; then
+ return
+ fi
+ while [ -n "${1}" ]; do
+ case "${1}" in
+ -h | --help) MODE="showhelp";;
+ -V | -v | --version) MODE="showversion";;
+ -i | --info) MODE="showdesc";;
+ -I | --info-installed) MODE="showinstdesc";;
+ -l | --local) SCOPE="local";;
+ -g | --global) SCOPE="global";;
+ -a | --active) MODE="showflags";;
+ -E | --enable) MODE="modify"; ACTION="add";;
+ -D | --disable) MODE="modify"; ACTION="remove";;
+ -P | --prune) MODE="modify"; ACTION="prune";;
+ -*)
+ echo "ERROR: unknown option ${1} specified."
+ echo
+ MODE="showhelp"
+ ;;
+ "%active")
+ get_useflags
+ ARGUMENTS="${ARGUMENTS} ${ACTIVE_FLAGS[9]}"
+ ;;
+ *)
+ ARGUMENTS="${ARGUMENTS} ${1}"
+ ;;
+ esac
+ shift
+ done
+}
+
+error() {
+ echo "ERROR: ${1}"
+ set +f
+ exit 1
+}
+
+get_real_path() {
+ set -P
+ cd "$1"
+ pwd
+ cd "$OLDPWD"
+ set +P
+}
+
+check_sanity() {
+ # file permission tests
+ local descdir
+ local make_defaults
+
+ descdir="$(get_portdir)/profiles"
+
+ [ ! -r "${MAKE_CONF_PATH}" ] && error "${MAKE_CONF_PATH} is not readable"
+ [ ! -r "${MAKE_GLOBALS_PATH}" ] && error "${MAKE_GLOBALS_PATH} is not readable"
+ [ ! -h "${MAKE_PROFILE_PATH}" ] && error "${MAKE_PROFILE_PATH} is not a symlink"
+ [ -z "$(get_portdir)" ] && error "\$PORTDIR couldn't be determined"
+ [ ! -d "${descdir}" ] && error "${descdir} does not exist or is not a directory"
+ [ ! -r "${descdir}/use.desc" ] && error "${descdir}/use.desc is not readable"
+ [ ! -r "${descdir}/use.local.desc" ] && error "${descdir}/use.local.desc is not readable"
+ for make_defaults in $(get_all_make_defaults); do
+ [ ! -r "$make_defaults" ] && error "$_make_defaults is not readable"
+ 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"
+}
+
+showhelp() {
+cat << HELP
+${PROGRAM_NAME} (${VERSION})
+
+Syntax: ${PROGRAM_NAME} <option> [suboptions] [useflaglist]
+
+Options: -h, --help - show this message
+ -V, --version - show version information
+ -i, --info - show descriptions for the given useflags
+ -I, --info-installed - show descriptions for the given useflags and
+ their current impact on the installed system
+ -g, --global - show only global use flags (suboption)
+ -l, --local - show only local use flags (suboption)
+ -a, --active - show currently active useflags and their origin
+ -E, --enable - enable the given useflags
+ -D, --disable - disable the given useflags
+ -P, --prune - remove all references to the given flags from
+ make.conf to revert to default settings
+
+Notes: ${PROGRAM_NAME} currently only works for global flags defined
+ in make.globals, make.defaults or make.conf, it doesn't handle
+ use.defaults, use.mask or package.use yet (see portage(5) for details on
+ these files). It also might have issues with cascaded profiles.
+ If multiple options are specified only the last one will be used.
+HELP
+}
+
+showversion() {
+cat << VER
+${PROGRAM_NAME} (${VERSION})
+Written by Marius Mauch
+
+Copyright (C) 2004-2010 Gentoo Foundation, Inc.
+This is free software; see the source for copying conditions.
+VER
+}
+
+# remove duplicate flags from the given list in both positive and negative forms
+# (but unlike portage always keep the last value even if it's negative)
+# Otherwise the status flags could be incorrect if a flag appers multiple times in
+# one location (like make.conf).
+# Using python here as bash sucks for list handling.
+# NOTE: bash isn't actually that bad at handling lists -- sh is. This may be
+# worth another look to avoid calling python unnecessariy. Or we could
+# just write the whole thing in python. ;)
+reduce_incrementals() {
+ echo $@ | python -c "import sys
+r=[]
+for x in sys.stdin.read().split():
+ 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 = []
+ r.append(x)
+ elif x not in r:
+ r.append(x)
+print ' '.join(r)"
+}
+
+# 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
+get_useflags() {
+ # only calculate once as calling emerge is painfully slow
+ [ -n "${USE_FLAGS_CALCULATED}" ] && return
+
+ # backup portdir so get_portdir() doesn't give false results later
+ portdir_backup="${PORTDIR}"
+
+ ACTIVE_FLAGS[0]="$(reduce_incrementals ${USE})"
+ USE=""
+ source "${MAKE_CONF_PATH}"
+ ACTIVE_FLAGS[1]="$(reduce_incrementals ${USE})"
+ USE=""
+ for x in $(get_all_make_defaults); do
+ source "${x}"
+ ACTIVE_FLAGS[2]="$(reduce_incrementals ${ACTIVE_FLAGS[2]} ${USE})"
+ done
+ USE=""
+ source "${MAKE_GLOBALS_PATH}"
+ ACTIVE_FLAGS[3]="$(reduce_incrementals ${USE})"
+
+ # restore saved env variables
+ USE="${ACTIVE_FLAGS[0]}"
+ PORTDIR="${portdir_backup}"
+
+ # 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')" #'
+ USE_FLAGS_CALCULATED=1
+}
+
+# get the list of all known USE flags by reading use.desc and/or use.local.desc
+# (depending on the value of $SCOPE)
+get_useflaglist() {
+ local descdir
+
+ descdir="$(get_portdir)/profiles"
+
+ if [ -z "${SCOPE}" -o "${SCOPE}" == "global" ]; then
+ egrep "^[^# ]+ +-" "${descdir}/use.desc" | cut -d\ -f 1
+ fi
+ if [ -z "${SCOPE}" -o "${SCOPE}" == "local" ]; then
+ egrep "^[^# :]+:[^ ]+ +-" "${descdir}/use.local.desc" | cut -d: -f 2 | cut -d\ -f 1
+ fi
+}
+
+# get all make.defaults by traversing the cascaded profile directories
+get_all_make_defaults() {
+ local curdir
+ local parent
+ local rvalue
+
+ curdir="${1:-$(get_real_path ${MAKE_PROFILE_PATH})}"
+
+ [ -f "${curdir}/make.defaults" ] && rvalue="${curdir}/make.defaults ${rvalue}"
+ if [ -f "${curdir}/parent" ]; then
+ for parent in $(egrep -v '(^#|^ *$)' ${curdir}/parent); do
+ pdir="$(get_real_path ${curdir}/${parent})"
+ rvalue="$(get_all_make_defaults ${pdir}) ${rvalue}"
+ done
+ fi
+
+ echo "${rvalue}"
+}
+
+# get the path to make.defaults by traversing the cascaded profile directories
+get_make_defaults() {
+ local curdir
+ local parent
+
+ curdir="${1:-$(get_real_path ${MAKE_PROFILE_PATH})}"
+
+ if [ ! -f "${curdir}/make.defaults" -a -f "${curdir}/parent" ]; then
+ for parent in $(egrep -v '(^#|^ *$)' ${curdir}/parent); do
+ if [ -f "$(get_make_defaults ${curdir}/${parent})" ]; then
+ curdir="${curdir}/${parent}"
+ break
+ fi
+ done
+ fi
+
+ echo "${curdir}/make.defaults"
+}
+
+# little helper function to get the status of a given flag in one of the
+# ACTIVE_FLAGS elements. Arguments are 1: flag to test, 2: index of ACTIVE_FLAGS,
+# 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
+ echo -n "${3}"
+ elif echo " ${ACTIVE_FLAGS[${2}]} " | grep " -${1} " > /dev/null; then
+ echo -n "$(echo ${3} | tr [[:upper:]] [[:lower:]])"
+ else
+ echo -n "${4:- }"
+ fi
+}
+
+# prints a status string for the given flag, each column indicating the presence
+# for portage, in the environment, in make.conf, in make.defaults and in make.globals.
+# full positive value would be "[+ECDG]", full negative value would be [-ecdg],
+# full missing value would be "[- ]" (portage only sees present or not present)
+get_flagstatus() {
+ get_useflags
+
+ echo -n '['
+ get_flagstatus_helper "${1}" 9 "+" "-"
+ get_flagstatus_helper "${1}" 0 "E"
+ get_flagstatus_helper "${1}" 1 "C"
+ get_flagstatus_helper "${1}" 2 "D"
+ get_flagstatus_helper "${1}" 3 "G"
+ echo -n '] '
+}
+
+# faster replacement to `portageq portdir`
+get_portdir() {
+ if [ -z "${PORTDIR}" ]; then
+ use_backup="${USE}"
+ source "${MAKE_GLOBALS_PATH}"
+ for x in $(get_all_make_defaults); do
+ source "${x}"
+ done
+ source "${MAKE_CONF_PATH}"
+ USE="${use_backup}"
+ fi
+ echo "${PORTDIR}"
+}
+
+# This function takes a list of use flags and shows the status and
+# the description for each one, honoring $SCOPE
+showdesc() {
+ local descdir
+ local current_desc
+ local found_one
+ local args
+
+ args="${*:-*}"
+
+ if [ -z "${SCOPE}" ]; then
+ SCOPE="global" showdesc ${args}
+ echo
+ SCOPE="local" showdesc ${args}
+ return
+ fi
+
+ descdir="$(get_portdir)/profiles"
+
+ [ "${SCOPE}" == "global" ] && echo "global use flags (searching: ${args})"
+ [ "${SCOPE}" == "local" ] && echo "local use flags (searching: ${args})"
+ echo "************************************************************"
+
+ if [ "${args}" == "*" ]; then
+ args="$(get_useflaglist | sort -u)"
+ fi
+
+ set ${args}
+
+ foundone=0
+ while [ -n "${1}" ]; do
+ if [ "${SCOPE}" == "global" ]; then
+ if grep "^${1} *-" "${descdir}/use.desc" > /dev/null; then
+ get_flagstatus "${1}"
+ foundone=1
+ fi
+ grep "^${1} *-" "${descdir}/use.desc"
+ fi
+ # local flags are a bit more complicated as there can be multiple
+ # entries per flag and we can't pipe into printf
+ if [ "${SCOPE}" == "local" ]; then
+ if grep ":${1} *-" "${descdir}/use.local.desc" > /dev/null; then
+ foundone=1
+ fi
+ grep ":${1} *-" "${descdir}/use.local.desc" \
+ | sed -e "s/^\([^:]\+\):\(${1}\) *- *\(.\+\)/\1|\2|\3/g" \
+ | while read line; do
+ pkg="$(echo $line | cut -d\| -f 1)"
+ flag="$(echo $line | cut -d\| -f 2)"
+ desc="$(echo $line | cut -d\| -f 3)"
+ get_flagstatus "${flag}"
+ printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc}"
+ done
+ fi
+ shift
+ done
+
+ if [ ${foundone} == 0 ]; then
+ echo "no matching entries found"
+ fi
+}
+
+# Works like showdesc() but displays only descriptions of which the appropriate
+# ebuild is installed and prints the name of those packages.
+showinstdesc() {
+ local descdir
+ local current_desc
+ local args
+ local -i foundone=0
+ local OIFS="$IFS"
+
+ args=("${@:-*}")
+
+ case "${SCOPE}" in
+ "global") echo "global use flags (searching: ${args})";;
+ "local") echo "local use flags (searching: ${args})";;
+ *) SCOPE="global" showinstdesc "${args[@]}"
+ echo
+ SCOPE="local" showinstdesc "${args[@]}"
+ return;;
+ esac
+
+ descdir="$(get_portdir)/profiles"
+ echo "************************************************************"
+
+ if [ "${args}" = "*" ]; then
+ args="$(get_useflaglist | sort -u)"
+ fi
+
+ set "${args[@]}"
+
+ while [ -n "${1}" ]; do
+ case "${SCOPE}" in
+ "global")
+ if desc=$(grep "^${1} *-" "${descdir}/use.desc"); then
+ get_flagstatus "${1}"
+ echo "$desc"
+ # get list of installed packages matching this USE flag.
+ IFS=$'\n'
+ packages=($(equery -q -C hasuse -i "${1}" | awk '{ print $(NF-1) }' | sort))
+ foundone+=${#packages[@]}
+ printf "\nInstalled packages matching this USE flag: "
+ if [ ${foundone} -gt 0 ]; then
+ echo $'\n'"${packages[*]}"
+ else
+ echo "none"
+ fi
+ fi
+ ;;
+ "local")
+ # local flags are a bit more complicated as there can be multiple
+ # entries per flag and we can't pipe into printf
+ IFS=': ' # Use a space instead of a dash because dashes occur in cat/pkg
+ while read pkg flag desc; do
+ # print name only if package is installed
+ # NOTE: If we implement bug #114086 's enhancement we can just use the
+ # 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
+ IFS="$OIFS"
+ get_flagstatus "${flag}"
+ IFS=': '
+ printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc#- }"
+ fi
+ done < <(grep ":${1} *-" "${descdir}/use.local.desc")
+ ;;
+ esac
+ shift
+ done
+
+ if [ ${foundone} -lt 1 ]; then
+ echo "no matching entries found"
+ fi
+ IFS="$OIFS"
+}
+
+# show a list of all currently active flags and where they are activated
+showflags() {
+ local args
+
+ get_useflags
+
+ args="${*:-*}"
+
+ if [ "${args}" == "*" ]; then
+ args="$(get_useflaglist | sort -u)"
+ fi
+
+ set ${args}
+
+ while [ -n "${1}" ]; do
+ if echo " ${ACTIVE_FLAGS[9]} " | grep " ${1} " > /dev/null; then
+ printf "%-20s" ${1}
+ get_flagstatus ${1}
+ echo
+ fi
+ shift
+ done
+}
+
+# two small helpers to add or remove a flag from a USE string
+add_flag() {
+ NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE} ${1}"
+}
+
+remove_flag() {
+ NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE// ${1} / }"
+}
+
+# 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 [ -z "${*}" ]; then
+ if [ "${ACTION}" != "prune" ]; then
+ echo "WARNING: no USE flags listed for modification, do you really"
+ echo " want to ${ACTION} *all* known USE flags?"
+ echo " If you don't please press Ctrl-C NOW!!!"
+ sleep 5
+ set $(get_useflaglist | sort -u)
+ fi
+ fi
+
+ get_useflags
+
+ NEW_MAKE_CONF_USE=" ${ACTIVE_FLAGS[1]} "
+
+ while [ -n "${1}" ]; do
+ if [ "${ACTION}" == "add" ]; then
+ if echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
+ shift
+ elif echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
+ remove_flag "-${1}"
+ else
+ add_flag "${1}"
+ shift
+ fi
+ elif [ "${ACTION}" == "remove" ]; then
+ if echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
+ shift
+ elif echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
+ remove_flag "${1}"
+ else
+ add_flag "-${1}"
+ shift
+ fi
+ elif [ "${ACTION}" == "prune" ]; then
+ if echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
+ remove_flag "${1}"
+ elif echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
+ remove_flag "-${1}"
+ fi
+ shift
+ fi
+ done
+
+ #echo "old flags:"
+ #echo ${ACTIVE_FLAGS[1]}
+ #echo
+ #echo "new flags:"
+ #echo ${NEW_MAKE_CONF_USE}
+
+ # a little loop to add linebreaks so we don't end with one ultra-long line
+ NEW_MAKE_CONF_USE_2=""
+ for x in ${NEW_MAKE_CONF_USE}; do
+ if [ $(((${#NEW_MAKE_CONF_USE_2}%70)+${#x}+2)) -gt 70 ]; then
+ NEW_MAKE_CONF_USE_2="${NEW_MAKE_CONF_USE_2}\\ \\n $x "
+ else
+ NEW_MAKE_CONF_USE_2="${NEW_MAKE_CONF_USE_2}${x} "
+ fi
+ done
+
+ # make a backup just in case the user doesn't like the new make.conf
+ cp -p "${MAKE_CONF_PATH}" "${MAKE_CONF_BACKUP_PATH}"
+
+ # as sed doesn't really work with multi-line patterns we have to replace USE
+ # on our own here. Basically just skip everything between USE=" and the
+ # closing ", printing our new USE line there instead.
+ inuse=0
+ had_use=0
+ x=0
+ (while [ "$x" -eq "0" ]; do
+ read -r line
+ x="$?"
+ [[ "${x}" -ne "0" ]] && break
+ [ "${line:0:4}" == "USE=" ] && inuse=1
+ [ "${inuse}" == "0" ] && echo -E "${line}"
+ if [ "${inuse}" == "1" ] && echo "${line}" | egrep '" *(#.*)?$' > /dev/null; then
+ echo -n 'USE="'
+ echo -ne "${NEW_MAKE_CONF_USE_2%% }"
+ echo '"'
+ inuse=0
+ had_use=1
+ fi
+ done
+ if [ ${had_use} -eq 0 ]; then
+ echo -n 'USE="'
+ echo -ne "${NEW_MAKE_CONF_USE_2%% }"
+ echo '"'
+ fi ) < "${MAKE_CONF_BACKUP_PATH}" | sed -e 's:\\ $:\\:' > "${MAKE_CONF_PATH}"
+
+ echo "${MAKE_CONF_PATH} was modified, a backup copy has been placed at ${MAKE_CONF_BACKUP_PATH}"
+}
+
+##### main program comes now #####
+
+# disable globbing as it fucks up with args=*
+set -f
+parse_arguments "$@"
+check_sanity
+
+eval ${MODE} ${ARGUMENTS}
+set +f