[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

wajig: a simple command line interface to Debian package mgmt



I've been juggling the use of various Debian Package Management tools
over the years (including the likes of dselect, deity, deity-gtk,
aptitutde, apt-get, dpkg, gnome-apt, apt-cache, and so on).

I've written a shell script front-end which I call "wajig" to do some
of the common tasks I do in managing various Debian installations. I
include the script below in case others might find it useful or others
might give me wisdom on how to do some of these better. I would not
yet vouch for it's accuracy (in terms of identifying new and updated
packages) 

WARNING: I suggest you review the code carefully to be sure for
yourself that I don't include any trojan horses. Currently I assume
the script is being run as root. Thus, someone with less scruples than
myself :-) could mislead you into running code as root that trashes
your system, or worse.  Nonetheless, I've used this for quite a while
now and I've never trashed my system.

In brief I use it as follows:

# wajig update				(update available list: apt-get update)
# wajig new				(list new packages to Debian)
# wajig newupgrade			(list upgradeable pkgs since update)
# wajig toupgrade 			(list all upgradeable pkgs)

# wajig install xmms                    (install the xmms package)
# wajig remove xmms

# wajig listfiles xmms			(list files supplied by installed pkg)

# wajig whichpkg ppmmake		(search Debian packages web page for
                                         packages containing ppmmake. This one
                                         lets me avoid going to the web page
                                         to find information each time)
                                                          
and many more, including upgrade, dist-upgrade, reconfigure,
repackage, source, clean, autoclean, status, describe, search.

Code is provided as is without warranty.

Finally, I've been using Debian for many years but am not an
officially registered Debian developer.

#!/bin/bash
#
# WAJIG: Debian Package Management Front End
#
# Remembering all the different commands to get different
# information about different aspects of Debian package management and 
# then using other commands to install and remove packages 
# was all becoming too much for me.  
# 
# Swaping between dselect, deity, deity-gtk, aptitutde, apt-get, dpkg, 
# gnome-apt, apt-cache, and so on was interesting but cumbersome.
#
# This script simply collects together what I have learnt about 
# various commands!  Clearly I have yet to learn all there is.
# Also, this script is a bit of a hack, and many things could surely be 
# done better. I find it useful and in case others do I release it.
#
# Suggestions are most welcome.  Email Graham.Williams@cmis.csiro.au.
#
# Currently it only runs as root which needs to be rectified. 
# Perhaps using fakeroot or sudo when (and only when) it is required.
#
# Copyright (c) 2001 Graham Williams, Kayon Toga.
#
# Code is provided as is without warranty.
#
# Released under the GNU General Public License.

self=$(basename $0)

init_dir=/root/.wajig
scratch_dir=${init_dir}

avail_now=${init_dir}/pkg.available
avail_tmp=${init_dir}/pkg.available.tmp
avail_prev=${init_dir}/pkg.available.prev

install_now=${init_dir}/pkg.installed

function usage ()
{
    echo "Usage: ${self} [-h|--help] <command> [<args>]"
    echo ""
    echo "       init                   Initialise the internal archives"
    echo "       reset                  Reset the internal archives"
    echo ""
    echo "       update                 Update the list of available packages"
    echo "       upgrade                Upgrade all installed pacakges"
    echo "       dist-upgrade           Upgrade to a new distribution"
    echo "       install <packages>     Install package from net"
    echo "       installdeb <deb>       Install package from a .deb file"
    echo "       force <packages>"
    echo "       reconfigure <packages>"
    echo "       repackage <package>    Generate .deb from installed package"
    echo "       remove <packages>"
    echo "       source <packages>      Retrieve package source from net"
    echo ""
    echo "       clean                  Remove all cached apt-get files"
    echo "       autoclean              Remove old cached apt-get files"
    echo ""
    echo "       status [<pattern>]"
    echo "       version [<pattern>]"
    echo "       available <packages>   List versions of given packages"
    echo "       describe <packages>"
    echo "       description <packages>"
    echo "       fulldescription <packages>"
    echo "       orphans [<packages>]"
    echo ""
    echo "       list"
    echo "       listnames [<pattern>]"
    echo "       listfiles <package>"
    echo "       search <pattern>"
    echo "       whichpkg <pattern>     Search for file in a package"
    echo ""
    echo "       toinstall"
    echo "       topurge"
    echo "       toupgrade              List packages with newer versions available"
    echo "       newupgrade"
    echo "       new			List new packages since last update"
    echo ""
    echo "       findfile <string>"
}

function update.available () 
{
  #
  # Generate current list of available packages, backing up the old list.
  #

  if [ ! -e ${avail_now} ]; then
    touch ${avail_now}
  fi

  mv -f ${avail_now} ${avail_tmp} 2>/dev/null

  apt-cache dumpavail | 
  egrep '^(Package|Version):' |
  awk '
      /^Package: / {pkg=$2}
      /^Version: / {print pkg,$2}
  ' > ${avail_now}
 
  mv -f ${avail_tmp} ${avail_prev}
  printf "There are $(wc -l ${avail_now} | awk '{print $1}') packages now "
  printf "available compared to $(wc -l ${avail_prev} | awk '{print $1}') "
  printf "previously.\n"
}

function update.installed () 
{

  # Generate current list of installed packages.

  if [ ! -e ${install_now} ]; then
    touch ${install_now}
  fi

  cat /var/lib/dpkg/status |
  egrep '^(Package|Status|Version):' |
  awk '
      /^Package: / {pkg=$2}
      /^Status: / {s1=$2;s2=$3;s3=$4}
      /^Version: / {print pkg,$2,s1,s2,s3}
  ' |

  grep " install ok installed" |
  awk '{print $1,$2}' | sort > ${install_now}

  echo "There are $(wc -l ${install_now} | awk '{print $1}') packages installed."

}

#
# Initialise the cache. 
#
if [ ! -e ${avail_now}   -o ! -e ${avail_prev} -o \
     ! -e ${install_now} -o ! -d ${init_dir} ]; then
  if [ "$1" = "init" ]; then
    rm -f ${avail_now} ${avail_prev} ${install_now}
    if [ ! -d ${init_dir} ]; then
      mkdir ${init_dir}
    fi
    update.available
    update.installed
    cp ${avail_now} ${avail_prev}
 else
    printf "*******************************************************************

Welcome to the ${self} Debain Package Information Toolkit

\tPlease initialise first with: ${self} init

\tThis will simply generate available and install lists that
\treflect the current status of the installation.

\tThis toolkit is intended to be run as root only (currently)
\tEventually it will be able to be run as any user and will use
\tsudo or fakeroot as appropriate.

\tCached information files are stored in ${init_dir}

*******************************************************************
"
  fi
  exit 0
fi

#
# Process command line options
#

case "$1" in

  --help|-h)
    usage
    exit 0
  ;;

  -*)
    echo -n "${self}: Error: "
    echo "Unrecognised option: $1"
    usage
    exit 1
  ;;

esac

#
# Perform the requested action
#

case "$1" in

  autoclean)
    if [ $# -gt 1 ]; then
      shift
      echo -n "${self}: Error: "
      echo "$1 requires no further arguments: $*"
      exit 1
    fi
    apt-get autoclean
  ;;

  available)
    if [ $# -eq 1 ]; then
      echo -n "${self}: Error: "
      echo "$1 requires a list of packages"
      exit 1
    fi
    shift
    echo "Package                 Available               Installed"
    echo "===================================================================="
    for package in $*; do
      join -a 1 -a 2 ${avail_now} ${install_now} |
      egrep "^${package} " |
      awk '{printf("%-20s\t%-20s\t%-20s\n", $1, $2, $3)}'    
    done
  ;;

  clean)
    if [ $# -gt 1 ]; then
      shift
      echo -n "${self}: Error: "
      echo "$1 requires no further arguments: $*"
      exit 1
    fi
    apt-get clean
  ;;

  describe)
    if [ $# -eq 1 ]; then
      echo -n "${self}: Error: "
      echo "$1 requires a list of packages"
      exit 1
    fi
    shift
    dpkg --status $* | 
    awk '
    /^Package:/ {printf("%-20s ",$2)}
    /^Description:/ {print}' |
    sed 's|Description:||'

  ;;

  description)
    if [ $# -eq 1 ]; then
      echo -n "${self}: Error: "
      echo "$1 requires a list of packages"
      exit 1
    fi
    shift
    for package in $*; do
      apt-cache dumpavail | 
      awk -v package=$package '
      BEGIN               {found=0}
      /^Package: /        {if ($2 == package) {found=1;printf("%s:", $2);next}
                           if (found==1)      {print "";found=0;next}
                          } 
      found==0            {next} 
      /^Description: /    {print} 
      /^ /                {print}' |
      sed 's|Description:||' 
    done

  ;;

  dist-upgrade)
    if [ $# -gt 1 ]; then
      shift
      echo -n "${self}: Error: "
      echo "$1 requires no further arguments: $*"
      exit 1
    fi
    apt-get dist-upgrade
    update.installed
  ;;

  findfile)
    shift
    dpkg --search $1
  ;;

  fulldescription)
    if [ $# -eq 1 ]; then
      echo -n "${self}: Error: "
      echo "$1 requires a list of packages"
      exit 1
    fi
    shift
    apt-cache show $*

  ;;

  force)
    if [ $# -eq 1 ]; then
      echo -n "${self}: Error: "
      echo "$1 requires a list of packages"
      exit 1
    fi
    shift
    dpkg --install --force overwrite $(ls /var/cache/apt/archives/$** | sort | tail -1)
    update.installed
  ;;

  init|reset)
    rm -f ${avail_now} ${avail_prev} ${install_now}
    update.available
    update.installed
    cp ${avail_now} ${avail_prev}
  ;;

  install)
    if [ $# -eq 1 ]; then
      echo -n "${self}: Error: "
      echo "$1 requires a list of packages"
      exit 1
    fi
    shift
    apt-get install $*
    update.installed
  ;;

  installdeb)
    if [ $# -eq 1 ]; then
      echo -n "${self}: Error: "
      echo "$1 requires the deb file to be installed"
      exit 1
    fi
    shift
    dpkg --install $1
    update.installed
  ;;

  list)
    shift
    dpkg -l '*'
  ;;

  listnames)
    if [ $# -eq 1 ]; then
      shift
      apt-cache pkgnames | sort
    else
      shift
      apt-cache pkgnames | grep $1 | sort 
    fi
  ;;

  listfiles)
    shift
    dpkg --listfiles $1
  ;;

  new)
    #
    # List packages that have appeared since last update.
    #
    if [ $# -gt 1 ]; then
      shift
      echo -n "${self}: Error: "
      echo "$1 requires no further arguments: $*"
      exit 1
    fi
    join -v 1 -a 2 ${avail_prev} ${avail_now}
  ;;

  newupgrade)
    #
    # Identify packages that have a newer version now available
    # as compared to prior to the update.
    #
    if [ $# -gt 1 ]; then
      shift
      echo -n "${self}: Error: "
      echo "$1 requires no further arguments: $*"
      exit 1
    fi
    echo "Package                 Available               Installed"
    echo "===================================================================="
    join -a 1 -a 2 ${avail_now} ${install_now} |
      awk 'NF==3 && $2 != $3 {print}' > ${init_dir}/pkg.tmp1
    join -a 1 -a 2 ${avail_prev} ${install_now} |
      awk 'NF==3 && $2 != $3 {print}' > ${init_dir}/pkg.tmp2
    join ${init_dir}/pkg.tmp1 ${init_dir}/pkg.tmp2 |
      awk 'NF==5 && $2 != $4 {printf("%-20s\t%-20s\t%-20s\n", $1, $2, $3)}' >\
      ${init_dir}/pkg.tmp3
    join -a 1 -v 2 ${init_dir}/pkg.tmp1 ${init_dir}/pkg.tmp2 |
      awk '{printf("%-20s\t%-20s\t%-20s\n", $1, $2, $3)}' >>\
      ${init_dir}/pkg.tmp3
    cat ${init_dir}/pkg.tmp3 | sort
    rm -f ${init_dir}/pkg.tmp?
  ;;


  orphans)
  # 
  # List those libraries that are not required by any other installed package
  #
    shift
    deborphan $*
  ;;

  reconfigure)
    shift
    dpkg-reconfigure $*
  ;;

  remove)
    if [ $# -eq 1 ]; then
      echo -n "${self}: Error: "
      echo "$1 requires a list of packages"
      exit 1
    fi
    shift
    apt-get remove $*
    update.installed
  ;;

  repackage)
    shift
    dpkg-repack $1
  ;;

  search)
    shift
    apt-cache search $*
  ;;

  source)
    if [ $# -eq 1 ]; then
      echo -n "${self}: Error: "
      echo "Please identify the packages you require sources for"
      exit 1
    fi
    shift
    apt-get source $*
  ;;

  status|version)
    shift
    dpkg --list $*
  ;;

  toinstall)
    echo "Packages marked to be installed but not yet installed:"
    echo "===================================================================="
    shift
    dpkg -l | head -5
    dpkg -l '*' | grep "^i[^i]"
  ;;

  topurge)
    echo "Packages marked to be purged but currently installed:"
    echo "===================================================================="
    shift
    dpkg -l '*' | grep "^pi"
  ;;

  toupgrade)
    #
    # Find packages that have an Available version more recent than Installed
    #
    if [ $# -gt 1 ]; then
      shift
      echo -n "${self}: Error: "
      echo "$1 requires no further arguments: $*"
      exit 1
    fi
    echo "Package                 Available               Installed"
    echo "===================================================================="
    join -a 1 -a 2 ${avail_now} ${install_now} |
    awk 'NF==3 && $2 != $3 {printf("%-20s\t%-20s\t%-20s\n", $1, $2, $3)}'    
  ;;

  upgrade)
    if [ $# -gt 1 ]; then
      shift
      echo -n "${self}: Error: "
      echo "$1 requires no further arguments: $*"
      exit 1
    fi
    apt-get upgrade
    update.installed
  ;;

  update)
    if [ $# -gt 1 ]; then
      shift
      echo -n "${self}: Error: "
      echo "$1 requires no further arguments: $*"
      exit 1
    fi
    apt-get update
    printf "Update: "
    update.available
  ;;

  whichpkg)
    if [ $# -ne 2 ]; then
      echo -n "${self}: Error: "
      echo "$1 requires a name to look for"
      exit 1
    fi
    shift
    if ping -c 1 packages.debian.org 2>&1 >/dev/null; then
      results=${scratch_dir}/search.results
      wget --output-document=${results} http://packages.debian.org/cgi-bin/search_contents.pl\?word=$1\&case=insensitive\&version=unstable\&arch=i386\&directories=yes 2> /dev/null
      cat ${results} |
        egrep -v '^<|^$|^Packages search page' |
        perl -p -e 's|<[^>]*>||g;s|<[^>]*$||g;s|^[^<]*>||g'
    else
      printf "${self}: Error: $1: Debian packages host not available.\n"
      exit 1
    fi 
  ;;

  *)
    echo "${self}: unrecognised command. Type ${self} --help for information."
    usage
    exit 1
  ;;
esac


Reply to: