Codebase list debian-goodies / debian/0.47 debmany / debmany
debian/0.47

Tree @debian/0.47 (Download .tar.gz)

debmany @debian/0.47raw · history · blame

#!/bin/bash
# script:      debmany
# author:      Michael Arlt
# description: select manpages+docs of any [not] installed debian package
# comment:     debmany is based on the work of debman and debget
# gui uses:    whiptail (preferred), dialog or zenity as well
# other uses:  curl, less (can be overwritten: -o)
# optional:    -k -g -x: kfmexec gnome-open xdg-open (xdg-utils)
# This is free software.  You may redistribute copies of it under the terms of
# the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
# There is NO WARRANTY, to the extent permitted by law.

# Tests for new releases:
# -L test downloadlimit and correct display of different sizes and units (http)
# -l several languages with and without "*" on installed and not installed packages
# -m -o test default and using parameters
# -z -k -g -x test
# open manpage,other file (usr/share/doc/...),manpage,other file
# check delivered debmany manpages
# check and test bash_completion
# check includes of installed (bash: bash-builtins) and uninstalled (ax25-tools:netrom-tools)
# test additionally the next operationg system (e.g. lenny)

LC_ALL=C

# defaults
mancmdline="man %s"     # manpageviewer
othercmdline="less %s"  # viewer for other files

curdir=`pwd`

error()
{
  # show errorcode and quit
  echo "ERROR: $*" >&2
  if [ "$cmd" = "zenity" ]
  then
    $cmd --error --text="$*"
  fi
  exit 1
}

debug()
{
  # show debugging
  test $debug && echo "$*" >&2
}

usage()
{
  echo "debmany $version Thu May 15 16:56:19 CEST 2008
Description: Display a manpage or documentation files from a Debian package.
             The list of files is displayed in a dialog.
             Supported locations for debian packages are: Local .deb-file,
             a package in the repository or an installed package.
             The default for manpages is man - less is used for other files.
             Default can be overwritten with -k|-g|-x and -m -o.
Syntax1 : debmany [-?|-h|--help]
Syntax2 : debmany [-v[v]] [-k|-g|-x] [-m manviewer] [-o otherviewer] [-L limit] [-l lang1[,...]] package[.deb]
Syntax3 : debmany [-v[v]] [-k|-g|-x] [-m manviewer] [-o otherviewer] [-L limit] [-l lang1[,...]] -z [package[.deb]]
Examples: debmany foo.deb  show manpages from a local package file foo.deb
          debmany foo      show manpages from a package, if the package is
                           not installed it is retrieved from the
                           configured repositories.
          debmany -k foo   show files using your preferred viewer (KDE)
                           man: kfmclient exec man:%s   other: kfmclient exec %s
          debmany -g foo   show files using your preferred viewer (GNOME)
                           man: gnome-open man:%s   other: gnome-open %s
          debmany -x foo   show files using your preferred viewer
                           man: xdg-open man:%s   other: xdg-open %s
                           using xdg-open from xdg-utils package (Xfce users)
          debmany -m 'konqueror man:%s' -l 'de*,fr*' -L 5M foo
                           show english, german and french manpages using
                           konqueror as man-viewer and ask if download size
                           exceeds 5M
          debmany -z -k    use zenity (as dialog) to select packages and files
          TMPDIR=~/tmp debmany -k -o 'foo.sh %s' -l de,fr -L 5M foo
                           use ~/tmp as temporary folder
                           use KDE-defaults but overwrite viewer for other files
          debmany -v foo   show some debugging information (-vv show more)
          alias debmany='debmany -l de -L 5M -k'; debmany -m man -l 'zh*' foo
                           set an alias with your preferred options and
                           overwrite them if needed"
  if [ $# -eq 0 ]
  then
    exit 0
  else
    error "$*"
  fi
}

while [ $# -gt 0 ]
do
  case $1 in
  "-?"|-h|--help) usage ;;
  -k) mancmdline='kfmclient exec man:%s'        # set kde viewers
      othercmdline='kfmclient exec %s';;
  -g) mancmdline='gnome-open man:%s'            # set gnome viewers
      othercmdline='gnome-open %s';;
  -x) mancmdline='xdg-open man:%s'              # set independant viewers
      othercmdline='xdg-open %s';;
  -m) # override default manpageviewer
      shift
      mancmdline="$1";;
  -o) # override default viewer for other data
      shift
      othercmdline="$1";;
  -l) shift; lang=$1;;          # remember language
  -L) shift; asksize=$1;;       # remember asksize
  -v) debug=1;;
  -vv) debug=2;;
  -z) cmd="zenity"
      # is zenity executeable?
      which $cmd >/dev/null 2>&1 || error "$cmd must be installed if you use parameter -z"
      ;;
  -*) usage "Unknown option '$1'.";;
  *)  package="$1";;
  esac
  shift
done

mancmd=($mancmdline) # get first word !dash
if which $mancmd >/dev/null 2>&1 # is the manpageviewer(first word) executeable?
then
  echo "$mancmdline" | grep -q "%s" || mancmdline="$mancmdline %s"
else
  usage "Manpageviewer '$mancmd' is not available or executable"
fi
othercmd=($othercmdline) # get first word !dash
if which $othercmd >/dev/null 2>&1 # is the manpageviewer executeable?
then
  echo "$othercmdline" | grep -q "%s" || othercmdline="$othercmdline %s"
else
  usage "Viewer for other data '$othercmd' is not available or executable"
fi

# Version of debmany
version=1.3

# choose whiptail or dialog
whiptail=/usr/bin/whiptail
dialog=/usr/bin/dialog

if [ "$cmd" ]
then
  # zenity version
  if [ -z "$package" ]
  then
    package=`$cmd --entry --title="Debmany $version" --text="Enter package or package.deb"` || exit 0
  fi
else
  test -z "$package" && usage "You must specify one package or a Debian package file."
  test -x $whiptail && cmd=$whiptail || cmd=$dialog

  # determine the size of your terminal
  read y x <<EOF
`stty size`
EOF

  # if it is impossible to determine the size
  if [ "$x" = "" ]
  then
    x=80
    y=25
    echo "Unable to determine the size of your terminal - using Console default: $x*$y" >&2
    sleep 3
  fi

  # test upon minimum resolution
  if [ $x -lt 40 -o $y -lt 9 ]
  then
    error "Resolution too small ($x*$y). I need a minimum of 40*9 - recommended is more..."
  fi

  debug "Terminalsize: ${x}x$y" # comment

  # set the size of the dialog window and menu
  x=$(($x-1))     # width of the dialog
  y=$(($y-1))     # height of the dialog
  h=$(($y-7))     # height of the menu
fi
debug "Using '$cmd' for selection" # comment


if [ "${package##*.}" = "deb" ]
then
  debug "Mode1: You want to see manpages from a .deb-file" # comment
  if [ -r "$package" ]
  then
    file=`readlink -f "$package"`
    status=file
  else
    error "The file $package cannot be read."
  fi
else
  debug "Test if the package '$package' is already installed" # comment
  if dpkg -l "$package" 2>/dev/null | grep -q ^i
  then
    debug "Package '$package' is already installed" # comment
    status=installed
    # create the list of all mandirs (with -e for grep) (X11R6 is only for sarge - didn't find it in etch anymore)
    mandirs="-e /usr/share/man/man.*/ -e /usr/share/doc/"
    # modify lang for grep regular expressions: fr -> fr\.* (-> fr+fr.ISO8859-1+"fr."...)
    for l in `echo "$lang"|sed -e "s/,/ /" -e "s/*/.*/"`
    do
      mandirs="$mandirs -e /usr/share/man/$l/"
    done
    debug "Using grep pattern '$mandirs'" # comment
    # list the manpage dirs
    set -f
    for man in `dpkg -L "$package" 2>/dev/null|grep $mandirs|sort`
    do
      # mode 2: add the manpages to the list
      test -f $man && manpages="$manpages $man ${man##*/}"
    done
    set +f
    if [ "$debug" = 2 ]
    then
      debug "Mode2: Found manpages/docs: $manpages" # comment
    else
      debug "Mode2: Found manpages/docs" # comment
    fi
  fi
fi

if [ "$status" = "installed" ]
then
  # mode 2
  cd /
else
  # mode 1 and 3
  trap 'test -n "$temp" && rm -rf "$temp"; exit' 0 2 15 # cleanup

  # find a directory for temporary files (you can use $TMPDIR to specify the destination)
  for tmp in "$TMPDIR" /dev/shm /tmp /var/tmp
  do
    test -d "$tmp" && break
  done

  # make a temporary folder for the manpages
  temp=`mktemp -d -p "$tmp" debmany.XXXXXXXXXX` || error "Unable to create a temporary folder in '$tmp'."
  debug "Mode1/3: Created temporary folder $temp" # comment

  if [ -z "$file" ]
  then
    debug "Mode3: Determining the path of '$package' (you use file:// in sources.list)" # comment
    aptdata=`apt-get -q2 --print-uris --reinstall install "$package" 2>/dev/null | tail -1`
    if [ -z "$aptdata" ]
    then
      error "There is no package called '$package'."
      exit 1
    fi

    url=`echo "$aptdata" | sed -e "s/^'\([^']*\)'.*$/\1/"`
    test -z "$url" && error "Could not obtain an URL for '$pkgspec'."

    debug "Mode3: Found package '$package' in the repository" # comment
    if [ "${url%%:*}" = "file" ]
    then
      file="${url#*:}"
      debug "Mode3: Access the local file '$file'" # comment
      if [ ! -r "$file" ]
      then
        error "Could not access '$file' from the repository."
      fi
      status=repos-file
    else
      file="$temp/tmp.deb"
      debug "Mode3: Preparing download of file '$url' to '$file'" # comment
      # if i should ask at a specific size
      if [ "$asksize" != "" ]
      then
        debug "Mode3: Determine the size of the file to download" # comment
        # determine the size of the file to download (*10 for 10,5M)
        size=`apt-cache show "$package"|grep ^"Size: "|head -1|cut -f2 -d" "`
        # determine the value of ask_size
        limit=`echo $asksize|tr -cd "[0-9]"`
        test "$limit" = "" && error "Parameter -L needs an argument - e.g. '10M'."
        # determine the unit of ask_size
        unit=`echo $asksize|tr -d "[0-9]"`
        debug "Mode3: Determined download limit is '$limit' '$unit'" # comment
        # calculate the limit !dash integer variables support < 2G
        case $unit in
          B|"") ;;
          K) limit=$(($limit*1024));;
          M) limit=$(($limit*1024*1024));;
          G) limit=$(($limit*1024*1024*1024));;
          T) limit=$(($limit*1024*1024*1024*1024));;
          *) error "Invalid unit '$unit' in command line."
        esac
        # calculate the human readable size and ask for download if size exceeds limit
        if [ $size -ge $limit ]
        then
          debug "Mode3: Size '$size' exceeds specified limit '$limit'" # comment
          unit=B
          size=$(($size*100)) # !dash 2G limit
          # reduce the size and correct the unit until it is human readable
          while [ $size -ge 10240 ]
          do
            size=$(($size/1024))
            # correct the unit every time /1024
            case $unit in
              G) unit=T;;
              M) unit=G;;
              K) unit=M;;
              B) unit=K;;
            esac
          done
          size=$((($size+5)/10)) # !dash 2G limit
          # set the comma (so if the file has a size of 5M we change 50 to 5,0M)
          commasize=`echo $size|sed "s/\(.*\)\(.\)/\1.\2/"`
          commasize=`printf "%.1f$unit" $commasize`
          # ask if the download may start - otherwise debmany exits
          if [ "$cmd" = "zenity" ]
          then
            if ! $cmd --question --text="Would you like to download the package with a size of $commasize?"
            then
              echo "Download undesired - $commasize is too big."
              exit
            fi
          else
            if ! $cmd --yesno "Would you like to download the package with a size of $commasize?" 9 40
            then
              echo "Download undesired - $commasize is too big."
              exit
            fi
          fi
        fi
      fi
      # download the package
      debug "Mode3: Start download using curl" # comment
      curl "$url" >"$file" || error "Failed to download '$url' to '$file'."
      status=repos-curl
    fi
  fi
  cd "$temp"
  # extract the manpages
  # create the list of all mandirs (X11R6 is only for sarge - didn't find it in etch anymore)
  # and add language specific manpages: fr -> fr.* (-> fr+fr.ISO8859-1+"fr."...)
  mandirs="./usr/share/man/man*/ /usr/share/man/man*/ ./usr/share/doc/ /usr/share/doc/"
  for l in `echo "$lang"|tr "," " "`
  do
    mandirs="$mandirs ./usr/share/man/$l/ /usr/share/man/$l/"
  done
  debug "Using tar pattern '$mandirs'" # comment
  debug "Mode1/3: Extract the manpage and doc dirs from '$file'" # comment
  dpkg --fsys-tarfile "$file" | tar --wildcards -xf - $mandirs 2>/dev/null
  # find all manpage files
  manpages=`find usr -type f 2>/dev/null|sort|sed -e 's§\([^/]*\)$§\1 \1§'`
fi

while true
do
  # test if manpages where found
  test -z "$manpages" && error "No manpage exists for package '$package'."

  # select your manpages using dialog
  if [ "$cmd" = "zenity" ]
  then
    return=`$cmd --title="Debmany: $package" --text="Select a file ($status:$package)" --width=800 --height=600 --list --column=Path --column=File $manpages`
  else
    exec 3>&1
    return=`$cmd --title "Select a file ($status:$package)" --menu '' $y $x $h $manpages 2>&1 1>&3`
    exec 3>&-
  fi

  if [ -n "$return" ]
  then
    # show the manpage
    if echo $return | grep -q usr/share/man
    then
      path=$(dirname `dirname "$return"`)
      file=`echo "$return"|sed "s§^$path/§§"`
      if [ "${return##/*}" ] # test relative path
      then
        # it is a temporary extracted archive
        debug "Going to manpage directory: $temp/$path" # comment
        cd "$temp/$path"
      else
        # installed manpage
        debug "Going to manpage directory: $path" # comment
        cd "$path"
      fi
      debug "Opening manpage file: "`printf "$mancmdline" "$PWD/$file"` # comment
      eval $(printf "$mancmdline" "$PWD/$file")
      cd - >/dev/null
    else
      # other file (usr/share/doc)
      debug "Opening other file: "`printf "$othercmdline" "$PWD/$return"` # comment
      eval $(printf "$othercmdline" "$PWD/$return")
    fi
  else
    cd "$curdir"
    exit
  fi
done