Skip to content

Instantly share code, notes, and snippets.

@kaworu
Created December 21, 2013 20:31
Show Gist options
  • Save kaworu/8074610 to your computer and use it in GitHub Desktop.
Save kaworu/8074610 to your computer and use it in GitHub Desktop.
#!/bin/sh
#
# eworld.sh
# basic shell script to handle portage world file.
#
# Author:
# Perrin "kAworu" Alexandre <kaworu(a)kaworu,ch>
#
################################################################################
# This program is free software; you can redistribute it and/or #
# modify it under the terms of the GNU General Public License #
# as published by the Free Software Foundation; either version 2 #
# of the License, or (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the Free Software #
# Foundation, Inc., 51 Franklin Street, Fifth Floor, #
# Boston, MA 02110-1301, USA. #
################################################################################
#
#
#--VARIABLES--------------------------------------------------------------------
# : ${YOUR_VAR="<default>"}
# script version
VERSION="0.3.0"
# world file path/name
: ${WORLD_FILE="/var/lib/portage/world"}
# world file copy
: ${WORLD_FILE_COPY="$HOME/world"}
# save directory
: ${SAVEDIR="$HOME/.eworld"}
# max files in $SAVEDIR
: ${SAVEDIR_MAXF="10"}
# auto-clean option
: ${AUTO_CLEAN="yes"}
# diff command (used by diff action)
: ${DIFF_CMD="vimdiff"}
# set to 1 or true or yes if you don't want color
: ${NOCOLOR="no"}
# temp directory
: ${TMPDIR="/tmp"}
#-/VARIABLES--------------------------------------------------------------------
#--TOOLS------------------------------------------------------------------------
# Avoid using _ at the begining of the tools function name.
# return 0 if we allow colors, 1 otherwhise.
colored()
{
test "$NOCOLOR" != "1" &&
test "$NOCOLOR" != "yes" &&
test "$NOCOLOR" != "true"
}
# error output and exit
# you can use cecho syntax.
err()
{
cecho -red "* " -bold "ERROR: " "$@"
exit 1
}
# colored echo
# ex : cecho -green "Gen" -blue "too" "GNU/Linux"
# cecho -nocolor -blue
cecho()
{
color=
one_line=0
while [ -n "$1" ]; do
case "$1" in
-file) color="\e[1m" ;; # bold
-dir) color="\e[1m" ;; # bold
-action) color="\e[36;01m" ;; # cyan
-cmd) color="\e[00m" ;; # nocolor
-var) color="\e[00m" ;; # nocolor
-args) color="\e[33;01m" ;; # yellow
-nc|-nocolor) color="\e[00m" ;;
-bold) color="\e[1m" ;;
-black) color="\e[30;01m" ;;
-red) color="\e[31;01m" ;;
-green) color="\e[32;01m" ;;
-yellow) color="\e[33;01m" ;;
-blue) color="\e[34;01m" ;;
-magenta) color="\e[35;01m" ;;
-cyan) color="\e[36;01m" ;;
-white) color="\e[37;01m" ;;
-darkblack) color="\e[30m" ;;
-darkred) color="\e[31m" ;;
-darkgreen) color="\e[32m" ;;
-darkyellow) color="\e[33m" ;;
-darkblue) color="\e[34m" ;;
-darkmagenta) color="\e[35m" ;;
-darkcyan) color="\e[36m" ;;
-darkwhite) color="\e[37m" ;;
-n) one_line=1; shift; continue ;;
*) echo -en "$1"; shift; continue ;;
esac
shift
colored && echo -en "$color"
echo -en "$1"
colored && echo -en "\e[00m"
shift
done
if [ $one_line -eq 0 ]; then
echo
fi
}
# test if a program is installed
# first arg is the command, and second arg the package (if different that the command)
# example:
# need xkill
# need iwconfig wireless-tools
need()
{
if ! which "$1" >/dev/null 2>/dev/null; then
err "this script need the \"$1\" command. please run " -cmd "emerge --ask --verbose ${2:-$1}"
fi
}
#-/TOOLS------------------------------------------------------------------------
#--ACTIONS----------------------------------------------------------------------
# add your function here. ALL new action function MUST be defined that way:
# _ew_<your_action_name>()
# {
# #help
# if [ "$1" = "help" ]; then
# cecho -action "<your_action_name>"
# cecho "description ..."
# cecho "..."
# return 0
# fi
# #/help
# ...
# <your code here>
# ...
# }
#
# any new action function will be automatically detected and added to help
# action if declared properly.
_ew_help()
{
#help
if [ "$1" = "help" ]; then
cecho -action "help"
cecho "display this help (you can use \"h\" or \"--help\" or \"-h\" also)"
return 0
fi
#/help
cecho "`basename "$0"` v$VERSION"
cecho "usage: " -cmd "`basename "$0"` " -action "<action> " -args "<arg>"
cecho "actions:\n"
for action in $__ACTIONS__; do
echo -n " "
$action "help"
echo
done
exit 0
}
_ew_emaint()
{
#help
if [ "$1" = "help" ]; then
cecho -action "emaint"
cecho "check the world file with the " -cmd "emaint " "portage tool."
return 0
fi
#/help
cecho -n -green "* " -action "emaint" ": Starting " -cmd "emaint --check world" "..."
emaint_error=`/usr/sbin/emaint --check world | awk "!/Checking world for problems|Finished/ {print}"`
if [ -n "$emaint_error" ]; then
echo
err -cmd "emaint" " reported problems in your world file, please fix them."
else
echo " done."
fi
return 0
}
_ew_copy()
{
#help
if [ "$1" = "help" ]; then
cecho -action "copy"
cecho "copy (and sort) " -file "$WORLD_FILE " "to " -args "<arg> " "(or " -file "$HOME/world " "if no arguments is given)"
return 0
fi
#/help
cecho -n -green "* " -action "copy" ": " -file "$WORLD_FILE " "to " -file "$dest" "..."
dest=${1:-"$WORLD_FILE_COPY"}
if sort "$WORLD_FILE" > "$dest"; then
echo " done."
else
echo
err -action "copy " ": " -file "$WORLD_FILE " "to " -file "$dest " ": Failed"
fi
return 0
}
_ew_backup()
{
#help
if [ "$1" = "help" ]; then
cecho -action "backup"
cecho "use " -action "copy " "to save the current " -file "$WORLD_FILE " "to " -dir "$SAVEDIR/backup/" "."
cecho "use " -action "clean " "if " -var "AUTO_CLEAN " "is set to \"yes\" (current value is $AUTO_CLEAN)"
return 0
fi
#/help
if [ ! -e "${SAVEDIR}/backup" ]; then
mkdir "${SAVEDIR}/backup" || err "can't create " -dir "${SAVEDIR}/backup " "directory"
fi
now=`date "+%Y-%m-%d_%H:%M:%S"`
backup_file="${SAVEDIR}/backup/`basename "$WORLD_FILE"`___${now}"
eworld_action copy "$backup_file"
if [ "$AUTO_CLEAN" = "yes" ]; then
eworld_action clean
fi
cecho -green "* " -action "backup" ": done."
return 0
}
_ew_clean()
{
#help
if [ "$1" = "help" ]; then
cecho -action "clean"
cecho "clean the " -dir "${SAVEDIR}/backup/ " "directory. Remove all files in this directory but the " -var "SAVEDIR_MAXF " "latest (current value is ${SAVEDIR_MAXF})"
return 0
fi
#/help
cecho -n -green "* " -action "clean" ": "
nb_files=`ls -1 "${SAVEDIR}/backup" | wc -l` # if you have a nice way to do that, please let me now.
if [ $nb_files -le $SAVEDIR_MAXF ]; then
echo "done. Nothing need to be cleanned ;)"
else
#nb_files_to_rm=`expr $nb_files_to_rm - $SAVEDIR_MAXF` # expr(1) version
nb_files_to_rm=$(($nb_files - $SAVEDIR_MAXF))
files_to_rm=`ls -1 -t "${SAVEDIR}/backup" | tail -n $nb_files_to_rm`
for _file in $files_to_rm; do
rm -f "${SAVEDIR}/backup/${_file}"
done
echo "done. ($nb_files_to_rm files removed)"
fi
return 0
}
_ew_update()
{
#help
if [ "$1" = "help" ]; then
cecho -action "update"
cecho "copy " -args "<arg> " "to " -file "$WORLD_FILE " "(default " -file "$WORLD_FILE_COPY" "). use " -cmd "sudo " "if needed."
cecho "call " -action "backup " "before update and " -action "emaint " "after update."
return 0
fi
#/help
if [ -w "$WORLD_FILE" ]; then
copy_command="cp"
else
need sudo
cecho -yellow "* " "using sudo"
copy_command="sudo cp"
fi
src_file=${1:-"$WORLD_FILE_COPY"}
if [ ! -f "$src_file" ]; then
err "No " -file "$src_file " "to copy"
fi
eworld_action backup
cecho -n -green "* " -action "update" ": $copy_command " -file "$src_file " -file "$WORLD_FILE" "..."
if $copy_command "$src_file" "$WORLD_FILE"; then
echo " done."
else
echo
err -action "update " "Failed !"
fi
eworld_action emaint
}
_ew_grep()
{
#help
if [ "$1" = "help" ]; then
cecho -action "grep"
cecho "grep " -args "<arg> " -file "$WORLD_FILE "
return 0
fi
#/help
if colored; then
grep --color=always "$@" "$WORLD_FILE"
else
grep "$@" "$WORLD_FILE"
fi
}
_ew_checkdep()
{
#help
if [ "$1" = "help" ]; then
cecho -action "checkdep"
cecho "for each package in " -file "$WORLD_FILE " "check if another world's package depend on it (useful to find library package that shouldn't belongs in world file)."
cecho "if " -args "<arg> " "is " -args "e " "or " -args "equery " "this action use " -cmd "equery " "from " -cmd "gentoolkit " "otherwise it use " -cmd "q" " from " -cmd "portage-utils" "."
cecho -cmd "q " "is used by default because it's faster (but less reliable)."
return 0
fi
#/help
eworld_action emaint
if [ "$1" = "equery" ] || [ "$1" = "e" ]; then
need equery gentoolkit
use_equery="true"
else
need qdepends portage-utils
use_equery="false"
fi
for pkg in `sort "$WORLD_FILE"`; do
depends=
if [ "$use_equery" = "true" ]; then
depends=`equery depends "$pkg" | awk '!/^Searching/ {print $1}'`
else
depends=`qdepends --verbose --nocolor --query "$pkg" | awk -F: 'BEGIN {regex="'${pkg}'"} {if ($1 !~ regex) print $1}'`
fi
if [ x"$depends" != x"" ]; then
cecho -file "$pkg"
cecho "$depends" | sed -e 's/^/\t/' # indent result
fi
done
}
_ew_diff()
{
#help
if [ "$1" = "help" ]; then
cecho -action "diff"
cecho "use " -action "copy " "with " -args "<arg>" " and cp latest saved world file by the " -action "backup " "action, then make a diff between these files (DIFF_CMD <backuped> <current>)."
cecho "both are copy then you can make any changes if you're using a programm like " -cmd "vimdiff" "."
cecho "the tmp file (from backup) is removed after diff. diff command is " -var "DIFF_CMD " "(current value is \"$DIFF_CMD\")"
return 0
fi
#/help
dest=${1:-"$WORLD_FILE_COPY"}
eworld_action copy "$dest"
last_world_file=`ls -1 -t "${SAVEDIR}/backup/" | head -n 1`
if [ ! -f "${SAVEDIR}/backup/${last_world_file}" ]; then
err "no file found in " -dir "${SAVEDIR}/backup/ " "directory !"
fi
tmpf="${TMPDIR}/${RANDOM}world.$$"
cp "${SAVEDIR}/backup/${last_world_file}" "$tmpf"
$DIFF_CMD "$tmpf" "$dest" || return $?
rm -f "$tmpf"
}
#-/ACTIONS----------------------------------------------------------------------
#- TESTS------------------------------------------------------------------------
# avoid adding test unless you really think that it'll be useful for some other
# action.
# $WORLD_FILE must exists
if [ ! -f "$WORLD_FILE" ]; then
err "file not found : " -file "$WORLD_FILE"
fi
# creat the $SAVEDIR if not present
if [ ! -e "$SAVEDIR" ]; then
mkdir -p "${SAVEDIR}/backup" || err "Failed while creating " -dir "$SAVEDIR"
fi
# actions auto-detection.
__ACTIONS__=`awk '/^ *_ew_\w+ *()/ {gsub(/[ (){]/, ""); print}' "$0"`
#-/TESTS------------------------------------------------------------------------
#--MAIN-------------------------------------------------------------------------
# lauch the appropriate action. If no args action help is called.
# action caller method
eworld_action() {
for action in $__ACTIONS__; do
if [ "_ew_$1" = "$action" ]; then
shift
$action "$@"
return $?
fi
done
err -action "$1 " "is not a valid action, please run " -cmd "$0 help"
}
if [ $# -lt 1 ]; then
eworld_action "help"
else
case "$1" in
h|--help|-h) eworld_action "help" ;;
*) eworld_action "$@" ;;
esac
fi
#-/MAIN-------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment