Skip to content

Instantly share code, notes, and snippets.

@tpoechtrager
Created October 25, 2014 18:26
Show Gist options
  • Save tpoechtrager/75db965b025c5bf62b9a to your computer and use it in GitHub Desktop.
Save tpoechtrager/75db965b025c5bf62b9a to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
##
## TODO:
## * Locking
## * --help
## * upgrade
## * clear-cache
##
set -e
export LC_ALL=C
pushd "${0%/*}" &>/dev/null
MIRROR="$OSXCROSS_MACPORTS_MIRROR"
if [ -z "$MIRROR" ]; then
MIRROR="http://packages.macports.org"
fi
PUBKEYURL="https://svn.macports.org/repository/"
PUBKEYURL+="macports/trunk/base/macports-pubkey.pem"
PUBKEYSHA256="7f429799b3609b95ef1eb024182c973d"
PUBKEYSHA256+="35a4e1ef326abea4a0599cfb9ff70c77"
if [ -n "$OSXCROSS_MACPORTS_ENABLE_HTTPS" ]; then
MIRROR=$(echo $MIRROR | sed 's/http:/https:/g')
fi
if [ -z "$MACOSX_DEPLOYMENT_TARGET" ]; then
export MACOSX_DEPLOYMENT_TARGET=10.7
fi
ROOT="$PWD"
PUBKEY="$ROOT/mp-pubkey.pem"
INSTALLDB="$ROOT/INSTALLED"
CACHE="$ROOT/cache"
INSTALL="$ROOT/target"
LASTPKGNAME=""
if [ ! -d "$CACHE" ]; then
echo "creating cache directory: $CACHE"
mkdir -p $CACHE
fi
if [ ! -d "$INSTALL" ]; then
echo "creating install directory: $INSTALL"
mkdir -p $INSTALL
fi
errorMsg()
{
echo "$@" 1>&2
}
verboseMsg()
{
if [ -n "$VERBOSE" ]; then
errorMsg "$@"
fi
}
verbosePlaceHolder()
{
if [ -n "$VERBOSE" ]; then
errorMsg ""
fi
}
require()
{
set +e
which $1 &>/dev/null
if [ $? -ne 0 ]; then
errorMsg "$1 is required"
exit 1
fi
set -e
}
require "wget"
require "openssl"
require "sw_vers"
unsupportedDepTarget()
{
errorMsg "unsupported deployment target"
errorMsg -n "add 'export MACOSX_DEPLOYMENT_TARGET=10.6' (or later) "
errorMsg "to your bashrc."
exit 1
}
case $(sw_vers -productVersion) in
10.6 ) OSXVERSION="darwin_10" ;;
10.7 ) OSXVERSION="darwin_11" ;;
10.8 ) OSXVERSION="darwin_12" ;;
10.9 ) OSXVERSION="darwin_13" ;;
10.10 ) OSXVERSION="darwin_14" ;;
* ) unsupportedDepTarget ;;
esac
getFileStdout()
{
verbosePlaceHolder
local xargs=""
[ -z "$VERBOSE" ] && xargs+="--quiet"
wget "$1" -O- $xargs
#verbosePlaceHolder
}
getFile()
{
verbosePlaceHolder
local xargs=""
if [ $# -ge 2 ]; then
xargs+="-O $2 "
else
xargs+="-P $CACHE "
fi
[ -z "$VERBOSE" ] && xargs+="--quiet"
wget -c "$1" $xargs
#verbosePlaceHolder
}
verifyFileIntegrity()
{
local file="$1"
if [ ! -e "$PUBKEY" ]; then
echo "downloading macports public key ..."
getFile $PUBKEYURL "$PUBKEY"
fi
local hash=$(openssl sha256 "$PUBKEY" | awk '{print $2}')
if [ "$hash" != "$PUBKEYSHA256" ]; then
errorMsg "invalid macports public key! ($hash != $PUBKEYSHA256)"
exit 1
fi
verboseMsg "verifying file integrity ..."
set +e
openssl dgst -ripemd160 -verify "$PUBKEY" -signature \
"$CACHE/$file.rmd160" "$CACHE/$file" 1>/dev/null
if [ $? -ne 0 ]; then
errorMsg "file integrity check failed ($CACHE/$file)"
exit 2
fi
set -e
}
getPkgUrl()
{
local pkgname="$1"
local pkgs
local pkg
set +e
pkgs=$(getFileStdout "$MIRROR/$pkgname" | grep -o -E 'href="([^"#]+)"' | \
cut -d'"' -f2 | grep '.tbz2$')
local ec=$?
set -e
if [ $ec -ne 0 ]; then
errorMsg "no packages found"
return
fi
verboseMsg " candidates for $pkgname:"
for p in $pkgs; do
verboseMsg " $p"
done
local pkg=$(echo "$pkgs" | grep $OSXVERSION | sort | uniq | tail -n1)
verboseMsg " selected: $pkg"
if [ -z "$pkg" ]; then
verboseMsg -n " "
errorMsg "no suitable version found for $OSXVERSION"
return
fi
echo "$MIRROR/$pkgname/$pkg"
}
pkgInstalled()
{
local pkgname="$1"
if [ ! -e "$INSTALLDB" ]; then
echo 0
return
fi
set +e
grep -x "$pkgname" "$INSTALLDB" &>/dev/null
local status=$?
set -e
if [ $status -eq 0 ]; then
echo 1
else
echo 0
fi
}
installPkg()
{
local pkgname="$1"
LASTPKGNAME=$pkgname
if [ $(pkgInstalled $pkgname) -eq 1 ]; then
continue
fi
echo "searching for package $pkgname ..."
local pkgurl=$(getPkgUrl "$pkgname")
local pkgfile=$(echo "$pkgurl" | awk -F'/' '{print $NF}')
if [ -z "$pkgurl" ]; then
local oldpkgname=$pkgname
pkgname=$(echo "$pkgname" | cut -f1 -d'-')
if [ "$pkgname" != "$oldpkgname" ]; then
echo "trying $pkgname instead ..."
else
exit 3
fi
installPkg $pkgname
return
fi
echo "downloading $pkgfile ..."
getFile "$pkgurl"
verboseMsg "downloading $pkgname.rmd160 ..."
getFile "$pkgurl.rmd160"
verifyFileIntegrity "$pkgfile"
pushd $INSTALL &>/dev/null
echo "installing $pkgname ..."
verboseMsg " extracting $pkgfile ..."
tar xf "$CACHE/$pkgfile"
if [ -d opt/local ]; then
verboseMsg " fixing permissions ..."
find opt/local -type d -exec chmod 770 {} \;
find opt/local -type f -exec chmod 660 {} \;
if [ -d opt/local/lib ]; then
if [ -n "$STATIC" ]; then
[ -n "$VERBOSE" ] && echo -n " "
echo "removing dylibs ..."
find opt/local/lib -name "*.dylib" -exec rm {} \;
else
find opt/local/lib -type f -name "*.dylib" -exec chmod +x {} \;
fi
fi
verboseMsg " fixing directories ..."
set +e
cp -r opt/local/* $INSTALL
local status=$?
set -e
if [ $status -eq 1 ]; then
errorMsg "removing broken symlinks ..."
find . -type l -exec \
sh -c 'readlink -f "{}" 1>/dev/null || rm "{}"' -- "{}" \;
cp -r opt/local/* $INSTALL
fi
rm -rf opt
fi
local pkgdeps=$(grep '@pkgdep' \+CONTENTS | cut -d\ -f2 | \
rev | cut -f2-100 -d\- | rev)
popd &>/dev/null # INSTALL
for pkgdep in $pkgdeps; do
installPkg $pkgdep
done
test -e "$INSTALLDB" && cp "$INSTALLDB" "$INSTALLDB.old"
echo "$pkgname" >> "$INSTALLDB"
}
installPkgs()
{
local packages="$1"
for pkgname in $packages; do
if [ $(pkgInstalled $pkgname) == "1" ]; then
errorMsg "$pkgname is already installed"
continue
fi
installPkg $pkgname
rm -f $INSTALL/+*
done
}
updateSearchCache()
{
pushd $CACHE &>/dev/null
echo "generating index cache (this may take several minutes ...)"
getFile $MIRROR $CACHE/packages
cat packages | grep -o -E 'href="([^"#]+)"' | cut -d'"' -f2 | \
sed 's/.\{1\}$//' | uniq | sort > INDEXCACHE
rm -f packages
echo "generated index cache for $(cat INDEXCACHE | wc -l) packages"
popd &>/dev/null
}
searchPkg()
{
local pkg="$1"
pushd $CACHE &>/dev/null
if [ ! -e INDEXCACHE ]; then
updateSearchCache
fi
local packages=$(grep -i "$pkg" INDEXCACHE)
if [ -z "$packages" ]; then
echo "no matching packages found for $1"
return
fi
for pkg in $packages; do
echo $pkg
done
popd &>/dev/null
}
_exit()
{
local ec=$?
if [ $ec -ne 0 ]; then
if [ -n "$LASTPKGNAME" ]; then
errorMsg "failed to install $LASTPKGNAME, try with '-v'"
fi
if [ $ec -eq 3 ]; then
errorMsg -n "use '$0 fake-install <pkgname>' to "
errorMsg "fake install non-existing packages"
fi
fi
}
showHelpText()
{
errorMsg "TODO"
exit 1
}
main()
{
local args
local cmd
for opt in $@; do
if [[ $opt == -* ]]; then
if [ $opt == "-v" -o $opt == "--verbose" ]; then
VERBOSE=1
elif [ $opt == "-v=2" -o $opt == "--verbose=2" ]; then
set -x
VERBOSE=1
elif [ $opt == "-s" -o $opt == "--static" ]; then
STATIC=1
elif [ $opt == "-h" -o $opt == "--help" ]; then
showHelpText
else
errorMsg "unknown option: $opt"
exit 1
fi
else
if [ -z "$cmd" ]; then
cmd="$opt"
else
args+="$opt "
fi
fi
done
if [ -z "$cmd" ]; then
errorMsg "no command given"
showHelpText
fi
case "$cmd" in
updatecache )
updateSearchCache
exit
;;
upgrade )
echo "TODO"
exit
;;
esac
local packages="$args"
if [ -z "$packages" ]; then
errorMsg "no package name given"
exit 1
fi
case "$cmd" in
install )
installPkgs "$packages"
;;
fake*install )
for pkgname in $args; do
if [ $(pkgInstalled $pkgname) -eq 0 ]; then
echo $pkgname >> $INSTALLDB
fi
done
echo "done"
;;
search )
for pkgname in $args; do
searchPkg $pkgname
done
;;
esac
}
trap _exit EXIT
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment