From cb1338dedc3873ac81488df9dd3aa6f048e6b02f Mon Sep 17 00:00:00 2001 From: Alexandru DAMIAN Date: Fri, 11 Oct 2013 13:46:23 +0100 Subject: bitbake: add toaster code to bitbake This patch adds the Toaster component to Bitbake. Toaster is a module designed to record the progress of a Bitbake build, and data about the resultant artifacts. It contains a web-based interface and a REST API allowing post-facto inspection of the build process and artifacts. Features present in this build: * toaster start script * relational data model * Django boilerplate code * the REST API * the Simple UI web interface This patch has all the development history squashed together. Code portions contributed by Calin Dragomir . Signed-off-by: Alexandru DAMIAN --- bitbake/bin/toaster | 145 ++++++++++++ bitbake/lib/toaster/__init__.py | 0 bitbake/lib/toaster/bldviewer/__init__.py | 0 bitbake/lib/toaster/bldviewer/api.py | 37 +++ bitbake/lib/toaster/bldviewer/templates/base.html | 30 +++ .../toaster/bldviewer/templates/basebuildpage.html | 17 ++ .../lib/toaster/bldviewer/templates/basetable.html | 46 ++++ bitbake/lib/toaster/bldviewer/templates/bfile.html | 24 ++ .../lib/toaster/bldviewer/templates/bpackage.html | 44 ++++ bitbake/lib/toaster/bldviewer/templates/build.html | 43 ++++ .../toaster/bldviewer/templates/configuration.html | 20 ++ bitbake/lib/toaster/bldviewer/templates/layer.html | 34 +++ .../lib/toaster/bldviewer/templates/package.html | 36 +++ .../lib/toaster/bldviewer/templates/recipe.html | 54 +++++ bitbake/lib/toaster/bldviewer/templates/task.html | 63 +++++ .../lib/toaster/bldviewer/templatetags/__init__.py | 0 .../toaster/bldviewer/templatetags/projecttags.py | 26 +++ bitbake/lib/toaster/bldviewer/urls.py | 32 +++ bitbake/lib/toaster/bldviewer/views.py | 260 +++++++++++++++++++++ bitbake/lib/toaster/manage.py | 10 + bitbake/lib/toaster/orm/__init__.py | 0 bitbake/lib/toaster/orm/models.py | 258 ++++++++++++++++++++ bitbake/lib/toaster/toastergui/__init__.py | 0 .../lib/toaster/toastergui/static/images/yocto.jpg | Bin 0 -> 6582 bytes .../lib/toaster/toastergui/templates/index.html | 13 ++ bitbake/lib/toaster/toastergui/urls.py | 27 +++ bitbake/lib/toaster/toastergui/views.py | 26 +++ bitbake/lib/toaster/toastermain/__init__.py | 0 bitbake/lib/toaster/toastermain/settings.py | 190 +++++++++++++++ bitbake/lib/toaster/toastermain/urls.py | 41 ++++ bitbake/lib/toaster/toastermain/wsgi.py | 32 +++ 31 files changed, 1508 insertions(+) create mode 100755 bitbake/bin/toaster create mode 100644 bitbake/lib/toaster/__init__.py create mode 100644 bitbake/lib/toaster/bldviewer/__init__.py create mode 100644 bitbake/lib/toaster/bldviewer/api.py create mode 100644 bitbake/lib/toaster/bldviewer/templates/base.html create mode 100644 bitbake/lib/toaster/bldviewer/templates/basebuildpage.html create mode 100644 bitbake/lib/toaster/bldviewer/templates/basetable.html create mode 100644 bitbake/lib/toaster/bldviewer/templates/bfile.html create mode 100644 bitbake/lib/toaster/bldviewer/templates/bpackage.html create mode 100644 bitbake/lib/toaster/bldviewer/templates/build.html create mode 100644 bitbake/lib/toaster/bldviewer/templates/configuration.html create mode 100644 bitbake/lib/toaster/bldviewer/templates/layer.html create mode 100644 bitbake/lib/toaster/bldviewer/templates/package.html create mode 100644 bitbake/lib/toaster/bldviewer/templates/recipe.html create mode 100644 bitbake/lib/toaster/bldviewer/templates/task.html create mode 100644 bitbake/lib/toaster/bldviewer/templatetags/__init__.py create mode 100644 bitbake/lib/toaster/bldviewer/templatetags/projecttags.py create mode 100644 bitbake/lib/toaster/bldviewer/urls.py create mode 100644 bitbake/lib/toaster/bldviewer/views.py create mode 100755 bitbake/lib/toaster/manage.py create mode 100644 bitbake/lib/toaster/orm/__init__.py create mode 100644 bitbake/lib/toaster/orm/models.py create mode 100644 bitbake/lib/toaster/toastergui/__init__.py create mode 100644 bitbake/lib/toaster/toastergui/static/images/yocto.jpg create mode 100644 bitbake/lib/toaster/toastergui/templates/index.html create mode 100644 bitbake/lib/toaster/toastergui/urls.py create mode 100644 bitbake/lib/toaster/toastergui/views.py create mode 100644 bitbake/lib/toaster/toastermain/__init__.py create mode 100644 bitbake/lib/toaster/toastermain/settings.py create mode 100644 bitbake/lib/toaster/toastermain/urls.py create mode 100644 bitbake/lib/toaster/toastermain/wsgi.py diff --git a/bitbake/bin/toaster b/bitbake/bin/toaster new file mode 100755 index 0000000000..16de52b115 --- /dev/null +++ b/bitbake/bin/toaster @@ -0,0 +1,145 @@ +#!/bin/bash +# (c) 2013 Intel Corp. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +# This script enables toaster event logging and +# starts bitbake resident server +# use as: source toaster [start|stop] + +# Helper function to kill a background toaster development server + +function webserverKillAll() +{ + local pidfile + for pidfile in ${BUILDDIR}/.toastermain.pid; do + if [ -f ${pidfile} ]; then + while kill -0 $(< ${pidfile}) 2>/dev/null; do + kill -SIGTERM -$(< ${pidfile}) 2>/dev/null + sleep 1; + done; + rm ${pidfile} + fi + done +} + + +function webserverStartAll() +{ + retval=0 + python $BBBASEDIR/lib/toaster/manage.py syncdb || retval=1 + if [ $retval -eq 1 ]; then + echo "Failed db sync, stopping system start" 1>&2 + else + python $BBBASEDIR/lib/toaster/manage.py runserver 0.0.0.0:8000 ${BUILDDIR}/toaster_web.log 2>&1 & echo $! >${BUILDDIR}/.toastermain.pid + fi + return $retval +} + + +# We make sure we're running in the current shell and in a good environment + +if [ -z "$ZSH_NAME" ] && [ `basename \"$0\"` = `basename \"$BASH_SOURCE\"` ]; then + echo "Error: This script needs to be sourced. Please run as 'source toaster [start|stop]'" 1>&2; + exit 1 +fi + +if [ -z "$BUILDDIR" ] || [ -z `which bitbake` ]; then + echo "Error: Build environment is not setup or bitbake is not in path." 1>&2; + return 2 +fi + +BBBASEDIR=`dirname ${BASH_SOURCE}`/.. + + +# Verify prerequisites + +if ! echo "import django; print (1,4,5) == django.VERSION[0:3]" | python 2>/dev/null | grep True >/dev/null; then + echo -e "This program needs Django 1.4.5. Please install with\n\nsudo pip install django==1.4.5" + return 2 +fi + + + +# Determine the action. If specified by arguments, fine, if not, toggle it +if [ "x$1" == "xstart" ] || [ "x$1" == "xstop" ]; then + CMD="$1" +else + if [ -z "$BBSERVER" ]; then + CMD="start" + else + CMD="stop" + fi; +fi + +NOTOASTERUI=0 +if [ "x$2" == "xnoui" ]; then + NOTOASTERUI=1 +fi + +echo "The system will $CMD." + +# Make sure it's safe to run by checking bitbake lock + +lock=1 +if [ -e $BUILDDIR/bitbake.lock ]; then + (flock -n 200 ) 200<$BUILDDIR/bitbake.lock || lock=0 +fi + +if [ ${CMD} == "start" ] && ( [ $lock -eq 0 ] || [ -e $BUILDDIR/.toastermain.pid ] ); then + echo "Error: bitbake lock state error. System is already on." 2>&1 + return 3 +elif [ ${CMD} == "stop" ] && ( [ $lock -eq 1 ] || ! [ -e $BUILDDIR/.toastermain.pid ] ) ; then + echo "Error: bitbake lock state error. Trying to stop a stopped system ? +If you think the system is hanged up, you can try to manually stop system with the commands + +# BBSERVER=localhost:8200 bitbake -m + +and + +# webserverKillAll +" 2>&1 + return 3 +fi + + +# Execute the commands + +case $CMD in + start ) + webserverStartAll || return 4 + unset BBSERVER + bitbake --server-only -t xmlrpc -B localhost:8200 + export BBSERVER=localhost:8200 + if [ $NOTOASTERUI == 0 ]; then # we start the TOASTERUI only if not inhibited + bitbake --observe-only -u toasterui >${BUILDDIR}/toaster_ui.log 2>&1 & echo $! >${BUILDDIR}/.toasterui.pid + fi + ;; + stop ) + if [ -f ${BUILDDIR}/.toasterui.pid ]; then + kill $(< ${BUILDDIR}/.toasterui.pid ) + rm ${BUILDDIR}/.toasterui.pid + fi + bitbake -m + unset BBSERVER + webserverKillAll + # force stop any misbehaving bitbake server + lsof bitbake.lock | awk '{print $2}' | grep "[0-9]\+" | xargs -n1 -r kill + ;; +esac + +echo "Successful ${CMD}." + diff --git a/bitbake/lib/toaster/__init__.py b/bitbake/lib/toaster/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bitbake/lib/toaster/bldviewer/__init__.py b/bitbake/lib/toaster/bldviewer/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bitbake/lib/toaster/bldviewer/api.py b/bitbake/lib/toaster/bldviewer/api.py new file mode 100644 index 0000000000..f761ba65a9 --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/api.py @@ -0,0 +1,37 @@ +# +# BitBake Toaster Implementation +# +# Copyright (C) 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from django.conf.urls import patterns, include, url + + +urlpatterns = patterns('bldviewer.views', + url(r'^builds$', 'model_explorer', {'model_name':'build'}, name='builds'), + url(r'^targets$', 'model_explorer', {'model_name':'target'}, name='targets'), + url(r'^tasks$', 'model_explorer', {'model_name':'task'}, name='task'), + url(r'^task_dependencies$', 'model_explorer', {'model_name':'task_dependency'}, name='task_dependencies'), + url(r'^packages$', 'model_explorer', {'model_name':'build_package'}, name='build_packages'), + url(r'^package_dependencies$', 'model_explorer', {'model_name':'build_package_dependency'}, name='build_package_dependencies'), + url(r'^target_packages$', 'model_explorer', {'model_name':'target_package'}, name='target_packages'), + url(r'^package_files$', 'model_explorer', {'model_name':'build_file'}, name='build_files'), + url(r'^layers$', 'model_explorer', {'model_name':'layer'}, name='layer'), + url(r'^layerversions$', 'model_explorer', {'model_name':'layerversion'}, name='layerversion'), + url(r'^recipes$', 'model_explorer', {'model_name':'recipe'}, name='recipe'), + url(r'^recipe_dependencies$', 'model_explorer', {'model_name':'recipe_dependency'}, name='recipe_dependencies'), + url(r'^variables$', 'model_explorer', {'model_name':'variable'}, name='variables'), + url(r'^logmessages$', 'model_explorer', {'model_name':'logmessage'}, name='logmessages'), +) diff --git a/bitbake/lib/toaster/bldviewer/templates/base.html b/bitbake/lib/toaster/bldviewer/templates/base.html new file mode 100644 index 0000000000..101880d3ea --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/base.html @@ -0,0 +1,30 @@ + +{% load static %} + + + Toaster Simple Explorer + + + + + + +
+ + +
+{% block pagecontent %} +{% endblock %} +
+ +
+ + + diff --git a/bitbake/lib/toaster/bldviewer/templates/basebuildpage.html b/bitbake/lib/toaster/bldviewer/templates/basebuildpage.html new file mode 100644 index 0000000000..873f271bab --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/basebuildpage.html @@ -0,0 +1,17 @@ +{% extends "basetable.html" %} + +{% block pagename %} + +

Toaster - Build {% block pagetitle %} {% endblock %}

+{% endblock %} + diff --git a/bitbake/lib/toaster/bldviewer/templates/basetable.html b/bitbake/lib/toaster/bldviewer/templates/basetable.html new file mode 100644 index 0000000000..083bcb82e9 --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/basetable.html @@ -0,0 +1,46 @@ +{% extends "base.html" %} + +{% block pagecontent %} + +
+ + {% block pagename %} + {% endblock %} +
Search: +
+ {% if hideshowcols %} +
Show/Hide columns: + {% for i in hideshowcols %} + {{i.name}} | + {% endfor %} +
+ {% endif %} +
+
+ +{% block pagetable %} +{% endblock %} +
+
+ +{% endblock %} diff --git a/bitbake/lib/toaster/bldviewer/templates/bfile.html b/bitbake/lib/toaster/bldviewer/templates/bfile.html new file mode 100644 index 0000000000..d90f4fbddb --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/bfile.html @@ -0,0 +1,24 @@ +{% extends "basebuildpage.html" %} + +{% block pagetitle %}Files for package {{files.0.bpackage.name}} {% endblock %} +{% block pagetable %} + {% if not files %} +

No files were recorded for this package!

+ {% else %} + + + Name + Size (Bytes) + + + {% for file in files %} + + + {{file.path}} + {{file.size}} + + {% endfor %} + + {% endif %} + +{% endblock %} diff --git a/bitbake/lib/toaster/bldviewer/templates/bpackage.html b/bitbake/lib/toaster/bldviewer/templates/bpackage.html new file mode 100644 index 0000000000..2e254dbad6 --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/bpackage.html @@ -0,0 +1,44 @@ +{% extends "basebuildpage.html" %} + +{% block pagetitle %}Packages{% endblock %} +{% block pagetable %} + {% if not packages %} +

No packages were recorded for this target!

+ {% else %} + + + Name + Version + Recipe + Summary + Section + Description + Size on host disk (KBytes) + License + Dependencies List (all) + + + {% for package in packages %} + + + {{package.name}} ({{package.filelist_bpackage.count}} files) + {{package.version}}-{{package.revision}} + {{package.recipe.name}}{{package.package_name}} + + {{package.summary}} + {{package.section}} + {{package.description}} + {{package.size}} + {{package.license}} + +
+ {% for bpd in package.bpackage_dependencies_package.all %} + {{bpd.dep_type}}: {{bpd.depends_on}}
+ {% endfor %} +
+ + {% endfor %} + + {% endif %} + +{% endblock %} diff --git a/bitbake/lib/toaster/bldviewer/templates/build.html b/bitbake/lib/toaster/bldviewer/templates/build.html new file mode 100644 index 0000000000..ab6e19643b --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/build.html @@ -0,0 +1,43 @@ +{% extends "basetable.html" %} + +{% block pagename %} +

Toaster - Builds

+{% endblock %} + +{% block pagetable %} + + {% load projecttags %} + + Outcome + Started On + Completed On + Target + Machine + Time + Errors + Warnings + Output + Log + Bitbake Version + Build Name + + {% for build in builds %} + + {{build.get_outcome_display}} + {{build.started_on}} + {{build.completed_on}} + {% for t in build.target_set.all %}{{t.target}}{% if t.is_image %} (Img){% endif %}
{% endfor %} + {{build.machine}} + {% time_difference build.started_on build.completed_on %} + {{build.errors_no}}:{% if build.errors_no %}{% for error in logs %}{% if error.build == build %}{% if error.level == 2 %}

{{error.message}}

{% endif %}{% endif %}{% endfor %}{% else %}None{% endif %} + {{build.warnings_no}}:{% if build.warnings_no %}{% for warning in logs %}{% if warning.build == build %}{% if warning.level == 1 %}

{{warning.message}}

{% endif %}{% endif %}{% endfor %}{% else %}None{% endif %} + {% if build.outcome == 0 %}{% for t in build.target_set.all %}{% if t.is_image %}{{build.image_fstypes}}{% endif %}{% endfor %}{% endif %} + {{build.cooker_log_path}} + {{build.bitbake_version}} + {{build.build_name}} + + + {% endfor %} +{% endblock %} + + diff --git a/bitbake/lib/toaster/bldviewer/templates/configuration.html b/bitbake/lib/toaster/bldviewer/templates/configuration.html new file mode 100644 index 0000000000..052c37c4e8 --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/configuration.html @@ -0,0 +1,20 @@ +{% extends "basebuildpage.html" %} + +{% block pagetitle %}Configuration{% endblock %} +{% block pagetable %} + + + Name + Value + Description + + + {% for variable in configuration %} + + + {{variable.variable_name}} + {{variable.variable_value}} + {% if variable.description %}{{variable.description}}{% endif %} + {% endfor %} + +{% endblock %} diff --git a/bitbake/lib/toaster/bldviewer/templates/layer.html b/bitbake/lib/toaster/bldviewer/templates/layer.html new file mode 100644 index 0000000000..fa4fd9bde8 --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/layer.html @@ -0,0 +1,34 @@ +{% extends "basetable.html" %} + +{% block pagename %} +

Toaster - Layers

+{% endblock %} + +{% block pagetable %} + {% load projecttags %} + + + Name + Local Path + Layer Index URL + Known Versions + + + {% for layer in layers %} + + + {{layer.name}} + {{layer.local_path}} + {{layer.layer_index_url}} + + {% for lv in layer.versions %} + + {% endfor %} +
+ ({{lv.priority}}){{lv.branch}}:{{lv.commit}} ({{lv.count}} recipes) +
+ + + {% endfor %} + +{% endblock %} diff --git a/bitbake/lib/toaster/bldviewer/templates/package.html b/bitbake/lib/toaster/bldviewer/templates/package.html new file mode 100644 index 0000000000..642fcab9a1 --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/package.html @@ -0,0 +1,36 @@ +{% extends "basebuildpage.html" %} + +{% block pagetable %} + {% if not packages %} +

No packages were recorded for this target!

+ {% else %} + + + Name + Version + Size (Bytes) + Recipe + Depends on + + + {% for package in packages %} + + + {{package.name}} + {{package.version}} + {{package.size}} + + {{package.recipe.name}}{{package.package_name}} + +
+ {% for d in package.depends_on %} + {{d.name}}
+ {% endfor %} +
+ + + {% endfor %} + + {% endif %} + +{% endblock %} diff --git a/bitbake/lib/toaster/bldviewer/templates/recipe.html b/bitbake/lib/toaster/bldviewer/templates/recipe.html new file mode 100644 index 0000000000..a62437066d --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/recipe.html @@ -0,0 +1,54 @@ +{% extends "basetable.html" %} + +{% block pagename %} + +

Toaster - Recipes for a Layer

+{% endblock %} + +{% block pagetable %} + {% load projecttags %} + + + + Name + Version + Summary + Description + Section + License + License file + Homepage + Bugtracker + Author + File_path + Recipe Dependency + + + {% for recipe in recipes %} + + + {{recipe.name}} + {{recipe.version}} + {{recipe.summary}} + {{recipe.description}} + {{recipe.section}} + {{recipe.license}} + {{recipe.licensing_info}} + {{recipe.homepage}} + {{recipe.bugtracker}} + {{recipe.author}} + {{recipe.file_path}} + +
+ {% for rr in recipe.r_dependencies_recipe.all %} + {{rr.depends_on.name}}
+ {% endfor %} +
+ + + + {% endfor %} + +{% endblock %} diff --git a/bitbake/lib/toaster/bldviewer/templates/task.html b/bitbake/lib/toaster/bldviewer/templates/task.html new file mode 100644 index 0000000000..e7253698cd --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templates/task.html @@ -0,0 +1,63 @@ +{% extends "basebuildpage.html" %} + +{% block pagetitle %}Tasks{% endblock %} +{% block pagetable %} + {% if not tasks %} +

No tasks were executed in this build!

+ {% else %} + + + Order + Task + Recipe Version + Task Type + Checksum + Outcome + Message + Logfile + Time + CPU usage + Disk I/O + Script type + File path + Depends + + + {% for task in tasks %} + + + {{task.order}} + + {{task.recipe.name}}.{{task.task_name}} + {{task.recipe.version}} + + {% if task.task_executed %} + Executed + {% else %} + Prebuilt + {% endif %} + + {{task.sstate_checksum}} + {{task.get_outcome_display}}{% if task.provider %}
(by {{task.provider.recipe.name}}.{{task.provider.task_name}}){% endif %} +

{{task.message}} + {{task.logfile}} + {{task.elapsed_time}} + {{task.cpu_usage}} + {{task.disk_io}} + {{task.get_script_type_display}} + {{task.recipe.file_path}} + +

+ {% for tt in task.task_dependencies_task.all %} + + {{tt.depends_on.recipe.name}}.{{tt.depends_on.task_name}}
+ {% endfor %} +
+ + + + {% endfor %} + + {% endif %} + +{% endblock %} diff --git a/bitbake/lib/toaster/bldviewer/templatetags/__init__.py b/bitbake/lib/toaster/bldviewer/templatetags/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bitbake/lib/toaster/bldviewer/templatetags/projecttags.py b/bitbake/lib/toaster/bldviewer/templatetags/projecttags.py new file mode 100644 index 0000000000..0c0d804c0c --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/templatetags/projecttags.py @@ -0,0 +1,26 @@ +# +# BitBake Toaster Implementation +# +# Copyright (C) 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from datetime import datetime +from django import template + +register = template.Library() + +@register.simple_tag +def time_difference(start_time, end_time): + return end_time - start_time diff --git a/bitbake/lib/toaster/bldviewer/urls.py b/bitbake/lib/toaster/bldviewer/urls.py new file mode 100644 index 0000000000..becc679203 --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/urls.py @@ -0,0 +1,32 @@ +# +# BitBake Toaster Implementation +# +# Copyright (C) 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from django.conf.urls import patterns, include, url +from django.views.generic.simple import redirect_to + +urlpatterns = patterns('bldviewer.views', + url(r'^builds/$', 'build', name='all-builds'), + url(r'^build/(?P\d+)/task/$', 'task', name='task'), + url(r'^build/(?P\d+)/packages/$', 'bpackage', name='bpackage'), + url(r'^build/(?P\d+)/package/(?P\d+)/files/$', 'bfile', name='bfile'), + url(r'^build/(?P\d+)/target/(?P\d+)/packages/$', 'tpackage', name='tpackage'), + url(r'^build/(?P\d+)/configuration/$', 'configuration', name='configuration'), + url(r'^layers/$', 'layer', name='all-layers'), + url(r'^layerversions/(?P\d+)/recipes/.*$', 'layer_versions_recipes', name='layer_versions_recipes'), + url(r'^$', redirect_to, {'url': 'builds/'}), +) diff --git a/bitbake/lib/toaster/bldviewer/views.py b/bitbake/lib/toaster/bldviewer/views.py new file mode 100644 index 0000000000..7be4d4b899 --- /dev/null +++ b/bitbake/lib/toaster/bldviewer/views.py @@ -0,0 +1,260 @@ +# +# BitBake Toaster Implementation +# +# Copyright (C) 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import operator + +from django.db.models import Q +from django.shortcuts import render +from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, Target_Package, LogMessage, Variable +from orm.models import Task_Dependency, Recipe_Dependency, Build_Package, Build_File, Build_Package_Dependency +from django.views.decorators.cache import cache_control + +@cache_control(no_store=True) +def build(request): + template = 'build.html' + build_info = Build.objects.all() + + logs = LogMessage.objects.all() + + context = {'builds': build_info, 'logs': logs , + 'hideshowcols' : [ + {'name': 'Output', 'order':10}, + {'name': 'Log', 'order':11}, + ]} + + return render(request, template, context) + + +def _find_task_revdep(task): + tp = [] + for p in Task_Dependency.objects.filter(depends_on=task): + tp.append(p.task); + return tp + +def _find_task_provider(task): + task_revdeps = _find_task_revdep(task) + for tr in task_revdeps: + if tr.outcome != Task.OUTCOME_COVERED: + return tr + for tr in task_revdeps: + trc = _find_task_provider(tr) + if trc is not None: + return trc + return None + +def task(request, build_id): + template = 'task.html' + + tasks = Task.objects.filter(build=build_id) + + for t in tasks: + if t.outcome == Task.OUTCOME_COVERED: + t.provider = _find_task_provider(t) + + context = {'build': Build.objects.filter(pk=build_id)[0], 'tasks': tasks} + + return render(request, template, context) + +def configuration(request, build_id): + template = 'configuration.html' + variables = Variable.objects.filter(build=build_id) + context = {'build': Build.objects.filter(pk=build_id)[0], 'configuration' : variables} + return render(request, template, context) + +def bpackage(request, build_id): + template = 'bpackage.html' + packages = Build_Package.objects.filter(build = build_id) + context = {'build': Build.objects.filter(pk=build_id)[0], 'packages' : packages} + return render(request, template, context) + +def bfile(request, build_id, package_id): + template = 'bfile.html' + files = Build_File.objects.filter(bpackage = package_id) + context = {'build': Build.objects.filter(pk=build_id)[0], 'files' : files} + return render(request, template, context) + +def tpackage(request, build_id, target_id): + template = 'package.html' + + packages = Target_Package.objects.filter(target=target_id) + + context = {'build' : Build.objects.filter(pk=build_id)[0],'packages': packages} + + return render(request, template, context) + +def layer(request): + template = 'layer.html' + layer_info = Layer.objects.all() + + for li in layer_info: + li.versions = Layer_Version.objects.filter(layer = li) + for liv in li.versions: + liv.count = Recipe.objects.filter(layer_version__id = liv.id).count() + + context = {'layers': layer_info} + + return render(request, template, context) + + +def layer_versions_recipes(request, layerversion_id): + template = 'recipe.html' + recipes = Recipe.objects.filter(layer_version__id = layerversion_id) + + context = {'recipes': recipes, + 'layer_version' : Layer_Version.objects.filter( id = layerversion_id )[0] + } + + return render(request, template, context) + +#### API + +import json +from django.core import serializers +from django.http import HttpResponse, HttpResponseBadRequest + + +def model_explorer(request, model_name): + + DESCENDING = 'desc' + response_data = {} + model_mapping = { + 'build': Build, + 'target': Target, + 'target_package': Target_Package, + 'task': Task, + 'task_dependency': Task_Dependency, + 'package': Build_Package, + 'layer': Layer, + 'layerversion': Layer_Version, + 'recipe': Recipe, + 'recipe_dependency': Recipe_Dependency, + 'build_package': Build_Package, + 'build_package_dependency': Build_Package_Dependency, + 'build_file': Build_File, + 'variable': Variable, + 'logmessage': LogMessage, + } + + if model_name not in model_mapping.keys(): + return HttpResponseBadRequest() + + model = model_mapping[model_name] + + try: + limit = int(request.GET.get('limit', 0)) + except ValueError: + limit = 0 + + try: + offset = int(request.GET.get('offset', 0)) + except ValueError: + offset = 0 + + ordering_string, invalid = _validate_input(request.GET.get('orderby', ''), + model) + if invalid: + return HttpResponseBadRequest() + + filter_string, invalid = _validate_input(request.GET.get('filter', ''), + model) + if invalid: + return HttpResponseBadRequest() + + search_term = request.GET.get('search', '') + + if filter_string: + filter_terms = _get_filtering_terms(filter_string) + try: + queryset = model.objects.filter(**filter_terms) + except ValueError: + queryset = [] + else: + queryset = model.objects.all() + + if search_term: + queryset = _get_search_results(search_term, queryset, model) + + if ordering_string and queryset: + column, order = ordering_string.split(':') + if order.lower() == DESCENDING: + queryset = queryset.order_by('-' + column) + else: + queryset = queryset.order_by(column) + + if offset and limit: + queryset = queryset[offset:(offset+limit)] + elif offset: + queryset = queryset[offset:] + elif limit: + queryset = queryset[:limit] + + if queryset: + response_data['count'] = queryset.count() + else: + response_data['count'] = 0 + + response_data['list'] = serializers.serialize('json', queryset) + + return HttpResponse(json.dumps(response_data), + content_type='application/json') + +def _get_filtering_terms(filter_string): + + search_terms = filter_string.split(":") + keys = search_terms[0].split(',') + values = search_terms[1].split(',') + + return dict(zip(keys, values)) + +def _validate_input(input, model): + + invalid = 0 + + if input: + input_list = input.split(":") + + # Check we have only one colon + if len(input_list) != 2: + invalid = 1 + return None, invalid + + # Check we have an equal number of terms both sides of the colon + if len(input_list[0].split(',')) != len(input_list[1].split(',')): + invalid = 1 + return None, invalid + + # Check we are looking for a valid field + valid_fields = model._meta.get_all_field_names() + for field in input_list[0].split(','): + if field not in valid_fields: + invalid = 1 + return None, invalid + + return input, invalid + +def _get_search_results(search_term, queryset, model): + search_objects = [] + for st in search_term.split(" "): + q_map = map(lambda x: Q(**{x+'__icontains': st}), + model.search_allowed_fields) + + search_objects.append(reduce(operator.or_, q_map)) + search_object = reduce(operator.and_, search_objects) + queryset = queryset.filter(search_object) + + return queryset diff --git a/bitbake/lib/toaster/manage.py b/bitbake/lib/toaster/manage.py new file mode 100755 index 0000000000..ceaa11bfc5 --- /dev/null +++ b/bitbake/lib/toaster/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "toastermain.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/bitbake/lib/toaster/orm/__init__.py b/bitbake/lib/toaster/orm/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py new file mode 100644 index 0000000000..cb6581c9e1 --- /dev/null +++ b/bitbake/lib/toaster/orm/models.py @@ -0,0 +1,258 @@ +# +# BitBake Toaster Implementation +# +# Copyright (C) 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from django.db import models +from django.utils.encoding import python_2_unicode_compatible + + +class Build(models.Model): + SUCCEEDED = 0 + FAILED = 1 + IN_PROGRESS = 2 + + BUILD_OUTCOME = ( + (SUCCEEDED, 'Succeeded'), + (FAILED, 'Failed'), + (IN_PROGRESS, 'In Progress'), + ) + + search_allowed_fields = ['machine', + 'cooker_log_path'] + + machine = models.CharField(max_length=100) + image_fstypes = models.CharField(max_length=100) + distro = models.CharField(max_length=100) + distro_version = models.CharField(max_length=100) + started_on = models.DateTimeField() + completed_on = models.DateTimeField() + outcome = models.IntegerField(choices=BUILD_OUTCOME, default=IN_PROGRESS) + errors_no = models.IntegerField(default=0) + warnings_no = models.IntegerField(default=0) + cooker_log_path = models.CharField(max_length=500) + build_name = models.CharField(max_length=100) + bitbake_version = models.CharField(max_length=50) + +@python_2_unicode_compatible +class Target(models.Model): + search_allowed_fields = ['target', 'image_fstypes', 'file_name'] + build = models.ForeignKey(Build) + target = models.CharField(max_length=100) + is_image = models.BooleanField(default = False) + file_name = models.CharField(max_length=100) + file_size = models.IntegerField() + + def __str__(self): + return self.target + + +class Task(models.Model): + + SSTATE_NA = 0 + SSTATE_MISS = 1 + SSTATE_FAILED = 2 + SSTATE_RESTORED = 3 + + SSTATE_RESULT = ( + (SSTATE_NA, 'Not Applicable'), # For rest of tasks, but they still need checking. + (SSTATE_MISS, 'Missing'), # it is a miss + (SSTATE_FAILED, 'Failed'), # there was a pkg, but the script failed + (SSTATE_RESTORED, 'Restored'), # succesfully restored + ) + + CODING_PYTHON = 0 + CODING_SHELL = 1 + + TASK_CODING = ( + (CODING_PYTHON, 'Python'), + (CODING_SHELL, 'Shell'), + ) + + OUTCOME_SUCCESS = 0 + OUTCOME_COVERED = 1 + OUTCOME_SSTATE = 2 + OUTCOME_EXISTING = 3 + OUTCOME_FAILED = 4 + OUTCOME_NA = 5 + + TASK_OUTCOME = ( + (OUTCOME_SUCCESS, 'Succeeded'), + (OUTCOME_COVERED, 'Covered'), + (OUTCOME_SSTATE, 'Sstate'), + (OUTCOME_EXISTING, 'Existing'), + (OUTCOME_FAILED, 'Failed'), + (OUTCOME_NA, 'Not Available'), + ) + + build = models.ForeignKey(Build, related_name='task_build') + order = models.IntegerField(null=True) + task_executed = models.BooleanField(default=False) # True means Executed, False means Prebuilt + outcome = models.IntegerField(choices=TASK_OUTCOME, default=OUTCOME_NA) + sstate_checksum = models.CharField(max_length=100, blank=True) + path_to_sstate_obj = models.FilePathField(max_length=500, blank=True) + recipe = models.ForeignKey('Recipe', related_name='build_recipe') + task_name = models.CharField(max_length=100) + source_url = models.FilePathField(max_length=255, blank=True) + work_directory = models.FilePathField(max_length=255, blank=True) + script_type = models.IntegerField(choices=TASK_CODING, default=CODING_PYTHON) + line_number = models.IntegerField(default=0) + disk_io = models.IntegerField(null=True) + cpu_usage = models.DecimalField(max_digits=6, decimal_places=2, null=True) + elapsed_time = models.CharField(max_length=50, default=0) + sstate_result = models.IntegerField(choices=SSTATE_RESULT, default=SSTATE_NA) + message = models.CharField(max_length=240) + logfile = models.FilePathField(max_length=255, blank=True) + + class Meta: + ordering = ('order', 'recipe' ,) + + +class Task_Dependency(models.Model): + task = models.ForeignKey(Task, related_name='task_dependencies_task') + depends_on = models.ForeignKey(Task, related_name='task_dependencies_depends') + + +class Build_Package(models.Model): + build = models.ForeignKey('Build') + recipe = models.ForeignKey('Recipe', null=True) + name = models.CharField(max_length=100) + version = models.CharField(max_length=100, blank=True) + revision = models.CharField(max_length=32, blank=True) + summary = models.CharField(max_length=200, blank=True) + description = models.CharField(max_length=200, blank=True) + size = models.IntegerField(default=0) + section = models.CharField(max_length=80, blank=True) + license = models.CharField(max_length=80, blank=True) + +class Build_Package_Dependency(models.Model): + TYPE_RDEPENDS = 0 + TYPE_RPROVIDES = 1 + TYPE_RRECOMMENDS = 2 + TYPE_RSUGGESTS = 3 + TYPE_RREPLACES = 4 + TYPE_RCONFLICTS = 5 + DEPENDS_TYPE = ( + (TYPE_RDEPENDS, "rdepends"), + (TYPE_RPROVIDES, "rprovides"), + (TYPE_RRECOMMENDS, "rrecommends"), + (TYPE_RSUGGESTS, "rsuggests"), + (TYPE_RREPLACES, "rreplaces"), + (TYPE_RCONFLICTS, "rconflicts"), + ) + package = models.ForeignKey(Build_Package, related_name='bpackage_dependencies_package') + depends_on = models.CharField(max_length=100) # soft dependency + dep_type = models.IntegerField(choices=DEPENDS_TYPE) + + +class Target_Package(models.Model): + target = models.ForeignKey('Target') + recipe = models.ForeignKey('Recipe', null=True) + name = models.CharField(max_length=100) + version = models.CharField(max_length=100, blank=True) + size = models.IntegerField() + + +class Target_Package_Dependency(models.Model): + TYPE_DEPENDS = 0 + TYPE_RDEPENDS = 1 + TYPE_RECOMMENDS = 2 + + DEPENDS_TYPE = ( + (TYPE_DEPENDS, "depends"), + (TYPE_RDEPENDS, "rdepends"), + (TYPE_RECOMMENDS, "recommends"), + ) + package = models.ForeignKey(Target_Package, related_name='tpackage_dependencies_package') + depends_on = models.ForeignKey(Target_Package, related_name='tpackage_dependencies_depends') + dep_type = models.IntegerField(choices=DEPENDS_TYPE) + + +class Build_File(models.Model): + bpackage = models.ForeignKey(Build_Package, related_name='filelist_bpackage') + path = models.FilePathField(max_length=255, blank=True) + size = models.IntegerField() + +class Target_File(models.Model): + tpackage = models.ForeignKey(Target_Package, related_name='filelist_tpackage') + path = models.FilePathField(max_length=255, blank=True) + size = models.IntegerField() + + +class Recipe(models.Model): + name = models.CharField(max_length=100, blank=True) + version = models.CharField(max_length=100, blank=True) + layer_version = models.ForeignKey('Layer_Version', related_name='recipe_layer_version') + summary = models.CharField(max_length=100, blank=True) + description = models.CharField(max_length=100, blank=True) + section = models.CharField(max_length=100, blank=True) + license = models.CharField(max_length=200, blank=True) + licensing_info = models.TextField(blank=True) + homepage = models.URLField(blank=True) + bugtracker = models.URLField(blank=True) + author = models.CharField(max_length=100, blank=True) + file_path = models.FilePathField(max_length=255) + + +class Recipe_Dependency(models.Model): + TYPE_DEPENDS = 0 + TYPE_RDEPENDS = 1 + + DEPENDS_TYPE = ( + (TYPE_DEPENDS, "depends"), + (TYPE_RDEPENDS, "rdepends"), + ) + recipe = models.ForeignKey(Recipe, related_name='r_dependencies_recipe') + depends_on = models.ForeignKey(Recipe, related_name='r_dependencies_depends') + dep_type = models.IntegerField(choices=DEPENDS_TYPE) + +class Layer(models.Model): + name = models.CharField(max_length=100) + local_path = models.FilePathField(max_length=255) + layer_index_url = models.URLField() + + +class Layer_Version(models.Model): + layer = models.ForeignKey(Layer, related_name='layer_version_layer') + branch = models.CharField(max_length=50) + commit = models.CharField(max_length=100) + priority = models.IntegerField() + + +class Variable(models.Model): + build = models.ForeignKey(Build, related_name='variable_build') + variable_name = models.CharField(max_length=100) + variable_value = models.TextField(blank=True) + file = models.FilePathField(max_length=255) + changed = models.BooleanField(default=False) + human_readable_name = models.CharField(max_length=200) + description = models.TextField(blank=True) + + +class LogMessage(models.Model): + INFO = 0 + WARNING = 1 + ERROR = 2 + + LOG_LEVEL = ( (INFO, "info"), + (WARNING, "warn"), + (ERROR, "error") ) + + build = models.ForeignKey(Build) + level = models.IntegerField(choices=LOG_LEVEL, default=INFO) + message=models.CharField(max_length=240) + pathname = models.FilePathField(max_length=255, blank=True) + lineno = models.IntegerField(null=True) diff --git a/bitbake/lib/toaster/toastergui/__init__.py b/bitbake/lib/toaster/toastergui/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bitbake/lib/toaster/toastergui/static/images/yocto.jpg b/bitbake/lib/toaster/toastergui/static/images/yocto.jpg new file mode 100644 index 0000000000..5de4b7693a Binary files /dev/null and b/bitbake/lib/toaster/toastergui/static/images/yocto.jpg differ diff --git a/bitbake/lib/toaster/toastergui/templates/index.html b/bitbake/lib/toaster/toastergui/templates/index.html new file mode 100644 index 0000000000..80b02d94a9 --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/index.html @@ -0,0 +1,13 @@ + + + GUI Page + + +{% load staticfiles %} + +Yocto + +This is your basic index page! + + + \ No newline at end of file diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py new file mode 100644 index 0000000000..6dbf0c5a56 --- /dev/null +++ b/bitbake/lib/toaster/toastergui/urls.py @@ -0,0 +1,27 @@ +# +# BitBake Toaster Implementation +# +# Copyright (C) 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import os + +from django.conf import settings +from django.conf.urls import patterns, include, url + + +urlpatterns = patterns('toastergui.views', + url(r'^$', 'guihome', name='guihome'), +) diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py new file mode 100644 index 0000000000..ecb2f7e82f --- /dev/null +++ b/bitbake/lib/toaster/toastergui/views.py @@ -0,0 +1,26 @@ +# +# BitBake Toaster Implementation +# +# Copyright (C) 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from django.shortcuts import render +from orm.models import Build, Task + + +def guihome(request): + template = 'index.html' + + return render(request, template) diff --git a/bitbake/lib/toaster/toastermain/__init__.py b/bitbake/lib/toaster/toastermain/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bitbake/lib/toaster/toastermain/settings.py b/bitbake/lib/toaster/toastermain/settings.py new file mode 100644 index 0000000000..dd1e25c087 --- /dev/null +++ b/bitbake/lib/toaster/toastermain/settings.py @@ -0,0 +1,190 @@ +# +# BitBake Toaster Implementation +# +# Copyright (C) 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Django settings for Toaster project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + # ('Your Name', 'your_email@example.com'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': 'toaster.sqlite', # Or path to database file if using sqlite3. + 'USER': '', + 'PASSWORD': '', + 'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + 'PORT': '3306', # Set to empty string for default. + } +} + +# Hosts/domain names that are valid for this site; required if DEBUG is False +# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts +ALLOWED_HOSTS = [] + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# In a Windows environment this must be set to your system time zone. + +# Always use local computer's time zone +#TIME_ZONE = '' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale. +USE_L10N = True + +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = False + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/var/www/example.com/media/" +MEDIA_ROOT = '' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://example.com/media/", "http://media.example.com/" +MEDIA_URL = '' + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/var/www/example.com/static/" +STATIC_ROOT = '' + +# URL prefix for static files. +# Example: "http://example.com/static/", "http://static.example.com/" +STATIC_URL = '/static/' + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'NOT_SUITABLE_FOR_HOSTED_DEPLOYMENT' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +# 'django.template.loaders.eggs.Loader', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + # Uncomment the next line for simple clickjacking protection: + # 'django.middleware.clickjacking.XFrameOptionsMiddleware', +) + +ROOT_URLCONF = 'toastermain.urls' + +# Python dotted path to the WSGI application used by Django's runserver. +WSGI_APPLICATION = 'toastermain.wsgi.application' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +INSTALLED_APPS = ( + #'django.contrib.auth', + #'django.contrib.contenttypes', + #'django.contrib.sessions', + #'django.contrib.sites', + #'django.contrib.messages', + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + # 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + 'orm', + 'toastermain', + 'bldviewer', + 'toastergui', +) + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error when DEBUG=False. +# See http://docs.djangoproject.com/en/dev/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + } +} + +# If we're using sqlite, we need to tweak the performance a bit +from django.db.backends.signals import connection_created +def activate_synchronous_off(sender, connection, **kwargs): + if connection.vendor == 'sqlite': + cursor = connection.cursor() + cursor.execute('PRAGMA synchronous = 0;') +connection_created.connect(activate_synchronous_off) +# + + diff --git a/bitbake/lib/toaster/toastermain/urls.py b/bitbake/lib/toaster/toastermain/urls.py new file mode 100644 index 0000000000..d0606bce9e --- /dev/null +++ b/bitbake/lib/toaster/toastermain/urls.py @@ -0,0 +1,41 @@ +# +# BitBake Toaster Implementation +# +# Copyright (C) 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from django.conf.urls import patterns, include, url +from django.views.generic.simple import redirect_to +from django.views.decorators.cache import never_cache + + +# Uncomment the next two lines to enable the admin: +# from django.contrib import admin +# admin.autodiscover() + +urlpatterns = patterns('', + url(r'^simple/', include('bldviewer.urls')), + url(r'^api/1.0/', include('bldviewer.api')), + url(r'^gui/', include('toastergui.urls')), + url(r'^$', never_cache(redirect_to), {'url': '/simple/'}), + # Examples: + # url(r'^toaster/', include('toaster.foo.urls')), + + # Uncomment the admin/doc line below to enable admin documentation: + # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + # url(r'^admin/', include(admin.site.urls)), +) diff --git a/bitbake/lib/toaster/toastermain/wsgi.py b/bitbake/lib/toaster/toastermain/wsgi.py new file mode 100644 index 0000000000..6277eb4d5e --- /dev/null +++ b/bitbake/lib/toaster/toastermain/wsgi.py @@ -0,0 +1,32 @@ +""" +WSGI config for Toaster project. + +This module contains the WSGI application used by Django's development server +and any production WSGI deployments. It should expose a module-level variable +named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover +this application via the ``WSGI_APPLICATION`` setting. + +Usually you will have the standard Django WSGI application here, but it also +might make sense to replace the whole Django WSGI application with a custom one +that later delegates to the Django one. For example, you could introduce WSGI +middleware here, or combine a Django application with an application of another +framework. + +""" +import os + +# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks +# if running multiple sites in the same mod_wsgi process. To fix this, use +# mod_wsgi daemon mode with each site in its own daemon process, or use +# os.environ["DJANGO_SETTINGS_MODULE"] = "Toaster.settings" +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "toastermain.settings") + +# This application object is used by any WSGI server configured to use this +# file. This includes Django's development server, if the WSGI_APPLICATION +# setting points here. +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +# Apply WSGI middleware here. +# from helloworld.wsgi import HelloWorldApplication +# application = HelloWorldApplication(application) -- cgit v1.2.3-54-g00ecf