Created
December 21, 2013 20:31
-
-
Save kaworu/8074610 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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