Macos – How could you automate downloading and installing OS X applications

macos

iusethis.com redirects URLs like http://osx.iusethis.com/app/download/appname to download links, and you could curl MacUpdate pages for direct download links. Are there any more complete or reliable sources for download links?

How could you automate extracting different types of archives or running installers? DropZone comes with a script that accepts dmg or zip files as input and moves application bundles inside them to /Applications/. Does anyone know a similar script that would work with installers or more file types?

Best Answer

I ended up hacking together this shell script, but stopped maintaining it since many of the download links at iusethis.org are no longer valid and more applications are now distributed through the App Store. I'm leaving it here for the record anyway.

#!/bin/bash

export uuid1=$(uuidgen) uuid2=$(uuidgen)
export tmp1=/tmp/autoapp$uuid1 tmp2=/tmp/autoapp$uuid2
mkdir -p $tmp1 $tmp2

shopt -s nullglob
IFS=$'\n'

trap 'onexit &' EXIT
onexit() {
  for mp in $tmp1/mountpoint-*; do
    hdiutil detach -quiet -force $mp
  done
  rm -rf /tmp/autoapp$uuid1 /tmp/autoapp$uuid2
}

app() {
  basename="$(basename "$1")"
  ditto "$1" "/Applications/$basename" 2> /dev/null
  echo "Copied $basename to /Applications/"
}

prefpane() {
  basename="$(basename "$1")"
  ditto "$1" ~/"Library/PreferencePanes/$basename" 2> /dev/null
  echo "Copied $basename to PreferencePanes/"
}

wdgt() {
  basename="$(basename "$1")"
  ditto "$1" ~/"Library/Widgets/$basename" 2> /dev/null
  echo "Copied $basename to Widgets/" 
}

pkg() {
  basename="$(basename "$1")"
  sudo installer -pkg "$1" -target /
  if [[ $? != 0 ]]; then
    read -n 1 -p "Open $basename (y/n)? " answer
    echo
    [[ "$aswer" == y ]] && open "$f" && exit 1
  fi
}

dmg() {
  mp=$tmp1/mountpoint-$(uuidgen)
  basename="$(basename "$1")"
  echo "Mounting $basename"
  yes | hdiutil attach -noverify -nobrowse -mountpoint $mp "$1" > /dev/null
  getfound "$mp" && exit
  echo "Couldn't find an application or package inside $basename"
  exit 1
}

gettmp() {
  getfound $tmp2 && exit

  found="$(find $tmp2 -depth 1 -name "*.dmg" -print0 2> /dev/null |
  xargs -0 du -s | sort -n | tail -n 1 | cut -f 2)"
  [[ -n "$found" ]] && dmg "$found" && exit

  echo "Couldn't find an application or package"
}

getfound() {
  found="$(find "$1" -maxdepth 2 -name "*.app" -print0\
  -o -name "*.prefPane" -print0 -o -name "*.pkg" -print0\
  -o -name "*.mpkg" -print0 2> /dev/null |
  xargs -0 du -s | sort -n | tail -n 1 | cut -f 2)"
  if [[ "$found" == *.app ]]; then
    app "$found"
    exit
  elif [[ "$found" == *.prefPane ]]; then
    prefpane "$found"
    exit
  elif [[ "$found" == *.wdgt ]]; then
    wdgt "$found"
    exit
  elif [[ "$found" == *.safariextz ]]; then
    open "$found" && exit
  elif [[ "$found" == *.pkg || "$found" == *.mpkg ]]; then
    pkg "$found"
    exit
  fi
  exit 1
}

untradedouble() {
  echo -n "$1" | ruby -e 'require "CGI"
  x = $<.read
  if x =~ /^http:\/\/.*?tradedoubler.com.*?&url=(.+)/
    print CGI.unescape($1)
  else
    print x
  end'
}

[[ $# == 0 ]] && exit
[[ "$1" == "-h" || "$1" == "--help" || "$1" == "-help" ]] && exit

if [[ -e "$@" ]]; then
  [[ -e "$@" ]] && appfile="$@" || exit
elif [[ "$@" =~ "/" || "$@" =~ "." ]]; then
    echo "The file $@ does not exist"
    exit 1
else
  download=true
fi

if [[ $download ]]; then
  app="$@"
  app2="$(echo "$app" | tr '[:upper:]' '[:lower:]' | sed 's|[^a-z0-9\-]||g')"
  iut=http://osx.iusethis.com/app/download/
  head="$(curl --head --max-time 5 -s -w "%{url_effective}\n" -L "$iut$app2")"
  ok="$(echo "$head" | grep "HTTP/1.[01] [23]..")"
  redirect="$(echo "$head" | tail -n 1 | tr -d '\n')"
  bytes=$(echo "$head" | sed -n 's|Content-Length: ||p' |
  tail -n 1 | tr -d '\r')
  if [[ -z "$redirect" || -z "$ok" ]]; then
    read -n 1 -p "Couldn't find $app. Search with Google (y/n)? " answer
    echo
    google="http://www.google.com/search?q=mac+application+"
    [[ $answer =~ [y|Y] ]] && open "$google$app2"
    exit
  fi
  ext="${redirect##*.}"
  exts=" zip gz rar mpkg dmg safariextz prefPane "
  if [[ "$exts" != *" $ext "* || "$bytes" -le 5000 ]]; then
    redirect="$(untradedouble "$redirect")"
    echo "Redirected to $redirect"
    read -n 1 -p "Open in a browser (y/n)? " answer
    echo
    [[ $answer == "y" || $answer == "Y" ]] && open "$redirect"
    exit
  fi
  appfile="$tmp1/${redirect##*/}"
  echo "Downloading $redirect"
  curl "$redirect" -o "$appfile"
fi

appfile="$(echo -n "$appfile" | sed 's|/$||')"

if [[ "$appfile" == *.app ]]; then
  app "$appfile"
elif [[ "$appfile" == *.prefPane ]]; then
  prefpane "$appfile"
elif [[ "$appfile" == *.wdgt ]]; then
  wdgt "$appfile"
elif [[ "$appfile" == *.safariextz ]]; then
  open "$appfile"
elif [[ "$appfile" == *.zip ]]; then
  unzip -q "$appfile" -d $tmp2
  gettmp
elif [[ "$appfile" == *.tar.gz ]]; then
  tar -xf $appfile -C $tmp2
  gettmp
elif [[ "$appfile" == *.dmg ]]; then
  dmg "$appfile"
elif [[ "$appfile" == *.pkg || "$appfile" == *.mpkg ]]; then
  pkg "$appfile"
else
  echo "Couldn't process $(basename "$appfile")"
  exit
fi
Related Question