summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/bldcontrol
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/toaster/bldcontrol')
-rw-r--r--bitbake/lib/toaster/bldcontrol/__init__.py0
-rw-r--r--bitbake/lib/toaster/bldcontrol/admin.py8
-rw-r--r--bitbake/lib/toaster/bldcontrol/bbcontroller.py183
-rw-r--r--bitbake/lib/toaster/bldcontrol/localhostbecontroller.py191
-rw-r--r--bitbake/lib/toaster/bldcontrol/management/__init__.py0
-rw-r--r--bitbake/lib/toaster/bldcontrol/management/commands/__init__.py0
-rw-r--r--bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py212
-rw-r--r--bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py90
-rw-r--r--bitbake/lib/toaster/bldcontrol/migrations/0001_initial.py154
-rw-r--r--bitbake/lib/toaster/bldcontrol/migrations/0002_auto__add_field_buildenvironment_sourcedir__add_field_buildenvironment.py106
-rw-r--r--bitbake/lib/toaster/bldcontrol/migrations/0003_auto__add_field_brlayer_dirpath.py99
-rw-r--r--bitbake/lib/toaster/bldcontrol/migrations/0004_loadinitialdata.py104
-rw-r--r--bitbake/lib/toaster/bldcontrol/migrations/0005_auto__add_brerror.py112
-rw-r--r--bitbake/lib/toaster/bldcontrol/migrations/0006_auto__add_brbitbake.py128
-rw-r--r--bitbake/lib/toaster/bldcontrol/migrations/__init__.py0
-rw-r--r--bitbake/lib/toaster/bldcontrol/models.py98
-rw-r--r--bitbake/lib/toaster/bldcontrol/sshbecontroller.py193
-rw-r--r--bitbake/lib/toaster/bldcontrol/tests.py149
-rw-r--r--bitbake/lib/toaster/bldcontrol/views.py1
19 files changed, 1828 insertions, 0 deletions
diff --git a/bitbake/lib/toaster/bldcontrol/__init__.py b/bitbake/lib/toaster/bldcontrol/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/__init__.py
diff --git a/bitbake/lib/toaster/bldcontrol/admin.py b/bitbake/lib/toaster/bldcontrol/admin.py
new file mode 100644
index 0000000000..fcbe5f5935
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/admin.py
@@ -0,0 +1,8 @@
1from django.contrib import admin
2from django.contrib.admin.filters import RelatedFieldListFilter
3from .models import BuildEnvironment
4
5class BuildEnvironmentAdmin(admin.ModelAdmin):
6 pass
7
8admin.site.register(BuildEnvironment, BuildEnvironmentAdmin)
diff --git a/bitbake/lib/toaster/bldcontrol/bbcontroller.py b/bitbake/lib/toaster/bldcontrol/bbcontroller.py
new file mode 100644
index 0000000000..6812ae3e6e
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/bbcontroller.py
@@ -0,0 +1,183 @@
1#
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# BitBake Toaster Implementation
6#
7# Copyright (C) 2014 Intel Corporation
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22
23import os
24import sys
25import re
26from django.db import transaction
27from django.db.models import Q
28from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake
29
30# load Bitbake components
31path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
32sys.path.insert(0, path)
33import bb.server.xmlrpc
34
35class BitbakeController(object):
36 """ This is the basic class that controlls a bitbake server.
37 It is outside the scope of this class on how the server is started and aquired
38 """
39
40 def __init__(self, connection):
41 self.connection = connection
42
43 def _runCommand(self, command):
44 result, error = self.connection.connection.runCommand(command)
45 if error:
46 raise Exception(error)
47 return result
48
49 def disconnect(self):
50 return self.connection.removeClient()
51
52 def setVariable(self, name, value):
53 return self._runCommand(["setVariable", name, value])
54
55 def build(self, targets, task = None):
56 if task is None:
57 task = "build"
58 return self._runCommand(["buildTargets", targets, task])
59
60
61
62def getBuildEnvironmentController(**kwargs):
63 """ Gets you a BuildEnvironmentController that encapsulates a build environment,
64 based on the query dictionary sent in.
65
66 This is used to retrieve, for example, the currently running BE from inside
67 the toaster UI, or find a new BE to start a new build in it.
68
69 The return object MUST always be a BuildEnvironmentController.
70 """
71
72 from localhostbecontroller import LocalhostBEController
73 from sshbecontroller import SSHBEController
74
75 be = BuildEnvironment.objects.filter(Q(**kwargs))[0]
76 if be.betype == BuildEnvironment.TYPE_LOCAL:
77 return LocalhostBEController(be)
78 elif be.betype == BuildEnvironment.TYPE_SSH:
79 return SSHBEController(be)
80 else:
81 raise Exception("FIXME: Implement BEC for type %s" % str(be.betype))
82
83
84def _getgitcheckoutdirectoryname(url):
85 """ Utility that returns the last component of a git path as directory
86 """
87 import re
88 components = re.split(r'[:\.\/]', url)
89 return components[-2] if components[-1] == "git" else components[-1]
90
91
92class BuildEnvironmentController(object):
93 """ BuildEnvironmentController (BEC) is the abstract class that defines the operations that MUST
94 or SHOULD be supported by a Build Environment. It is used to establish the framework, and must
95 not be instantiated directly by the user.
96
97 Use the "getBuildEnvironmentController()" function to get a working BEC for your remote.
98
99 How the BuildEnvironments are discovered is outside the scope of this class.
100
101 You must derive this class to teach Toaster how to operate in your own infrastructure.
102 We provide some specific BuildEnvironmentController classes that can be used either to
103 directly set-up Toaster infrastructure, or as a model for your own infrastructure set:
104
105 * Localhost controller will run the Toaster BE on the same account as the web server
106 (current user if you are using the the Django development web server)
107 on the local machine, with the "build/" directory under the "poky/" source checkout directory.
108 Bash is expected to be available.
109
110 * SSH controller will run the Toaster BE on a remote machine, where the current user
111 can connect without raise Exception("FIXME: implement")word (set up with either ssh-agent or raise Exception("FIXME: implement")phrase-less key authentication)
112
113 """
114 def __init__(self, be):
115 """ Takes a BuildEnvironment object as parameter that points to the settings of the BE.
116 """
117 self.be = be
118 self.connection = None
119
120
121 def startBBServer(self):
122 """ Starts a BB server with Toaster toasterui set up to record the builds, an no controlling UI.
123 After this method executes, self.be bbaddress/bbport MUST point to a running and free server,
124 and the bbstate MUST be updated to "started".
125 """
126 raise Exception("Must override in order to actually start the BB server")
127
128 def stopBBServer(self):
129 """ Stops the currently running BB server.
130 The bbstate MUST be updated to "stopped".
131 self.connection must be none.
132 """
133
134 def setLayers(self, bbs, ls):
135 """ Checks-out bitbake executor and layers from git repositories.
136 Sets the layer variables in the config file, after validating local layer paths.
137 The bitbakes must be a 1-length list of BRBitbake
138 The layer paths must be in a list of BRLayer object
139
140 a word of attention: by convention, the first layer for any build will be poky!
141 """
142 raise Exception("Must override setLayers")
143
144
145 def getBBController(self):
146 """ returns a BitbakeController to an already started server; this is the point where the server
147 starts if needed; or reconnects to the server if we can
148 """
149 if not self.connection:
150 self.startBBServer()
151 self.be.lock = BuildEnvironment.LOCK_RUNNING
152 self.be.save()
153
154 server = bb.server.xmlrpc.BitBakeXMLRPCClient()
155 server.initServer()
156 server.saveConnectionDetails("%s:%s" % (self.be.bbaddress, self.be.bbport))
157 self.connection = server.establishConnection([])
158
159 self.be.bbtoken = self.connection.transport.connection_token
160 self.be.save()
161
162 return BitbakeController(self.connection)
163
164 def getArtifact(path):
165 """ This call returns an artifact identified by the 'path'. How 'path' is interpreted as
166 up to the implementing BEC. The return MUST be a REST URL where a GET will actually return
167 the content of the artifact, e.g. for use as a "download link" in a web UI.
168 """
169 raise Exception("Must return the REST URL of the artifact")
170
171 def release(self):
172 """ This stops the server and releases any resources. After this point, all resources
173 are un-available for further reference
174 """
175 raise Exception("Must override BE release")
176
177class ShellCmdException(Exception):
178 pass
179
180
181class BuildSetupException(Exception):
182 pass
183
diff --git a/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py b/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
new file mode 100644
index 0000000000..fe7fd81fb9
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
@@ -0,0 +1,191 @@
1#
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# BitBake Toaster Implementation
6#
7# Copyright (C) 2014 Intel Corporation
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22
23import os
24import sys
25import re
26from django.db import transaction
27from django.db.models import Q
28from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake
29import subprocess
30
31from toastermain import settings
32
33from bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException, _getgitcheckoutdirectoryname
34
35class LocalhostBEController(BuildEnvironmentController):
36 """ Implementation of the BuildEnvironmentController for the localhost;
37 this controller manages the default build directory,
38 the server setup and system start and stop for the localhost-type build environment
39
40 """
41
42 def __init__(self, be):
43 super(LocalhostBEController, self).__init__(be)
44 self.dburl = settings.getDATABASE_URL()
45 self.pokydirname = None
46 self.islayerset = False
47
48 def _shellcmd(self, command, cwd = None):
49 if cwd is None:
50 cwd = self.be.sourcedir
51
52 p = subprocess.Popen(command, cwd = cwd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
53 (out,err) = p.communicate()
54 if p.returncode:
55 if len(err) == 0:
56 err = "command: %s \n%s" % (command, out)
57 else:
58 err = "command: %s \n%s" % (command, err)
59 raise ShellCmdException(err)
60 else:
61 return out
62
63 def _createdirpath(self, path):
64 from os.path import dirname as DN
65 if path == "":
66 raise Exception("Invalid path creation specified.")
67 if not os.path.exists(DN(path)):
68 self._createdirpath(DN(path))
69 if not os.path.exists(path):
70 os.mkdir(path, 0755)
71
72 def _setupBE(self):
73 assert self.pokydirname and os.path.exists(self.pokydirname)
74 self._createdirpath(self.be.builddir)
75 self._shellcmd("bash -c \"source %s/oe-init-build-env %s\"" % (self.pokydirname, self.be.builddir))
76
77 def startBBServer(self):
78 assert self.pokydirname and os.path.exists(self.pokydirname)
79 assert self.islayerset
80 print("DEBUG: executing ", "bash -c \"source %s/oe-init-build-env %s && DATABASE_URL=%s source toaster start noweb && sleep 1\"" % (self.pokydirname, self.be.builddir, self.dburl))
81 print self._shellcmd("bash -c \"source %s/oe-init-build-env %s && DATABASE_URL=%s source toaster start noweb && sleep 1\"" % (self.pokydirname, self.be.builddir, self.dburl))
82 # FIXME unfortunate sleep 1 - we need to make sure that bbserver is started and the toaster ui is connected
83 # but since they start async without any return, we just wait a bit
84 print "Started server"
85 assert self.be.sourcedir and os.path.exists(self.be.builddir)
86 self.be.bbaddress = "localhost"
87 self.be.bbport = "8200"
88 self.be.bbstate = BuildEnvironment.SERVER_STARTED
89 self.be.save()
90
91 def stopBBServer(self):
92 assert self.pokydirname and os.path.exists(self.pokydirname)
93 assert self.islayerset
94 print self._shellcmd("bash -c \"source %s/oe-init-build-env %s && %s source toaster stop\"" %
95 (self.pokydirname, self.be.builddir, (lambda: "" if self.be.bbtoken is None else "BBTOKEN=%s" % self.be.bbtoken)()))
96 self.be.bbstate = BuildEnvironment.SERVER_STOPPED
97 self.be.save()
98 print "Stopped server"
99
100 def setLayers(self, bitbakes, layers):
101 """ a word of attention: by convention, the first layer for any build will be poky! """
102
103 assert self.be.sourcedir is not None
104 assert len(bitbakes) == 1
105 # set layers in the layersource
106
107 # 1. get a list of repos, and map dirpaths for each layer
108 gitrepos = {}
109 gitrepos[bitbakes[0].giturl] = []
110 gitrepos[bitbakes[0].giturl].append( ("bitbake", bitbakes[0].dirpath, bitbakes[0].commit) )
111
112 for layer in layers:
113 # we don't process local URLs
114 if layer.giturl.startswith("file://"):
115 continue
116 if not layer.giturl in gitrepos:
117 gitrepos[layer.giturl] = []
118 gitrepos[layer.giturl].append( (layer.name, layer.dirpath, layer.commit))
119 for giturl in gitrepos.keys():
120 commitid = gitrepos[giturl][0][2]
121 for e in gitrepos[giturl]:
122 if commitid != e[2]:
123 raise BuildSetupException("More than one commit per git url, unsupported configuration")
124
125
126 layerlist = []
127
128 # 2. checkout the repositories
129 for giturl in gitrepos.keys():
130 localdirname = os.path.join(self.be.sourcedir, _getgitcheckoutdirectoryname(giturl))
131 print "DEBUG: giturl ", giturl ,"checking out in current directory", localdirname
132
133 # make sure our directory is a git repository
134 if os.path.exists(localdirname):
135 if not giturl in self._shellcmd("git remote -v", localdirname):
136 raise BuildSetupException("Existing git repository at %s, but with different remotes (not '%s'). Aborting." % (localdirname, giturl))
137 else:
138 self._shellcmd("git clone \"%s\" \"%s\"" % (giturl, localdirname))
139 # checkout the needed commit
140 commit = gitrepos[giturl][0][2]
141
142 # branch magic name "HEAD" will inhibit checkout
143 if commit != "HEAD":
144 print "DEBUG: checking out commit ", commit, "to", localdirname
145 self._shellcmd("git fetch --all && git checkout \"%s\"" % commit , localdirname)
146
147 # take the localdirname as poky dir if we can find the oe-init-build-env
148 if self.pokydirname is None and os.path.exists(os.path.join(localdirname, "oe-init-build-env")):
149 print "DEBUG: selected poky dir name", localdirname
150 self.pokydirname = localdirname
151
152 # verify our repositories
153 for name, dirpath, commit in gitrepos[giturl]:
154 localdirpath = os.path.join(localdirname, dirpath)
155 if not os.path.exists(localdirpath):
156 raise BuildSetupException("Cannot find layer git path '%s' in checked out repository '%s:%s'. Aborting." % (localdirpath, giturl, commit))
157
158 if name != "bitbake":
159 layerlist.append(localdirpath)
160
161 print "DEBUG: current layer list ", layerlist
162
163 # 3. configure the build environment, so we have a conf/bblayers.conf
164 assert self.pokydirname is not None
165 self._setupBE()
166
167 # 4. update the bblayers.conf
168 bblayerconf = os.path.join(self.be.builddir, "conf/bblayers.conf")
169 if not os.path.exists(bblayerconf):
170 raise BuildSetupException("BE is not consistent: bblayers.conf file missing at %s" % bblayerconf)
171
172 conflines = open(bblayerconf, "r").readlines()
173
174 bblayerconffile = open(bblayerconf, "w")
175 for i in xrange(len(conflines)):
176 if conflines[i].startswith("# line added by toaster"):
177 i += 2
178 else:
179 bblayerconffile.write(conflines[i])
180
181 bblayerconffile.write("\n# line added by toaster build control\nBBLAYERS = \"" + " ".join(layerlist) + "\"")
182 bblayerconffile.close()
183
184 self.islayerset = True
185 return True
186
187 def release(self):
188 assert self.be.sourcedir and os.path.exists(self.be.builddir)
189 import shutil
190 shutil.rmtree(os.path.join(self.be.sourcedir, "build"))
191 assert not os.path.exists(self.be.builddir)
diff --git a/bitbake/lib/toaster/bldcontrol/management/__init__.py b/bitbake/lib/toaster/bldcontrol/management/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/management/__init__.py
diff --git a/bitbake/lib/toaster/bldcontrol/management/commands/__init__.py b/bitbake/lib/toaster/bldcontrol/management/commands/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/management/commands/__init__.py
diff --git a/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py b/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py
new file mode 100644
index 0000000000..4f6a66e711
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py
@@ -0,0 +1,212 @@
1from django.core.management.base import NoArgsCommand, CommandError
2from django.db import transaction
3from orm.models import LayerSource, ToasterSetting, Branch, Layer, Layer_Version
4from orm.models import BitbakeVersion, Release, ReleaseDefaultLayer
5from bldcontrol.bbcontroller import getBuildEnvironmentController, ShellCmdException
6from bldcontrol.models import BuildRequest, BuildEnvironment
7import os
8
9def DN(path):
10 if path is None:
11 return ""
12 else:
13 return os.path.dirname(path)
14
15
16class Command(NoArgsCommand):
17 args = ""
18 help = "Verifies that the configured settings are valid and usable, or prompts the user to fix the settings."
19
20 def _reduce_canon_path(self, path):
21 components = []
22 for c in path.split("/"):
23 if c == "..":
24 del components[-1]
25 elif c == ".":
26 pass
27 else:
28 components.append(c)
29 return "/".join(components)
30
31 def _find_first_path_for_file(self, startdirectory, filename, level = 0):
32 if level < 0:
33 return None
34 dirs = []
35 for i in os.listdir(startdirectory):
36 j = os.path.join(startdirectory, i)
37 if os.path.isfile(j):
38 if i == filename:
39 return startdirectory
40 elif os.path.isdir(j):
41 dirs.append(j)
42 for j in dirs:
43 ret = self._find_first_path_for_file(j, filename, level - 1)
44 if ret is not None:
45 return ret
46 return None
47
48 def _get_suggested_sourcedir(self, be):
49 if be.betype != BuildEnvironment.TYPE_LOCAL:
50 return ""
51 return DN(DN(DN(self._find_first_path_for_file(self.guesspath, "toasterconf.json", 4))))
52
53 def _get_suggested_builddir(self, be):
54 if be.betype != BuildEnvironment.TYPE_LOCAL:
55 return ""
56 return DN(self._find_first_path_for_file(self.guesspath, "bblayers.conf", 3))
57
58 def _import_layer_config(self, baselayerdir):
59 filepath = os.path.join(baselayerdir, "meta/conf/toasterconf.json")
60 if not os.path.exists(filepath) or not os.path.isfile(filepath):
61 raise Exception("Failed to find toaster config file %s ." % filepath)
62
63 import json, pprint
64 data = json.loads(open(filepath, "r").read())
65
66 # verify config file validity before updating settings
67 for i in ['bitbake', 'releases', 'defaultrelease', 'config', 'layersources']:
68 assert i in data
69
70 # import bitbake data
71 for bvi in data['bitbake']:
72 bvo, created = BitbakeVersion.objects.get_or_create(name=bvi['name'])
73 bvo.giturl = bvi['giturl']
74 bvo.branch = bvi['branch']
75 bvo.dirpath = bvi['dirpath']
76 bvo.save()
77
78 # set the layer sources
79 for lsi in data['layersources']:
80 assert 'sourcetype' in lsi
81 assert 'apiurl' in lsi
82 assert 'name' in lsi
83 assert 'branches' in lsi
84
85 if lsi['sourcetype'] == LayerSource.TYPE_LAYERINDEX or lsi['apiurl'].startswith("/"):
86 apiurl = lsi['apiurl']
87 else:
88 apiurl = self._reduce_canon_path(os.path.join(DN(filepath), lsi['apiurl']))
89
90 try:
91 ls = LayerSource.objects.get(sourcetype = lsi['sourcetype'], apiurl = apiurl)
92 except LayerSource.DoesNotExist:
93 ls = LayerSource.objects.create(
94 name = lsi['name'],
95 sourcetype = lsi['sourcetype'],
96 apiurl = apiurl
97 )
98
99 layerbranches = []
100 for branchname in lsi['branches']:
101 bo, created = Branch.objects.get_or_create(layer_source = ls, name = branchname)
102 layerbranches.append(bo)
103
104 if 'layers' in lsi:
105 for layerinfo in lsi['layers']:
106 lo, created = Layer.objects.get_or_create(layer_source = ls, name = layerinfo['name'])
107 if layerinfo['local_path'].startswith("/"):
108 lo.local_path = layerinfo['local_path']
109 else:
110 lo.local_path = self._reduce_canon_path(os.path.join(DN(filepath), layerinfo['local_path']))
111 lo.layer_index_url = layerinfo['layer_index_url']
112 if 'vcs_url' in layerinfo:
113 lo.vcs_url = layerinfo['vcs_url']
114 lo.save()
115
116 for branch in layerbranches:
117 lvo, created = Layer_Version.objects.get_or_create(layer_source = ls,
118 up_branch = branch,
119 commit = branch.name,
120 layer = lo)
121 lvo.dirpath = layerinfo['dirpath']
122 lvo.save()
123 # set releases
124 for ri in data['releases']:
125 bvo = BitbakeVersion.objects.get(name = ri['bitbake'])
126 assert bvo is not None
127
128 ro, created = Release.objects.get_or_create(name = ri['name'], bitbake_version = bvo)
129 ro.description = ri['description']
130 ro.branch = ri['branch']
131 ro.save()
132
133 for dli in ri['defaultlayers']:
134 lsi, layername = dli.split(":")
135 layer, created = Layer.objects.get_or_create(
136 layer_source = LayerSource.objects.get(name = lsi),
137 name = layername
138 )
139 ReleaseDefaultLayer.objects.get_or_create( release = ro, layer = layer)
140
141 # set default release
142 if ToasterSetting.objects.filter(name = "DEFAULT_RELEASE").count() > 0:
143 ToasterSetting.objects.filter(name = "DEFAULT_RELEASE").update(value = data['defaultrelease'])
144 else:
145 ToasterSetting.objects.create(name = "DEFAULT_RELEASE", value = data['defaultrelease'])
146
147 # set default config variables
148 for configname in data['config']:
149 if ToasterSetting.objects.filter(name = "DEFCONF_" + configname).count() > 0:
150 ToasterSetting.objects.filter(name = "DEFCONF_" + configname).update(value = data['config'][configname])
151 else:
152 ToasterSetting.objects.create(name = "DEFCONF_" + configname, value = data['config'][configname])
153
154 def handle(self, **options):
155 self.guesspath = DN(DN(DN(DN(DN(DN(DN(__file__)))))))
156
157 # we make sure we have builddir and sourcedir for all defined build envionments
158 for be in BuildEnvironment.objects.all():
159 def _verify_be():
160 is_changed = False
161 print("Verifying the Build Environment type %s id %d." % (be.get_betype_display(), be.pk))
162 if len(be.sourcedir) == 0:
163 suggesteddir = self._get_suggested_sourcedir(be)
164 be.sourcedir = raw_input(" -- Layer sources checkout directory may not be empty [guessed \"%s\"]:" % suggesteddir)
165 if len(be.sourcedir) == 0 and len(suggesteddir) > 0:
166 be.sourcedir = suggesteddir
167 is_changed = True
168
169 if not be.sourcedir.startswith("/"):
170 be.sourcedir = raw_input(" -- Layer sources checkout directory must be an absolute path:")
171 is_changed = True
172
173 if len(be.builddir) == 0:
174 suggesteddir = self._get_suggested_builddir(be)
175 be.builddir = raw_input(" -- Build directory may not be empty [guessed \"%s\"]:" % suggesteddir)
176 if len(be.builddir) == 0 and len(suggesteddir) > 0:
177 be.builddir = suggesteddir
178 is_changed = True
179
180 if not be.builddir.startswith("/"):
181 be.builddir = raw_input(" -- Build directory must be an absolute path:")
182 is_changed = True
183
184
185
186 if is_changed:
187 print "Build configuration saved"
188 be.save()
189
190 if is_changed and be.betype == BuildEnvironment.TYPE_LOCAL:
191 baselayerdir = DN(DN(self._find_first_path_for_file(be.sourcedir, "toasterconf.json", 3)))
192 if baselayerdir:
193 i = raw_input(" -- Do you want to import basic layer configuration from \"%s\" ? (y/N):" % baselayerdir)
194 if len(i) and i.upper()[0] == 'Y':
195 self._import_layer_config(baselayerdir)
196 # we run lsupdates after config update
197 print "Updating information from the layer source, please wait."
198 from django.core.management import call_command
199 call_command("lsupdates")
200 pass
201
202 return is_changed
203
204 while (_verify_be()):
205 pass
206
207 # verify that default settings are there
208 if ToasterSetting.objects.filter(name = 'DEFAULT_RELEASE').count() != 1:
209 ToasterSetting.objects.filter(name = 'DEFAULT_RELEASE').delete()
210 ToasterSetting.objects.get_or_create(name = 'DEFAULT_RELEASE', value = '')
211
212 return 0
diff --git a/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py b/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py
new file mode 100644
index 0000000000..8efe8e62bc
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py
@@ -0,0 +1,90 @@
1from django.core.management.base import NoArgsCommand, CommandError
2from django.db import transaction
3from orm.models import Build
4from bldcontrol.bbcontroller import getBuildEnvironmentController, ShellCmdException, BuildSetupException
5from bldcontrol.models import BuildRequest, BuildEnvironment, BRError
6import os
7
8class Command(NoArgsCommand):
9 args = ""
10 help = "Schedules and executes build requests as possible. Does not return (interrupt with Ctrl-C)"
11
12
13 @transaction.commit_on_success
14 def _selectBuildEnvironment(self):
15 bec = getBuildEnvironmentController(lock = BuildEnvironment.LOCK_FREE)
16 bec.be.lock = BuildEnvironment.LOCK_LOCK
17 bec.be.save()
18 return bec
19
20 @transaction.commit_on_success
21 def _selectBuildRequest(self):
22 br = BuildRequest.objects.filter(state = BuildRequest.REQ_QUEUED).order_by('pk')[0]
23 br.state = BuildRequest.REQ_INPROGRESS
24 br.save()
25 return br
26
27 def schedule(self):
28 import traceback
29 try:
30 br = None
31 try:
32 # select the build environment and the request to build
33 br = self._selectBuildRequest()
34 except IndexError as e:
35 return
36 try:
37 bec = self._selectBuildEnvironment()
38 except IndexError as e:
39 # we could not find a BEC; postpone the BR
40 br.state = BuildRequest.REQ_QUEUED
41 br.save()
42 return
43
44 # set up the buid environment with the needed layers
45 print "Build %s, Environment %s" % (br, bec.be)
46 bec.setLayers(br.brbitbake_set.all(), br.brlayer_set.all())
47
48 # get the bb server running
49 bbctrl = bec.getBBController()
50
51 # let toasterui that this is a managed build
52 bbctrl.setVariable("TOASTER_BRBE", "%d:%d" % (br.pk, bec.be.pk))
53
54 # set the build configuration
55 for variable in br.brvariable_set.all():
56 bbctrl.setVariable(variable.name, variable.value)
57
58 # trigger the build command
59 bbctrl.build(list(map(lambda x:x.target, br.brtarget_set.all())))
60
61 print "Build launched, exiting"
62 # disconnect from the server
63 bbctrl.disconnect()
64
65 # cleanup to be performed by toaster when the deed is done
66
67
68 except Exception as e:
69 print " EE Error executing shell command\n", e
70 traceback.print_exc(e)
71 BRError.objects.create(req = br,
72 errtype = str(type(e)),
73 errmsg = str(e),
74 traceback = traceback.format_exc(e))
75 br.state = BuildRequest.REQ_FAILED
76 br.save()
77 bec.be.lock = BuildEnvironment.LOCK_FREE
78 bec.be.save()
79
80
81 def cleanup(self):
82 from django.utils import timezone
83 from datetime import timedelta
84 # environments locked for more than 30 seconds - they should be unlocked
85 BuildEnvironment.objects.filter(lock=BuildEnvironment.LOCK_LOCK).filter(updated__lt = timezone.now() - timedelta(seconds = 30)).update(lock = BuildEnvironment.LOCK_FREE)
86
87
88 def handle_noargs(self, **options):
89 self.cleanup()
90 self.schedule()
diff --git a/bitbake/lib/toaster/bldcontrol/migrations/0001_initial.py b/bitbake/lib/toaster/bldcontrol/migrations/0001_initial.py
new file mode 100644
index 0000000000..a7e6350a6d
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/migrations/0001_initial.py
@@ -0,0 +1,154 @@
1# -*- coding: utf-8 -*-
2from south.utils import datetime_utils as datetime
3from south.db import db
4from south.v2 import SchemaMigration
5from django.db import models
6
7
8class Migration(SchemaMigration):
9
10 def forwards(self, orm):
11 # Adding model 'BuildEnvironment'
12 db.create_table(u'bldcontrol_buildenvironment', (
13 (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
14 ('address', self.gf('django.db.models.fields.CharField')(max_length=254)),
15 ('betype', self.gf('django.db.models.fields.IntegerField')()),
16 ('bbaddress', self.gf('django.db.models.fields.CharField')(max_length=254, blank=True)),
17 ('bbport', self.gf('django.db.models.fields.IntegerField')(default=-1)),
18 ('bbtoken', self.gf('django.db.models.fields.CharField')(max_length=126, blank=True)),
19 ('bbstate', self.gf('django.db.models.fields.IntegerField')(default=0)),
20 ('lock', self.gf('django.db.models.fields.IntegerField')(default=0)),
21 ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
22 ('updated', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
23 ))
24 db.send_create_signal(u'bldcontrol', ['BuildEnvironment'])
25
26 # Adding model 'BuildRequest'
27 db.create_table(u'bldcontrol_buildrequest', (
28 (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
29 ('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['orm.Project'])),
30 ('build', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['orm.Build'], null=True)),
31 ('state', self.gf('django.db.models.fields.IntegerField')(default=0)),
32 ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
33 ('updated', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
34 ))
35 db.send_create_signal(u'bldcontrol', ['BuildRequest'])
36
37 # Adding model 'BRLayer'
38 db.create_table(u'bldcontrol_brlayer', (
39 (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
40 ('req', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['bldcontrol.BuildRequest'])),
41 ('name', self.gf('django.db.models.fields.CharField')(max_length=100)),
42 ('giturl', self.gf('django.db.models.fields.CharField')(max_length=254)),
43 ('commit', self.gf('django.db.models.fields.CharField')(max_length=254)),
44 ))
45 db.send_create_signal(u'bldcontrol', ['BRLayer'])
46
47 # Adding model 'BRVariable'
48 db.create_table(u'bldcontrol_brvariable', (
49 (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
50 ('req', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['bldcontrol.BuildRequest'])),
51 ('name', self.gf('django.db.models.fields.CharField')(max_length=100)),
52 ('value', self.gf('django.db.models.fields.TextField')(blank=True)),
53 ))
54 db.send_create_signal(u'bldcontrol', ['BRVariable'])
55
56 # Adding model 'BRTarget'
57 db.create_table(u'bldcontrol_brtarget', (
58 (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
59 ('req', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['bldcontrol.BuildRequest'])),
60 ('target', self.gf('django.db.models.fields.CharField')(max_length=100)),
61 ('task', self.gf('django.db.models.fields.CharField')(max_length=100, null=True)),
62 ))
63 db.send_create_signal(u'bldcontrol', ['BRTarget'])
64
65
66 def backwards(self, orm):
67 # Deleting model 'BuildEnvironment'
68 db.delete_table(u'bldcontrol_buildenvironment')
69
70 # Deleting model 'BuildRequest'
71 db.delete_table(u'bldcontrol_buildrequest')
72
73 # Deleting model 'BRLayer'
74 db.delete_table(u'bldcontrol_brlayer')
75
76 # Deleting model 'BRVariable'
77 db.delete_table(u'bldcontrol_brvariable')
78
79 # Deleting model 'BRTarget'
80 db.delete_table(u'bldcontrol_brtarget')
81
82
83 models = {
84 u'bldcontrol.brlayer': {
85 'Meta': {'object_name': 'BRLayer'},
86 'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
87 'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
88 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
89 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
90 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"})
91 },
92 u'bldcontrol.brtarget': {
93 'Meta': {'object_name': 'BRTarget'},
94 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
95 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
96 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
97 'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
98 },
99 u'bldcontrol.brvariable': {
100 'Meta': {'object_name': 'BRVariable'},
101 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
102 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
103 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
104 'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
105 },
106 u'bldcontrol.buildenvironment': {
107 'Meta': {'object_name': 'BuildEnvironment'},
108 'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
109 'bbaddress': ('django.db.models.fields.CharField', [], {'max_length': '254', 'blank': 'True'}),
110 'bbport': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
111 'bbstate': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
112 'bbtoken': ('django.db.models.fields.CharField', [], {'max_length': '126', 'blank': 'True'}),
113 'betype': ('django.db.models.fields.IntegerField', [], {}),
114 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
115 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
116 'lock': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
117 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
118 },
119 u'bldcontrol.buildrequest': {
120 'Meta': {'object_name': 'BuildRequest'},
121 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']", 'null': 'True'}),
122 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
123 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
124 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
125 'state': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
126 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
127 },
128 u'orm.build': {
129 'Meta': {'object_name': 'Build'},
130 'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
131 'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
132 'completed_on': ('django.db.models.fields.DateTimeField', [], {}),
133 'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
134 'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
135 'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
136 'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
137 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
138 'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
139 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
140 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']", 'null': 'True'}),
141 'started_on': ('django.db.models.fields.DateTimeField', [], {}),
142 'timespent': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
143 'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'})
144 },
145 u'orm.project': {
146 'Meta': {'object_name': 'Project'},
147 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
148 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
149 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
150 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
151 }
152 }
153
154 complete_apps = ['bldcontrol']
diff --git a/bitbake/lib/toaster/bldcontrol/migrations/0002_auto__add_field_buildenvironment_sourcedir__add_field_buildenvironment.py b/bitbake/lib/toaster/bldcontrol/migrations/0002_auto__add_field_buildenvironment_sourcedir__add_field_buildenvironment.py
new file mode 100644
index 0000000000..f522a500b6
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/migrations/0002_auto__add_field_buildenvironment_sourcedir__add_field_buildenvironment.py
@@ -0,0 +1,106 @@
1# -*- coding: utf-8 -*-
2from south.utils import datetime_utils as datetime
3from south.db import db
4from south.v2 import SchemaMigration
5from django.db import models
6
7
8class Migration(SchemaMigration):
9
10 def forwards(self, orm):
11 # Adding field 'BuildEnvironment.sourcedir'
12 db.add_column(u'bldcontrol_buildenvironment', 'sourcedir',
13 self.gf('django.db.models.fields.CharField')(default='', max_length=512, blank=True),
14 keep_default=False)
15
16 # Adding field 'BuildEnvironment.builddir'
17 db.add_column(u'bldcontrol_buildenvironment', 'builddir',
18 self.gf('django.db.models.fields.CharField')(default='', max_length=512, blank=True),
19 keep_default=False)
20
21
22 def backwards(self, orm):
23 # Deleting field 'BuildEnvironment.sourcedir'
24 db.delete_column(u'bldcontrol_buildenvironment', 'sourcedir')
25
26 # Deleting field 'BuildEnvironment.builddir'
27 db.delete_column(u'bldcontrol_buildenvironment', 'builddir')
28
29
30 models = {
31 u'bldcontrol.brlayer': {
32 'Meta': {'object_name': 'BRLayer'},
33 'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
34 'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
35 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
36 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
37 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"})
38 },
39 u'bldcontrol.brtarget': {
40 'Meta': {'object_name': 'BRTarget'},
41 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
42 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
43 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
44 'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
45 },
46 u'bldcontrol.brvariable': {
47 'Meta': {'object_name': 'BRVariable'},
48 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
49 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
50 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
51 'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
52 },
53 u'bldcontrol.buildenvironment': {
54 'Meta': {'object_name': 'BuildEnvironment'},
55 'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
56 'bbaddress': ('django.db.models.fields.CharField', [], {'max_length': '254', 'blank': 'True'}),
57 'bbport': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
58 'bbstate': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
59 'bbtoken': ('django.db.models.fields.CharField', [], {'max_length': '126', 'blank': 'True'}),
60 'betype': ('django.db.models.fields.IntegerField', [], {}),
61 'builddir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
62 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
63 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
64 'lock': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
65 'sourcedir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
66 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
67 },
68 u'bldcontrol.buildrequest': {
69 'Meta': {'object_name': 'BuildRequest'},
70 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']", 'null': 'True'}),
71 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
72 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
73 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
74 'state': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
75 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
76 },
77 u'orm.build': {
78 'Meta': {'object_name': 'Build'},
79 'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
80 'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
81 'completed_on': ('django.db.models.fields.DateTimeField', [], {}),
82 'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
83 'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
84 'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
85 'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
86 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
87 'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
88 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
89 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']", 'null': 'True'}),
90 'started_on': ('django.db.models.fields.DateTimeField', [], {}),
91 'timespent': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
92 'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'})
93 },
94 u'orm.project': {
95 'Meta': {'object_name': 'Project'},
96 'branch': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
97 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
98 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
99 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
100 'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
101 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
102 'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
103 }
104 }
105
106 complete_apps = ['bldcontrol'] \ No newline at end of file
diff --git a/bitbake/lib/toaster/bldcontrol/migrations/0003_auto__add_field_brlayer_dirpath.py b/bitbake/lib/toaster/bldcontrol/migrations/0003_auto__add_field_brlayer_dirpath.py
new file mode 100644
index 0000000000..b9ba838d90
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/migrations/0003_auto__add_field_brlayer_dirpath.py
@@ -0,0 +1,99 @@
1# -*- coding: utf-8 -*-
2from south.utils import datetime_utils as datetime
3from south.db import db
4from south.v2 import SchemaMigration
5from django.db import models
6
7
8class Migration(SchemaMigration):
9
10 def forwards(self, orm):
11 # Adding field 'BRLayer.dirpath'
12 db.add_column(u'bldcontrol_brlayer', 'dirpath',
13 self.gf('django.db.models.fields.CharField')(default='', max_length=254),
14 keep_default=False)
15
16
17 def backwards(self, orm):
18 # Deleting field 'BRLayer.dirpath'
19 db.delete_column(u'bldcontrol_brlayer', 'dirpath')
20
21
22 models = {
23 u'bldcontrol.brlayer': {
24 'Meta': {'object_name': 'BRLayer'},
25 'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
26 'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
27 'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
28 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
29 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
30 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"})
31 },
32 u'bldcontrol.brtarget': {
33 'Meta': {'object_name': 'BRTarget'},
34 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
35 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
36 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
37 'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
38 },
39 u'bldcontrol.brvariable': {
40 'Meta': {'object_name': 'BRVariable'},
41 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
42 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
43 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
44 'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
45 },
46 u'bldcontrol.buildenvironment': {
47 'Meta': {'object_name': 'BuildEnvironment'},
48 'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
49 'bbaddress': ('django.db.models.fields.CharField', [], {'max_length': '254', 'blank': 'True'}),
50 'bbport': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
51 'bbstate': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
52 'bbtoken': ('django.db.models.fields.CharField', [], {'max_length': '126', 'blank': 'True'}),
53 'betype': ('django.db.models.fields.IntegerField', [], {}),
54 'builddir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
55 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
56 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
57 'lock': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
58 'sourcedir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
59 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
60 },
61 u'bldcontrol.buildrequest': {
62 'Meta': {'object_name': 'BuildRequest'},
63 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']", 'null': 'True'}),
64 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
65 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
66 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
67 'state': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
68 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
69 },
70 u'orm.build': {
71 'Meta': {'object_name': 'Build'},
72 'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
73 'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
74 'completed_on': ('django.db.models.fields.DateTimeField', [], {}),
75 'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
76 'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
77 'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
78 'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
79 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
80 'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
81 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
82 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']", 'null': 'True'}),
83 'started_on': ('django.db.models.fields.DateTimeField', [], {}),
84 'timespent': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
85 'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'})
86 },
87 u'orm.project': {
88 'Meta': {'object_name': 'Project'},
89 'branch': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
90 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
91 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
92 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
93 'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
94 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
95 'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
96 }
97 }
98
99 complete_apps = ['bldcontrol'] \ No newline at end of file
diff --git a/bitbake/lib/toaster/bldcontrol/migrations/0004_loadinitialdata.py b/bitbake/lib/toaster/bldcontrol/migrations/0004_loadinitialdata.py
new file mode 100644
index 0000000000..d908578133
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/migrations/0004_loadinitialdata.py
@@ -0,0 +1,104 @@
1# -*- coding: utf-8 -*-
2from south.utils import datetime_utils as datetime
3from south.db import db
4from south.v2 import DataMigration
5from django.db import models
6
7class Migration(DataMigration):
8
9 def forwards(self, orm):
10 "Write your forwards methods here."
11 # Note: Don't use "from appname.models import ModelName".
12 # Use orm.ModelName to refer to models in this application,
13 # and orm['appname.ModelName'] for models in other applications.
14 try:
15 orm.BuildEnvironment.objects.get(pk = 1)
16 except:
17 from django.utils import timezone
18 orm.BuildEnvironment.objects.create(pk = 1,
19 created = timezone.now(),
20 updated = timezone.now(),
21 betype = 0)
22
23 def backwards(self, orm):
24 "Write your backwards methods here."
25
26 models = {
27 u'bldcontrol.brlayer': {
28 'Meta': {'object_name': 'BRLayer'},
29 'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
30 'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
31 'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
32 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
33 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
34 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"})
35 },
36 u'bldcontrol.brtarget': {
37 'Meta': {'object_name': 'BRTarget'},
38 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
39 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
40 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
41 'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
42 },
43 u'bldcontrol.brvariable': {
44 'Meta': {'object_name': 'BRVariable'},
45 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
46 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
47 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
48 'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
49 },
50 u'bldcontrol.buildenvironment': {
51 'Meta': {'object_name': 'BuildEnvironment'},
52 'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
53 'bbaddress': ('django.db.models.fields.CharField', [], {'max_length': '254', 'blank': 'True'}),
54 'bbport': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
55 'bbstate': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
56 'bbtoken': ('django.db.models.fields.CharField', [], {'max_length': '126', 'blank': 'True'}),
57 'betype': ('django.db.models.fields.IntegerField', [], {}),
58 'builddir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
59 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
60 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
61 'lock': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
62 'sourcedir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
63 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
64 },
65 u'bldcontrol.buildrequest': {
66 'Meta': {'object_name': 'BuildRequest'},
67 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']", 'null': 'True'}),
68 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
69 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
70 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
71 'state': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
72 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
73 },
74 u'orm.build': {
75 'Meta': {'object_name': 'Build'},
76 'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
77 'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
78 'completed_on': ('django.db.models.fields.DateTimeField', [], {}),
79 'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
80 'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
81 'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
82 'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
83 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
84 'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
85 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
86 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']", 'null': 'True'}),
87 'started_on': ('django.db.models.fields.DateTimeField', [], {}),
88 'timespent': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
89 'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'})
90 },
91 u'orm.project': {
92 'Meta': {'object_name': 'Project'},
93 'branch': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
94 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
95 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
96 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
97 'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
98 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
99 'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
100 }
101 }
102
103 complete_apps = ['bldcontrol']
104 symmetrical = True
diff --git a/bitbake/lib/toaster/bldcontrol/migrations/0005_auto__add_brerror.py b/bitbake/lib/toaster/bldcontrol/migrations/0005_auto__add_brerror.py
new file mode 100644
index 0000000000..98aeb41ceb
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/migrations/0005_auto__add_brerror.py
@@ -0,0 +1,112 @@
1# -*- coding: utf-8 -*-
2from south.utils import datetime_utils as datetime
3from south.db import db
4from south.v2 import SchemaMigration
5from django.db import models
6
7
8class Migration(SchemaMigration):
9
10 def forwards(self, orm):
11 # Adding model 'BRError'
12 db.create_table(u'bldcontrol_brerror', (
13 (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
14 ('req', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['bldcontrol.BuildRequest'])),
15 ('errtype', self.gf('django.db.models.fields.CharField')(max_length=100)),
16 ('errmsg', self.gf('django.db.models.fields.TextField')()),
17 ('traceback', self.gf('django.db.models.fields.TextField')()),
18 ))
19 db.send_create_signal(u'bldcontrol', ['BRError'])
20
21
22 def backwards(self, orm):
23 # Deleting model 'BRError'
24 db.delete_table(u'bldcontrol_brerror')
25
26
27 models = {
28 u'bldcontrol.brerror': {
29 'Meta': {'object_name': 'BRError'},
30 'errmsg': ('django.db.models.fields.TextField', [], {}),
31 'errtype': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
32 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
33 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
34 'traceback': ('django.db.models.fields.TextField', [], {})
35 },
36 u'bldcontrol.brlayer': {
37 'Meta': {'object_name': 'BRLayer'},
38 'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
39 'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
40 'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
41 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
42 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
43 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"})
44 },
45 u'bldcontrol.brtarget': {
46 'Meta': {'object_name': 'BRTarget'},
47 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
48 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
49 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
50 'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
51 },
52 u'bldcontrol.brvariable': {
53 'Meta': {'object_name': 'BRVariable'},
54 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
55 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
56 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
57 'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
58 },
59 u'bldcontrol.buildenvironment': {
60 'Meta': {'object_name': 'BuildEnvironment'},
61 'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
62 'bbaddress': ('django.db.models.fields.CharField', [], {'max_length': '254', 'blank': 'True'}),
63 'bbport': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
64 'bbstate': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
65 'bbtoken': ('django.db.models.fields.CharField', [], {'max_length': '126', 'blank': 'True'}),
66 'betype': ('django.db.models.fields.IntegerField', [], {}),
67 'builddir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
68 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
69 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
70 'lock': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
71 'sourcedir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
72 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
73 },
74 u'bldcontrol.buildrequest': {
75 'Meta': {'object_name': 'BuildRequest'},
76 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']", 'null': 'True'}),
77 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
78 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
79 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
80 'state': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
81 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
82 },
83 u'orm.build': {
84 'Meta': {'object_name': 'Build'},
85 'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
86 'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
87 'completed_on': ('django.db.models.fields.DateTimeField', [], {}),
88 'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
89 'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
90 'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
91 'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
92 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
93 'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
94 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
95 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']", 'null': 'True'}),
96 'started_on': ('django.db.models.fields.DateTimeField', [], {}),
97 'timespent': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
98 'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'})
99 },
100 u'orm.project': {
101 'Meta': {'object_name': 'Project'},
102 'branch': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
103 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
104 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
105 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
106 'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
107 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
108 'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
109 }
110 }
111
112 complete_apps = ['bldcontrol'] \ No newline at end of file
diff --git a/bitbake/lib/toaster/bldcontrol/migrations/0006_auto__add_brbitbake.py b/bitbake/lib/toaster/bldcontrol/migrations/0006_auto__add_brbitbake.py
new file mode 100644
index 0000000000..74388f8434
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/migrations/0006_auto__add_brbitbake.py
@@ -0,0 +1,128 @@
1# -*- coding: utf-8 -*-
2from south.utils import datetime_utils as datetime
3from south.db import db
4from south.v2 import SchemaMigration
5from django.db import models
6
7
8class Migration(SchemaMigration):
9
10 def forwards(self, orm):
11 # Adding model 'BRBitbake'
12 db.create_table(u'bldcontrol_brbitbake', (
13 (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
14 ('req', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['bldcontrol.BuildRequest'], unique=True)),
15 ('giturl', self.gf('django.db.models.fields.CharField')(max_length=254)),
16 ('commit', self.gf('django.db.models.fields.CharField')(max_length=254)),
17 ('dirpath', self.gf('django.db.models.fields.CharField')(max_length=254)),
18 ))
19 db.send_create_signal(u'bldcontrol', ['BRBitbake'])
20
21
22 def backwards(self, orm):
23 # Deleting model 'BRBitbake'
24 db.delete_table(u'bldcontrol_brbitbake')
25
26
27 models = {
28 u'bldcontrol.brbitbake': {
29 'Meta': {'object_name': 'BRBitbake'},
30 'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
31 'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
32 'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
33 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
34 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']", 'unique': 'True'})
35 },
36 u'bldcontrol.brerror': {
37 'Meta': {'object_name': 'BRError'},
38 'errmsg': ('django.db.models.fields.TextField', [], {}),
39 'errtype': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
40 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
41 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
42 'traceback': ('django.db.models.fields.TextField', [], {})
43 },
44 u'bldcontrol.brlayer': {
45 'Meta': {'object_name': 'BRLayer'},
46 'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
47 'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
48 'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
49 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
50 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
51 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"})
52 },
53 u'bldcontrol.brtarget': {
54 'Meta': {'object_name': 'BRTarget'},
55 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
56 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
57 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
58 'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
59 },
60 u'bldcontrol.brvariable': {
61 'Meta': {'object_name': 'BRVariable'},
62 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
63 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
64 'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
65 'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
66 },
67 u'bldcontrol.buildenvironment': {
68 'Meta': {'object_name': 'BuildEnvironment'},
69 'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
70 'bbaddress': ('django.db.models.fields.CharField', [], {'max_length': '254', 'blank': 'True'}),
71 'bbport': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
72 'bbstate': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
73 'bbtoken': ('django.db.models.fields.CharField', [], {'max_length': '126', 'blank': 'True'}),
74 'betype': ('django.db.models.fields.IntegerField', [], {}),
75 'builddir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
76 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
77 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
78 'lock': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
79 'sourcedir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
80 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
81 },
82 u'bldcontrol.buildrequest': {
83 'Meta': {'object_name': 'BuildRequest'},
84 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']", 'null': 'True'}),
85 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
86 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
87 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
88 'state': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
89 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
90 },
91 u'orm.bitbakeversion': {
92 'Meta': {'object_name': 'BitbakeVersion'},
93 'branch': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
94 'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
95 'giturl': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
96 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
97 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'})
98 },
99 u'orm.build': {
100 'Meta': {'object_name': 'Build'},
101 'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
102 'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
103 'completed_on': ('django.db.models.fields.DateTimeField', [], {}),
104 'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
105 'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
106 'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
107 'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
108 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
109 'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
110 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
111 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']", 'null': 'True'}),
112 'started_on': ('django.db.models.fields.DateTimeField', [], {}),
113 'timespent': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
114 'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'})
115 },
116 u'orm.project': {
117 'Meta': {'object_name': 'Project'},
118 'bitbake_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.BitbakeVersion']"}),
119 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
120 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
121 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
122 'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
123 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
124 'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
125 }
126 }
127
128 complete_apps = ['bldcontrol'] \ No newline at end of file
diff --git a/bitbake/lib/toaster/bldcontrol/migrations/__init__.py b/bitbake/lib/toaster/bldcontrol/migrations/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/migrations/__init__.py
diff --git a/bitbake/lib/toaster/bldcontrol/models.py b/bitbake/lib/toaster/bldcontrol/models.py
new file mode 100644
index 0000000000..4c54a59b1a
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/models.py
@@ -0,0 +1,98 @@
1from django.db import models
2from django.core.validators import MaxValueValidator, MinValueValidator
3from orm.models import Project, ProjectLayer, ProjectVariable, ProjectTarget, Build
4
5# a BuildEnvironment is the equivalent of the "build/" directory on the localhost
6class BuildEnvironment(models.Model):
7 SERVER_STOPPED = 0
8 SERVER_STARTED = 1
9 SERVER_STATE = (
10 (SERVER_STOPPED, "stopped"),
11 (SERVER_STARTED, "started"),
12 )
13
14 TYPE_LOCAL = 0
15 TYPE_SSH = 1
16 TYPE = (
17 (TYPE_LOCAL, "local"),
18 (TYPE_SSH, "ssh"),
19 )
20
21 LOCK_FREE = 0
22 LOCK_LOCK = 1
23 LOCK_RUNNING = 2
24 LOCK_STATE = (
25 (LOCK_FREE, "free"),
26 (LOCK_LOCK, "lock"),
27 (LOCK_RUNNING, "running"),
28 )
29
30 address = models.CharField(max_length = 254)
31 betype = models.IntegerField(choices = TYPE)
32 bbaddress = models.CharField(max_length = 254, blank = True)
33 bbport = models.IntegerField(default = -1)
34 bbtoken = models.CharField(max_length = 126, blank = True)
35 bbstate = models.IntegerField(choices = SERVER_STATE, default = SERVER_STOPPED)
36 sourcedir = models.CharField(max_length = 512, blank = True)
37 builddir = models.CharField(max_length = 512, blank = True)
38 lock = models.IntegerField(choices = LOCK_STATE, default = LOCK_FREE)
39 created = models.DateTimeField(auto_now_add = True)
40 updated = models.DateTimeField(auto_now = True)
41
42
43# a BuildRequest is a request that the scheduler will build using a BuildEnvironment
44# the build request queue is the table itself, ordered by state
45
46class BuildRequest(models.Model):
47 REQ_CREATED = 0
48 REQ_QUEUED = 1
49 REQ_INPROGRESS = 2
50 REQ_COMPLETED = 3
51 REQ_FAILED = 4
52
53 REQUEST_STATE = (
54 (REQ_CREATED, "created"),
55 (REQ_QUEUED, "queued"),
56 (REQ_INPROGRESS, "in progress"),
57 (REQ_COMPLETED, "completed"),
58 (REQ_FAILED, "failed"),
59 )
60
61 project = models.ForeignKey(Project)
62 build = models.ForeignKey(Build, null = True) # TODO: toasterui should set this when Build is created
63 state = models.IntegerField(choices = REQUEST_STATE, default = REQ_CREATED)
64 created = models.DateTimeField(auto_now_add = True)
65 updated = models.DateTimeField(auto_now = True)
66
67
68# These tables specify the settings for running an actual build.
69# They MUST be kept in sync with the tables in orm.models.Project*
70
71class BRLayer(models.Model):
72 req = models.ForeignKey(BuildRequest)
73 name = models.CharField(max_length = 100)
74 giturl = models.CharField(max_length = 254)
75 commit = models.CharField(max_length = 254)
76 dirpath = models.CharField(max_length = 254)
77
78class BRBitbake(models.Model):
79 req = models.ForeignKey(BuildRequest, unique = True) # only one bitbake for a request
80 giturl = models.CharField(max_length =254)
81 commit = models.CharField(max_length = 254)
82 dirpath = models.CharField(max_length = 254)
83
84class BRVariable(models.Model):
85 req = models.ForeignKey(BuildRequest)
86 name = models.CharField(max_length=100)
87 value = models.TextField(blank = True)
88
89class BRTarget(models.Model):
90 req = models.ForeignKey(BuildRequest)
91 target = models.CharField(max_length=100)
92 task = models.CharField(max_length=100, null=True)
93
94class BRError(models.Model):
95 req = models.ForeignKey(BuildRequest)
96 errtype = models.CharField(max_length=100)
97 errmsg = models.TextField()
98 traceback = models.TextField()
diff --git a/bitbake/lib/toaster/bldcontrol/sshbecontroller.py b/bitbake/lib/toaster/bldcontrol/sshbecontroller.py
new file mode 100644
index 0000000000..64674953dc
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/sshbecontroller.py
@@ -0,0 +1,193 @@
1#
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# BitBake Toaster Implementation
6#
7# Copyright (C) 2014 Intel Corporation
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22
23import sys
24import re
25from django.db import transaction
26from django.db.models import Q
27from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake
28import subprocess
29
30from toastermain import settings
31
32from bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException, _getgitcheckoutdirectoryname
33
34def DN(path):
35 return "/".join(path.split("/")[0:-1])
36
37class SSHBEController(BuildEnvironmentController):
38 """ Implementation of the BuildEnvironmentController for the localhost;
39 this controller manages the default build directory,
40 the server setup and system start and stop for the localhost-type build environment
41
42 """
43
44 def __init__(self, be):
45 super(SSHBEController, self).__init__(be)
46 self.dburl = settings.getDATABASE_URL()
47 self.pokydirname = None
48 self.islayerset = False
49
50 def _shellcmd(self, command, cwd = None):
51 if cwd is None:
52 cwd = self.be.sourcedir
53
54 p = subprocess.Popen("ssh %s 'cd %s && %s'" % (self.be.address, cwd, command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
55 (out,err) = p.communicate()
56 if p.returncode:
57 if len(err) == 0:
58 err = "command: %s \n%s" % (command, out)
59 else:
60 err = "command: %s \n%s" % (command, err)
61 raise ShellCmdException(err)
62 else:
63 return out.strip()
64
65 def _pathexists(self, path):
66 try:
67 self._shellcmd("test -e \"%s\"" % path)
68 return True
69 except ShellCmdException as e:
70 return False
71
72 def _pathcreate(self, path):
73 self._shellcmd("mkdir -p \"%s\"" % path)
74
75 def _setupBE(self):
76 assert self.pokydirname and self._pathexists(self.pokydirname)
77 self._pathcreate(self.be.builddir)
78 self._shellcmd("bash -c \"source %s/oe-init-build-env %s\"" % (self.pokydirname, self.be.builddir))
79
80 def startBBServer(self):
81 assert self.pokydirname and self._pathexists(self.pokydirname)
82 assert self.islayerset
83 print self._shellcmd("bash -c \"source %s/oe-init-build-env %s && DATABASE_URL=%s source toaster start noweb && sleep 1\"" % (self.pokydirname, self.be.builddir, self.dburl))
84 # FIXME unfortunate sleep 1 - we need to make sure that bbserver is started and the toaster ui is connected
85 # but since they start async without any return, we just wait a bit
86 print "Started server"
87 assert self.be.sourcedir and self._pathexists(self.be.builddir)
88 self.be.bbaddress = self.be.address.split("@")[-1]
89 self.be.bbport = "8200"
90 self.be.bbstate = BuildEnvironment.SERVER_STARTED
91 self.be.save()
92
93 def stopBBServer(self):
94 assert self.pokydirname and self._pathexists(self.pokydirname)
95 assert self.islayerset
96 print self._shellcmd("bash -c \"source %s/oe-init-build-env %s && %s source toaster stop\"" %
97 (self.pokydirname, self.be.builddir, (lambda: "" if self.be.bbtoken is None else "BBTOKEN=%s" % self.be.bbtoken)()))
98 self.be.bbstate = BuildEnvironment.SERVER_STOPPED
99 self.be.save()
100 print "Stopped server"
101
102 def setLayers(self, bitbakes, layers):
103 """ a word of attention: by convention, the first layer for any build will be poky! """
104
105 assert self.be.sourcedir is not None
106 assert len(bitbakes) == 1
107 # set layers in the layersource
108
109 # 1. get a list of repos, and map dirpaths for each layer
110 gitrepos = {}
111 gitrepos[bitbakes[0].giturl] = []
112 gitrepos[bitbakes[0].giturl].append( ("bitbake", bitbakes[0].dirpath, bitbakes[0].commit) )
113
114 for layer in layers:
115 # we don't process local URLs
116 if layer.giturl.startswith("file://"):
117 continue
118 if not layer.giturl in gitrepos:
119 gitrepos[layer.giturl] = []
120 gitrepos[layer.giturl].append( (layer.name, layer.dirpath, layer.commit))
121 for giturl in gitrepos.keys():
122 commitid = gitrepos[giturl][0][2]
123 for e in gitrepos[giturl]:
124 if commitid != e[2]:
125 raise BuildSetupException("More than one commit per git url, unsupported configuration")
126
127 layerlist = []
128
129 # 2. checkout the repositories
130 for giturl in gitrepos.keys():
131 import os
132 localdirname = os.path.join(self.be.sourcedir, _getgitcheckoutdirectoryname(giturl))
133 print "DEBUG: giturl ", giturl ,"checking out in current directory", localdirname
134
135 # make sure our directory is a git repository
136 if self._pathexists(localdirname):
137 if not giturl in self._shellcmd("git remote -v", localdirname):
138 raise BuildSetupException("Existing git repository at %s, but with different remotes (not '%s'). Aborting." % (localdirname, giturl))
139 else:
140 self._shellcmd("git clone \"%s\" \"%s\"" % (giturl, localdirname))
141 # checkout the needed commit
142 commit = gitrepos[giturl][0][2]
143
144 # branch magic name "HEAD" will inhibit checkout
145 if commit != "HEAD":
146 print "DEBUG: checking out commit ", commit, "to", localdirname
147 self._shellcmd("git fetch --all && git checkout \"%s\"" % commit , localdirname)
148
149 # take the localdirname as poky dir if we can find the oe-init-build-env
150 if self.pokydirname is None and self._pathexists(os.path.join(localdirname, "oe-init-build-env")):
151 print "DEBUG: selected poky dir name", localdirname
152 self.pokydirname = localdirname
153
154 # verify our repositories
155 for name, dirpath, commit in gitrepos[giturl]:
156 localdirpath = os.path.join(localdirname, dirpath)
157 if not self._pathexists(localdirpath):
158 raise BuildSetupException("Cannot find layer git path '%s' in checked out repository '%s:%s'. Aborting." % (localdirpath, giturl, commit))
159
160 if name != "bitbake":
161 layerlist.append(localdirpath)
162
163 print "DEBUG: current layer list ", layerlist
164
165 # 3. configure the build environment, so we have a conf/bblayers.conf
166 assert self.pokydirname is not None
167 self._setupBE()
168
169 # 4. update the bblayers.conf
170 bblayerconf = os.path.join(self.be.builddir, "conf/bblayers.conf")
171 if not self._pathexists(bblayerconf):
172 raise BuildSetupException("BE is not consistent: bblayers.conf file missing at %s" % bblayerconf)
173
174 conflines = open(bblayerconf, "r").readlines()
175
176 bblayerconffile = open(bblayerconf, "w")
177 for i in xrange(len(conflines)):
178 if conflines[i].startswith("# line added by toaster"):
179 i += 2
180 else:
181 bblayerconffile.write(conflines[i])
182
183 bblayerconffile.write("\n# line added by toaster build control\nBBLAYERS = \"" + " ".join(layerlist) + "\"")
184 bblayerconffile.close()
185
186 self.islayerset = True
187 return True
188
189 def release(self):
190 assert self.be.sourcedir and self._pathexists(self.be.builddir)
191 import shutil
192 shutil.rmtree(os.path.join(self.be.sourcedir, "build"))
193 assert not self._pathexists(self.be.builddir)
diff --git a/bitbake/lib/toaster/bldcontrol/tests.py b/bitbake/lib/toaster/bldcontrol/tests.py
new file mode 100644
index 0000000000..4577c3f03b
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/tests.py
@@ -0,0 +1,149 @@
1"""
2This file demonstrates writing tests using the unittest module. These will pass
3when you run "manage.py test".
4
5Replace this with more appropriate tests for your application.
6"""
7
8from django.test import TestCase
9
10from bldcontrol.bbcontroller import BitbakeController
11from bldcontrol.localhostbecontroller import LocalhostBEController
12from bldcontrol.sshbecontroller import SSHBEController
13from bldcontrol.models import BuildEnvironment, BuildRequest
14from bldcontrol.management.commands.runbuilds import Command
15
16import socket
17import subprocess
18
19# standard poky data hardcoded for testing
20BITBAKE_LAYERS = [type('bitbake_info', (object,), { "giturl": "git://git.yoctoproject.org/poky.git", "dirpath": "", "commit": "HEAD"})]
21POKY_LAYERS = [
22 type('poky_info', (object,), { "name": "meta", "giturl": "git://git.yoctoproject.org/poky.git", "dirpath": "meta", "commit": "HEAD"}),
23 type('poky_info', (object,), { "name": "meta-yocto", "giturl": "git://git.yoctoproject.org/poky.git", "dirpath": "meta-yocto", "commit": "HEAD"}),
24 type('poky_info', (object,), { "name": "meta-yocto-bsp", "giturl": "git://git.yoctoproject.org/poky.git", "dirpath": "meta-yocto-bsp", "commit": "HEAD"}),
25 ]
26
27
28
29# we have an abstract test class designed to ensure that the controllers use a single interface
30# specific controller tests only need to override the _getBuildEnvironment() method
31
32class BEControllerTests(object):
33
34 def _serverForceStop(self, bc):
35 err = bc._shellcmd("netstat -tapn 2>/dev/null | grep 8200 | awk '{print $7}' | sort -fu | cut -d \"/\" -f 1 | grep -v -- - | tee /dev/fd/2 | xargs -r kill")
36 self.assertTrue(err == '', "bitbake server pid %s not stopped" % err)
37
38 def test_serverStartAndStop(self):
39 obe = self._getBuildEnvironment()
40 bc = self._getBEController(obe)
41 bc.setLayers(BITBAKE_LAYERS, POKY_LAYERS) # setting layers, skip any layer info
42
43 hostname = self.test_address.split("@")[-1]
44
45 # test start server and stop
46 self.assertTrue(socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect_ex((hostname, 8200)), "Port already occupied")
47 bc.startBBServer()
48 self.assertFalse(socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect_ex((hostname, 8200)), "Server not answering")
49
50 bc.stopBBServer()
51 self.assertTrue(socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect_ex((hostname, 8200)), "Server not stopped")
52
53 self._serverForceStop(bc)
54
55 def test_getBBController(self):
56 obe = self._getBuildEnvironment()
57 bc = self._getBEController(obe)
58 bc.setLayers(BITBAKE_LAYERS, POKY_LAYERS) # setting layers, skip any layer info
59
60 bbc = bc.getBBController()
61 self.assertTrue(isinstance(bbc, BitbakeController))
62 # test set variable, use no build marker -1 for BR value
63 try:
64 bbc.setVariable("TOASTER_BRBE", "%d:%d" % (-1, obe.pk))
65 except Exception as e :
66 self.fail("setVariable raised %s", e)
67
68 bc.stopBBServer()
69
70 self._serverForceStop(bc)
71
72class LocalhostBEControllerTests(TestCase, BEControllerTests):
73 def __init__(self, *args):
74 super(LocalhostBEControllerTests, self).__init__(*args)
75 # hardcoded for Alex's machine; since the localhost BE is machine-dependent,
76 # I found no good way to abstractize this
77 self.test_sourcedir = "/home/ddalex/ssd/yocto"
78 self.test_builddir = "/home/ddalex/ssd/yocto/build"
79 self.test_address = "localhost"
80
81 def _getBuildEnvironment(self):
82 return BuildEnvironment.objects.create(
83 lock = BuildEnvironment.LOCK_FREE,
84 betype = BuildEnvironment.TYPE_LOCAL,
85 address = self.test_address,
86 sourcedir = self.test_sourcedir,
87 builddir = self.test_builddir )
88
89 def _getBEController(self, obe):
90 return LocalhostBEController(obe)
91
92class SSHBEControllerTests(TestCase, BEControllerTests):
93 def __init__(self, *args):
94 super(SSHBEControllerTests, self).__init__(*args)
95 self.test_address = "ddalex-desktop.local"
96 # hardcoded for ddalex-desktop.local machine; since the localhost BE is machine-dependent,
97 # I found no good way to abstractize this
98 self.test_sourcedir = "/home/ddalex/ssd/yocto"
99 self.test_builddir = "/home/ddalex/ssd/yocto/build"
100
101 def _getBuildEnvironment(self):
102 return BuildEnvironment.objects.create(
103 lock = BuildEnvironment.LOCK_FREE,
104 betype = BuildEnvironment.TYPE_SSH,
105 address = self.test_address,
106 sourcedir = self.test_sourcedir,
107 builddir = self.test_builddir )
108
109 def _getBEController(self, obe):
110 return SSHBEController(obe)
111
112 def test_pathExists(self):
113 obe = BuildEnvironment.objects.create(betype = BuildEnvironment.TYPE_SSH, address= self.test_address)
114 sbc = SSHBEController(obe)
115 self.assertTrue(sbc._pathexists("/"))
116 self.assertFalse(sbc._pathexists("/.deadbeef"))
117 self.assertTrue(sbc._pathexists(sbc._shellcmd("pwd")))
118
119
120class RunBuildsCommandTests(TestCase):
121 def test_bec_select(self):
122 """
123 Tests that we can find and lock a build environment
124 """
125
126 obe = BuildEnvironment.objects.create(lock = BuildEnvironment.LOCK_FREE, betype = BuildEnvironment.TYPE_LOCAL)
127 command = Command()
128 bec = command._selectBuildEnvironment()
129
130 # make sure we select the object we've just built
131 self.assertTrue(bec.be.id == obe.id, "Environment is not properly selected")
132 # we have a locked environment
133 self.assertTrue(bec.be.lock == BuildEnvironment.LOCK_LOCK, "Environment is not locked")
134 # no more selections possible here
135 self.assertRaises(IndexError, command._selectBuildEnvironment)
136
137 def test_br_select(self):
138 from orm.models import Project, Release, BitbakeVersion
139 p = Project.objects.create_project("test", Release.objects.get_or_create(name = "HEAD", bitbake_version = BitbakeVersion.objects.get_or_create(name="HEAD", branch="HEAD")[0])[0])
140 obr = BuildRequest.objects.create(state = BuildRequest.REQ_QUEUED, project = p)
141 command = Command()
142 br = command._selectBuildRequest()
143
144 # make sure we select the object we've just built
145 self.assertTrue(obr.id == br.id, "Request is not properly selected")
146 # we have a locked environment
147 self.assertTrue(br.state == BuildRequest.REQ_INPROGRESS, "Request is not updated")
148 # no more selections possible here
149 self.assertRaises(IndexError, command._selectBuildRequest)
diff --git a/bitbake/lib/toaster/bldcontrol/views.py b/bitbake/lib/toaster/bldcontrol/views.py
new file mode 100644
index 0000000000..60f00ef0ef
--- /dev/null
+++ b/bitbake/lib/toaster/bldcontrol/views.py
@@ -0,0 +1 @@
# Create your views here.