| #! /usr/bin/env python |
| # ex:ts=4:sw=4:sts=4:et |
| # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- |
| # |
| # BitBake Toaster Implementation |
| # |
| # Copyright (C) 2016 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 |
| import sys |
| import time |
| import unittest |
| |
| from orm.models import Project, Release, ProjectTarget, Build, ProjectVariable |
| from bldcontrol.models import BuildEnvironment |
| |
| from bldcontrol.management.commands.runbuilds import Command\ |
| as RunBuildsCommand |
| |
| from django.core.management import call_command |
| |
| import subprocess |
| import logging |
| |
| logger = logging.getLogger("toaster") |
| |
| # We use unittest.TestCase instead of django.test.TestCase because we don't |
| # want to wrap everything in a database transaction as an external process |
| # (bitbake needs access to the database) |
| |
| def load_build_environment(): |
| call_command('loaddata', 'settings.xml', app_label="orm") |
| call_command('loaddata', 'poky.xml', app_label="orm") |
| |
| current_builddir = os.environ.get("BUILDDIR") |
| if current_builddir: |
| BuildTest.BUILDDIR = current_builddir |
| else: |
| # Setup a builddir based on default layout |
| # bitbake inside openebedded-core |
| oe_init_build_env_path = os.path.join( |
| os.path.dirname(os.path.abspath(__file__)), |
| os.pardir, |
| os.pardir, |
| os.pardir, |
| os.pardir, |
| os.pardir, |
| 'oe-init-build-env' |
| ) |
| if not os.path.exists(oe_init_build_env_path): |
| raise Exception("We had no BUILDDIR set and couldn't " |
| "find oe-init-build-env to set this up " |
| "ourselves please run oe-init-build-env " |
| "before running these tests") |
| |
| oe_init_build_env_path = os.path.realpath(oe_init_build_env_path) |
| cmd = "bash -c 'source oe-init-build-env %s'" % BuildTest.BUILDDIR |
| p = subprocess.Popen( |
| cmd, |
| cwd=os.path.dirname(oe_init_build_env_path), |
| shell=True, |
| stdout=subprocess.PIPE, |
| stderr=subprocess.PIPE) |
| |
| output, err = p.communicate() |
| p.wait() |
| |
| logger.info("oe-init-build-env %s %s" % (output, err)) |
| |
| os.environ['BUILDDIR'] = BuildTest.BUILDDIR |
| |
| # Setup the path to bitbake we know where to find this |
| bitbake_path = os.path.join( |
| os.path.dirname(os.path.abspath(__file__)), |
| os.pardir, |
| os.pardir, |
| os.pardir, |
| os.pardir, |
| 'bin', |
| 'bitbake') |
| if not os.path.exists(bitbake_path): |
| raise Exception("Could not find bitbake at the expected path %s" |
| % bitbake_path) |
| |
| os.environ['BBBASEDIR'] = bitbake_path |
| |
| class BuildTest(unittest.TestCase): |
| |
| PROJECT_NAME = "Testbuild" |
| BUILDDIR = "/tmp/build/" |
| |
| def build(self, target): |
| # So that the buildinfo helper uses the test database' |
| self.assertEqual( |
| os.environ.get('DJANGO_SETTINGS_MODULE', ''), |
| 'toastermain.settings_test', |
| "Please initialise django with the tests settings: " |
| "DJANGO_SETTINGS_MODULE='toastermain.settings_test'") |
| |
| built = self.target_already_built(target) |
| if built: |
| return built |
| |
| load_build_environment() |
| |
| BuildEnvironment.objects.get_or_create( |
| betype=BuildEnvironment.TYPE_LOCAL, |
| sourcedir=BuildTest.BUILDDIR, |
| builddir=BuildTest.BUILDDIR |
| ) |
| |
| release = Release.objects.get(name='local') |
| |
| # Create a project for this build to run in |
| project = Project.objects.create_project(name=BuildTest.PROJECT_NAME, |
| release=release) |
| |
| if os.environ.get("TOASTER_TEST_USE_SSTATE_MIRROR"): |
| ProjectVariable.objects.get_or_create( |
| name="SSTATE_MIRRORS", |
| value="file://.* http://autobuilder.yoctoproject.org/pub/sstate/PATH;downloadfilename=PATH", |
| project=project) |
| |
| ProjectTarget.objects.create(project=project, |
| target=target, |
| task="") |
| build_request = project.schedule_build() |
| |
| # run runbuilds command to dispatch the build |
| # e.g. manage.py runubilds |
| RunBuildsCommand().runbuild() |
| |
| build_pk = build_request.build.pk |
| while Build.objects.get(pk=build_pk).outcome == Build.IN_PROGRESS: |
| sys.stdout.write("\rBuilding %s %d%%" % |
| (target, |
| build_request.build.completeper())) |
| sys.stdout.flush() |
| time.sleep(1) |
| |
| self.assertEqual(Build.objects.get(pk=build_pk).outcome, |
| Build.SUCCEEDED, |
| "Build did not SUCCEEDED") |
| |
| logger.info("\nBuild finished %s" % build_request.build.outcome) |
| return build_request.build |
| |
| def target_already_built(self, target): |
| """ If the target is already built no need to build it again""" |
| for build in Build.objects.filter( |
| project__name=BuildTest.PROJECT_NAME): |
| targets = build.target_set.values_list('target', flat=True) |
| if target in targets: |
| return build |
| |
| return None |