diff options
Diffstat (limited to 'bitbake/lib/toaster/bldcontrol')
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 @@ | |||
1 | from django.contrib import admin | ||
2 | from django.contrib.admin.filters import RelatedFieldListFilter | ||
3 | from .models import BuildEnvironment | ||
4 | |||
5 | class BuildEnvironmentAdmin(admin.ModelAdmin): | ||
6 | pass | ||
7 | |||
8 | admin.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 | |||
23 | import os | ||
24 | import sys | ||
25 | import re | ||
26 | from django.db import transaction | ||
27 | from django.db.models import Q | ||
28 | from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake | ||
29 | |||
30 | # load Bitbake components | ||
31 | path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) | ||
32 | sys.path.insert(0, path) | ||
33 | import bb.server.xmlrpc | ||
34 | |||
35 | class 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 | |||
62 | def 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 | |||
84 | def _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 | |||
92 | class 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 | |||
177 | class ShellCmdException(Exception): | ||
178 | pass | ||
179 | |||
180 | |||
181 | class 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 | |||
23 | import os | ||
24 | import sys | ||
25 | import re | ||
26 | from django.db import transaction | ||
27 | from django.db.models import Q | ||
28 | from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake | ||
29 | import subprocess | ||
30 | |||
31 | from toastermain import settings | ||
32 | |||
33 | from bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException, _getgitcheckoutdirectoryname | ||
34 | |||
35 | class 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 @@ | |||
1 | from django.core.management.base import NoArgsCommand, CommandError | ||
2 | from django.db import transaction | ||
3 | from orm.models import LayerSource, ToasterSetting, Branch, Layer, Layer_Version | ||
4 | from orm.models import BitbakeVersion, Release, ReleaseDefaultLayer | ||
5 | from bldcontrol.bbcontroller import getBuildEnvironmentController, ShellCmdException | ||
6 | from bldcontrol.models import BuildRequest, BuildEnvironment | ||
7 | import os | ||
8 | |||
9 | def DN(path): | ||
10 | if path is None: | ||
11 | return "" | ||
12 | else: | ||
13 | return os.path.dirname(path) | ||
14 | |||
15 | |||
16 | class 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 @@ | |||
1 | from django.core.management.base import NoArgsCommand, CommandError | ||
2 | from django.db import transaction | ||
3 | from orm.models import Build | ||
4 | from bldcontrol.bbcontroller import getBuildEnvironmentController, ShellCmdException, BuildSetupException | ||
5 | from bldcontrol.models import BuildRequest, BuildEnvironment, BRError | ||
6 | import os | ||
7 | |||
8 | class 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 -*- | ||
2 | from south.utils import datetime_utils as datetime | ||
3 | from south.db import db | ||
4 | from south.v2 import SchemaMigration | ||
5 | from django.db import models | ||
6 | |||
7 | |||
8 | class 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 -*- | ||
2 | from south.utils import datetime_utils as datetime | ||
3 | from south.db import db | ||
4 | from south.v2 import SchemaMigration | ||
5 | from django.db import models | ||
6 | |||
7 | |||
8 | class 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 -*- | ||
2 | from south.utils import datetime_utils as datetime | ||
3 | from south.db import db | ||
4 | from south.v2 import SchemaMigration | ||
5 | from django.db import models | ||
6 | |||
7 | |||
8 | class 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 -*- | ||
2 | from south.utils import datetime_utils as datetime | ||
3 | from south.db import db | ||
4 | from south.v2 import DataMigration | ||
5 | from django.db import models | ||
6 | |||
7 | class 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 -*- | ||
2 | from south.utils import datetime_utils as datetime | ||
3 | from south.db import db | ||
4 | from south.v2 import SchemaMigration | ||
5 | from django.db import models | ||
6 | |||
7 | |||
8 | class 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 -*- | ||
2 | from south.utils import datetime_utils as datetime | ||
3 | from south.db import db | ||
4 | from south.v2 import SchemaMigration | ||
5 | from django.db import models | ||
6 | |||
7 | |||
8 | class 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 @@ | |||
1 | from django.db import models | ||
2 | from django.core.validators import MaxValueValidator, MinValueValidator | ||
3 | from orm.models import Project, ProjectLayer, ProjectVariable, ProjectTarget, Build | ||
4 | |||
5 | # a BuildEnvironment is the equivalent of the "build/" directory on the localhost | ||
6 | class 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 | |||
46 | class 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 | |||
71 | class 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 | |||
78 | class 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 | |||
84 | class BRVariable(models.Model): | ||
85 | req = models.ForeignKey(BuildRequest) | ||
86 | name = models.CharField(max_length=100) | ||
87 | value = models.TextField(blank = True) | ||
88 | |||
89 | class 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 | |||
94 | class 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 | |||
23 | import sys | ||
24 | import re | ||
25 | from django.db import transaction | ||
26 | from django.db.models import Q | ||
27 | from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake | ||
28 | import subprocess | ||
29 | |||
30 | from toastermain import settings | ||
31 | |||
32 | from bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException, _getgitcheckoutdirectoryname | ||
33 | |||
34 | def DN(path): | ||
35 | return "/".join(path.split("/")[0:-1]) | ||
36 | |||
37 | class 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 | """ | ||
2 | This file demonstrates writing tests using the unittest module. These will pass | ||
3 | when you run "manage.py test". | ||
4 | |||
5 | Replace this with more appropriate tests for your application. | ||
6 | """ | ||
7 | |||
8 | from django.test import TestCase | ||
9 | |||
10 | from bldcontrol.bbcontroller import BitbakeController | ||
11 | from bldcontrol.localhostbecontroller import LocalhostBEController | ||
12 | from bldcontrol.sshbecontroller import SSHBEController | ||
13 | from bldcontrol.models import BuildEnvironment, BuildRequest | ||
14 | from bldcontrol.management.commands.runbuilds import Command | ||
15 | |||
16 | import socket | ||
17 | import subprocess | ||
18 | |||
19 | # standard poky data hardcoded for testing | ||
20 | BITBAKE_LAYERS = [type('bitbake_info', (object,), { "giturl": "git://git.yoctoproject.org/poky.git", "dirpath": "", "commit": "HEAD"})] | ||
21 | POKY_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 | |||
32 | class 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 | |||
72 | class 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 | |||
92 | class 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 | |||
120 | class 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. | |||