#!/bin/bash # apt-cyg: install tool for cygwin similar to debian apt-get # # Copyright (C) 2005-9, Stephen Jungels # # 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. # # (http://www.fsf.org/licensing/licenses/gpl.html) # this script requires some packages WGET=`which wget 2> /dev/null` BZIP2=`which bzip2 2> /dev/null` TAR=`which tar 2> /dev/null` GAWK=`which awk 2> /dev/null` if test "-$WGET-" = "--" || test "-$BZIP2-" = "--" || test "-$TAR-" = "--" \ || test "-$GAWK-" = "--" then echo You must install wget, tar, gawk and bzip2 to use apt-cyg. exit 1 fi function usage() { echo apt-cyg: Installs and removes Cygwin packages. echo " \"apt-cyg install \" to install packages" echo " \"apt-cyg remove \" to remove packages" echo " \"apt-cyg update\" to update setup.ini" echo " \"apt-cyg show\" to show installed packages" echo " \"apt-cyg find \" to find packages matching patterns" echo " \"apt-cyg search \" to find packages matching patterns (alias of find)" echo " \"apt-cyg describe \" to describe packages matching patterns" echo " \"apt-cyg packageof \" to locate parent packages" echo "Options:" echo " --mirror, -m : set mirror" echo " --cache, -c : set cache" echo " --file, -f : read package names from file" echo " --noupdate, -u : don't update setup.ini from mirror" echo " --ignore-case, -i : Ignore case distinctions in when finding packages" echo " --help" echo " --version" } function version() { echo "apt-cyg version 0.57" echo "Written by Stephen Jungels" echo "" echo "Copyright (c) 2005-9 Stephen Jungels. Released under the GPL." } function findworkspace() { # default working directory and mirror mirror=ftp://mirror.mcs.anl.gov/pub/cygwin cache=/setup # work wherever setup worked last, if possible if test -e /etc/setup/last-cache then tmp="`head -1 /etc/setup/last-cache`" cache="`cygpath -au "$tmp"`" fi if test -e /etc/setup/last-mirror then mirror="`head -1 /etc/setup/last-mirror`" fi mirrordir="`echo "$mirror" | sed -e "s/:/%3a/g" -e "s:/:%2f:g"`" echo Working directory is $cache echo Mirror is $mirror mkdir -p "$cache/$mirrordir" cd "$cache/$mirrordir" } function getsetup() { if test "$noscripts" == "0" -a "$noupdate" == "0" then touch setup.ini mv setup.ini setup.ini-save wget -N $mirror/setup.bz2 if test -e setup.bz2 && test $? -eq 0 then bunzip2 setup.bz2 mv setup setup.ini echo Updated setup.ini else wget -N $mirror/setup.ini if test -e setup.ini && test $? -eq 0 then echo Updated setup.ini else mv setup.ini-save setup.ini echo Error updating setup.ini, reverting fi fi fi } function checkpackages() { if test "-$packages-" = "--" then echo Nothing to do, exiting exit 0 fi } # process options noscripts=0 noupdate=0 file="" dofile=0 nocase=0 command="" filepackages="" packages="" function process_args () { while test $# -gt 0 do case "$1" in --mirror|-m) echo "$2" > /etc/setup/last-mirror shift ; shift ;; --cache|-c) cygpath -aw "$2" > /etc/setup/last-cache shift ; shift ;; --noscripts) noscripts=1 shift ;; --noupdate|-u) noupdate=1 shift ;; --help) usage exit 0 ;; --version) version exit 0 ;; --file|-f) if ! test "-$2-" = "--" then file="$2" dofile=1 shift else echo 1>&2 No file name provided, ignoring $1 fi shift ;; --ignore-case|-i) nocase=1 shift ;; --no-ignore-case|-no-i) nocase=0 shift ;; update|show|search|find|describe|packageof|install|remove) if test "-$command-" = "--" then command=$1 else packages="$packages $1" fi shift ;; *) packages="$packages $1" shift ;; esac done } # Check to see if global options are defined if [[ ! -z "$APTCYG_OPTIONS" ]] ; then # If we only have one element, assume it's a string to split # and parse as an array if [[ "${#APTCYG_OPTIONS[*]}" -eq "1" ]] ; then APTCYG_OPTIONS=($APTCYG_OPTIONS) fi process_args "${APTCYG_OPTIONS[@]}" fi process_args "$@" if test $dofile = 1 then if test -f "$file" then filepackages="$filepackages `cat "$file" | awk '{printf "%s ", $0}'`" else echo File $file not found, skipping fi packages="$packages $filepackages" fi case "$command" in update) findworkspace getsetup ;; show) echo 1>&2 The following packages are installed: cat /etc/setup/installed.db | awk '/[^ ]+ [^ ]+ 0/ {print $1}' ;; find|search) checkpackages findworkspace getsetup for pkg in $packages do echo "" echo Searching for installed packages matching $pkg: awk -v nocase="$nocase" '/[^ ]+ [^ ]+ 0/ { if (nocase == 1 ) { IGNORECASE=1 } if ($1 ~ query) { print $1 } }' query="$pkg" /etc/setup/installed.db echo "" echo Searching for installable packages matching $pkg: if [[ "$nocase" -eq "1" ]] ; then cat setup.ini | awk -v query="$pkg" \ 'BEGIN{RS="\n\n@ "; FS="\n"; ORS="\n"} {IGNORECASE=1; if ($1 ~ query) {print $1}}' else cat setup.ini | awk -v query="$pkg" \ 'BEGIN{RS="\n\n@ "; FS="\n"; ORS="\n"} {if ($1 ~ query) {print $1}}' fi done ;; describe) checkpackages findworkspace getsetup for pkg in $packages do echo "" cat setup.ini | awk -v nocase="$nocase" -v query="$pkg" \ 'BEGIN{RS="\n\n@ "; FS="\n"; ORS="\n"} {if (nocase == 1 ) { IGNORECASE=1 } if ($1 ~ query) {print $0 "\n"}}' done ;; packageof) checkpackages for pkg in $packages do key=`which "$pkg" 2>/dev/null | sed "s:^/::"` if test "-$key-" = "--" then key="$pkg" fi for manifest in /etc/setup/*.lst.gz do found=`cat $manifest | gzip -d | grep -c "$key"` if test $found -gt 0 then package=`echo $manifest | sed -e "s:/etc/setup/::" -e "s/.lst.gz//"` echo Found $key in the package $package fi done done ;; install) checkpackages findworkspace getsetup declare -A pkg_lookup declare -A pkg_already_installed # sanity check - find our currently installed packages, and resolve all case-insensitive names to their correct ones for pkg in $packages ; do # check for previously installed packages pkg_already_installed[$pkg]="0" pkg_lookup[$pkg]="$pkg" # case insensitive search if [[ "$nocase" -eq "1" ]] ; then already=`grep -ic "^$pkg " /etc/setup/installed.db` if test $already -ge 1 ; then # get the proper name for the package proper_name=`grep -i "^$pkg " /etc/setup/installed.db | awk '{ print $1 }'` # set our lookup value pkg_lookup[$pkg]="$proper_name" pkg_already_installed[$pkg]="1" fi # case sensitive search else already=`grep -c "^$pkg " /etc/setup/installed.db` fi if test $already -ge 1 ; then pkg_already_installed[$pkg]="1" continue fi # check for new packages and find their proper names if [[ "$nocase" -eq "1" ]] ; then proper_name=`cat setup.ini | awk -v package="$pkg" \ 'BEGIN{IGNORECASE=1; RS="\n\n@ "; FS="\n"} { if ($1 == package) { propername = $1 ; desc = $0; px++ } } \ END {if (px == 1 && desc != "") { print propername ; exit 0 } else { print "Package not found" ; exit 1 } }'` if [[ "$?" != "0" ]] ; then echo "Could not find $pkg, aborting..." exit else echo proper name of $pkg is: $proper_name pkg_lookup[$pkg]="$proper_name" continue fi fi done for pkg in $packages do if [[ ${pkg_already_installed[$pkg]} -eq 1 ]] ; then echo "Package $pkg is already installed, skipping" continue fi echo Installing $pkg as ${pkg_lookup[$pkg]}... user_pkg_name="$pkg" pkg="${pkg_lookup[$pkg]}" echo "" echo Installing $pkg # look for package and save desc file mkdir -p "release/$pkg" cat setup.ini | awk > "release/$pkg/desc" -v package="$pkg" \ 'BEGIN{RS="\n\n@ "; FS="\n"} {if ($1 == package) {desc = $0; px++}} \ END {if (px == 1 && desc != "") print desc; else print "Package not found"}' desc=`cat "release/$pkg/desc"` if test "-$desc-" = "-Package not found-" then echo Package $pkg not found or ambiguous name, exiting rm -r "release/$pkg" exit 1 fi echo Found package $pkg # download and unpack the bz2 file # pick the latest version, which comes first install=`cat "release/$pkg/desc" | awk '/^install: / { print $2; exit }'` category=`cat "release/$pkg/desc" | awk '/^category: / { print $2; exit }'` requires=`cat "release/$pkg/desc" | awk '/^requires: / { print $2; exit }'` if test "-$install-" = "--" then if [[ "$category" == "_obsolete" && ! -z "$requires" ]] ; then echo "$pkg is obsolete and replaced by: $requires" else echo "Could not find \"install\" in package description: obsolete package?" fi exit 1 fi file=`basename $install` cd "release/$pkg" wget -nc $mirror/$install # check the md5 digest=`cat "desc" | awk '/^install: / { print $4; exit }'` digactual=`md5sum $file | awk '{print $1}'` if ! test $digest = $digactual then echo MD5 sum did not match, exiting exit 1 fi echo "Unpacking..." cat $file | bunzip2 | tar > "/etc/setup/$pkg.lst" xvf - -C / gzip -f "/etc/setup/$pkg.lst" cd ../.. # update the package database cat /etc/setup/installed.db | awk > /tmp/awk.$$ -v pkg="$pkg" -v bz=$file \ '{if (ins != 1 && pkg < $1) {print pkg " " bz " 0"; ins=1}; print $0} \ END{if (ins != 1) print pkg " " bz " 0"}' mv /etc/setup/installed.db /etc/setup/installed.db-save mv /tmp/awk.$$ /etc/setup/installed.db # recursively install required packages echo > /tmp/awk.$$ '/^requires: / {s=gensub("(requires: )?([^ ]+) ?", "\\2 ", "g", $0); print s}' requires=`cat "release/$pkg/desc" | awk -f /tmp/awk.$$` warn=0 if ! test "-$requires-" = "--" then echo Package $pkg requires the following packages, installing: echo $requires for package in $requires do already=`grep -c "^$package " /etc/setup/installed.db` if test $already -ge 1 then echo Package $package is already installed, skipping continue fi apt-cyg --noscripts install $package if ! test $? = 0 ; then warn=1; fi done fi if ! test $warn = 0 then echo "Warning: some required packages did not install, continuing" fi # run all postinstall scripts pis=`ls /etc/postinstall/*.sh 2>/dev/null | wc -l` if test $pis -gt 0 && ! test $noscripts -eq 1 then echo Running postinstall scripts for script in /etc/postinstall/*.sh do $script mv $script $script.done done fi echo Package $pkg installed done ;; remove) checkpackages for pkg in $packages do already=`grep -c "^$pkg " /etc/setup/installed.db` if test $already = 0 then echo Package $pkg is not installed, skipping continue fi dontremove="cygwin coreutils gawk bzip2 tar wget bash" for req in $dontremove do if test "-$pkg-" = "-$req-" then echo apt-cyg cannot remove package $pkg, exiting exit 1 fi done if ! test -e "/etc/setup/$pkg.lst.gz" then echo Package manifest missing, cannot remove $pkg. Exiting exit 1 fi echo Removing $pkg # run preremove scripts if test -e "/etc/preremove/$pkg.sh" then "/etc/preremove/$pkg.sh" rm "/etc/preremove/$pkg.sh" fi cat "/etc/setup/$pkg.lst.gz" | gzip -d | awk '/[^\/]$/ {print "rm -f \"/" $0 "\""}' | sh rm "/etc/setup/$pkg.lst.gz" rm -f /etc/postinstall/$pkg.sh.done cat /etc/setup/installed.db | awk > /tmp/awk.$$ -v pkg="$pkg" '{if (pkg != $1) print $0}' mv /etc/setup/installed.db /etc/setup/installed.db-save mv /tmp/awk.$$ /etc/setup/installed.db echo Package $pkg removed done ;; *) usage ;; esac