#!/bin/bash

# Poznamka ohladom patchovania:
# Upravovat subory z ineho modulu alebo z jadra sa v Drupale neodporuca,
# ale pri .htaccess apod. nemas inu moznost. Patchovaci system v tomto
# skripte vznikol na to, aby to islo automatizovat.
# Ak su v adresari patches/ nejake SPUSTITELNE subory nazvane balik-* alebo
# all-*, tak tento skript vypise prikazy, co ich spustia. Ako jediny argument
# dostanu adresar, kam bol dany balik rozbaleny.
# Dany subor moze byt cokolvek, ale ak chces pouzit skutocny patch, co spravil
# diff, daj na zaciatok toto:
# #!/bin/bash
# exec patch -d "$1" -p0 <"$0"
# Program patch odignoruje veci na zaciatku vstupu, takze mu to nebude vadit,
# a -d zabezpeci, ze sa presunie do toho adresara.
# Skripty zacinajuce na all- sa spustia pri kazdom baliku. Z toho argumentu
# mozu zistit, o aky balik ide.

usage () {
  echo "$0 - sympaticky upgradovac Drupal stranok

Usage:
export DBUSER=uzivatel DBNAME=databaza
  nepovinne - nech to vypluje v mysqldump prikaze korektne udaje.
$0 balik iny_balik ...
  povie ti, ako upgradovat dane baliky. pri kazdom prikaze sa opyta, ci ho ma
  rovno vykonat. toto je tak preto, aby si do celej veci co najviac videl.
  balik je bud cesta k suboru alebo ho pohladam v packages/balik-*.
  bez parametrov sa pouzije vsetko v packages/. ak tam nic nie je, najprv
  spusti $0 --download.
$0 balik iny_balik ... <&-
  ked je stdin zavrety, nic sa nevypytuje ani nevykonava.
$0 balik iny_balik ... >subor.sh
  ked stdout nie je terminal, tiez sa nic nevypytuje, a nekresli farby.
$0 --download
  zisti cez Drupal, co sa da upgradnut, a rovno to stiahne do packages/"
  exit 1
}

note () {
  echo "$blue$1$none"
}

cmd () {
  echo "$red$1$none"
  if [ "$havein" ] && [ "$ttyout" ]; then
    if [ "$ttyin" ]; then
      read -p "${white}Vykonat? (y/n) [$default]$none " answer
      [ -z "$answer" ] && answer=$default
    else
      # neukazuj zbytocne prompt ked vstup ide cez ruru (napr. od yes)
      read answer
    fi
    case "$answer" in
      y*|Y*)
        default=y
        if ! eval "$1"; then
          echo "${red}Prikaz skoncil s chybou!$none
Ked tu chybu odstranis a opravis pripadne skody, spusti ma znovu a na vsetky
prikazy pred tymto daj 'n', cim ich preskocis a mozes zase ist od tohto."
          exit 1
        fi
        ;;
      *)
        default=n
        ;;
    esac
  fi
}

# prepiseme mysqldump nasou vlastnou funkciou
mysqldump () {
  if [ "$*" == "-u uzivatel -p databaza" ]; then
    # tamto asi nie je to, co by to chcelo
    echo "# prihlasovacie udaje su v sites/$SITEID/settings.php." >&2
    read -p "Database: " DBNAME
    read -p "User: " DBUSER
    command mysqldump -u $DBUSER -p $DBNAME
  else
    command mysqldump "$@"
  fi
}

# okrem --download nemame ziadne moznosti
if [ "$#" == 1 ] && [ "$1" == --download ]; then
  download=yes
else
  download=
  for arg; do if [[ $arg == -* ]]; then usage; fi; done
fi

# posledna pouzita odpoved pri cmd
default=n

# sme pripojeni na terminal?
[ -e /dev/stdin ] && havein=yes || havein=
[ -e /dev/stdin ] && [ -t 0 ] && ttyin=yes || ttyin=
[ -t 1 ] && ttyout=yes || ttyout=
blue=${ttyout:+$'\e[1;36m'}
red=${ttyout:+$'\e[1;31m'}
white=${ttyout:+$'\e[37m'}
none=${ttyout:+$'\e[0m'}

# kedze na jednom jadre Drupalu moze bezat viacere stranky, musime zistit,
# ktoru to chceme upgradovat.
[ ! -d sites/all ] && echo $'Pustaj ma z adresaru s Drupalom!\n' && usage
if [ ! -n "$SITEID" ]; then
  # ak je v sites/ prave jeden adresar (okrem all), vyber ho.
  tmp=( `find sites/ -mindepth 1 -maxdepth 1 ! -name all` )
  [ ${#tmp[@]} == 1 ] && SITEID=${tmp[0]##*/}
fi
if [ ! -n "$SITEID" ]; then
  echo "Hmm, ktoru zo stranok v sites/ to chces upgradovat?" >&2
  ls -1 -I all sites/ >&2
  echo "Vyber si a daj: export SITEID=stranka" >&2
  exit
fi

UPGRADES=upgrade-$SITEID-`date +%m%d`

if [ "$download" ]; then
  set -e
  echo "${blue}Stahujem neaktualne baliky...$none" >&2
  # toto chceme spravit bez uzivatelskeho zasahu, takze sa nemozme spoliehat,
  # ze sme do Drupalu prihlaseni ako admin. pouzijeme PHP CLI, a sikovne
  # nastavenym HTTP_HOST a SCRIPT_NAME zabezpecime, ze sa zoberu nastavenia
  # zo sites/$SITEID. (vid zdrojaky conf_path().)
  code='
    // $_SERVER["HTTP_HOST"] is unset
    $_SERVER["SCRIPT_NAME"]     = "'"${SITEID//./\/}"'/";
    $_SERVER["SERVER_SOFTWARE"] = "PHP CLI";
    $_SERVER["REQUEST_METHOD"]  = "GET";

    require_once "includes/bootstrap.inc";
    drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

    function get_availability_data() {
      module_load_include("inc", "update", "update.report");
      if($available = update_get_available(TRUE)) {
        $data = update_calculate_project_data($available);
        foreach($data as $project) {
          if($project["status"] == UPDATE_NOT_SECURE ||
              $project["status"] == UPDATE_REVOKED ||
              $project["status"] == UPDATE_NOT_SUPPORTED ||
              $project["status"] == UPDATE_NOT_CURRENT) {
            if (isset($project["recommended"])) {
              print $project["releases"][$project["recommended"]]["download_link"]."\n";
            }
          }
        }
      }
    }

    get_availability_data();'
  if ! urls=`php -r "$code"`; then
    mkdir -p packages
    echo "Chyba pri hladani dostupnych aktualizacii."
    echo "Stiahni vsetko do packages/ rucne."
    exit
  fi
  if [ -n "$urls" ]; then
    mkdir -p packages
    cd packages
    for url in $urls; do
      echo "$url" >&2
      curl -# -O "$url" >&2
    done
  fi
  exit
fi

# zoznam balikov, co budem instalovat.
targets=()
if [ $# == 0 ]; then
  targets=( packages/* )
  if [ ! -f "${targets[0]}" ]; then
    # v packages/ nic nie je, spustime download
    $BASH $0 --download || exit
    targets=( packages/* )
    if [ ! -f "${targets[0]}" ]; then
      echo "Nemam aky balik upgradovat, koncim."
      exit
    fi
  fi
else
  for arg; do
    # zmenime nazov baliku na nazov suboru v packages
    if [[ $arg != */* ]]; then
      tmp=( packages/$package-[0-9]* )
      if [ "${#tmp[@]}" == 1 ] && [ -f "${tmp[0]}" ]; then
        arg=${tmp[0]}
      else
        echo "Neviem v packages/ najst balik $arg."
        exit
      fi
    fi
    targets+=( $arg )
  done
fi

note "
# odporuca sa precitat si UPGRADE.txt. (ma to len dve strany.) tento skript
# vacsinu z toho automatizuje, ale je tam kopa uzitocnych informacii, zvlast
# pri vacsich upgradoch alebo keby sa nieco pokazilo."

if [ -e "$UPGRADES" ]; then
  note "
# mozno by sa hodilo najprv stary docasny priecinok odstranit, ale posud sam."
  cmd "rm -rf $UPGRADES"
fi

note "
# spravime docasny priecinok na rozbalovanie veci.
# ked pri instalacii baliku vymazeme staru verziu a hned tam dame novu, tie
# subory budu chybat iba malu chvilku, a snad si to nikto nevsimne. tento
# sposob je pre nase ucely postacujuci.
# dame chmod 700, lebo tam neskor bude aj zaloha SQL databazy."
cmd "mkdir $UPGRADES"
cmd "chmod 700 $UPGRADES"

dirs=()
for archivefile in "${targets[@]}"; do
  note ""
  archivebasename=${archivefile##*/}
  package=${archivebasename%%-[0-9].x-*}
  dir=$package
  # vacsinou ked mas cck-6.x-1.0-beta2.tar.gz, vnutri je adresar cck
  if [[ $archivebasename == drupal-[0-9]* ]]; then
    # pri jadre ked mas drupal-6.13.tar.gz, vnutri je adresar drupal-6.13
    dir=${archivebasename%%.[^0-9]*}
    package=drupal
  fi
  if [[ $archivebasename == drupal-7.* ]]; then
    note "# Co, uz Drupal 7? Nechces ten upgrade nahodou odlozit (vymazat ho
# z packages/)? Ak nie, vela stastia, a pamataj, RTFM na drupal.org a
# v subore UPGRADE.txt z novej verzie."
  fi
  cmd "tar xf $archivefile -C $UPGRADES --no-same-owner"
  for file in ./patches/{all,$package}-*[^~]; do
    [ -x "$file" ] && cmd "$file $UPGRADES/$dir"
  done
  dirs+=($dir)
done

note "
# vsetko zazalohujeme.
# obnova: mysql -u uzivatel -p databaza <$UPGRADES/backup.sql"
cmd "mysqldump -u ${DBUSER:-uzivatel} -p ${DBNAME:-databaza} >$UPGRADES/backup.sql"
note "# obnova: vsetko okrem $UPGRADES zmazes a toto sem rozbalis.
# (rozbaluj ako root, aby sa zachovalo, co vlastni apache a co nie.)
# (nic nekomprimujem, lebo sucastou zalohy je files/ a to trva vecnost.)"
cmd "tar cf $UPGRADES/backup.tar \`ls -A -I $UPGRADES -I packages\`"

note "
# sme pripraveni instalovat.
# POZOR: prudko sa odporuca dat teraz stranku off-line (uzivatelia nebudu nic
# vidiet). v anglictine je to v administracii 'maintenance mode', v slovencine
# tusim 'udrzba'."

for dir in ${dirs[@]}; do
  note ""
  if [[ $dir == drupal-* ]]; then
    note "# instalujeme jadro.
# nemusime mazat .php subory, aj tak ich mv prepise. ale zmazeme vsetky
# adresare, lebo ak v tomto update nejaky subor odbudol, mv by ho tam nechal.
# vnutri sites/ je vsetko, co neni sucastou jadra, tak to neprepisujeme."
    cmd "rm -rf includes misc modules profiles scripts themes &&
  mv $UPGRADES/$dir/{.htaccess,[^.s]*,scripts} ."
  else
    # je to modul? je to tema? kde je nainstalovany? zistime to.
    founddest=()
    for search in sites/{all,$SITEID}/{modules,themes}/$dir; do
      [ -e "$search" ] && founddest+=($search)
    done
    # zvolime defaultnu moznost...
    if [ "${#founddest[@]}" == 0 ]; then
      note "# POZOR! nieco je zle! neviem najst, kde bol $dir doteraz.
# dam ho do sites/all/modules/$dir/, ale je to nejake podozrive.
# ak tam doteraz nebol nainstalovany, preco ho tam teraz davam?
# (ak si ten subor do packages/ dal rucne a je tvojim zamerom ho nainstalovat
# do sites/all/modules/, potom je vsetko v poriadku.)"
      founddest=(sites/all/modules/$dir)
    fi
    if [ "${#founddest[@]}" != 1 ]; then
      note "# POZOR! nieco je zle! neviem najst, kde bol $dir doteraz.
# $dir uz doteraz bol na tychto miestach:"
      for f in "${founddest[@]}"; do note "# $f"; done
      note "# beriem prvy z nich, ale skutocne len hadam."
    fi
    cmd "rm -rf ${founddest[0]} && mv $UPGRADES/$dir ${founddest[0]}"
  fi
done

note "
# teraz chod na http://example.com/update.php (ale s adresou tvojej stranky).
# musis byt prihlaseny ako uzivatel #1. ak to neni mozne, na chvilu zmen
# v sites/$SITEID/settings.php \$update_free_access = TRUE.

# daj vsetko zase on-line a over, ci vsetko funguje. potom mozes dat:"
cmd "rm -rf $UPGRADES"
cmd "rm -rf packages"
note ""


