TIP_Speeding_up_portage_with_tmpfs
| Terminals / Shells • Network • X Window System • Portage • System • Filesystems • Kernel • Other |
Contents |
Introduction
Compiling from source takes a long time. Tweaking around let me compile xorg-x11 (-minimal!) within about 15 minutes on 1800+ AMD CPU
How is that possible?
When emerging a package, Portage creates many temporary files in ${PORTAGE_TMPDIR} (default: /var/tmp) and transfers a lot of temporary data to/from the filesystem. With a tmpfs mounted on ${PORTAGE_TMPDIR}, the temporary data is kept in RAM, which is much faster than the hard disk. This speeds up the compilation, avoids hard disk fragmentation and avoids hard disk wearing.
Requirements
One should have at least 512 MB RAM to emerge a Desktop Environment like KDE or GNOME. Some especially troublesome packages such as Firefox require even more memory.
Kernel support for tmpfs is also required.
File systems -> Pseudo filesystems -> Virtual memory file system support (former shm fs)
tmpfs size requirements
If you have a swap partition activated, then your system will fallback to the the swap space when RAM memory is filled up. A cap of about 900 MB mounted tmpfs ("MEMSIZE=900") should suffice for most builds.
A 300 MB tmpfs is not enough to compile:
450 MB is not enough to compile:
500 MB is enough for:
Compiling www-client/mozilla-firefox-3.0 with no USE flags enabled and an empty LINGUAS variable took 662 MiB.
850 MB is not enough to compile:
850 MB is enough for:
Compiling sys-devel/gcc-4.3.1-r1 with USE flags fortran gcj gtk mudflap openmp enabled took 1606 MiB
Greater than 1.5 mounted GB is needed for wxGTK. You may also need to adjust the number of inodes.
It is possible to compile KDE in 350 MB if you compile X11 and QT seperately.
openoffice needs a lot of memory, and at least with 3.4G mounted, 2G physical, its 10 min slower than without tmpfs.
With big applications there is also problem with number of inodes. One inode = one file and source code have big number of small files. For big applications you must increase number of inodes.
Set-up
As root, run this:
| Code: mounting tmpfs |
for 50% of your RAM: mount -t tmpfs tmpfs /var/tmp/portage for about 850 MB of your RAM and one million inodes: mount -t tmpfs tmpfs -o size=850M,nr_inodes=1M /var/tmp/portage |
Check if it's mounted with
df -h | grep tmpfs
You can also mount tmpfs at boot by adding this to /etc/fstab :
none /var/tmp/portage tmpfs size=1000M,nr_inodes=1M 0 0
You can use bigger size, if you have big swap. On my machine I have 5 GB of swap, one 1 GB tmpfs mounted in /var/tmp/portage and 3 GB in /tmp. Tmpfs swapping is very fast.
Testing
Well, emerge something!
# emerge xorg-x11
Use genlop to check whether it's faster or not.
| Code: Example (from my 1400 centrino celeron) |
tmpfs:??? USE="=???" emerge genlop -n genlop -t xorg-x11 * x11-base/xorg-x11 Wed Apr 6 17:33:07 2005 >>> x11-base/xorg-x11-6.8.2-r1 merge time: 7 minutes and 9 seconds. |
| Code: Example (from a 2400 Athlon XP) |
tmpfs: 1024M
USE="-3dfx -3dnow +bitmap-fonts -cjk -debug -dlloader -dmx -doc -font-server -insecure-drivers \
+ipv6 -minimal -mmx +nls -nocxx +opengl +pam -sdk -sse -static +truetype-fonts \
+type1-fonts (-uclibc) -xprint +xv"
emerge genlop -n
genlop -t xorg-x11
* x11-base/xorg-x11
Fri Feb 10 10:45:02 2006 >>> x11-base/xorg-x11-6.8.2-r6
merge time: 35 minutes and 19 seconds.
|
Script
A small script that mounts tmpfs for you. Go to any binary-dir on your $PATH, like /usr/local/bin, and create temerge with your $EDITOR.
FIXME: setuping the /etc/fstab file correctly could be easier (someone please fill in the details)
| File: temerge |
#!/bin/bash
MEMSIZE=850M
mounted=false
. /etc/init.d/functions.sh
mounttmpfs() {
mount -t tmpfs tmpfs -o size=$MEMSIZE /var/tmp/portage
mounted="true"
}
compile() {
einfo "emerging ${*}"
emerge ${*}
}
unmount() {
ebegin "unmounting tmpfs"
umount -f /var/tmp/portage
eend $?
}
ebegin "Mounting $MEMSIZE of memory to /var/tmp/portage"
if [ -z "$(mount | grep /var/tmp/portage)" ]
then
mounttmpfs
else
eerror "tmpfs already mounted!"
exit 0
fi
eend $?
compile ${*}
if [ -n "$mounted" ]
then
unmount
fi
|
chmod u+x temerge and use temerge instead of emerge for emerging. Use emerge for fetching/pretending.
Adding bash completion
If you are accustomed to using bash completion with emerge (highly recommended), you may quickly find yourself getting annoyed that temerge doesn't have it. I managed to accomplish this (in a somewhat hackish manner) by modifying /usr/share/bash-completion/gentoo in order to create a bash completion for temerge.
| Code: Create our temerge completion script |
# If you put temerge in /usr/local/bin (as recommended above), then # the following directory is a good place for our completion script mkdir -p /usr/local/share/bash-completion $EDITOR /usr/local/share/bash-completion/temerge |
| File: /usr/local/share/bash-completion/temerge |
# Gentoo Linux Bash Shell Command Completion
#
# $Id: gentoo 57 2005-05-16 06:50:02Z ka0ttic $
#
# Copyright 1999-2005 Gentoo Foundation
# Distributed under the terms of the GNU General Public License, v2 or later
# also defined in bash_completion proper however, will produce command
# not found warnings when this is only enabled "locally" so we define it
# here as well.
have()
{
unset -v have
PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin type $1 >&/dev/null && have="yes"
}
#
# Retrieve PORTDIR/PORTDIR_OVERLAY location from user's make.conf or, if it
# is not defined there, from make.globals.
#
_portdir()
{
sed -n -e '/^PORTDIR=/ { s/^[^=]\+="\?\([^"]\+\|\S\+\).*/\1/p ; q }' \
/etc/make.{conf,globals} 2>/dev/null
if [[ $1 == '-o' ]] ; then
sed -n -e '/^PORTDIR_OVERLAY=/ { s/^[^=]\+="\?\([^"]\+\|\S\+\).*/\1/p ; q }' \
/etc/make.conf 2>/dev/null
fi
}
# like _pkgname but completes on package names only (no category)
_pkgname_only()
{
local i pd
local cur="$1"
shift
local dir="$@"
COMPREPLY=($(compgen -W "$(\
for pd in $dir ; do \
builtin cd ${pd}; \
for i in *-*/${cur}*; do \
[[ -d ${i} ]] && { local x=${i##*/} ; echo ${x%-[0-9]*}; } \
done ; \
done)" -- ${cur}))
}
#
# This function completes package names.
#
# usage: pkgname <mode> <current-directory>
#
# Where mode is one of:
# -A Search all available packages (except for those in the overlays)
# -I Only search the installed packages
#
# TODO: Look at breaking this function out and making it a "universal"
# category/package name completion function.
#
_pkgname()
{
local mode cur portdir only
mode="$1"
cur="$2"
portdir=$(_portdir -o)
# Ignore '=' at the beginning of the current completion
[[ ${cur:1:1} == "=" ]] && cur=${cur:2}
[[ ${cur:0:1} == "=" ]] && cur=${cur:1}
case $mode in
-I)
# Complete either the category or the complete package name
if [[ $cur == */* ]]; then
COMPREPLY=($(builtin cd /var/db/pkg; compgen -W "$(compgen -G "$cur*" )" -- $cur))
else
COMPREPLY=($(builtin cd /var/db/pkg; compgen -W "$(compgen -G "$cur*" -S /)" -- $cur))
fi
# We may just have finished completing the category.
# Make sure there isn't anything more to complete now.
if [[ ${#COMPREPLY[@]} == 1 ]]; then
COMPREPLY=($(builtin cd /var/db/pkg; compgen -W "$(compgen -G "$COMPREPLY*")" -- $cur))
fi
if [[ -z "${COMPREPLY}" ]] ; then
only=1
_pkgname_only ${cur} /var/db/pkg
fi
;;
-A)
# Complete either the category or the complete package name
if [[ $cur == */* ]]; then
# Once the category has been completed, it's safe to use ${portdir}
# to continue completion.
COMPREPLY=($(\
for pd in ${portdir} ; do \
builtin cd ${pd}; \
compgen -W "$(compgen -G "${cur}*")" -- "${cur}" ; \
done))
# When we've completed most of the name, also display the version for
# possible completion.
if [[ ${#COMPREPLY[@]} -le 1 || ${cur:${#cur}-1:1} == "-" ]] &&
[[ ${cur} != */ ]]; then
# The portage cache is appropriate to complete specific versions from.
COMPREPLY=(${COMPREPLY[@]} $(\
for pd in ${portdir} ; do \
if [[ -d ${pd}/metadata/cache ]] ; then \
builtin cd ${pd}/metadata/cache; \
compgen -W "$(compgen -G "${cur}*")" -- "${cur}" ; \
fi ; \
done))
fi
else
COMPREPLY=( $(compgen -W "$(\
for pd in ${portdir} ; do \
if [[ -d ${pd}/metadata/cache ]] ; then
builtin cd ${pd}/metadata/cache; \
compgen -G "$cur*" -S / ; \
fi ; \
done)" -- $cur) )
if [[ ${#COMPREPLY[@]} == 1 ]]; then
COMPREPLY=($(compgen -W "$(\
for pd in ${portdir} ; do \
if [[ -d ${pd}/metadata/cache ]] ; then
builtin cd ${pd}/metadata/cache; \
compgen -G "$COMPREPLY*" ; \
fi ; \
done)" -- $cur))
fi
fi
if [[ -z "${COMPREPLY}" ]] ; then
only=1
_pkgname_only ${cur} ${portdir}
fi
;;
*)
# Somebody screwed up! :-)
;;
esac
# 'equery' wants an '=' in front of specific package versions.
# Add it if there is only one selected package and it isn't there already.
if [[ ${#COMPREPLY[@]} == 1 && ${COMP_WORDS[COMP_CWORD]:0:1} != "=" ]]
then
[[ -z "${only}" ]] && COMPREPLY=("="$COMPREPLY)
fi
}
#
# This is an helper function for completion of "-o <list>" / "--option=<list>"
# kind of command lines options.
#
# Usage: _list_compgen <current> <sep> <item1>[<sep><item2> ...]
# - <current>: what we have so far on the command line
# - <sep>: the separator character used in lists
# - <itemN>: a valid item
# Returns: the function outputs each possible completion (one per line),
# and returns 0. Typical usage is COMPREPLY=($(_list_compgen ...)).
#
# Note: items must not contain the <sep> character (no backslash escaping has
# been implemented).
#
_list_compgen()
{
# Read the three parameters.
local current="${1}" ; shift
local sep="${1}" ; shift
local items="${*}"
# This is the maximum number of "<current><sep><other_item>" possible
# completions that should be listed in case <current> is a valid list.
# Setting it to a negative value means "no bound" (always list everything).
# Setting it to 0 means "never list anything" (only suggest <sep>).
# Setting it to a positive value N means "list up to N possible items, and
# only suggest <sep> if there are more".
# It is probably not worth a parameter, thus it will defaults to my
# prefered setting (1) if not already defined in the environment.
local max_others_number=${max_others_number:-1}
# Save IFS. The <sep> character will be used instead in the following.
local saved_IFS="${IFS}"
IFS="${sep}"
# Split the current items list in two parts:
# - current_item is the last one (maybe partial or even empty)
# - prefix_item are items are the previous ones
local current_item="${current##*${sep}}"
local prefix_items="${current%${current_item}}"
# Iterate through valid items to recognize those that are:
# - partial matches of the <current_item>
# - already used in the list prefix
# - not used in the list prefix, and not an exact match of <current_item>
# Also check whether the <current_item> is exactly a valid one.
local matching_items
local other_items
local exact_match
local my_item
for my_item in ${items} ; do
if [[ "${sep}${prefix_items}${sep}" == *"${sep}${my_item}${sep}"* ]] ; then
# The item has already been used in the list prefix: ignore it.
continue
elif [[ "${my_item}" == "${current_item}" ]] ; then
# The item _exactly_ matches the <current_item>: that means that we
# will have to suggest some more items to add behind.
exact_match=1
elif [[ "${my_item}" == "${current_item}"* ]] ; then
# The item matches the <current_item>: it will be a possible
# completion. It will also be a possible additional item in case of
# exact match.
matching_items="${matching_items}${sep}${my_item}"
other_items="${other_items}${sep}${my_item}"
else
# The item neither matches the <current_item> nor has been already
# used: it will only be a possible additional item in case of exact
# match.
other_items="${other_items}${sep}${my_item}"
fi
done
matching_items="${matching_items#${sep}}"
other_items="${other_items#${sep}}"
# Takes care of the case where <current_item> is not exactly valid but
# there is only one matching item: force this completion, and handle it
# just as an exact match.
if [[ -z "${exact_match}" ]] \
&& [[ "${matching_items}" != *"${sep}"* ]] ; then
exact_match=1
current="${current%${current_item}}${matching_items}"
current_item="${matching_items}"
matching_items=""
other_items="${sep}${other_items}${sep}"
other_items="${other_items/${sep}${current_item}${sep}/${sep}}"
other_items="${other_items#${sep}}"
other_items="${other_items%${sep}}"
fi
# List all possible completions. They are stored in an array.
# XXX: maybe if should be COMPREPLY directly? (with no output at the end)
local my_compreply=()
local i=0
if [[ -n "${exact_match}" ]] ; then
# Found an exact match? Then add "<current>".
my_compreply[${i}]="${current}"
let i++
fi
if [[ -n "${matching_items}" ]] ; then
# Found some matching items?
# Then add "<prefix_items><matching_item>".
for my_item in ${matching_items} ; do
my_compreply[${i}]="${prefix_items}${my_item}"
let i++
done
fi
if [[ -n "${exact_match}" ]] \
&& [[ -n "${other_items}" ]] ; then
# Found an exact match and some other possible items remain?
# First, count them:
local count_others=0
for my_item in ${other_items} ; do
let count_others++
done
# Then decide how to behave depending on the max_others_number setting:
if (( max_others_number < 0 )) \
|| (( count_others <= max_others_number )) ; then
# List the possible "<current><sep><other_item>" completions.
for my_item in ${other_items} ; do
my_compreply[${i}]="${current}${sep}${my_item}"
let i++
done
else # Only suggest adding the <sep> character.
my_compreply[${i}]="${current}${sep}"
let i++
fi
fi
# Restore IFS.
IFS="${saved_IFS}"
# Output the array of possible completions and returns.
local j=0
while (( i > j )) ; do
echo ${my_compreply[$j]}
let j++
done
return 0
}
#
# temerge completion command
#
have temerge && {
_temerge()
{
local c cur prev curword numwords opts cond prepend
local words stopre stophere i x
local action actionpos actionre sysactions eactions pkgpos
local version_mode searchdesc_mode help_mode resume_mode
local portdir=$(_portdir -o)
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
numwords=${#COMP_WORDS[*]}
curword=${COMP_CWORD}
actionre='@(-?([A-Za-z]*)[CPcis]*|@(metadata|s@(y@(nc|stem)|earch)|regen|@(unmerg|prune)e|world|@(@(dep)@(clean)|@(in@(fo|ject)))))'
stopre=' @(?(--)depclean|?(--)info|?(--)metadata|regen|sy@(nc|stem)|world|--@(resume|s@(kipfirst|ync)))'
opts=''
if [[ ${prev} == '>' || ${prev} == '<' ]] ; then
COMPREPLY=($(compgen -f -- ${cur}))
return 0
fi
# find action
for x in ${COMP_LINE} ; do
if [[ ${x} == ${actionre} ]] ; then
action=${x}
break
fi
done
if [[ -n "${action}" ]]; then
for ((i = 0; i < ${numwords}; i++ )); do
if [[ ${COMP_WORDS[${i}]} == "${action}" ]]; then
actionpos=${i}
pkgpos=$((actionpos + 1))
break
fi
done
if [[ ${action} == -* && ${action} != --* ]] ; then
case "${action}" in
-*C*) action='unmerge' ;;
-*P*) action='prune' ;;
-*c*) action='clean' ;;
-*i*) action='inject' ;;
-*s*) action='search' ;;
esac
fi
else
for ((i = 1; i < ${numwords}; i++ )); do
if [[ ! "${COMP_WORDS[$i]}" == -* ]]; then
pkgpos=${i}
break
fi
done
[[ -n "${pkgpos}" ]] || pkgpos=${numwords}
fi
# Check for special cases.
[[ ${COMP_LINE} == *" "-@(V|-version)* ]] && version_mode=1
[[ ${COMP_LINE} == *" "-@(S|-searchdesc)* ]] && searchdesc_mode=1
[[ ${COMP_LINE} == *" "-@(h|-help)* ]] && help_mode=1
# Handle special cases.
if [[ "${action}" == 'search' ]] || [[ -n "${searchdesc_mode}" ]] || \
[[ -n "${version_mode}" ]] || [[ "${action}" == 'metadata' ]]
then
unset COMPREPLY
return 0
elif [[ -n "${help_mode}" ]]; then
unset COMPREPLY
[[ ${curword} -eq 2 ]] && COMPREPLY=($(compgen -W 'config sync system' -- ${cur}))
return 0
fi
# Complete on options.
if [[ "${cur}" == -* ]]; then
# If a resume option was specified, it needs special handling.
[[ ${COMP_LINE} == *--@(resume|skipfirst)* ]] && resume_mode=1
if [[ -n "${resume_mode}" ]]; then
if [[ "${cur}" == --* ]]; then
opts="--ask --pretend --resume --skipfirst"
elif [[ "${cur}" == -* ]]; then
[[ ${COMP_LINE} == *--@(ask|pretend)* ]] && ask_premode=1
[[ -n "${ask_premode}" ]] && opts="-a -p"
fi
elif [[ "${cur}" == --* ]]; then
# Complete on long options.
opts="--ask --autoclean \
--buildpkg --buildpkgonly \
--changelog --clean --columns \
--debug --deep \
--emptytree \
--fetch-all-uri --fetchonly \
--getbinpkg --getbinpkgonly \
--newuse --noconfmem --nodeps --noreplace --nospinner
--oneshot --onlydeps \
--pretend \
--quiet \
--sync \
--tree \
--update --upgradeonly --usepkg --usepkgonly \
--verbose --depclean --info --search"
if [[ ${curword} -eq 1 ]] && [[ ${numwords} -eq 2 ]] ; then
opts="${opts} --help --resume --searchdesc --version"
fi
elif [[ "${cur}" == -* ]]; then
# Complete on short options.
opts="-B -D -G -K -O -U -a -b -d -e -f -g -k -l -n -o -p -q -t -u -v"
if [[ ${curword} -eq 1 ]] && [[ ${numwords} -eq 2 ]] ; then
opts="${opts} -h -S -V"
fi
if [[ -z "${action}" ]] && [[ ${curword} -eq $((pkgpos - 1)) ]] ; then
opts="${opts} -C -P -c -i -s"
fi
fi
COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
# NOTE: This slows things down!
# (Adapted from bash_completion by Ian Macdonald <ian@caliban.org>)
# This removes any options from the list of completions that have
# already been specified on the command line.
COMPREPLY=($(echo "${COMP_WORDS[@]}" | \
(while read -d ' ' i; do
[[ "${i}" == "" ]] && continue
# flatten array with spaces on either side,
# otherwise we cannot grep on word boundaries of
# first and last word
COMPREPLY=" ${COMPREPLY[@]} "
# remove word from list of completions
COMPREPLY=(${COMPREPLY/ ${i%% *} / })
done
echo ${COMPREPLY[@]})))
return 0
fi
# Stop completion if a special case is encountered.
if [[ ${COMP_LINE} == *${stopre}* ]] ; then
unset COMPREPLY
return 0
fi
# Complete on installed packages when unmerging.
if [[ "${action}" == 'unmerge' ]]; then
if [[ -n "${cur}" ]] ; then
if [[ "${cur}" == */* ]]; then
words=$(builtin cd /var/db/pkg; compgen -G "${cur}*")
else
words=$(builtin cd /var/db/pkg; compgen -S '/' -G "${cur}*")
local n=0
for i in ${words} ; do
[[ ${i} == ${cur}* ]] && n=$((n+1))
done
if [[ ${n} -eq 1 ]] ; then
words="$(builtin cd /var/db/pkg ; compgen -G "*-*/*")"
fi
fi
COMPREPLY=($(for i in ${words} ; do \
[[ ${i} == ${cur}* ]] && echo ${i} ; \
done))
else
COMPREPLY=($(builtin cd /var/db/pkg ; compgen -S '/' -G "*-*"))
fi
[[ -z "${COMPREPLY}" ]] && _pkgname_only ${cur} /var/db/pkg
return 0
fi
# Check for conditional.
cond="${cur%%[A-Za-z0-9]*}"
cur="${cur:${#cond}}"
if [[ ${cond:0:1} == "'" || ${cond:0:1} == '"' ]] ; then
prepend="-P ${cond:1}"
c="${cond:1}"
else
c="${cond}"
fi
# Handle cases where a conditional is specified.
if [[ -n "${cond}" ]]; then
if [[ -n "${cur}" ]]; then
if [[ ${cur} == */* ]]; then
if [[ ${cur} == *-[0-9]* ]] ; then
words="$(\
for pd in ${portdir} ; do \
builtin cd ${pd} ; \
local cat="${cur%/*}" ; \
local pkg="$(echo ${cur%-[0-9]*})" ; \
pkg="${pkg##*/}" ; \
for x in ${cat}/${pkg}/*.ebuild ; do \
[[ -f ${x} ]] || continue ; \
x="${x/${pkg}\/}" ; \
echo "${x%*.ebuild}" ; \
done ; \
done)"
else
words="$(\
for pd in ${portdir} ; do \
builtin cd ${pd}; \
compgen -X "*metadata.xml" -G "${cur}*" -- ${cur} ; \
done)"
fi
local w
for x in $words ; do
w="${x}\n${w}"
done
words=$(echo -ne ${w} | sort | uniq)
COMPREPLY=( ${words} )
# Complete on the specific versions (if appropriate).
if [[ ${#COMPREPLY[@]} -le 1 ]] ; then
COMPREPLY=($(\
for pd in ${portdir} ; do \
if [[ -d ${pd}/metadata/cache ]] ; then
builtin cd ${pd}/metadata/cache; \
compgen ${prepend} -G "${cur}*" -- "${cur}" ; \
else \
builtin cd ${pd} ; \
local cat="${cur%/*}" ; \
local pkg="$(echo ${cur%-[0-9]*}*)" ; \
pkg="${pkg##*/}" ; \
for x in ${cat}/${pkg}/*.ebuild ; do \
[[ -f "${x}" ]] || continue ; \
x="${x/${pkg}\/}" ; \
if [[ ${cond:0:1} == "'" ]] || \
[[ ${cond:0:1} == '"' ]] ; then
echo "${c}${x%*.ebuild}" ; \
else
echo "${x%*.ebuild}" ; \
fi ; \
done ; \
fi ; \
done))
else
COMPREPLY=($(compgen ${prepend} -W "${words}" -- $cur))
fi
else
words="$(\
for pd in ${portdir} ; do \
builtin cd ${pd} ; \
compgen ${prepend} -S '/' -G "${cur}*" -- "${cur}" ; \
done)"
local w
for x in words ; do
w="${x}\n${w}"
done
COMPREPLY=($(echo -e ${w} | uniq))
[[ ${#COMPREPLY[@]} = 1 ]] && \
COMPREPLY=($(\
for pd in ${portdir} ; do \
builtin cd ${pd} ; \
compgen ${prepend} -G "${cur}*/*" -- "${cur}" ; \
done))
fi
else
words="$(\
for pd in ${portdir} ; do \
builtin cd ${pd}; \
compgen -G "*-*"; \
done)"
COMPREPLY=($(compgen -W "${words}" -- "${cur}"))
fi
# If all else fails, try to complete on package names without the
# category being specified.
if [[ -z "${COMPREPLY}" ]]; then
words="$(\
for pd in ${portdir} ; do \
builtin cd ${pd}; \
for i in *-*/${cur}*; do \
[[ -d $i ]] && echo ${i##*/}; \
done ; \
done)"
COMPREPLY=($(compgen ${prepend} -W "${words}" -- ${cur}))
if [[ ${#COMPREPLY[@]} -le 1 ]]; then
# Now complete on the specific versions.
words="$(\
for pd in ${portdir} ; do \
if [[ -d ${pd}/metadata/cache ]] ; then \
builtin cd ${pd}/metadata/cache; \
for i in */${cur}*; do \
[[ -f $i ]] && echo ${i##*/}; \
done ; \
fi ; \
done)"
COMPREPLY=($(compgen ${prepend} -W "${words}" -- "${cur}"))
fi
fi
return 0
fi
# Complete on packages.
if [[ ${COMP_CWORD} -eq 1 ]] ; then
if [[ $numwords -le 2 ]]; then
sysactions=$'\n'"system"$'\n'"world"$'\n'"sync"$'\n'"metadata"
else
sysactions=$'\n'"system"$'\n'"world"$'\n'"sync"
fi
else
# Only allow these actions if no packages have been specified.
#
# TODO: This doesn't block these actions if no categories are
# specified. Please fix me.
#
# e.g. temerge -a gentoo-dev-sources
#
# will still allow system and world actions to be specified,
# as opposed to
#
# temerge -a sys-kernel/gentoo-dev-sources
#
if [[ ! " ${COMP_LINE} " == *" "*[/]*" "* ]]; then
sysactions=$'\n'"system"$'\n'"world"
else
sysactions=''
fi
fi
if [[ -z "${action}" ]] && [[ ${curword} -le ${pkgpos} ]] ; then
eactions=$'\n'"clean"$'\n'"depclean"$'\n'"inject"$'\n'"prune"$'\n'"regen"$'\n'"search"$'\n'"unmerge"
fi
if [[ -n "${cur}" ]] ; then
if [[ ${cur} == virtual/* ]] ; then
words=$(\
for pd in ${portdir} ; do \
if [[ -d ${pd}/profiles ]] ; then
find ${pd}/profiles -name virtuals -exec \
sed -n -e 's|^\(virtual/[[:alnum:]]\+\).*$|\1|p' {} \; | \
sort -u
fi ; \
done)
elif [[ ${cur} == */* ]] ; then
words=$(\
for pd in ${portdir} ; do \
builtin cd ${pd}; \
compgen -X "*metadata.xml" -G "${cur}*" ; \
done)"${sysactions}""${eactions}"
else
local ww=$(\
for pd in ${portdir} ; do \
builtin cd ${pd} ; \
compgen -S '/' -G "${cur}*"; \
done)"${sysactions}""${eactions}"
# complete on virtuals
ww="${ww} $(\
for pd in ${portdir} ; do \
if [[ -d ${pd}/profiles ]] ; then
find ${pd}/profiles -name virtuals -exec \
sed -n -e 's|^\(virtual/[[:alnum:]]\+\).*$|\1|p' {} \; | \
sort -u
fi ; \
done)"
local w
for x in ${ww} ; do w="${x}\n${w}" ; done
words=$(echo -e ${w} | sort -u)
local n=0
for i in ${words} ; do
[[ ${i} == ${cur}* ]] && n=$((n+1))
done
if [[ ${n} -eq 1 ]] ; then
words=$(for pd in ${portdir} ; do \
builtin cd ${pd} ; \
compgen -G "*-*/*" ; \
done)"${sysactions}""${eactions}"
fi
fi
COMPREPLY=($(for i in ${words} ; do \
[[ ${i} == ${cur}* ]] && echo ${i} ; \
done))
else
words="$(\
for pd in ${portdir} ; do \
builtin cd ${pd} ; \
compgen -S '/' -G "*-*" ; \
done)""${sysactions}""${eactions}"
COMPREPLY=($(compgen -W "${words}" -- ${cur}))
fi
# If all else fails, try to complete on package names without the
# category being specified.
if [[ -z "${COMPREPLY}" ]]; then
words="$(\
for pd in ${portdir} ; do \
builtin cd ${pd}; \
for i in [a-z]*-[a-z0-9]*/${cur}*; do \
[[ -d $i ]] && echo ${i##*/}; \
done ; \
done)"
COMPREPLY=($(compgen -W "${words}" -- ${cur}))
fi
return 0
}
complete -o filenames -F _temerge temerge
}
|
| Code: Create the link |
ln -s /usr/local/share/bash-completion/temerge /etc/bash_completion.d/ # refresh our login session in order to get bash completion for temerge source /etc/profile |
Created by NickStallman.net, Luxury Homes Australia
Real estate agents should be using interactive floor plans and real estate agent tools.
