summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
diff options
context:
space:
mode:
authorDavid Reyna <David.Reyna@windriver.com>2018-08-15 18:04:09 -0700
committerRichard Purdie <richard.purdie@linuxfoundation.org>2018-08-20 10:20:51 +0100
commit08fbdc02e32d715ae94e3b9603fb3ec8351c8fd3 (patch)
tree8b1eb6531f782ba531903cc7248fbd5705e5adf3 /bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
parent9af0f1a46bbb6ad9ee8b35957251f4aa826b023f (diff)
downloadpoky-08fbdc02e32d715ae94e3b9603fb3ec8351c8fd3.tar.gz
bitbake: Toaster: Implement the project-specific feature and releated enhancements and defects.
Here is the primary driving enhancement: * Bug 12785 - Support Project Specific configuration for external tools (e.g. ISS, Eclipse) - Isolated project-specific configuration page (full Toaster context hidden) - Support for new project, reconfigure existing project, and import existing command line project - Ability to define variables (e.g. image recipe) and pass them back to external GUI - Ability to execute the cloning phase, so that external GUI receive a buildable project - Ability to call back to the external GUI when updates are completed and ready - Compatibility of above projects with the normal full Toaster interface - Ability to pass to a 'complete' or 'cancel' web page so that the external GUI can immediately stop that Toaster instance, and not leave dangling servers nor edit sessions open Here are the supporting enhancements, where at least the back end is implemented: * Bug 12821 - Make Toaster conf changes compatible with command line usage * Bug 12822 - Support importing user changes to conf files into Toaster * Bug 12823 - Support importing user build directories into Toaster * Bug 12824 - Scan imported layers for content so that they are immediately available * Bug 12825 - show layer clone item in progress bar Here are defects fixed: * Bug 12817 - builddelete.py requires explicit 'add_arguments' * Bug 12818 - Remove orphaned imported layers when project is deleted * Bug 12826 - fix imported layer management * Bug 12819 - build using selected bitbake env, not Toaster's env * Bug 12820 - Toaster randomizes the layer order in toaster_bblayers.conf [YOCTO #12785] (Bitbake rev: 985d6cec290bdd80998a63483561a73c75d82d65) Signed-off-by: David Reyna <David.Reyna@windriver.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/bldcontrol/localhostbecontroller.py')
-rw-r--r--bitbake/lib/toaster/bldcontrol/localhostbecontroller.py172
1 files changed, 139 insertions, 33 deletions
diff --git a/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py b/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
index 16c7c80441..6bdd743b8b 100644
--- a/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
+++ b/bitbake/lib/toaster/bldcontrol/localhostbecontroller.py
@@ -27,8 +27,9 @@ import shutil
27import time 27import time
28from django.db import transaction 28from django.db import transaction
29from django.db.models import Q 29from django.db.models import Q
30from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake 30from bldcontrol.models import BuildEnvironment, BuildRequest, BRLayer, BRVariable, BRTarget, BRBitbake, Build
31from orm.models import CustomImageRecipe, Layer, Layer_Version, ProjectLayer, ToasterSetting 31from orm.models import CustomImageRecipe, Layer, Layer_Version, Project, ProjectLayer, ToasterSetting
32from orm.models import signal_runbuilds
32import subprocess 33import subprocess
33 34
34from toastermain import settings 35from toastermain import settings
@@ -38,6 +39,8 @@ from bldcontrol.bbcontroller import BuildEnvironmentController, ShellCmdExceptio
38import logging 39import logging
39logger = logging.getLogger("toaster") 40logger = logging.getLogger("toaster")
40 41
42install_dir = os.environ.get('TOASTER_DIR')
43
41from pprint import pprint, pformat 44from pprint import pprint, pformat
42 45
43class LocalhostBEController(BuildEnvironmentController): 46class LocalhostBEController(BuildEnvironmentController):
@@ -87,10 +90,10 @@ class LocalhostBEController(BuildEnvironmentController):
87 #logger.debug("localhostbecontroller: using HEAD checkout in %s" % local_checkout_path) 90 #logger.debug("localhostbecontroller: using HEAD checkout in %s" % local_checkout_path)
88 return local_checkout_path 91 return local_checkout_path
89 92
90 93 def setCloneStatus(self,bitbake,status,total,current,repo_name):
91 def setCloneStatus(self,bitbake,status,total,current):
92 bitbake.req.build.repos_cloned=current 94 bitbake.req.build.repos_cloned=current
93 bitbake.req.build.repos_to_clone=total 95 bitbake.req.build.repos_to_clone=total
96 bitbake.req.build.progress_item=repo_name
94 bitbake.req.build.save() 97 bitbake.req.build.save()
95 98
96 def setLayers(self, bitbake, layers, targets): 99 def setLayers(self, bitbake, layers, targets):
@@ -100,6 +103,7 @@ class LocalhostBEController(BuildEnvironmentController):
100 103
101 layerlist = [] 104 layerlist = []
102 nongitlayerlist = [] 105 nongitlayerlist = []
106 layer_index = 0
103 git_env = os.environ.copy() 107 git_env = os.environ.copy()
104 # (note: add custom environment settings here) 108 # (note: add custom environment settings here)
105 109
@@ -113,7 +117,7 @@ class LocalhostBEController(BuildEnvironmentController):
113 if bitbake.giturl and bitbake.commit: 117 if bitbake.giturl and bitbake.commit:
114 gitrepos[(bitbake.giturl, bitbake.commit)] = [] 118 gitrepos[(bitbake.giturl, bitbake.commit)] = []
115 gitrepos[(bitbake.giturl, bitbake.commit)].append( 119 gitrepos[(bitbake.giturl, bitbake.commit)].append(
116 ("bitbake", bitbake.dirpath)) 120 ("bitbake", bitbake.dirpath, 0))
117 121
118 for layer in layers: 122 for layer in layers:
119 # We don't need to git clone the layer for the CustomImageRecipe 123 # We don't need to git clone the layer for the CustomImageRecipe
@@ -124,12 +128,13 @@ class LocalhostBEController(BuildEnvironmentController):
124 # If we have local layers then we don't need clone them 128 # If we have local layers then we don't need clone them
125 # For local layers giturl will be empty 129 # For local layers giturl will be empty
126 if not layer.giturl: 130 if not layer.giturl:
127 nongitlayerlist.append(layer.layer_version.layer.local_source_dir) 131 nongitlayerlist.append( "%03d:%s" % (layer_index,layer.local_source_dir) )
128 continue 132 continue
129 133
130 if not (layer.giturl, layer.commit) in gitrepos: 134 if not (layer.giturl, layer.commit) in gitrepos:
131 gitrepos[(layer.giturl, layer.commit)] = [] 135 gitrepos[(layer.giturl, layer.commit)] = []
132 gitrepos[(layer.giturl, layer.commit)].append( (layer.name, layer.dirpath) ) 136 gitrepos[(layer.giturl, layer.commit)].append( (layer.name,layer.dirpath,layer_index) )
137 layer_index += 1
133 138
134 139
135 logger.debug("localhostbecontroller, our git repos are %s" % pformat(gitrepos)) 140 logger.debug("localhostbecontroller, our git repos are %s" % pformat(gitrepos))
@@ -159,9 +164,9 @@ class LocalhostBEController(BuildEnvironmentController):
159 # 3. checkout the repositories 164 # 3. checkout the repositories
160 clone_count=0 165 clone_count=0
161 clone_total=len(gitrepos.keys()) 166 clone_total=len(gitrepos.keys())
162 self.setCloneStatus(bitbake,'Started',clone_total,clone_count) 167 self.setCloneStatus(bitbake,'Started',clone_total,clone_count,'')
163 for giturl, commit in gitrepos.keys(): 168 for giturl, commit in gitrepos.keys():
164 self.setCloneStatus(bitbake,'progress',clone_total,clone_count) 169 self.setCloneStatus(bitbake,'progress',clone_total,clone_count,gitrepos[(giturl, commit)][0][0])
165 clone_count += 1 170 clone_count += 1
166 171
167 localdirname = os.path.join(self.be.sourcedir, self.getGitCloneDirectory(giturl, commit)) 172 localdirname = os.path.join(self.be.sourcedir, self.getGitCloneDirectory(giturl, commit))
@@ -205,16 +210,16 @@ class LocalhostBEController(BuildEnvironmentController):
205 self._shellcmd("git clone -b \"%s\" \"%s\" \"%s\" " % (bitbake.commit, bitbake.giturl, os.path.join(self.pokydirname, 'bitbake')),env=git_env) 210 self._shellcmd("git clone -b \"%s\" \"%s\" \"%s\" " % (bitbake.commit, bitbake.giturl, os.path.join(self.pokydirname, 'bitbake')),env=git_env)
206 211
207 # verify our repositories 212 # verify our repositories
208 for name, dirpath in gitrepos[(giturl, commit)]: 213 for name, dirpath, index in gitrepos[(giturl, commit)]:
209 localdirpath = os.path.join(localdirname, dirpath) 214 localdirpath = os.path.join(localdirname, dirpath)
210 logger.debug("localhostbecontroller: localdirpath expected '%s'" % localdirpath) 215 logger.debug("localhostbecontroller: localdirpath expects '%s'" % localdirpath)
211 if not os.path.exists(localdirpath): 216 if not os.path.exists(localdirpath):
212 raise BuildSetupException("Cannot find layer git path '%s' in checked out repository '%s:%s'. Aborting." % (localdirpath, giturl, commit)) 217 raise BuildSetupException("Cannot find layer git path '%s' in checked out repository '%s:%s'. Aborting." % (localdirpath, giturl, commit))
213 218
214 if name != "bitbake": 219 if name != "bitbake":
215 layerlist.append(localdirpath.rstrip("/")) 220 layerlist.append("%03d:%s" % (index,localdirpath.rstrip("/")))
216 221
217 self.setCloneStatus(bitbake,'complete',clone_total,clone_count) 222 self.setCloneStatus(bitbake,'complete',clone_total,clone_count,'')
218 logger.debug("localhostbecontroller: current layer list %s " % pformat(layerlist)) 223 logger.debug("localhostbecontroller: current layer list %s " % pformat(layerlist))
219 224
220 if self.pokydirname is None and os.path.exists(os.path.join(self.be.sourcedir, "oe-init-build-env")): 225 if self.pokydirname is None and os.path.exists(os.path.join(self.be.sourcedir, "oe-init-build-env")):
@@ -232,7 +237,7 @@ class LocalhostBEController(BuildEnvironmentController):
232 customrecipe, layers) 237 customrecipe, layers)
233 238
234 if os.path.isdir(custom_layer_path): 239 if os.path.isdir(custom_layer_path):
235 layerlist.append(custom_layer_path) 240 layerlist.append("%03d:%s" % (layer_index,custom_layer_path))
236 241
237 except CustomImageRecipe.DoesNotExist: 242 except CustomImageRecipe.DoesNotExist:
238 continue # not a custom recipe, skip 243 continue # not a custom recipe, skip
@@ -240,7 +245,11 @@ class LocalhostBEController(BuildEnvironmentController):
240 layerlist.extend(nongitlayerlist) 245 layerlist.extend(nongitlayerlist)
241 logger.debug("\n\nset layers gives this list %s" % pformat(layerlist)) 246 logger.debug("\n\nset layers gives this list %s" % pformat(layerlist))
242 self.islayerset = True 247 self.islayerset = True
243 return layerlist 248
249 # restore the order of layer list for bblayers.conf
250 layerlist.sort()
251 sorted_layerlist = [l[4:] for l in layerlist]
252 return sorted_layerlist
244 253
245 def setup_custom_image_recipe(self, customrecipe, layers): 254 def setup_custom_image_recipe(self, customrecipe, layers):
246 """ Set up toaster-custom-images layer and recipe files """ 255 """ Set up toaster-custom-images layer and recipe files """
@@ -310,31 +319,115 @@ class LocalhostBEController(BuildEnvironmentController):
310 319
311 def triggerBuild(self, bitbake, layers, variables, targets, brbe): 320 def triggerBuild(self, bitbake, layers, variables, targets, brbe):
312 layers = self.setLayers(bitbake, layers, targets) 321 layers = self.setLayers(bitbake, layers, targets)
322 is_merged_attr = bitbake.req.project.merged_attr
323
324 git_env = os.environ.copy()
325 # (note: add custom environment settings here)
326 try:
327 # insure that the project init/build uses the selected bitbake, and not Toaster's
328 del git_env['TEMPLATECONF']
329 del git_env['BBBASEDIR']
330 del git_env['BUILDDIR']
331 except KeyError:
332 pass
313 333
314 # init build environment from the clone 334 # init build environment from the clone
315 builddir = '%s-toaster-%d' % (self.be.builddir, bitbake.req.project.id) 335 if bitbake.req.project.builddir:
336 builddir = bitbake.req.project.builddir
337 else:
338 builddir = '%s-toaster-%d' % (self.be.builddir, bitbake.req.project.id)
316 oe_init = os.path.join(self.pokydirname, 'oe-init-build-env') 339 oe_init = os.path.join(self.pokydirname, 'oe-init-build-env')
317 # init build environment 340 # init build environment
318 try: 341 try:
319 custom_script = ToasterSetting.objects.get(name="CUSTOM_BUILD_INIT_SCRIPT").value 342 custom_script = ToasterSetting.objects.get(name="CUSTOM_BUILD_INIT_SCRIPT").value
320 custom_script = custom_script.replace("%BUILDDIR%" ,builddir) 343 custom_script = custom_script.replace("%BUILDDIR%" ,builddir)
321 self._shellcmd("bash -c 'source %s'" % (custom_script)) 344 self._shellcmd("bash -c 'source %s'" % (custom_script),env=git_env)
322 except ToasterSetting.DoesNotExist: 345 except ToasterSetting.DoesNotExist:
323 self._shellcmd("bash -c 'source %s %s'" % (oe_init, builddir), 346 self._shellcmd("bash -c 'source %s %s'" % (oe_init, builddir),
324 self.be.sourcedir) 347 self.be.sourcedir,env=git_env)
325 348
326 # update bblayers.conf 349 # update bblayers.conf
327 bblconfpath = os.path.join(builddir, "conf/toaster-bblayers.conf") 350 if not is_merged_attr:
328 with open(bblconfpath, 'w') as bblayers: 351 bblconfpath = os.path.join(builddir, "conf/toaster-bblayers.conf")
329 bblayers.write('# line added by toaster build control\n' 352 with open(bblconfpath, 'w') as bblayers:
330 'BBLAYERS = "%s"' % ' '.join(layers)) 353 bblayers.write('# line added by toaster build control\n'
331 354 'BBLAYERS = "%s"' % ' '.join(layers))
332 # write configuration file 355
333 confpath = os.path.join(builddir, 'conf/toaster.conf') 356 # write configuration file
334 with open(confpath, 'w') as conf: 357 confpath = os.path.join(builddir, 'conf/toaster.conf')
335 for var in variables: 358 with open(confpath, 'w') as conf:
336 conf.write('%s="%s"\n' % (var.name, var.value)) 359 for var in variables:
337 conf.write('INHERIT+="toaster buildhistory"') 360 conf.write('%s="%s"\n' % (var.name, var.value))
361 conf.write('INHERIT+="toaster buildhistory"')
362 else:
363 # Append the Toaster-specific values directly to the bblayers.conf
364 bblconfpath = os.path.join(bitbake.req.project.builddir, "conf/bblayers.conf")
365 bblconfpath_save = os.path.join(bitbake.req.project.builddir, "conf/bblayers.conf.save")
366 shutil.copyfile(bblconfpath, bblconfpath_save)
367 with open(bblconfpath) as bblayers:
368 content = bblayers.readlines()
369 do_write = True
370 was_toaster = False
371 with open(bblconfpath,'w') as bblayers:
372 for line in content:
373 #line = line.strip('\n')
374 if 'TOASTER_CONFIG_PROLOG' in line:
375 do_write = False
376 was_toaster = True
377 elif 'TOASTER_CONFIG_EPILOG' in line:
378 do_write = True
379 elif do_write:
380 bblayers.write(line)
381 if not was_toaster:
382 bblayers.write('\n')
383 bblayers.write('#=== TOASTER_CONFIG_PROLOG ===\n')
384 bblayers.write('BBLAYERS = "\\\n')
385 for layer in layers:
386 bblayers.write(' %s \\\n' % layer)
387 bblayers.write(' "\n')
388 bblayers.write('#=== TOASTER_CONFIG_EPILOG ===\n')
389 # Append the Toaster-specific values directly to the local.conf
390 bbconfpath = os.path.join(bitbake.req.project.builddir, "conf/local.conf")
391 bbconfpath_save = os.path.join(bitbake.req.project.builddir, "conf/local.conf.save")
392 shutil.copyfile(bbconfpath, bbconfpath_save)
393 with open(bbconfpath) as f:
394 content = f.readlines()
395 do_write = True
396 was_toaster = False
397 with open(bbconfpath,'w') as conf:
398 for line in content:
399 #line = line.strip('\n')
400 if 'TOASTER_CONFIG_PROLOG' in line:
401 do_write = False
402 was_toaster = True
403 elif 'TOASTER_CONFIG_EPILOG' in line:
404 do_write = True
405 elif do_write:
406 conf.write(line)
407 if not was_toaster:
408 conf.write('\n')
409 conf.write('#=== TOASTER_CONFIG_PROLOG ===\n')
410 for var in variables:
411 if (not var.name.startswith("INTERNAL_")) and (not var.name == "BBLAYERS"):
412 conf.write('%s="%s"\n' % (var.name, var.value))
413 conf.write('#=== TOASTER_CONFIG_EPILOG ===\n')
414
415 # If 'target' is just the project preparation target, then we are done
416 for target in targets:
417 if "_PROJECT_PREPARE_" == target.target:
418 logger.debug('localhostbecontroller: Project has been prepared. Done.')
419 # Update the Build Request and release the build environment
420 bitbake.req.state = BuildRequest.REQ_COMPLETED
421 bitbake.req.save()
422 self.be.lock = BuildEnvironment.LOCK_FREE
423 self.be.save()
424 # Close the project build and progress bar
425 bitbake.req.build.outcome = Build.SUCCEEDED
426 bitbake.req.build.save()
427 # Update the project status
428 bitbake.req.project.set_variable(Project.PROJECT_SPECIFIC_STATUS,Project.PROJECT_SPECIFIC_CLONING_SUCCESS)
429 signal_runbuilds()
430 return
338 431
339 # clean the Toaster to build environment 432 # clean the Toaster to build environment
340 env_clean = 'unset BBPATH;' # clean BBPATH for <= YP-2.4.0 433 env_clean = 'unset BBPATH;' # clean BBPATH for <= YP-2.4.0
@@ -342,9 +435,14 @@ class LocalhostBEController(BuildEnvironmentController):
342 # run bitbake server from the clone 435 # run bitbake server from the clone
343 bitbake = os.path.join(self.pokydirname, 'bitbake', 'bin', 'bitbake') 436 bitbake = os.path.join(self.pokydirname, 'bitbake', 'bin', 'bitbake')
344 toasterlayers = os.path.join(builddir,"conf/toaster-bblayers.conf") 437 toasterlayers = os.path.join(builddir,"conf/toaster-bblayers.conf")
345 self._shellcmd('%s bash -c \"source %s %s; BITBAKE_UI="knotty" %s --read %s --read %s ' 438 if not is_merged_attr:
346 '--server-only -B 0.0.0.0:0\"' % (env_clean, oe_init, 439 self._shellcmd('%s bash -c \"source %s %s; BITBAKE_UI="knotty" %s --read %s --read %s '
347 builddir, bitbake, confpath, toasterlayers), self.be.sourcedir) 440 '--server-only -B 0.0.0.0:0\"' % (env_clean, oe_init,
441 builddir, bitbake, confpath, toasterlayers), self.be.sourcedir)
442 else:
443 self._shellcmd('%s bash -c \"source %s %s; BITBAKE_UI="knotty" %s '
444 '--server-only -B 0.0.0.0:0\"' % (env_clean, oe_init,
445 builddir, bitbake), self.be.sourcedir)
348 446
349 # read port number from bitbake.lock 447 # read port number from bitbake.lock
350 self.be.bbport = -1 448 self.be.bbport = -1
@@ -390,12 +488,20 @@ class LocalhostBEController(BuildEnvironmentController):
390 log = os.path.join(builddir, 'toaster_ui.log') 488 log = os.path.join(builddir, 'toaster_ui.log')
391 local_bitbake = os.path.join(os.path.dirname(os.getenv('BBBASEDIR')), 489 local_bitbake = os.path.join(os.path.dirname(os.getenv('BBBASEDIR')),
392 'bitbake') 490 'bitbake')
393 self._shellcmd(['%s bash -c \"(TOASTER_BRBE="%s" BBSERVER="0.0.0.0:%s" ' 491 if not is_merged_attr:
492 self._shellcmd(['%s bash -c \"(TOASTER_BRBE="%s" BBSERVER="0.0.0.0:%s" '
394 '%s %s -u toasterui --read %s --read %s --token="" >>%s 2>&1;' 493 '%s %s -u toasterui --read %s --read %s --token="" >>%s 2>&1;'
395 'BITBAKE_UI="knotty" BBSERVER=0.0.0.0:%s %s -m)&\"' \ 494 'BITBAKE_UI="knotty" BBSERVER=0.0.0.0:%s %s -m)&\"' \
396 % (env_clean, brbe, self.be.bbport, local_bitbake, bbtargets, confpath, toasterlayers, log, 495 % (env_clean, brbe, self.be.bbport, local_bitbake, bbtargets, confpath, toasterlayers, log,
397 self.be.bbport, bitbake,)], 496 self.be.bbport, bitbake,)],
398 builddir, nowait=True) 497 builddir, nowait=True)
498 else:
499 self._shellcmd(['%s bash -c \"(TOASTER_BRBE="%s" BBSERVER="0.0.0.0:%s" '
500 '%s %s -u toasterui --token="" >>%s 2>&1;'
501 'BITBAKE_UI="knotty" BBSERVER=0.0.0.0:%s %s -m)&\"' \
502 % (env_clean, brbe, self.be.bbport, local_bitbake, bbtargets, log,
503 self.be.bbport, bitbake,)],
504 builddir, nowait=True)
399 505
400 logger.debug('localhostbecontroller: Build launched, exiting. ' 506 logger.debug('localhostbecontroller: Build launched, exiting. '
401 'Follow build logs at %s' % log) 507 'Follow build logs at %s' % log)