You are not logged in.

#1 2012-03-13 09:01:10

AnimaInvicta
Member
Registered: 2012-03-04
Posts: 2

Arch Linux Pacman Proxy Script

Since my Arch box has no internet connection (yes, I'm that much of a masochist), I wrote a bash script to act as a proxy of sorts for pacman, at least as regards downloading. It took a while to get it working (intermittent web access and all) but here it finally is, as promised.
It works well for me, and I only hope that it will help anyone else in the same situation (if there is anyone else in the same situation).

The script has various options to explain everything you need to know, but here's a quick word of warning: it only works on POSIX-compatible computers (i.e. no Wintendows, usually) and the proxy box needs to have bash, wget, tar, grep and sed installed. I don't see this as being a problem, but if I'm wrong, tell me all about it.

#!/bin/bash

readonly VER="2.1"
readonly wgetVER=`wget -V|sed '1!d'`
# DEBUG levels:
# Set to 0 for ALERT-level messages only
# Set to 1 for INFO-level messages (I prefer this)
# Set to 2 for DEBUG-level messages
# Set to 3 for all messages
readonly DEBUG=0
# Set DEBUGLOG=1 to print ALERT, INFO and DEBUG messages to DEBUG.log
readonly DEBUGLOG=0
readonly COLOUR=true
if [[ $COLOUR == true ]] ; then
 readonly red='\e[31m'
 readonly warn='\e[31;7m '
 readonly green='\e[32m'
 readonly lgreen='\e[32;1m'
 readonly yellow='\e[33;1m'
 readonly lblue='\e[34;1m'
 readonly dull='\e[0m' ; fi

# Sticky details:
# tar seems very slow (vfat? transform? USB?)

function bugspray {
 [[ -z $2 ]] && verbosity=1 || verbosity=$2
 if (( DEBUG >= verbosity )) ; then
  (( $2 == 0 )) && intro="${warn}ALERT${dull} | "
  (( $2 == 1 )) && intro=" INFO  | "
  (( $2 > 1 )) && intro=" ${yellow}DEBUG${dull} | "
  echo -e "$intro$1"
  (( DEBUGLOG == 1 )) && echo "`date +%F_%T` | $1">>log-alpps/DEBUG.log ; fi ; }

function compare_versions {
 # Requires two ordinary, untweaked version strings, first local, second distant
 if [[ -z $2 ]] ; then
  bugspray "compare_versions didn't receive two variables." 2 ; fi
 update='no'
 [[ -z $2 ]] && return
 local localversion=(`echo $1|sed -r 's/([[:alpha:]]+)/ \1 /g;s/[\.:~_-]/ /g'`)
 local distantversion=(`echo $2|sed -r 's/([[:alpha:]]+)/ \1 /g;s/[\.:~_-]/ /g'`)
 local max=$((${#distantversion[*]}))
 bugspray "localversion: ${localversion[*]}; distantversion: ${distantversion[*]}" 2
 for (( x=0 ; (( x < $max )) ; $((x++)) )) ; do
  bugspray "local version part: `echo ${localversion[$x]}` | distant version part: `echo ${distantversion[$x]}`" 2
  if [[ `echo ${localversion[$x]}|grep -E '^[0-9]*$'` && `echo ${distantversion[$x]}|grep -E '^[0-9]*$'` ]] ; then
   bugspray "Numerical comparison" 2
   bugspray "localver (${localversion[$x]}) less than distantver (${distantversion[$x]}): $(( 10#${localversion[$x]} < 10#${distantversion[$x]} ))" 3
   # Different compare methods for numbers, single letters and multiple letters.
   if (( 10#${localversion[$x]} < 10#${distantversion[$x]} )) ; then
    update='yes'
    break ; fi ; fi
  if [[ `echo ${localversion[$x]}|grep -E '^[[:alpha:]]$'` && `echo ${distantversion[$x]}|grep -E '^[[:alpha:]]$'` ]] ; then # single letter -> compare
   bugspray "Lexicographical comparison" 2
   bugspray "localver (${localversion[$x]}) less than distantver (${distantversion[$x]}): [[ ${localversion[$x]} < ${distantversion[$x]} ]]" 3
   if [[ ${localversion[$x]} < ${distantversion[$x]} ]] ; then
    update='yes'
    break ; fi ; fi
  if [[ `echo ${localversion[$x]}|grep -E '^[[:alpha:]]+$'` && `echo ${distantversion[$x]}|grep -E '^[[:alpha:]]+$'` ]] ; then # string -> drop
   # cvs / git / beta -> what are the rules?
   bugspray "Sequence of letters. Not treating as version number." 2 ; fi
  done ; }

function find_dependencies {
 # Determine existence via unique path
 bugspray "+ ${lgreen}Building download list for package \"$1\"${dull}" 1
 local packagename
 local dlfile
 local package_found=no
 if [[ `ls .temp-alpps/*.db/$1-* 2>/dev/null` ]] ; then
  bugspray "Analogous package-name file(s) found" 2
  for x in `ls .temp-alpps/*.db/$1-*/desc` ; do
   bugspray "Checking $x" 2
   packagename=`sed -r '/%NAME%/,+1!d;/%NAME%/d' $x`
   if [[ j$packagename == j$1 ]] ; then
    bugspray "Exact match found: $packagename = $1" 2
    dlfile=`sed '/%FILENAME%/,+1!d;/%FILENAME%/d' $x`
    local distantversion=`sed '/%VERSION%/,+1!d;/%VERSION%/d' $x`
    local package_full=$packagename-$distantversion
    local the_repo=`echo $x|sed -r 's/.temp-alpps\/(.*)\.db.*/\1/'`
    local the_path=`echo $x|sed -r 's/desc//'`
    unplus=`echo $packagename|sed 's/\+/\\\+/g'`
    local local_version=`sed -r '/^'$unplus' /!d;s/.* //' .temp-alpps/snapshot.state`
    package_found=yes
    break ; fi ; done ; fi
 if [[ -z $dlfile ]] ; then
  bugspray "Exact match not found -> looking for replacements." 2
  if ! [[ -z `grep $1 .temp-alpps/*.db/*/depends` ]] ; then
   local provisional=`grep $1 .temp-alpps/*.db/*/depends|sed -r 's/\/depends.*//'`
   for package in $provisional ; do
    local providence=`sed -r '/%PROVIDES%/,/^$/!d;/%PROVIDES%/d;/^$/d;s/>.*//;s/=.*//' $package/depends`
    for y in $providence ; do
     if [[ j$y == j$1 ]] ; then
      # But what about when several packages provide the same thing and ALPPS picks the wrong one? Can it happen?
      local newdep=`sed -r '/%NAME%/,+1!d;/%NAME%/d' $package/desc`
      bugspray " -> Package \"$newdep\" provides \"$1\"." 1
      find_dependencies $newdep
      break 2 ; fi ; done ; done
   if [[ -z $newdep ]] ; then
    bugspray "${warn}Warning:${dull} package \"$1\" not found in database." 0 ; fi ; fi ; fi
 bugspray "package: $1 | package_found = $package_found" 2
 # Add file to download_list if not up to date and if not already present
 if [[ j$package_found == jyes ]] ; then
  local already_got_one=no
   unplus=`echo $dlfile|sed 's/\+/\\\+/g'`
  [[ `echo $download_files|grep $unplus` ]] && already_got_one="yes" && bugspray "${green}Package in queue${dull}" 1
  [[ `ls downloads/$dlfile 2>/dev/null` ]] && already_got_one="yes" && bugspray "${green}Package proxied${dull}" 1
  compare_versions $local_version $distantversion
  bugspray "compare_versions says: $update" 2
  ! [[ -z $local_version || $update == yes ]] && already_got_one="yes" && bugspray "${green}Package already installed and up-to-date${dull}" 1
  if [[ j$already_got_one != jyes ]] ; then
   bugspray "${green}Confirm downloading${dull}" 1
   download_files+="$dlfile "
   download_array[${dlfile}]=$the_repo
   bugspray "Checking for further dependencies" 2
   if [[ -a $the_path/depends && `grep -E '^%DEPENDS%$' $the_path/depends` ]] ; then
    local dependency=`sed -r '/%DEPENDS%/d;/^$/q' $the_path/depends`
    bugspray "Dependencies of \"$packagename\":$dependency" 3
    for x in $dependency ; do
     # Is this dependency already installed? Sort-of the same as higher up; it just saves time here.
     local depname=`echo $x|sed -r 's/>.*//;s/=.*//'`
     local depminver=`echo $x|sed -r 's/.*>//'`
     bugspray "Dependency name: \"$depname\"" 2
     if ! [[ `grep -E '^$depname ' .temp-alpps/snapshot.state` ]] ; then
      find_dependencies $depname ; fi ; done
   else
    bugspray "${lblue}End of the line${dull}: package \"$packagename\" has no dependencies." 2
    true ; fi ; fi ; fi ; }

function failover_fetch {
 echo "Downloading `echo $1|sed 's/.*\///'`"
 [[ -d log-alpps/ ]] || mkdir log-alpps/
 [[ -z $success ]] || unset success
 for mirror in $(<.temp-alpps/snapshot.mirrorlist) ; do
  # If DEBUG>0, shouldn't redirect output
  url=`echo $mirror|sed 's/$arch/'$arch'/;s/$repo/'${download_array[$1]}'/'`/$1
  bugspray "Connecting to $url" 2
  wget -o .temp-alpps/very-temp-log -U "Arch Linux Pacman Proxy Script version $VER / $wgetVER" -P downloads/ $url && success=true
  cat .temp-alpps/very-temp-log>>log-alpps/download.log
  rm -f .temp-alpps/very-temp-log
  if [[ -n $success ]] ; then
   bugspray "Download: \$success = true" 2
   break ; fi ; done
 if [[ -z $success ]] ; then
  bugspray "${warn}FAIL:${dull} $1 not accessible on known mirrors." 0 ; fi ; }

case $1 in
 warranty)
  echo
  echo -e " ${green}Warranty${dull}"
  echo -e " ${green}========${dull}"
  echo "  This program is free software. It comes without any warranty, to"
  echo "  the extent permitted by applicable law. You can redistribute it"
  echo "  and/or modify it under the terms of the Do What The Fuck You Want"
  echo "  To Public License, Version 2, as published by Sam Hocevar. See"
  echo "  http://sam.zoy.org/wtfpl/COPYING for more details."
  echo
  ;;
 howto)
  echo
  echo -e " ${green}How to use ALPPS${dull}"
  echo -e " ${green}================${dull}"
  echo -e "  ${yellow}+ Step 0${dull}: prime the engine"
  echo "    On your offline box, copy the ALPPS script onto a removable medium, cd into"
  echo "    it's directory, then run it with the \"init\" option. This essentially"
  echo "    takes a snapshot of your system, package-wise. Your removable medium is"
  echo "    now ready for use!"
  echo -e "  ${yellow}+ Step 1${dull}:"
  echo "    On the proxy box the first order of business is to download and decompress"
  echo "    the current package lists. You can do this with the \"fetchdb\" option."
  echo -e "  ${yellow}+ Step 1 alt${dull}:"
  echo "    If you want to download the package lists without decompressing them,"
  echo "    \"fetchdb simple\" will do this. It's a lot quicker, but please keep"
  echo "    in mind that you cannot then do anything in step 2."
  echo -e "  ${yellow}+ Step 2${dull}:"
  echo "    If you want to download packages (and why wouldn't you?), the easiest way"
  echo "    is to prepare a simple text file containing the names of the packages you"
  echo "    want, one on each line. Run ALPPS with the option \"fetch <filename>\" and"
  echo "    sit back and wait until it's done. Don't worry about dependencies: ALPPS"
  echo "    handles them automatically."
  echo -e "  ${yellow}+ Step 2 alt${dull}:"
  echo "    As a convenience, \"fetch full\" will download all the packages needed to"
  echo "    update the offline box."
  echo -e "  ${yellow}+ Step 3${dull}:"
  echo "    Finally, back on your offline box, run ALPPS again with the \"install\""
  echo "    option. This will update the package list and copy the package files into"
  echo "    local cache. You can now run \"pacman -S <package names>\" to finish"
  echo "    installing the packages."
            # ALPPS no longer installs the packages, just caches them locally.
            # Not entirely sure why; it just felt too klutzy.
  echo -e "  ${yellow}+ Step 4${dull}:"
  echo "    You will now probably want to delete all the stuff you no longer need. Run"
  echo "    ALPPS with the option \"clean\". This won't touch your request file(s). It"
  echo -e "    ${red}WILL${dull} delete log files, so if you want to keep them, back them up first."
  echo "    Next time you do this, don't forget to run ALPPS with \"init\" again."
  echo
  ;;
 bugs)
  echo
  echo -e " ${green}Where this goes wrong${dull}"
  echo -e " ${green}=====================${dull}"
  echo "  + ALPPS is a bit slow when packages have many dependencies. It's a recursive"
  echo "    shell script: what did you expect?"
  echo "  + It only uses the settings in /etc/pacman.conf. If your conf file is"
  echo "    elsewhere, you're SOL. Similarly, the repositories are all taken from"
  echo "    /etc/pacman.d/mirrorlist. If you added any custom repositories in"
  echo "    /etc/pacman.conf (or any other file), ALPPS ignores them."
  echo "  + As it stands, ALPPS only works when the proxy box has bash, wget, sed,"
  echo "    grep and tar installed. The offline box needs bash, pacman and sed (in"
  echo "    theory, this shouldn't be a problem...)."
  echo "  + There is as yet no way of handling package groups, short of listing every"
  echo "    member of the group."
  echo "  + I don't think ALPPS will ever be able to handle AUR packages. Of course, if"
  echo "    you're compiling AUR packages, you probably won't need something like this!"
  echo
  ;;
 faq)
  echo
  echo -e " ${green}Frequently Asked Questions${dull}"
  echo -e " ${green}==========================${dull}"
  echo
  echo -e "  ${red}Q:${dull} Can I run the whole thing off a USB stick?"
  echo -e "  ${lblue}A:${dull} Certainly."
  echo
  echo -e "  ${red}Q:${dull} Can I use a non-POSIX computer as a proxy (e.g. Windows)?"
  echo -e "  ${lblue}A:${dull} Probably not, unless that computer has a POSIX-compatibility layer"
  echo "     installed (such as Cygwin) with bash, wget, tar, sed and grep."
  echo
  echo -e "  ${red}Q:${dull} Do I need to download the package list, waste time updating my computer,"
  echo "     then go back again to download the packages I want?"
  echo -e "  ${lblue}A:${dull} Nope! You can update the packagelist database and download piping-hot"
  echo "     fresh packages, all in one sitting."
  echo -e "  ${red}Q:${dull} You mean I won't have to futz around with package lists that keep updating"
  echo "     ten minutes after I download them?"
  echo -e "  ${lblue}A:${dull} Exactly. Nice, isn't it?"
  echo
  echo -e "  ${red}Q:${dull} Does this thing handle SSL and signed packages?"
  echo -e "  ${lblue}A:${dull} ALPPS uses SSL if:"
  echo "     - the mirror has an https address (at present, none do), and"
  echo "     - wget on the proxy box is compiled with SSL support"
  echo "     Concerning signed packages: no, but then again, it doesn't need to. ALPPS"
  echo "     downloads packages; it's pacman's responsibility to verify them. Your"
  echo "     system remains safe (or as safe as it ever was, at any rate)."
  echo -e "  ${red}Q:${dull} What about gpg keys? I need to get them."
  echo -e "  ${lblue}A:${dull} ...maybe later, say, in version 3."
  echo
  echo -e "  ${red}Q:${dull} ALPPS says it \`prepares databases´. Can pacman still use them after this?"
  echo -e "  ${lblue}A:${dull} Yes, it can. In fact, what ALPPS does is extract the databases into a"
  echo "     temp directory, without altering the original .db files."
  echo
  echo -e "  ${red}Q:${dull} Where can I contact you?"
  echo -e "  ${lblue}A:${dull} For constructive, useful questions and comments: tacredips@gmail.com and"
  echo "     be sure to mention Arch Linux in the subject."
  echo "     For flames, trolling, spam and the like, visit your local bitbucket."
  echo
  ;;
 todo)
  echo
  echo -e " ${green}What's next?${dull}"
  echo -e " ${green}============${dull}"
  echo -e "  + I ${red}might${dull} be able to extend the reach of this thing to the AUR."
  echo "    Yes, I know I said ALPPS couldn't (in \"bugs\"), but I've learned"
  echo "    something new since then. It'll be tricky, though, since the AUR web"
  echo "    interface delivers results in python. While this should be a Good Thing,"
  echo "    bash isn't very good at handling python-format lists and dicts."
  echo
  ;;
 -v|ver|version|--ver|--version)
  echo -e "${lgreen}Arch Linux pacman proxy script${dull} | ${yellow}version $VER${dull}"
  ;;
 dl_list) # Debugging
  (( DEBUG == 0 )) && echo "the \"dl_list\" option is only for debugging" && exit 0
  arch=$(<.temp-alpps/snapshot.architecture)
  unset download_files
  unset download_array
  declare -A download_array
  find_dependencies $2
  bugspray "Download list: $download_files" 3
  echo "Download list v2:"
  for x in $download_files ; do
   bugspray " File \"$x\" from repo \"${download_array[$x]}\"" 3
   echo " Full URL: http://mirror.archlinux.org/${download_array[$x]}/os/$arch/$x" ; done
  ;;
 verint) # Debugging
  (( DEBUG == 0 )) && echo "the \"verint\" option is only for debugging" && exit 0
  for x in `ls .temp-alpps/*/$2-*/desc` ; do
   packagename=`sed -r '/%NAME%/,+1!d;/%NAME%/d' $x`
   if [[ j$packagename == j$2 ]] ; then
    bugspray "Unique package-name file found: $packagename=$2" 2
    distantversion=`sed '/%VERSION%/,+1!d;/%VERSION%/d' $x`
    dlfile=`sed '/%FILENAME%/,+1!d;/%FILENAME%/d' $x`
    package_full=$packagename-$distantversion
    the_repo=`echo $x|sed -r 's/.temp-alpps\/(.*)\.db.*/\1/'`
    the_path=`echo $x|sed -r 's/desc//'`
    local_version=`sed -r '/^'$packagename' /!d;s/.* //' .temp-alpps/snapshot.state`
    break ; fi ; done
  echo "full package filename: $dlfile"
  echo "Comparing local ($local_version) and distant ($distantversion) versions of $2..."
  compare_versions $local_version $distantversion
  #compare_versions 2.5beta3-2 2.5cvs4-1
  echo "...and the verdict is: $update"
  ;;
 init)
  x=`uname -m`
  if [[ -x /usr/bin/pacman ]] ; then
   [[ -d .temp-alpps ]] || mkdir .temp-alpps/
   pacman -Q>.temp-alpps/snapshot.state
   sed -r '/^Se/!d;s/Server = //' /etc/pacman.d/mirrorlist>.temp-alpps/snapshot.mirrorlist
   sed -r '/^\[/!d;/options/d;s/\[(.*)\]/\1/' /etc/pacman.conf>.temp-alpps/snapshot.repositories
   sed -r '/^Architecture/!d;s/^.*= //' /etc/pacman.conf>.temp-alpps/snapshot.architecture
   [[ ! -s .temp-alpps/snapshot.architecture || auto == $(<.temp-alpps/snapshot.architecture) ]] && $x>.temp-alpps/snapshot.architecture
   sed -r '/^SyncFirst/!d;s/.*= //;s/ /\n/g' /etc/pacman.conf>.temp-alpps/snapshot.prioritypackages
   echo "Current state recorded."
  else
   echo "You seem to be running ALPPs on an unsupported system."
   echo "ALPPS is the ${lgreen}Arch Linux Pacman Proxy Script${dull} and simply"
   echo "won't run properly on a non-pacman OS (except when proxying)."
   echo "Aborting. Sorry."
   exit 1 ; fi
  ;;
 fetchdb)
  [[ -d downloads ]] || mkdir downloads
  arch=$(<.temp-alpps/snapshot.architecture)
  declare -A download_array
  for repo in $(<.temp-alpps/snapshot.repositories) ; do
   download_array[${repo}.db]=$repo
   location="${repo}.db"
   failover_fetch $location ; done
  if [[ j$2 != jsimple ]] ; then
   [[ -d log-alpps ]] || mkdir log-alpps
   [[ -a syncfirst ]] && rm -f syncfirst
   echo "Preparing databases for local processing. This might take a while."
   for x in $(<.temp-alpps/snapshot.repositories) ; do
    echo "Preparing $x.db"
    if [[ -a downloads/$x.db ]] ; then
     [[ -d .temp-alpps/$x.db ]] || mkdir .temp-alpps/$x.db/
     tar -xzC .temp-alpps/$x.db/ -f downloads/$x.db --transform 's/:/§/' --no-same-owner && echo "$x database ready for use."
    else
     echo -e "Database $x.db is missing. Skipping. This will probably cause problems." ; fi ; done
   # SyncFirst package warning
   [[ -z $download_list ]] || unset download_list
   [[ -a syncfirst ]] && rm -f syncfirst
   for x in $(<.temp-alpps/snapshot.prioritypackages) ; do
    find_dependencies $x ; done
   bugspray "download_files: $download_files" 2
   if [[ ! -z $download_files ]] ; then
    echo "New version(s) of SyncFirst package(s):"
    for x in $(<.temp-alpps/snapshot.prioritypackages) ; do
     [[ ! -z `echo $download_files|grep $x` ]] && echo "- $x" && echo $x>>syncfirst ; done
    echo "Package names placed in 'syncfirst'. Don't forget to download them!" ; fi ; fi
  ;;
 fetch)
  for x in $(<.temp-alpps/snapshot.repositories) ; do
   if ! [[ -d .temp-alpps/$x.db/ ]] ; then
    bugspray "You must first download a fresh database with the \"fetchdb\" option" 0
    exit 1 ; fi ; done
  arch=$(<.temp-alpps/snapshot.architecture)
  unset download_array
  declare -A download_array
  unset download_files
  if [[ $2 == full ]] ; then
   echo " Building full upgrade list. This will almost certainly take a while."
   echo " Please wait..."
   for y in `sed -r 's/^(.*) .*/\1/' .temp-alpps/snapshot.state` ; do
    bugspray "Examining $y" 1
    find_dependencies $y ; done
  elif [[ -a $2 ]] ; then
   echo " Determining dependencies. This might take a while. Please wait."
   for y in $(<$2) ; do
    bugspray "Examining $y" 1
    find_dependencies $y ; done
  else
   echo " Error: you should provide a list-file or the keyword \"full\"."
   echo "        (see 'alpps.sh howto', step 2)"
  exit 1 ; fi
  if [[ -z $download_files ]] ; then
   echo " No files to download: either none found, or all found are up to date."
  else
   [[ -d downloads ]] || mkdir downloads
   for x in $download_files ; do
    failover_fetch $x ; done ; fi
  ;;
 install)
  dbpath=`sed -r '/^DBPath/!d;s/^.*= //' /etc/pacman.conf`
  [[ -z $dbpath ]] && dbpath="/var/lib/pacman/"
  bugspray "dbpath: $dbpath" 2
  echo " Updating databases"
  cp -ft ${dbpath}sync/ downloads/*.db
  cachedir=`sed -r '/^CacheDir/!d;s/^.*= //' /etc/pacman.conf`
  [[ -z $cachedir ]] && cachedir="/var/cache/pacman/pkg/"
  echo " Caching packages"
  cp -f downloads/*.pkg.tar.xz $cachedir
  echo
  echo " Don't forget to install/update your packages."
  echo " Exercise proper caution."
  echo " Have fun!"
  ;;
 clean)
  echo "Cleaning up. This might take a while."
  rm -fr .temp-alpps/ && echo "Buffer directory deleted" || echo "Problem deleting buffer directory '.temp-alpps/'"
  rm -fr log-alpps/ && echo "Log directory deleted" || echo "Problem deleting 'log-alpps/'"
  rm -fr downloads/ && echo "Downloaded packages deleted" || echo "Problem deleting 'downloads/'"
  ;;
 *)
  echo
  echo -e "                         ${lgreen}Arch Linux pacman proxy script${dull}"
  echo
  echo -e " ${green}Description${dull}"
  echo -e " ${green}===========${dull}"
  echo -e "  This is a bash script to fetch and install packages for an offline Arch box"
  echo "  using another, online box as a proxy of sorts. So far, this only works if"
  echo "  the proxy box has bash, wget, tar, sed and grep installed."
  echo "  It's probably also entirely unsafe, incompatible and will destroy your box"
  echo "  in a fiery blaze if you try to use it (you know the drill)."
  echo
  echo -e " ${green}Options${dull}"
  echo -e " ${green}=======${dull}"
  echo "  init           Step 0 (as it were): take a snapshot of your system"
  echo "  fetchdb        Step 1: download the packagelist database"
  echo "  fetch <file>   Step 2: download requested packages"
  echo "  install        Step 3: update your system"
  echo "  clean          Step 4: delete any unneeded files"
  echo
  echo "  howto      More detailed instructions"
  echo "  bugs       Problems and future plans"
  echo "  faq        As it says"
  echo "  warranty   (in case it ever becomes necessary)"
  echo "  version    (to be honest, I wasn't expecting to go beyond v1-rc or so)"
  echo "  help       You're reading it, doofus :^)"
  echo
  #       dl_list  Test the find_dependencies function"
  #       verint   Test the compare_versions function"
  ;;
esac

Offline

#2 2012-03-13 20:44:31

doctorzeus
Member
Registered: 2011-12-24
Posts: 79

Re: Arch Linux Pacman Proxy Script

AnimaInvicta wrote:

Since my Arch box has no internet connection (yes, I'm that much of a masochist), I wrote a bash script to act as a proxy of sorts for pacman, at least as regards downloading. It took a while to get it working (intermittent web access and all) but here it finally is, as promised.
It works well for me, and I only hope that it will help anyone else in the same situation (if there is anyone else in the same situation).

The script has various options to explain everything you need to know, but here's a quick word of warning: it only works on POSIX-compatible computers (i.e. no Wintendows, usually) and the proxy box needs to have bash, wget, tar, grep and sed installed. I don't see this as being a problem, but if I'm wrong, tell me all about it.

#!/bin/bash

readonly VER="2.1"
readonly wgetVER=`wget -V|sed '1!d'`
# DEBUG levels:
# Set to 0 for ALERT-level messages only
# Set to 1 for INFO-level messages (I prefer this)
# Set to 2 for DEBUG-level messages
# Set to 3 for all messages
readonly DEBUG=0
# Set DEBUGLOG=1 to print ALERT, INFO and DEBUG messages to DEBUG.log
readonly DEBUGLOG=0
readonly COLOUR=true
if [[ $COLOUR == true ]] ; then
 readonly red='\e[31m'
 readonly warn='\e[31;7m '
 readonly green='\e[32m'
 readonly lgreen='\e[32;1m'
 readonly yellow='\e[33;1m'
 readonly lblue='\e[34;1m'
 readonly dull='\e[0m' ; fi

# Sticky details:
# tar seems very slow (vfat? transform? USB?)

function bugspray {
 [[ -z $2 ]] && verbosity=1 || verbosity=$2
 if (( DEBUG >= verbosity )) ; then
  (( $2 == 0 )) && intro="${warn}ALERT${dull} | "
  (( $2 == 1 )) && intro=" INFO  | "
  (( $2 > 1 )) && intro=" ${yellow}DEBUG${dull} | "
  echo -e "$intro$1"
  (( DEBUGLOG == 1 )) && echo "`date +%F_%T` | $1">>log-alpps/DEBUG.log ; fi ; }

function compare_versions {
 # Requires two ordinary, untweaked version strings, first local, second distant
 if [[ -z $2 ]] ; then
  bugspray "compare_versions didn't receive two variables." 2 ; fi
 update='no'
 [[ -z $2 ]] && return
 local localversion=(`echo $1|sed -r 's/([[:alpha:]]+)/ \1 /g;s/[\.:~_-]/ /g'`)
 local distantversion=(`echo $2|sed -r 's/([[:alpha:]]+)/ \1 /g;s/[\.:~_-]/ /g'`)
 local max=$((${#distantversion[*]}))
 bugspray "localversion: ${localversion[*]}; distantversion: ${distantversion[*]}" 2
 for (( x=0 ; (( x < $max )) ; $((x++)) )) ; do
  bugspray "local version part: `echo ${localversion[$x]}` | distant version part: `echo ${distantversion[$x]}`" 2
  if [[ `echo ${localversion[$x]}|grep -E '^[0-9]*$'` && `echo ${distantversion[$x]}|grep -E '^[0-9]*$'` ]] ; then
   bugspray "Numerical comparison" 2
   bugspray "localver (${localversion[$x]}) less than distantver (${distantversion[$x]}): $(( 10#${localversion[$x]} < 10#${distantversion[$x]} ))" 3
   # Different compare methods for numbers, single letters and multiple letters.
   if (( 10#${localversion[$x]} < 10#${distantversion[$x]} )) ; then
    update='yes'
    break ; fi ; fi
  if [[ `echo ${localversion[$x]}|grep -E '^[[:alpha:]]$'` && `echo ${distantversion[$x]}|grep -E '^[[:alpha:]]$'` ]] ; then # single letter -> compare
   bugspray "Lexicographical comparison" 2
   bugspray "localver (${localversion[$x]}) less than distantver (${distantversion[$x]}): [[ ${localversion[$x]} < ${distantversion[$x]} ]]" 3
   if [[ ${localversion[$x]} < ${distantversion[$x]} ]] ; then
    update='yes'
    break ; fi ; fi
  if [[ `echo ${localversion[$x]}|grep -E '^[[:alpha:]]+$'` && `echo ${distantversion[$x]}|grep -E '^[[:alpha:]]+$'` ]] ; then # string -> drop
   # cvs / git / beta -> what are the rules?
   bugspray "Sequence of letters. Not treating as version number." 2 ; fi
  done ; }

function find_dependencies {
 # Determine existence via unique path
 bugspray "+ ${lgreen}Building download list for package \"$1\"${dull}" 1
 local packagename
 local dlfile
 local package_found=no
 if [[ `ls .temp-alpps/*.db/$1-* 2>/dev/null` ]] ; then
  bugspray "Analogous package-name file(s) found" 2
  for x in `ls .temp-alpps/*.db/$1-*/desc` ; do
   bugspray "Checking $x" 2
   packagename=`sed -r '/%NAME%/,+1!d;/%NAME%/d' $x`
   if [[ j$packagename == j$1 ]] ; then
    bugspray "Exact match found: $packagename = $1" 2
    dlfile=`sed '/%FILENAME%/,+1!d;/%FILENAME%/d' $x`
    local distantversion=`sed '/%VERSION%/,+1!d;/%VERSION%/d' $x`
    local package_full=$packagename-$distantversion
    local the_repo=`echo $x|sed -r 's/.temp-alpps\/(.*)\.db.*/\1/'`
    local the_path=`echo $x|sed -r 's/desc//'`
    unplus=`echo $packagename|sed 's/\+/\\\+/g'`
    local local_version=`sed -r '/^'$unplus' /!d;s/.* //' .temp-alpps/snapshot.state`
    package_found=yes
    break ; fi ; done ; fi
 if [[ -z $dlfile ]] ; then
  bugspray "Exact match not found -> looking for replacements." 2
  if ! [[ -z `grep $1 .temp-alpps/*.db/*/depends` ]] ; then
   local provisional=`grep $1 .temp-alpps/*.db/*/depends|sed -r 's/\/depends.*//'`
   for package in $provisional ; do
    local providence=`sed -r '/%PROVIDES%/,/^$/!d;/%PROVIDES%/d;/^$/d;s/>.*//;s/=.*//' $package/depends`
    for y in $providence ; do
     if [[ j$y == j$1 ]] ; then
      # But what about when several packages provide the same thing and ALPPS picks the wrong one? Can it happen?
      local newdep=`sed -r '/%NAME%/,+1!d;/%NAME%/d' $package/desc`
      bugspray " -> Package \"$newdep\" provides \"$1\"." 1
      find_dependencies $newdep
      break 2 ; fi ; done ; done
   if [[ -z $newdep ]] ; then
    bugspray "${warn}Warning:${dull} package \"$1\" not found in database." 0 ; fi ; fi ; fi
 bugspray "package: $1 | package_found = $package_found" 2
 # Add file to download_list if not up to date and if not already present
 if [[ j$package_found == jyes ]] ; then
  local already_got_one=no
   unplus=`echo $dlfile|sed 's/\+/\\\+/g'`
  [[ `echo $download_files|grep $unplus` ]] && already_got_one="yes" && bugspray "${green}Package in queue${dull}" 1
  [[ `ls downloads/$dlfile 2>/dev/null` ]] && already_got_one="yes" && bugspray "${green}Package proxied${dull}" 1
  compare_versions $local_version $distantversion
  bugspray "compare_versions says: $update" 2
  ! [[ -z $local_version || $update == yes ]] && already_got_one="yes" && bugspray "${green}Package already installed and up-to-date${dull}" 1
  if [[ j$already_got_one != jyes ]] ; then
   bugspray "${green}Confirm downloading${dull}" 1
   download_files+="$dlfile "
   download_array[${dlfile}]=$the_repo
   bugspray "Checking for further dependencies" 2
   if [[ -a $the_path/depends && `grep -E '^%DEPENDS%$' $the_path/depends` ]] ; then
    local dependency=`sed -r '/%DEPENDS%/d;/^$/q' $the_path/depends`
    bugspray "Dependencies of \"$packagename\":$dependency" 3
    for x in $dependency ; do
     # Is this dependency already installed? Sort-of the same as higher up; it just saves time here.
     local depname=`echo $x|sed -r 's/>.*//;s/=.*//'`
     local depminver=`echo $x|sed -r 's/.*>//'`
     bugspray "Dependency name: \"$depname\"" 2
     if ! [[ `grep -E '^$depname ' .temp-alpps/snapshot.state` ]] ; then
      find_dependencies $depname ; fi ; done
   else
    bugspray "${lblue}End of the line${dull}: package \"$packagename\" has no dependencies." 2
    true ; fi ; fi ; fi ; }

function failover_fetch {
 echo "Downloading `echo $1|sed 's/.*\///'`"
 [[ -d log-alpps/ ]] || mkdir log-alpps/
 [[ -z $success ]] || unset success
 for mirror in $(<.temp-alpps/snapshot.mirrorlist) ; do
  # If DEBUG>0, shouldn't redirect output
  url=`echo $mirror|sed 's/$arch/'$arch'/;s/$repo/'${download_array[$1]}'/'`/$1
  bugspray "Connecting to $url" 2
  wget -o .temp-alpps/very-temp-log -U "Arch Linux Pacman Proxy Script version $VER / $wgetVER" -P downloads/ $url && success=true
  cat .temp-alpps/very-temp-log>>log-alpps/download.log
  rm -f .temp-alpps/very-temp-log
  if [[ -n $success ]] ; then
   bugspray "Download: \$success = true" 2
   break ; fi ; done
 if [[ -z $success ]] ; then
  bugspray "${warn}FAIL:${dull} $1 not accessible on known mirrors." 0 ; fi ; }

case $1 in
 warranty)
  echo
  echo -e " ${green}Warranty${dull}"
  echo -e " ${green}========${dull}"
  echo "  This program is free software. It comes without any warranty, to"
  echo "  the extent permitted by applicable law. You can redistribute it"
  echo "  and/or modify it under the terms of the Do What The Fuck You Want"
  echo "  To Public License, Version 2, as published by Sam Hocevar. See"
  echo "  http://sam.zoy.org/wtfpl/COPYING for more details."
  echo
  ;;
 howto)
  echo
  echo -e " ${green}How to use ALPPS${dull}"
  echo -e " ${green}================${dull}"
  echo -e "  ${yellow}+ Step 0${dull}: prime the engine"
  echo "    On your offline box, copy the ALPPS script onto a removable medium, cd into"
  echo "    it's directory, then run it with the \"init\" option. This essentially"
  echo "    takes a snapshot of your system, package-wise. Your removable medium is"
  echo "    now ready for use!"
  echo -e "  ${yellow}+ Step 1${dull}:"
  echo "    On the proxy box the first order of business is to download and decompress"
  echo "    the current package lists. You can do this with the \"fetchdb\" option."
  echo -e "  ${yellow}+ Step 1 alt${dull}:"
  echo "    If you want to download the package lists without decompressing them,"
  echo "    \"fetchdb simple\" will do this. It's a lot quicker, but please keep"
  echo "    in mind that you cannot then do anything in step 2."
  echo -e "  ${yellow}+ Step 2${dull}:"
  echo "    If you want to download packages (and why wouldn't you?), the easiest way"
  echo "    is to prepare a simple text file containing the names of the packages you"
  echo "    want, one on each line. Run ALPPS with the option \"fetch <filename>\" and"
  echo "    sit back and wait until it's done. Don't worry about dependencies: ALPPS"
  echo "    handles them automatically."
  echo -e "  ${yellow}+ Step 2 alt${dull}:"
  echo "    As a convenience, \"fetch full\" will download all the packages needed to"
  echo "    update the offline box."
  echo -e "  ${yellow}+ Step 3${dull}:"
  echo "    Finally, back on your offline box, run ALPPS again with the \"install\""
  echo "    option. This will update the package list and copy the package files into"
  echo "    local cache. You can now run \"pacman -S <package names>\" to finish"
  echo "    installing the packages."
            # ALPPS no longer installs the packages, just caches them locally.
            # Not entirely sure why; it just felt too klutzy.
  echo -e "  ${yellow}+ Step 4${dull}:"
  echo "    You will now probably want to delete all the stuff you no longer need. Run"
  echo "    ALPPS with the option \"clean\". This won't touch your request file(s). It"
  echo -e "    ${red}WILL${dull} delete log files, so if you want to keep them, back them up first."
  echo "    Next time you do this, don't forget to run ALPPS with \"init\" again."
  echo
  ;;
 bugs)
  echo
  echo -e " ${green}Where this goes wrong${dull}"
  echo -e " ${green}=====================${dull}"
  echo "  + ALPPS is a bit slow when packages have many dependencies. It's a recursive"
  echo "    shell script: what did you expect?"
  echo "  + It only uses the settings in /etc/pacman.conf. If your conf file is"
  echo "    elsewhere, you're SOL. Similarly, the repositories are all taken from"
  echo "    /etc/pacman.d/mirrorlist. If you added any custom repositories in"
  echo "    /etc/pacman.conf (or any other file), ALPPS ignores them."
  echo "  + As it stands, ALPPS only works when the proxy box has bash, wget, sed,"
  echo "    grep and tar installed. The offline box needs bash, pacman and sed (in"
  echo "    theory, this shouldn't be a problem...)."
  echo "  + There is as yet no way of handling package groups, short of listing every"
  echo "    member of the group."
  echo "  + I don't think ALPPS will ever be able to handle AUR packages. Of course, if"
  echo "    you're compiling AUR packages, you probably won't need something like this!"
  echo
  ;;
 faq)
  echo
  echo -e " ${green}Frequently Asked Questions${dull}"
  echo -e " ${green}==========================${dull}"
  echo
  echo -e "  ${red}Q:${dull} Can I run the whole thing off a USB stick?"
  echo -e "  ${lblue}A:${dull} Certainly."
  echo
  echo -e "  ${red}Q:${dull} Can I use a non-POSIX computer as a proxy (e.g. Windows)?"
  echo -e "  ${lblue}A:${dull} Probably not, unless that computer has a POSIX-compatibility layer"
  echo "     installed (such as Cygwin) with bash, wget, tar, sed and grep."
  echo
  echo -e "  ${red}Q:${dull} Do I need to download the package list, waste time updating my computer,"
  echo "     then go back again to download the packages I want?"
  echo -e "  ${lblue}A:${dull} Nope! You can update the packagelist database and download piping-hot"
  echo "     fresh packages, all in one sitting."
  echo -e "  ${red}Q:${dull} You mean I won't have to futz around with package lists that keep updating"
  echo "     ten minutes after I download them?"
  echo -e "  ${lblue}A:${dull} Exactly. Nice, isn't it?"
  echo
  echo -e "  ${red}Q:${dull} Does this thing handle SSL and signed packages?"
  echo -e "  ${lblue}A:${dull} ALPPS uses SSL if:"
  echo "     - the mirror has an https address (at present, none do), and"
  echo "     - wget on the proxy box is compiled with SSL support"
  echo "     Concerning signed packages: no, but then again, it doesn't need to. ALPPS"
  echo "     downloads packages; it's pacman's responsibility to verify them. Your"
  echo "     system remains safe (or as safe as it ever was, at any rate)."
  echo -e "  ${red}Q:${dull} What about gpg keys? I need to get them."
  echo -e "  ${lblue}A:${dull} ...maybe later, say, in version 3."
  echo
  echo -e "  ${red}Q:${dull} ALPPS says it \`prepares databases´. Can pacman still use them after this?"
  echo -e "  ${lblue}A:${dull} Yes, it can. In fact, what ALPPS does is extract the databases into a"
  echo "     temp directory, without altering the original .db files."
  echo
  echo -e "  ${red}Q:${dull} Where can I contact you?"
  echo -e "  ${lblue}A:${dull} For constructive, useful questions and comments: tacredips@gmail.com and"
  echo "     be sure to mention Arch Linux in the subject."
  echo "     For flames, trolling, spam and the like, visit your local bitbucket."
  echo
  ;;
 todo)
  echo
  echo -e " ${green}What's next?${dull}"
  echo -e " ${green}============${dull}"
  echo -e "  + I ${red}might${dull} be able to extend the reach of this thing to the AUR."
  echo "    Yes, I know I said ALPPS couldn't (in \"bugs\"), but I've learned"
  echo "    something new since then. It'll be tricky, though, since the AUR web"
  echo "    interface delivers results in python. While this should be a Good Thing,"
  echo "    bash isn't very good at handling python-format lists and dicts."
  echo
  ;;
 -v|ver|version|--ver|--version)
  echo -e "${lgreen}Arch Linux pacman proxy script${dull} | ${yellow}version $VER${dull}"
  ;;
 dl_list) # Debugging
  (( DEBUG == 0 )) && echo "the \"dl_list\" option is only for debugging" && exit 0
  arch=$(<.temp-alpps/snapshot.architecture)
  unset download_files
  unset download_array
  declare -A download_array
  find_dependencies $2
  bugspray "Download list: $download_files" 3
  echo "Download list v2:"
  for x in $download_files ; do
   bugspray " File \"$x\" from repo \"${download_array[$x]}\"" 3
   echo " Full URL: http://mirror.archlinux.org/${download_array[$x]}/os/$arch/$x" ; done
  ;;
 verint) # Debugging
  (( DEBUG == 0 )) && echo "the \"verint\" option is only for debugging" && exit 0
  for x in `ls .temp-alpps/*/$2-*/desc` ; do
   packagename=`sed -r '/%NAME%/,+1!d;/%NAME%/d' $x`
   if [[ j$packagename == j$2 ]] ; then
    bugspray "Unique package-name file found: $packagename=$2" 2
    distantversion=`sed '/%VERSION%/,+1!d;/%VERSION%/d' $x`
    dlfile=`sed '/%FILENAME%/,+1!d;/%FILENAME%/d' $x`
    package_full=$packagename-$distantversion
    the_repo=`echo $x|sed -r 's/.temp-alpps\/(.*)\.db.*/\1/'`
    the_path=`echo $x|sed -r 's/desc//'`
    local_version=`sed -r '/^'$packagename' /!d;s/.* //' .temp-alpps/snapshot.state`
    break ; fi ; done
  echo "full package filename: $dlfile"
  echo "Comparing local ($local_version) and distant ($distantversion) versions of $2..."
  compare_versions $local_version $distantversion
  #compare_versions 2.5beta3-2 2.5cvs4-1
  echo "...and the verdict is: $update"
  ;;
 init)
  x=`uname -m`
  if [[ -x /usr/bin/pacman ]] ; then
   [[ -d .temp-alpps ]] || mkdir .temp-alpps/
   pacman -Q>.temp-alpps/snapshot.state
   sed -r '/^Se/!d;s/Server = //' /etc/pacman.d/mirrorlist>.temp-alpps/snapshot.mirrorlist
   sed -r '/^\[/!d;/options/d;s/\[(.*)\]/\1/' /etc/pacman.conf>.temp-alpps/snapshot.repositories
   sed -r '/^Architecture/!d;s/^.*= //' /etc/pacman.conf>.temp-alpps/snapshot.architecture
   [[ ! -s .temp-alpps/snapshot.architecture || auto == $(<.temp-alpps/snapshot.architecture) ]] && $x>.temp-alpps/snapshot.architecture
   sed -r '/^SyncFirst/!d;s/.*= //;s/ /\n/g' /etc/pacman.conf>.temp-alpps/snapshot.prioritypackages
   echo "Current state recorded."
  else
   echo "You seem to be running ALPPs on an unsupported system."
   echo "ALPPS is the ${lgreen}Arch Linux Pacman Proxy Script${dull} and simply"
   echo "won't run properly on a non-pacman OS (except when proxying)."
   echo "Aborting. Sorry."
   exit 1 ; fi
  ;;
 fetchdb)
  [[ -d downloads ]] || mkdir downloads
  arch=$(<.temp-alpps/snapshot.architecture)
  declare -A download_array
  for repo in $(<.temp-alpps/snapshot.repositories) ; do
   download_array[${repo}.db]=$repo
   location="${repo}.db"
   failover_fetch $location ; done
  if [[ j$2 != jsimple ]] ; then
   [[ -d log-alpps ]] || mkdir log-alpps
   [[ -a syncfirst ]] && rm -f syncfirst
   echo "Preparing databases for local processing. This might take a while."
   for x in $(<.temp-alpps/snapshot.repositories) ; do
    echo "Preparing $x.db"
    if [[ -a downloads/$x.db ]] ; then
     [[ -d .temp-alpps/$x.db ]] || mkdir .temp-alpps/$x.db/
     tar -xzC .temp-alpps/$x.db/ -f downloads/$x.db --transform 's/:/§/' --no-same-owner && echo "$x database ready for use."
    else
     echo -e "Database $x.db is missing. Skipping. This will probably cause problems." ; fi ; done
   # SyncFirst package warning
   [[ -z $download_list ]] || unset download_list
   [[ -a syncfirst ]] && rm -f syncfirst
   for x in $(<.temp-alpps/snapshot.prioritypackages) ; do
    find_dependencies $x ; done
   bugspray "download_files: $download_files" 2
   if [[ ! -z $download_files ]] ; then
    echo "New version(s) of SyncFirst package(s):"
    for x in $(<.temp-alpps/snapshot.prioritypackages) ; do
     [[ ! -z `echo $download_files|grep $x` ]] && echo "- $x" && echo $x>>syncfirst ; done
    echo "Package names placed in 'syncfirst'. Don't forget to download them!" ; fi ; fi
  ;;
 fetch)
  for x in $(<.temp-alpps/snapshot.repositories) ; do
   if ! [[ -d .temp-alpps/$x.db/ ]] ; then
    bugspray "You must first download a fresh database with the \"fetchdb\" option" 0
    exit 1 ; fi ; done
  arch=$(<.temp-alpps/snapshot.architecture)
  unset download_array
  declare -A download_array
  unset download_files
  if [[ $2 == full ]] ; then
   echo " Building full upgrade list. This will almost certainly take a while."
   echo " Please wait..."
   for y in `sed -r 's/^(.*) .*/\1/' .temp-alpps/snapshot.state` ; do
    bugspray "Examining $y" 1
    find_dependencies $y ; done
  elif [[ -a $2 ]] ; then
   echo " Determining dependencies. This might take a while. Please wait."
   for y in $(<$2) ; do
    bugspray "Examining $y" 1
    find_dependencies $y ; done
  else
   echo " Error: you should provide a list-file or the keyword \"full\"."
   echo "        (see 'alpps.sh howto', step 2)"
  exit 1 ; fi
  if [[ -z $download_files ]] ; then
   echo " No files to download: either none found, or all found are up to date."
  else
   [[ -d downloads ]] || mkdir downloads
   for x in $download_files ; do
    failover_fetch $x ; done ; fi
  ;;
 install)
  dbpath=`sed -r '/^DBPath/!d;s/^.*= //' /etc/pacman.conf`
  [[ -z $dbpath ]] && dbpath="/var/lib/pacman/"
  bugspray "dbpath: $dbpath" 2
  echo " Updating databases"
  cp -ft ${dbpath}sync/ downloads/*.db
  cachedir=`sed -r '/^CacheDir/!d;s/^.*= //' /etc/pacman.conf`
  [[ -z $cachedir ]] && cachedir="/var/cache/pacman/pkg/"
  echo " Caching packages"
  cp -f downloads/*.pkg.tar.xz $cachedir
  echo
  echo " Don't forget to install/update your packages."
  echo " Exercise proper caution."
  echo " Have fun!"
  ;;
 clean)
  echo "Cleaning up. This might take a while."
  rm -fr .temp-alpps/ && echo "Buffer directory deleted" || echo "Problem deleting buffer directory '.temp-alpps/'"
  rm -fr log-alpps/ && echo "Log directory deleted" || echo "Problem deleting 'log-alpps/'"
  rm -fr downloads/ && echo "Downloaded packages deleted" || echo "Problem deleting 'downloads/'"
  ;;
 *)
  echo
  echo -e "                         ${lgreen}Arch Linux pacman proxy script${dull}"
  echo
  echo -e " ${green}Description${dull}"
  echo -e " ${green}===========${dull}"
  echo -e "  This is a bash script to fetch and install packages for an offline Arch box"
  echo "  using another, online box as a proxy of sorts. So far, this only works if"
  echo "  the proxy box has bash, wget, tar, sed and grep installed."
  echo "  It's probably also entirely unsafe, incompatible and will destroy your box"
  echo "  in a fiery blaze if you try to use it (you know the drill)."
  echo
  echo -e " ${green}Options${dull}"
  echo -e " ${green}=======${dull}"
  echo "  init           Step 0 (as it were): take a snapshot of your system"
  echo "  fetchdb        Step 1: download the packagelist database"
  echo "  fetch <file>   Step 2: download requested packages"
  echo "  install        Step 3: update your system"
  echo "  clean          Step 4: delete any unneeded files"
  echo
  echo "  howto      More detailed instructions"
  echo "  bugs       Problems and future plans"
  echo "  faq        As it says"
  echo "  warranty   (in case it ever becomes necessary)"
  echo "  version    (to be honest, I wasn't expecting to go beyond v1-rc or so)"
  echo "  help       You're reading it, doofus :^)"
  echo
  #       dl_list  Test the find_dependencies function"
  #       verint   Test the compare_versions function"
  ;;
esac

I've always resorted to use VPN, then I started using cntlm, this looks very useful (and a lot of work on your part!) Thanks alot!

DoctorZeus

Offline

Board footer

Powered by FluxBB