summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/bldcontrol/bbcontroller.py
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2014-09-04 15:27:32 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2014-09-05 10:14:25 +0100
commit32a27931db7dc29c528a516bf666ce96806887fe (patch)
tree331c64af1d50059ef0db81c157a9e79ee4c363b5 /bitbake/lib/toaster/bldcontrol/bbcontroller.py
parent5bd2b3f9a6ad85a6c5d1fe90e91aed64ef658962 (diff)
downloadpoky-32a27931db7dc29c528a516bf666ce96806887fe.tar.gz
bitbake: toaster: enable SSH-based remote build support
We enable support for starting builds on remote machines through SSH. The support is limited to poky-based distributions. We refactor localhost build support and we update bldcontrol application tests to uniformely test the APIs of localhost and SSH build controllers. [YOCTO #6240] (Bitbake rev: c2ad9c9bb83f61c171434324df8c4d5ee655a556) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/bldcontrol/bbcontroller.py')
-rw-r--r--bitbake/lib/toaster/bldcontrol/bbcontroller.py170
1 files changed, 12 insertions, 158 deletions
diff --git a/bitbake/lib/toaster/bldcontrol/bbcontroller.py b/bitbake/lib/toaster/bldcontrol/bbcontroller.py
index bf9cdf9f67..6812ae3e6e 100644
--- a/bitbake/lib/toaster/bldcontrol/bbcontroller.py
+++ b/bitbake/lib/toaster/bldcontrol/bbcontroller.py
@@ -26,10 +26,6 @@ import re
26from django.db import transaction 26from django.db import transaction
27from django.db.models import Q 27from django.db.models import Q
28from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake 28from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake
29import subprocess
30
31from toastermain import settings
32
33 29
34# load Bitbake components 30# load Bitbake components
35path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) 31path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
@@ -72,6 +68,10 @@ def getBuildEnvironmentController(**kwargs):
72 68
73 The return object MUST always be a BuildEnvironmentController. 69 The return object MUST always be a BuildEnvironmentController.
74 """ 70 """
71
72 from localhostbecontroller import LocalhostBEController
73 from sshbecontroller import SSHBEController
74
75 be = BuildEnvironment.objects.filter(Q(**kwargs))[0] 75 be = BuildEnvironment.objects.filter(Q(**kwargs))[0]
76 if be.betype == BuildEnvironment.TYPE_LOCAL: 76 if be.betype == BuildEnvironment.TYPE_LOCAL:
77 return LocalhostBEController(be) 77 return LocalhostBEController(be)
@@ -81,6 +81,13 @@ def getBuildEnvironmentController(**kwargs):
81 raise Exception("FIXME: Implement BEC for type %s" % str(be.betype)) 81 raise Exception("FIXME: Implement BEC for type %s" % str(be.betype))
82 82
83 83
84def _getgitcheckoutdirectoryname(url):
85 """ Utility that returns the last component of a git path as directory
86 """
87 import re
88 components = re.split(r'[:\.\/]', url)
89 return components[-2] if components[-1] == "git" else components[-1]
90
84 91
85class BuildEnvironmentController(object): 92class BuildEnvironmentController(object):
86 """ BuildEnvironmentController (BEC) is the abstract class that defines the operations that MUST 93 """ BuildEnvironmentController (BEC) is the abstract class that defines the operations that MUST
@@ -110,6 +117,7 @@ class BuildEnvironmentController(object):
110 self.be = be 117 self.be = be
111 self.connection = None 118 self.connection = None
112 119
120
113 def startBBServer(self): 121 def startBBServer(self):
114 """ Starts a BB server with Toaster toasterui set up to record the builds, an no controlling UI. 122 """ Starts a BB server with Toaster toasterui set up to record the builds, an no controlling UI.
115 After this method executes, self.be bbaddress/bbport MUST point to a running and free server, 123 After this method executes, self.be bbaddress/bbport MUST point to a running and free server,
@@ -173,157 +181,3 @@ class ShellCmdException(Exception):
173class BuildSetupException(Exception): 181class BuildSetupException(Exception):
174 pass 182 pass
175 183
176class LocalhostBEController(BuildEnvironmentController):
177 """ Implementation of the BuildEnvironmentController for the localhost;
178 this controller manages the default build directory,
179 the server setup and system start and stop for the localhost-type build environment
180
181 """
182
183 def __init__(self, be):
184 super(LocalhostBEController, self).__init__(be)
185 self.dburl = settings.getDATABASE_URL()
186 self.pokydirname = None
187
188 def _shellcmd(self, command, cwd = None):
189 if cwd is None:
190 cwd = self.be.sourcedir
191
192 p = subprocess.Popen(command, cwd = cwd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
193 (out,err) = p.communicate()
194 if p.returncode:
195 if len(err) == 0:
196 err = "command: %s \n%s" % (command, out)
197 else:
198 err = "command: %s \n%s" % (command, err)
199 raise ShellCmdException(err)
200 else:
201 return out
202
203 def _createdirpath(self, path):
204 from os.path import dirname as DN
205 if not os.path.exists(DN(path)):
206 self._createdirpath(DN(path))
207 if not os.path.exists(path):
208 os.mkdir(path, 0755)
209
210 def _startBE(self):
211 assert self.pokydirname and os.path.exists(self.pokydirname)
212 self._createdirpath(self.be.builddir)
213 self._shellcmd("bash -c \"source %s/oe-init-build-env %s\"" % (self.pokydirname, self.be.builddir))
214
215 def startBBServer(self):
216 assert self.pokydirname and os.path.exists(self.pokydirname)
217 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))
218 # FIXME unfortunate sleep 1 - we need to make sure that bbserver is started and the toaster ui is connected
219 # but since they start async without any return, we just wait a bit
220 print "Started server"
221 assert self.be.sourcedir and os.path.exists(self.be.builddir)
222 self.be.bbaddress = "localhost"
223 self.be.bbport = "8200"
224 self.be.bbstate = BuildEnvironment.SERVER_STARTED
225 self.be.save()
226
227 def stopBBServer(self):
228 assert self.be.sourcedir
229 print self._shellcmd("bash -c \"source %s/oe-init-build-env %s && %s source toaster stop\"" %
230 (self.be.sourcedir, self.be.builddir, (lambda: "" if self.be.bbtoken is None else "BBTOKEN=%s" % self.be.bbtoken)()))
231 self.be.bbstate = BuildEnvironment.SERVER_STOPPED
232 self.be.save()
233 print "Stopped server"
234
235 def setLayers(self, bitbakes, layers):
236 """ a word of attention: by convention, the first layer for any build will be poky! """
237
238 assert self.be.sourcedir is not None
239 assert len(bitbakes) == 1
240 # set layers in the layersource
241
242 # 1. get a list of repos, and map dirpaths for each layer
243 gitrepos = {}
244 gitrepos[bitbakes[0].giturl] = []
245 gitrepos[bitbakes[0].giturl].append( ("bitbake", bitbakes[0].dirpath, bitbakes[0].commit) )
246
247 for layer in layers:
248 # we don't process local URLs
249 if layer.giturl.startswith("file://"):
250 continue
251 if not layer.giturl in gitrepos:
252 gitrepos[layer.giturl] = []
253 gitrepos[layer.giturl].append( (layer.name, layer.dirpath, layer.commit))
254 for giturl in gitrepos.keys():
255 commitid = gitrepos[giturl][0][2]
256 for e in gitrepos[giturl]:
257 if commitid != e[2]:
258 raise BuildSetupException("More than one commit per git url, unsupported configuration")
259
260 def _getgitdirectoryname(url):
261 import re
262 components = re.split(r'[:\.\/]', url)
263 return components[-2] if components[-1] == "git" else components[-1]
264
265 layerlist = []
266
267 # 2. checkout the repositories
268 for giturl in gitrepos.keys():
269 localdirname = os.path.join(self.be.sourcedir, _getgitdirectoryname(giturl))
270 print "DEBUG: giturl ", giturl ,"checking out in current directory", localdirname
271
272 # make sure our directory is a git repository
273 if os.path.exists(localdirname):
274 if not giturl in self._shellcmd("git remote -v", localdirname):
275 raise BuildSetupException("Existing git repository at %s, but with different remotes (not '%s'). Aborting." % (localdirname, giturl))
276 else:
277 self._shellcmd("git clone \"%s\" \"%s\"" % (giturl, localdirname))
278 # checkout the needed commit
279 commit = gitrepos[giturl][0][2]
280
281 # branch magic name "HEAD" will inhibit checkout
282 if commit != "HEAD":
283 print "DEBUG: checking out commit ", commit, "to", localdirname
284 self._shellcmd("git fetch --all && git checkout \"%s\"" % commit , localdirname)
285
286 # take the localdirname as poky dir if we can find the oe-init-build-env
287 if self.pokydirname is None and os.path.exists(os.path.join(localdirname, "oe-init-build-env")):
288 print "DEBUG: selected poky dir name", localdirname
289 self.pokydirname = localdirname
290
291 # verify our repositories
292 for name, dirpath, commit in gitrepos[giturl]:
293 localdirpath = os.path.join(localdirname, dirpath)
294 if not os.path.exists(localdirpath):
295 raise BuildSetupException("Cannot find layer git path '%s' in checked out repository '%s:%s'. Aborting." % (localdirpath, giturl, commit))
296
297 if name != "bitbake":
298 layerlist.append(localdirpath)
299
300 print "DEBUG: current layer list ", layerlist
301
302 # 3. configure the build environment, so we have a conf/bblayers.conf
303 assert self.pokydirname is not None
304 self._startBE()
305
306 # 4. update the bblayers.conf
307 bblayerconf = os.path.join(self.be.builddir, "conf/bblayers.conf")
308 if not os.path.exists(bblayerconf):
309 raise BuildSetupException("BE is not consistent: bblayers.conf file missing at %s" % bblayerconf)
310
311 conflines = open(bblayerconf, "r").readlines()
312
313 bblayerconffile = open(bblayerconf, "w")
314 for i in xrange(len(conflines)):
315 if conflines[i].startswith("# line added by toaster"):
316 i += 2
317 else:
318 bblayerconffile.write(conflines[i])
319
320 bblayerconffile.write("\n# line added by toaster build control\nBBLAYERS = \"" + " ".join(layerlist) + "\"")
321 bblayerconffile.close()
322
323 return True
324
325 def release(self):
326 assert self.be.sourcedir and os.path.exists(self.be.builddir)
327 import shutil
328 shutil.rmtree(os.path.join(self.be.sourcedir, "build"))
329 assert not os.path.exists(self.be.builddir)