apt-cyg/apt-cyg

621 lines
12 KiB
Plaintext
Raw Normal View History

2013-07-28 09:12:28 -07:00
#!/bin/bash
# apt-cyg: install tool for Cygwin similar to debian apt-get
#
2013-07-28 09:12:28 -07:00
# The MIT License (MIT)
#
2013-07-28 09:12:28 -07:00
# Copyright (c) 2013 Trans-code Design
#
2013-07-28 09:12:28 -07:00
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
2013-07-28 09:12:28 -07:00
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
2013-07-28 09:12:28 -07:00
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
2014-06-15 14:17:50 -07:00
ARCH=${HOSTTYPE/i6/x}
2013-07-28 09:12:28 -07:00
function wget {
if command wget -h &>/dev/null
then
command wget "$@"
else
warn wget is not installed, using lynx as fallback
set "${*: -1}"
lynx -source "$1" > "${1##*/}"
fi
}
2014-08-04 09:14:43 -07:00
function usage {
hr '
usage: apt-cyg [command] [options] [packages]
Commands:
install Install packages
remove Remove packages
update Update setup.ini
download Download only - do NOT install or unpack archives
show Displays the package records for the named packages
depends Performs recursive dependency listings
rdepends Display packages which require X to be installed,
AKA show reverse dependencies
list List packages matching given pattern. If no pattern is given,
list all installed packages.
category List packages matching given category
2014-08-04 09:14:43 -07:00
listfiles List files owned by packages
search Search for a filename from installed packages
searchall Search for a filename from all available packages
Options:
-c, --cache <dir> set cache
-f, --file <file> read package names from file
-m, --mirror <url> set mirror
--help
--version
'
2013-07-28 09:12:28 -07:00
}
2014-08-04 09:14:43 -07:00
function version {
hr '
apt-cyg version 0.59
2014-08-04 09:14:43 -07:00
The MIT License (MIT)
2014-06-12 15:12:10 -07:00
2014-08-04 09:14:43 -07:00
Copyright (c) 2005-9 Stephen Jungels
'
2013-07-28 09:12:28 -07:00
}
2014-08-04 09:14:43 -07:00
function find-workspace {
2013-07-28 09:12:28 -07:00
# default working directory and mirror
# work wherever setup worked last, if possible
cache=$(awk '
/last-cache/ {
getline
print $1
}
' /etc/setup/setup.rc | cygpath -f-)
mirror=$(awk '
/last-mirror/ {
getline
print $1
}
' /etc/setup/setup.rc)
mirrordir=$(sed '
s / %2f g
s : %3a g
' <<< "$mirror")
mkdir -p "$cache/$mirrordir/$ARCH"
cd "$cache/$mirrordir/$ARCH"
if [ -e setup.ini ]
then
return 0
else
get-setup
return 1
fi
}
2014-08-04 09:14:43 -07:00
function get-setup {
touch setup.ini
mv setup.ini setup.ini-save
wget -N $mirror/$ARCH/setup.bz2
if [ -e setup.bz2 ]
then
bunzip2 setup.bz2
mv setup setup.ini
echo Updated setup.ini
else
echo Error updating setup.ini, reverting
mv setup.ini-save setup.ini
fi
2013-07-28 09:12:28 -07:00
}
2014-08-04 09:14:43 -07:00
function check-packages {
if [[ $pks ]]
then
return 0
else
echo No packages found
return 1
fi
2013-07-28 09:12:28 -07:00
}
function info {
printf '\e[36m%s\e[m\n' "$*" >&2
}
function warn {
printf '\e[1;31m%s\e[m\n' "$*" >&2
}
2014-08-04 09:14:43 -07:00
function apt-update {
if find-workspace
then
get-setup
fi
}
function apt-category {
2014-10-31 22:30:30 -07:00
check-packages
find-workspace
2014-10-31 22:30:30 -07:00
for pkg in "${pks[@]}"
do
awk '
$1 == "@" {
pck = $2
}
$1 == "category:" && $0 ~ query {
print pck
2014-10-31 22:30:30 -07:00
}
' query="$pks" setup.ini
done
}
2014-08-04 09:14:43 -07:00
function apt-list {
find-workspace
local sbq
for pkg in "${pks[@]}"
do
(( sbq++ )) && echo
info Searching for installed packages matching "$pkg":
2014-11-14 17:23:18 -08:00
awk 'NR>1 && $1~ENVIRON["pkg"] && $0=$1' /etc/setup/installed.db
echo
info Searching for installable packages matching "$pkg":
2014-11-14 17:23:18 -08:00
awk '$1 ~ ENVIRON["pkg"] && $0 = $1' RS='\n\n@ ' FS='\n' setup.ini
done
(( sbq )) && return
info The following packages are installed:
awk 'NR>1 && $0=$1' /etc/setup/installed.db
}
2014-08-04 09:14:43 -07:00
function apt-listfiles {
check-packages
find-workspace
local pkg sbq
for pkg in "${pks[@]}"
do
(( sbq++ )) && echo
if [ ! -e /etc/setup/"$pkg".lst.gz ]
then
download "$pkg"
fi
gzip -cd /etc/setup/"$pkg".lst.gz
done
}
2014-08-04 09:14:43 -07:00
function apt-show {
find-workspace
check-packages
for pkg in "${pks[@]}"
do
(( notfirst++ )) && echo
awk '
$1 == query {
print
fd++
}
END {
if (! fd)
print "Unable to locate package " query
}
' RS='\n\n@ ' FS='\n' query="$pkg" setup.ini
done
}
2014-08-04 09:14:43 -07:00
function apt-depends {
find-workspace
check-packages
for pkg in "${pks[@]}"
do
awk '
@include "join"
$1 == "@" {
apg = $2
}
$1 == "requires:" {
for (z=2; z<=NF; z++)
reqs[apg][z-1] = $z
}
END {
prpg(ENVIRON["pkg"])
}
function smartmatch(small, large, values) {
for (each in large)
values[large[each]]
return small in values
}
function prpg(fpg) {
if (smartmatch(fpg, spath)) return
spath[length(spath)+1] = fpg
print join(spath, 1, length(spath), " > ")
if (isarray(reqs[fpg]))
for (each in reqs[fpg])
prpg(reqs[fpg][each])
delete spath[length(spath)]
}
' setup.ini
done
}
2014-08-04 09:14:43 -07:00
function apt-rdepends {
find-workspace
for pkg in "${pks[@]}"
do
awk '
@include "join"
$1 == "@" {
apg = $2
}
$1 == "requires:" {
for (z=2; z<=NF; z++)
reqs[$z][length(reqs[$z])+1] = apg
}
END {
prpg(ENVIRON["pkg"])
}
function smartmatch(small, large, values) {
for (each in large)
values[large[each]]
return small in values
}
function prpg(fpg) {
if (smartmatch(fpg, spath)) return
spath[length(spath)+1] = fpg
print join(spath, 1, length(spath), " < ")
if (isarray(reqs[fpg]))
for (each in reqs[fpg])
prpg(reqs[fpg][each])
delete spath[length(spath)]
}
' setup.ini
done
}
2014-08-04 09:14:43 -07:00
function apt-download {
check-packages
find-workspace
local pkg sbq
for pkg in "${pks[@]}"
do
(( sbq++ )) && echo
download "$pkg"
done
}
2014-08-04 09:14:43 -07:00
function download {
local pkg digest digactual
pkg=$1
# look for package and save desc file
awk '$1 == pc' RS='\n\n@ ' FS='\n' pc=$pkg setup.ini > desc
if [ ! -s desc ]
then
echo Unable to locate package $pkg
exit 1
fi
# download and unpack the bz2 or xz file
# pick the latest version, which comes first
set -- $(awk '$1 == "install:"' desc)
if (( ! $# ))
then
echo 'Could not find "install" in package description: obsolete package?'
exit 1
fi
dn=$(dirname $2)
bn=$(basename $2)
# check the md5
digest=$4
mkdir -p $cache/$mirrordir/$dn
cd $cache/$mirrordir/$dn
wget -nc $mirror/$dn/$bn
digactual=$(md5sum $bn | awk NF=1)
if [ $digest != $digactual ]
then
echo MD5 sum did not match, exiting
exit 1
fi
tar tf $bn | gzip > /etc/setup/"$pkg".lst.gz
cd ~-
2014-06-15 22:56:06 -07:00
mv desc $cache/$mirrordir/$dn
echo $dn $bn > /tmp/dwn
}
2014-08-04 09:14:43 -07:00
function apt-search {
check-packages
2014-06-03 21:51:18 -07:00
echo Searching downloaded packages...
for pkg in "${pks[@]}"
do
key=$(type -P "$pkg" | sed s./..)
[[ $key ]] || key=$pkg
for manifest in /etc/setup/*.lst.gz
do
if gzip -cd $manifest | grep -q "$key"
then
package=$(sed '
s,/etc/setup/,,
s,.lst.gz,,
' <<< $manifest)
2014-06-03 21:51:18 -07:00
echo $package
fi
done
done
}
2014-08-04 09:14:43 -07:00
function apt-searchall {
cd /tmp
for pkg in "${pks[@]}"
do
printf -v qs 'text=1&arch=%s&grep=%s' $ARCH "$pkg"
wget -O matches cygwin.com/cgi-bin2/package-grep.cgi?"$qs"
awk '
{
if (NR == 1)
next
if (mc[$1]++)
next
if (/-debuginfo-/)
next
print $1
}
' FS=-[[:digit:]] matches
done
}
2014-08-04 09:14:43 -07:00
function apt-install {
check-packages
find-workspace
local pkg dn bn requires wr package script
for pkg in "${pks[@]}"
do
if grep -q "^$pkg " /etc/setup/installed.db
then
echo Package $pkg is already installed, skipping
continue
fi
echo
echo Installing $pkg
download $pkg
read dn bn </tmp/dwn
echo Unpacking...
cd $cache/$mirrordir/$dn
tar -x -C / -f $bn
# update the package database
awk '
ins != 1 && pkg < $1 {
print pkg, bz, 0
ins = 1
}
1
END {
if (ins != 1) print pkg, bz, 0
}
' pkg="$pkg" bz=$bn /etc/setup/installed.db > /tmp/awk.$$
mv /etc/setup/installed.db /etc/setup/installed.db-save
mv /tmp/awk.$$ /etc/setup/installed.db
# recursively install required packages
requires=$(awk '$1=="requires", $0=$2' FS=': ' desc)
cd ~-
wr=0
if [[ $requires ]]
then
echo Package $pkg requires the following packages, installing:
echo $requires
for package in $requires
do
if grep -q "^$package " /etc/setup/installed.db
then
echo Package $package is already installed, skipping
continue
fi
apt-cyg install --noscripts $package || (( wr++ ))
done
fi
if (( wr ))
then
info some required packages did not install, continuing
fi
# run all postinstall scripts
(( noscripts )) && continue
find /etc/postinstall -name '*.sh' | while read script
do
echo Running $script
$script
mv $script $script.done
done
echo Package $pkg installed
done
}
2014-08-04 09:14:43 -07:00
function apt-remove {
check-packages
for pkg in "${pks[@]}"
do
if ! grep -q "^$pkg " /etc/setup/installed.db
then
echo Package $pkg is not installed, skipping
continue
fi
cygcheck awk bash bunzip2 grep gzip mv sed tar xargs xz | awk '
/bin/ &&
!fd[$NF]++ &&
$0 = $NF
' FS='\\' > /tmp/cygcheck.txt
apt-cyg listfiles $pkg | awk '
$0 = $NF
' FS=/ > /tmp/listfiles.txt
if grep -xf /tmp/cygcheck.txt /tmp/listfiles.txt
then
echo apt-cyg cannot remove package $pkg, exiting
exit 1
fi
if [ ! -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 [ -e /etc/preremove/"$pkg".sh ]
then
/etc/preremove/"$pkg".sh
rm /etc/preremove/"$pkg".sh
fi
gzip -cd /etc/setup/"$pkg".lst.gz | sed '\./$.d;s.^./.' | xargs rm -f
rm /etc/setup/"$pkg".lst.gz
rm -f /etc/postinstall/$pkg.sh.done
awk '$1 != pkg' pkg="$pkg" /etc/setup/installed.db > /tmp/awk.$$
mv /etc/setup/installed.db /etc/setup/installed.db-save
mv /tmp/awk.$$ /etc/setup/installed.db
echo Package $pkg removed
done
}
2014-08-04 09:14:43 -07:00
function hr {
sed '
1d
$d
s/ //
' <<< "$1"
}
if [ -p /dev/stdin ]
then
mapfile -t pks
fi
2013-07-28 09:12:28 -07:00
# process options
while (( $# ))
2013-07-28 09:12:28 -07:00
do
case "$1" in
--mirror | -m)
awk -i inplace '
1
/last-mirror/ {
getline
print "\t" rpc
}
' rpc="$2" /etc/setup/setup.rc
shift 2
2013-07-28 09:12:28 -07:00
;;
--cache | -c)
rpc=$(cygpath -aw "$2" | sed 's \\ \\\\ g')
awk -i inplace '
1
/last-cache/ {
getline
print "\t" rpc
}
' rpc="$rpc" /etc/setup/setup.rc
shift 2
2013-07-28 09:12:28 -07:00
;;
--noscripts)
noscripts=1
shift
;;
2013-07-28 09:12:28 -07:00
--help)
usage
exit 0
;;
--version)
version
exit 0
;;
--file | -f)
if [[ $2 ]]
2013-07-28 09:12:28 -07:00
then
mf=$2
if [ -f "$mf" ]
2014-06-03 21:51:18 -07:00
then
mapfile -t pks < "$mf"
2014-06-03 21:51:18 -07:00
else
echo File "$mf" not found, skipping
2014-06-03 21:51:18 -07:00
fi
2013-07-28 09:12:28 -07:00
shift
else
info No file name provided, ignoring $1
2013-07-28 09:12:28 -07:00
fi
shift
;;
update)
command=$1
shift
;;
install \
| remove \
| download \
| show \
| depends \
| rdepends \
| list \
| category \
| listfiles \
| search \
| searchall)
if [[ $command ]]
2013-07-28 09:12:28 -07:00
then
pks+=("$1")
2013-07-28 09:12:28 -07:00
else
command=$1
2013-07-28 09:12:28 -07:00
fi
shift
;;
*)
pks+=("$1")
2013-07-28 09:12:28 -07:00
shift
;;
esac
done
set -a
if type -t apt-$command | grep -q function
then
apt-$command
else
usage
fi