Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | #!/bin/sh |
| 2 | # (c) 2013 Intel Corp. |
| 3 | |
| 4 | # This program is free software; you can redistribute it and/or modify |
| 5 | # it under the terms of the GNU General Public License as published by |
| 6 | # the Free Software Foundation; either version 2 of the License, or |
| 7 | # (at your option) any later version. |
| 8 | # |
| 9 | # This program is distributed in the hope that it will be useful, |
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | # GNU General Public License for more details. |
| 13 | # |
| 14 | # You should have received a copy of the GNU General Public License |
| 15 | # along with this program; if not, write to the Free Software |
| 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 17 | |
| 18 | |
| 19 | # This script can be run in two modes. |
| 20 | |
| 21 | # When used with "source", from a build directory, |
| 22 | # it enables toaster event logging and starts the bitbake resident server. |
| 23 | # use as: source toaster [start|stop] [noweb] [noui] |
| 24 | |
| 25 | # When it is called as a stand-alone script, it starts just the |
| 26 | # web server, and the building shall be done through the web interface. |
| 27 | # As script, it will not return to the command prompt. Stop with Ctrl-C. |
| 28 | |
| 29 | # Helper function to kill a background toaster development server |
| 30 | |
| 31 | webserverKillAll() |
| 32 | { |
| 33 | local pidfile |
| 34 | for pidfile in ${BUILDDIR}/.toastermain.pid; do |
| 35 | if [ -f ${pidfile} ]; then |
| 36 | pid=`cat ${pidfile}` |
| 37 | while kill -0 $pid 2>/dev/null; do |
| 38 | kill -SIGTERM -$pid 2>/dev/null |
| 39 | sleep 1 |
| 40 | # Kill processes if they are still running - may happen in interactive shells |
| 41 | ps fux | grep "python.*manage.py runserver" | awk '{print $2}' | xargs kill |
| 42 | done |
| 43 | rm ${pidfile} |
| 44 | fi |
| 45 | done |
| 46 | } |
| 47 | |
| 48 | webserverStartAll() |
| 49 | { |
| 50 | # do not start if toastermain points to a valid process |
| 51 | if ! cat "${BUILDDIR}/.toastermain.pid" 2>/dev/null | xargs -I{} kill -0 {} ; then |
| 52 | retval=1 |
| 53 | rm "${BUILDDIR}/.toastermain.pid" |
| 54 | fi |
| 55 | |
| 56 | retval=0 |
| 57 | if [ "$TOASTER_MANAGED" '=' '1' ]; then |
| 58 | python $BBBASEDIR/lib/toaster/manage.py syncdb || retval=1 |
| 59 | else |
| 60 | python $BBBASEDIR/lib/toaster/manage.py syncdb --noinput || retval=1 |
| 61 | fi |
| 62 | python $BBBASEDIR/lib/toaster/manage.py migrate orm || retval=2 |
| 63 | if [ $retval -eq 1 ]; then |
| 64 | echo "Failed db sync, stopping system start" 1>&2 |
| 65 | elif [ $retval -eq 2 ]; then |
| 66 | printf "\nError on migration, trying to recover... \n" |
| 67 | python $BBBASEDIR/lib/toaster/manage.py migrate orm 0001_initial --fake |
| 68 | retval=0 |
| 69 | python $BBBASEDIR/lib/toaster/manage.py migrate orm || retval=1 |
| 70 | fi |
| 71 | if [ "$TOASTER_MANAGED" = '1' ]; then |
| 72 | python $BBBASEDIR/lib/toaster/manage.py migrate bldcontrol || retval=1 |
| 73 | python $BBBASEDIR/lib/toaster/manage.py checksettings --traceback || retval=1 |
| 74 | fi |
| 75 | if [ $retval -eq 0 ]; then |
| 76 | echo "Starting webserver..." |
| 77 | python $BBBASEDIR/lib/toaster/manage.py runserver "0.0.0.0:$WEB_PORT" </dev/null >>${BUILDDIR}/toaster_web.log 2>&1 & echo $! >${BUILDDIR}/.toastermain.pid |
| 78 | sleep 1 |
| 79 | if ! cat "${BUILDDIR}/.toastermain.pid" | xargs -I{} kill -0 {} ; then |
| 80 | retval=1 |
| 81 | rm "${BUILDDIR}/.toastermain.pid" |
| 82 | else |
| 83 | echo "Webserver address: http://0.0.0.0:$WEB_PORT/" |
| 84 | fi |
| 85 | fi |
| 86 | return $retval |
| 87 | } |
| 88 | |
| 89 | # Helper functions to add a special configuration file |
| 90 | |
| 91 | addtoConfiguration() |
| 92 | { |
| 93 | file=$1 |
| 94 | shift |
| 95 | echo "#Created by toaster start script" > ${BUILDDIR}/conf/$file |
| 96 | for var in "$@"; do echo $var >> ${BUILDDIR}/conf/$file; done |
| 97 | } |
| 98 | |
| 99 | INSTOPSYSTEM=0 |
| 100 | |
| 101 | # define the stop command |
| 102 | stop_system() |
| 103 | { |
| 104 | # prevent reentry |
| 105 | if [ $INSTOPSYSTEM -eq 1 ]; then return; fi |
| 106 | INSTOPSYSTEM=1 |
| 107 | if [ -f ${BUILDDIR}/.toasterui.pid ]; then |
| 108 | kill `cat ${BUILDDIR}/.toasterui.pid` 2>/dev/null |
| 109 | rm ${BUILDDIR}/.toasterui.pid |
| 110 | fi |
| 111 | BBSERVER=0.0.0.0:-1 bitbake -m |
| 112 | unset BBSERVER |
| 113 | webserverKillAll |
| 114 | # force stop any misbehaving bitbake server |
| 115 | lsof bitbake.lock | awk '{print $2}' | grep "[0-9]\+" | xargs -n1 -r kill |
| 116 | trap - SIGHUP |
| 117 | #trap - SIGCHLD |
| 118 | INSTOPSYSTEM=0 |
| 119 | } |
| 120 | |
| 121 | check_pidbyfile() { |
| 122 | [ -e $1 ] && kill -0 `cat $1` 2>/dev/null |
| 123 | } |
| 124 | |
| 125 | |
| 126 | notify_chldexit() { |
| 127 | if [ $NOTOASTERUI -eq 0 ]; then |
| 128 | check_pidbyfile ${BUILDDIR}/.toasterui.pid && return |
| 129 | stop_system |
| 130 | fi |
| 131 | } |
| 132 | |
| 133 | |
| 134 | verify_prereq() { |
| 135 | # Verify prerequisites |
| 136 | |
| 137 | if ! echo "import django; print (1,) == django.VERSION[0:1] and django.VERSION[1:2][0] in (6,)" | python 2>/dev/null | grep True >/dev/null; then |
| 138 | printf "This program needs Django 1.6. Please install with\n\npip install django==1.6\n" |
| 139 | return 2 |
| 140 | fi |
| 141 | |
| 142 | if ! echo "import south; print reduce(lambda x, y: 2 if x==2 else 0 if x == 0 else y, map(lambda x: 1+cmp(x[1]-x[0],0), zip([0,8,4], map(int,south.__version__.split(\".\"))))) > 0" | python 2>/dev/null | grep True >/dev/null; then |
| 143 | printf "This program needs South 0.8.4. Please install with\n\npip install south==0.8.4\n" |
| 144 | return 2 |
| 145 | fi |
| 146 | return 0 |
| 147 | } |
| 148 | |
| 149 | |
| 150 | # read command line parameters |
| 151 | if [ -n "$BASH_SOURCE" ] ; then |
| 152 | TOASTER=${BASH_SOURCE} |
| 153 | elif [ -n "$ZSH_NAME" ] ; then |
| 154 | TOASTER=${(%):-%x} |
| 155 | else |
| 156 | TOASTER=$0 |
| 157 | fi |
| 158 | |
| 159 | BBBASEDIR=`dirname $TOASTER`/.. |
| 160 | |
| 161 | RUNNING=0 |
| 162 | |
| 163 | NOTOASTERUI=0 |
| 164 | WEBSERVER=1 |
| 165 | TOASTER_BRBE="" |
| 166 | WEB_PORT="8000" |
| 167 | NOBROWSER=0 |
| 168 | |
| 169 | for param in $*; do |
| 170 | case $param in |
| 171 | noui ) |
| 172 | NOTOASTERUI=1 |
| 173 | ;; |
| 174 | noweb ) |
| 175 | WEBSERVER=0 |
| 176 | ;; |
| 177 | nobrowser ) |
| 178 | NOBROWSER=1 |
| 179 | ;; |
| 180 | brbe=* ) |
| 181 | TOASTER_BRBE=$'\n'"TOASTER_BRBE=\""${param#*=}"\"" |
| 182 | ;; |
| 183 | webport=*) |
| 184 | WEB_PORT="${param#*=}" |
| 185 | esac |
| 186 | done |
| 187 | |
| 188 | [ -n "${BASH_SOURCE}" ] && SRCFILE=${BASH_SOURCE} || SRCFILE=$_ |
| 189 | |
| 190 | if [ `basename \"$0\"` = `basename \"${SRCFILE}\"` ]; then |
| 191 | # We are called as standalone. We refuse to run in a build environment - we need the interactive mode for that. |
| 192 | # Start just the web server, point the web browser to the interface, and start any Django services. |
| 193 | |
| 194 | if ! verify_prereq; then |
| 195 | echo "Error: Could not verify that the needed dependencies are installed. Please use virtualenv and pip to install dependencies listed in toaster-requirements.txt" 1>&2 |
| 196 | exit 1 |
| 197 | fi |
| 198 | |
| 199 | if [ -n "$BUILDDIR" ]; then |
| 200 | printf "Error: It looks like you sourced oe-init-build-env. Toaster cannot start in build mode from an oe-core build environment.\n You should be starting Toaster from a new terminal window." 1>&2 |
| 201 | exit 1 |
| 202 | fi |
| 203 | |
| 204 | # Define a fake builddir where only the pid files are actually created. No real builds will take place here. |
| 205 | BUILDDIR=/tmp/toaster_$$ |
| 206 | if [ -d "$BUILDDIR" ]; then |
| 207 | echo "Previous toaster run directory $BUILDDIR found, cowardly refusing to start. Please remove the directory when that toaster instance is over" 2>&1 |
| 208 | exit 1 |
| 209 | fi |
| 210 | |
| 211 | mkdir -p "$BUILDDIR" |
| 212 | |
| 213 | RUNNING=1 |
| 214 | trap_ctrlc() { |
| 215 | echo "** Stopping system" |
| 216 | webserverKillAll |
| 217 | RUNNING=0 |
| 218 | } |
| 219 | |
| 220 | do_cleanup() { |
| 221 | find "$BUILDDIR" -type f | xargs rm |
| 222 | rmdir "$BUILDDIR" |
| 223 | } |
| 224 | cleanup() { |
| 225 | if grep -ir error "$BUILDDIR" >/dev/null; then |
| 226 | if grep -irn "That port is already in use" "$BUILDDIR"; then |
| 227 | echo "You can use the \"webport=PORTNUMBER\" parameter to start Toaster on a different port (port $WEB_PORT is already in use)" |
| 228 | do_cleanup |
| 229 | else |
| 230 | printf "\nErrors found in the Toaster log files present in '$BUILDDIR'. Directory will not be cleaned.\n Please review the errors and notify toaster@yoctoproject.org or submit a bug https://bugzilla.yoctoproject.org/enter_bug.cgi?product=Toaster" |
| 231 | fi |
| 232 | else |
| 233 | echo "No errors found, removing the run directory '$BUILDDIR'" |
| 234 | do_cleanup |
| 235 | fi |
| 236 | } |
| 237 | TOASTER_MANAGED=1 |
| 238 | export TOASTER_MANAGED=1 |
| 239 | if [ $WEBSERVER -gt 0 ] && ! webserverStartAll; then |
| 240 | echo "Failed to start the web server, stopping" 1>&2 |
| 241 | cleanup |
| 242 | exit 1 |
| 243 | fi |
| 244 | if [ $WEBSERVER -gt 0 ] && [ $NOBROWSER -eq 0 ] ; then |
| 245 | echo "Starting browser..." |
| 246 | xdg-open http://127.0.0.1:$WEB_PORT/ >/dev/null 2>&1 & |
| 247 | fi |
| 248 | trap trap_ctrlc 2 |
| 249 | echo "Toaster is now running. You can stop it with Ctrl-C" |
| 250 | while [ $RUNNING -gt 0 ]; do |
| 251 | python $BBBASEDIR/lib/toaster/manage.py runbuilds 2>&1 | tee -a "$BUILDDIR/toaster.log" |
| 252 | sleep 1 |
| 253 | done |
| 254 | cleanup |
| 255 | echo "**** Exit" |
| 256 | exit 0 |
| 257 | fi |
| 258 | |
| 259 | |
| 260 | if ! verify_prereq; then |
| 261 | echo "Error: Could not verify that the needed dependencies are installed. Please use virtualenv and pip to install dependencies listed in toaster-requirements.txt" 1>&2 |
| 262 | return 1 |
| 263 | fi |
| 264 | |
| 265 | |
| 266 | # We make sure we're running in the current shell and in a good environment |
| 267 | if [ -z "$BUILDDIR" ] || ! which bitbake >/dev/null 2>&1 ; then |
| 268 | echo "Error: Build environment is not setup or bitbake is not in path." 1>&2 |
| 269 | return 2 |
| 270 | fi |
| 271 | |
| 272 | |
| 273 | # Determine the action. If specified by arguments, fine, if not, toggle it |
| 274 | if [ "$1" = 'start' ] || [ "$1" = 'stop' ]; then |
| 275 | CMD="$1" |
| 276 | else |
| 277 | if [ -z "$BBSERVER" ]; then |
| 278 | CMD="start" |
| 279 | else |
| 280 | CMD="stop" |
| 281 | fi |
| 282 | fi |
| 283 | |
| 284 | echo "The system will $CMD." |
| 285 | |
| 286 | # Make sure it's safe to run by checking bitbake lock |
| 287 | |
| 288 | lock=1 |
| 289 | if [ -e $BUILDDIR/bitbake.lock ]; then |
| 290 | python -c "import fcntl; fcntl.flock(open(\"$BUILDDIR/bitbake.lock\"), fcntl.LOCK_EX|fcntl.LOCK_NB)" 2>/dev/null || lock=0 |
| 291 | fi |
| 292 | |
| 293 | if [ ${CMD} = 'start' ] && [ $lock -eq 0 ]; then |
| 294 | echo "Error: bitbake lock state error. File locks show that the system is on." 1>&2 |
| 295 | echo "Please wait for the current build to finish, stop and then start the system again." 1>&2 |
| 296 | return 3 |
| 297 | fi |
| 298 | |
| 299 | if [ ${CMD} = 'start' ] && [ -e $BUILDDIR/.toastermain.pid ] && kill -0 `cat $BUILDDIR/.toastermain.pid`; then |
| 300 | echo "Warning: bitbake appears to be dead, but the Toaster web server is running. Something fishy is going on." 1>&2 |
| 301 | echo "Cleaning up the web server to start from a clean slate." |
| 302 | webserverKillAll |
| 303 | fi |
| 304 | |
| 305 | |
| 306 | # Execute the commands |
| 307 | |
| 308 | case $CMD in |
| 309 | start ) |
| 310 | start_success=1 |
| 311 | addtoConfiguration toaster.conf "INHERIT+=\"toaster buildhistory\"" $TOASTER_BRBE |
| 312 | if [ $WEBSERVER -gt 0 ] && ! webserverStartAll; then |
| 313 | echo "Failed ${CMD}." |
| 314 | return 4 |
| 315 | fi |
| 316 | unset BBSERVER |
| 317 | PREREAD="" |
| 318 | if [ -e ${BUILDDIR}/conf/toaster-pre.conf ]; then |
| 319 | rm ${BUILDDIR}/conf/toaster-pre.conf |
| 320 | fi |
| 321 | bitbake $PREREAD --postread conf/toaster.conf --server-only -t xmlrpc -B 0.0.0.0:0 |
| 322 | if [ $? -ne 0 ]; then |
| 323 | start_success=0 |
| 324 | echo "Bitbake server start failed" |
| 325 | else |
| 326 | export BBSERVER=0.0.0.0:-1 |
| 327 | if [ $NOTOASTERUI -eq 0 ]; then # we start the TOASTERUI only if not inhibited |
| 328 | bitbake --observe-only -u toasterui >>${BUILDDIR}/toaster_ui.log 2>&1 & echo $! >${BUILDDIR}/.toasterui.pid |
| 329 | fi |
| 330 | fi |
| 331 | if [ $start_success -eq 1 ]; then |
| 332 | # set fail safe stop system on terminal exit |
| 333 | trap stop_system SIGHUP |
| 334 | echo "Successful ${CMD}." |
| 335 | return 0 |
| 336 | else |
| 337 | # failed start, do stop |
| 338 | stop_system |
| 339 | echo "Failed ${CMD}." |
| 340 | return 1 |
| 341 | fi |
| 342 | # stop system on terminal exit |
| 343 | set -o monitor |
| 344 | trap stop_system SIGHUP |
| 345 | #trap notify_chldexit SIGCHLD |
| 346 | ;; |
| 347 | stop ) |
| 348 | stop_system |
| 349 | echo "Successful ${CMD}." |
| 350 | ;; |
| 351 | esac |
| 352 | |