summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastermain/management/commands/buildimport.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/toastermain/management/commands/buildimport.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/toastermain/management/commands/buildimport.py')
-rw-r--r--bitbake/lib/toaster/toastermain/management/commands/buildimport.py586
1 files changed, 586 insertions, 0 deletions
diff --git a/bitbake/lib/toaster/toastermain/management/commands/buildimport.py b/bitbake/lib/toaster/toastermain/management/commands/buildimport.py
new file mode 100644
index 0000000000..791d528231
--- /dev/null
+++ b/bitbake/lib/toaster/toastermain/management/commands/buildimport.py
@@ -0,0 +1,586 @@
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) 2018 Wind River Systems
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# buildimport: import a project for project specific configuration
23#
24# Usage:
25# (a) Set up Toaster environent
26#
27# (b) Call buildimport
28# $ /path/to/bitbake/lib/toaster/manage.py buildimport \
29# --name=$PROJECTNAME \
30# --path=$BUILD_DIRECTORY \
31# --callback="$CALLBACK_SCRIPT" \
32# --command="configure|reconfigure|import"
33#
34# (c) Return is "|Default_image=%s|Project_id=%d"
35#
36# (d) Open Toaster to this project using for example:
37# $ xdg-open http://localhost:$toaster_port/toastergui/project_specific/$project_id
38#
39# (e) To delete a project:
40# $ /path/to/bitbake/lib/toaster/manage.py buildimport \
41# --name=$PROJECTNAME --delete-project
42#
43
44
45# ../bitbake/lib/toaster/manage.py buildimport --name=test --path=`pwd` --callback="" --command=import
46
47from django.core.management.base import BaseCommand, CommandError
48from django.core.exceptions import ObjectDoesNotExist
49from orm.models import ProjectManager, Project, Release, ProjectVariable
50from orm.models import Layer, Layer_Version, LayerSource, ProjectLayer
51from toastergui.api import scan_layer_content
52from django.db import OperationalError
53
54import os
55import re
56import os.path
57import subprocess
58
59# Toaster variable section delimiters
60TOASTER_PROLOG = '#=== TOASTER_CONFIG_PROLOG ==='
61TOASTER_EPILOG = '#=== TOASTER_CONFIG_EPILOG ==='
62
63# quick development/debugging support
64verbose = 2
65def _log(msg):
66 if 1 == verbose:
67 print(msg)
68 elif 2 == verbose:
69 f1=open('/tmp/toaster.log', 'a')
70 f1.write("|" + msg + "|\n" )
71 f1.close()
72
73
74__config_regexp__ = re.compile( r"""
75 ^
76 (?P<exp>export\s+)?
77 (?P<var>[a-zA-Z0-9\-_+.${}/~]+?)
78 (\[(?P<flag>[a-zA-Z0-9\-_+.]+)\])?
79
80 \s* (
81 (?P<colon>:=) |
82 (?P<lazyques>\?\?=) |
83 (?P<ques>\?=) |
84 (?P<append>\+=) |
85 (?P<prepend>=\+) |
86 (?P<predot>=\.) |
87 (?P<postdot>\.=) |
88 =
89 ) \s*
90
91 (?!'[^']*'[^']*'$)
92 (?!\"[^\"]*\"[^\"]*\"$)
93 (?P<apo>['\"])
94 (?P<value>.*)
95 (?P=apo)
96 $
97 """, re.X)
98
99class Command(BaseCommand):
100 args = "<name> <path> <release>"
101 help = "Import a command line build directory"
102 vars = {}
103 toaster_vars = {}
104
105 def add_arguments(self, parser):
106 parser.add_argument(
107 '--name', dest='name', required=True,
108 help='name of the project',
109 )
110 parser.add_argument(
111 '--path', dest='path', required=True,
112 help='path to the project',
113 )
114 parser.add_argument(
115 '--release', dest='release', required=False,
116 help='release for the project',
117 )
118 parser.add_argument(
119 '--callback', dest='callback', required=False,
120 help='callback for project config update',
121 )
122 parser.add_argument(
123 '--delete-project', dest='delete_project', required=False,
124 help='delete this project from the database',
125 )
126 parser.add_argument(
127 '--command', dest='command', required=False,
128 help='command (configure,reconfigure,import)',
129 )
130
131 # Extract the bb variables from a conf file
132 def scan_conf(self,fn):
133 vars = self.vars
134 toaster_vars = self.toaster_vars
135
136 #_log("scan_conf:%s" % fn)
137 if not os.path.isfile(fn):
138 return
139 f = open(fn, 'r')
140
141 #statements = ast.StatementGroup()
142 lineno = 0
143 is_toaster_section = False
144 while True:
145 lineno = lineno + 1
146 s = f.readline()
147 if not s:
148 break
149 w = s.strip()
150 # skip empty lines
151 if not w:
152 continue
153 # evaluate Toaster sections
154 if w.startswith(TOASTER_PROLOG):
155 is_toaster_section = True
156 continue
157 if w.startswith(TOASTER_EPILOG):
158 is_toaster_section = False
159 continue
160 s = s.rstrip()
161 while s[-1] == '\\':
162 s2 = f.readline().strip()
163 lineno = lineno + 1
164 if (not s2 or s2 and s2[0] != "#") and s[0] == "#" :
165 echo("There is a confusing multiline, partially commented expression on line %s of file %s (%s).\nPlease clarify whether this is all a comment or should be parsed." % (lineno, fn, s))
166 s = s[:-1] + s2
167 # skip comments
168 if s[0] == '#':
169 continue
170 # process the line for just assignments
171 m = __config_regexp__.match(s)
172 if m:
173 groupd = m.groupdict()
174 var = groupd['var']
175 value = groupd['value']
176
177 if groupd['lazyques']:
178 if not var in vars:
179 vars[var] = value
180 continue
181 if groupd['ques']:
182 if not var in vars:
183 vars[var] = value
184 continue
185 # preset empty blank for remaining operators
186 if not var in vars:
187 vars[var] = ''
188 if groupd['append']:
189 vars[var] += value
190 elif groupd['prepend']:
191 vars[var] = "%s%s" % (value,vars[var])
192 elif groupd['predot']:
193 vars[var] = "%s %s" % (value,vars[var])
194 elif groupd['postdot']:
195 vars[var] = "%s %s" % (vars[var],value)
196 else:
197 vars[var] = "%s" % (value)
198 # capture vars in a Toaster section
199 if is_toaster_section:
200 toaster_vars[var] = vars[var]
201
202 # DONE WITH PARSING
203 f.close()
204 self.vars = vars
205 self.toaster_vars = toaster_vars
206
207 # Update the scanned project variables
208 def update_project_vars(self,project,name):
209 pv, create = ProjectVariable.objects.get_or_create(project = project, name = name)
210 if (not name in self.vars.keys()) or (not self.vars[name]):
211 self.vars[name] = pv.value
212 else:
213 if pv.value != self.vars[name]:
214 pv.value = self.vars[name]
215 pv.save()
216
217 # Find the git version of the installation
218 def find_layer_dir_version(self,path):
219 # * rocko ...
220
221 install_version = ''
222 cwd = os.getcwd()
223 os.chdir(path)
224 p = subprocess.Popen(['git', 'branch', '-av'], stdout=subprocess.PIPE,
225 stderr=subprocess.PIPE)
226 out, err = p.communicate()
227 out = out.decode("utf-8")
228 for branch in out.split('\n'):
229 if ('*' == branch[0:1]) and ('no branch' not in branch):
230 install_version = re.sub(' .*','',branch[2:])
231 break
232 if 'remotes/m/master' in branch:
233 install_version = re.sub('.*base/','',branch)
234 break
235 os.chdir(cwd)
236 return install_version
237
238 # Compute table of the installation's registered layer versions (branch or commit)
239 def find_layer_dir_versions(self,INSTALL_URL_PREFIX):
240 lv_dict = {}
241 layer_versions = Layer_Version.objects.all()
242 for lv in layer_versions:
243 layer = Layer.objects.filter(pk=lv.layer.pk)[0]
244 if layer.vcs_url:
245 url_short = layer.vcs_url.replace(INSTALL_URL_PREFIX,'')
246 else:
247 url_short = ''
248 # register the core, branch, and the version variations
249 lv_dict["%s,%s,%s" % (url_short,lv.dirpath,'')] = (lv.id,layer.name)
250 lv_dict["%s,%s,%s" % (url_short,lv.dirpath,lv.branch)] = (lv.id,layer.name)
251 lv_dict["%s,%s,%s" % (url_short,lv.dirpath,lv.commit)] = (lv.id,layer.name)
252 #_log(" (%s,%s,%s|%s) = (%s,%s)" % (url_short,lv.dirpath,lv.branch,lv.commit,lv.id,layer.name))
253 return lv_dict
254
255 # Apply table of all layer versions
256 def extract_bblayers(self):
257 # set up the constants
258 bblayer_str = self.vars['BBLAYERS']
259 TOASTER_DIR = os.environ.get('TOASTER_DIR')
260 INSTALL_CLONE_PREFIX = os.path.dirname(TOASTER_DIR) + "/"
261 TOASTER_CLONE_PREFIX = TOASTER_DIR + "/_toaster_clones/"
262 INSTALL_URL_PREFIX = ''
263 layers = Layer.objects.filter(name='openembedded-core')
264 for layer in layers:
265 if layer.vcs_url:
266 INSTALL_URL_PREFIX = layer.vcs_url
267 break
268 INSTALL_URL_PREFIX = INSTALL_URL_PREFIX.replace("/poky","/")
269 INSTALL_VERSION_DIR = TOASTER_DIR
270 INSTALL_URL_POSTFIX = INSTALL_URL_PREFIX.replace(':','_')
271 INSTALL_URL_POSTFIX = INSTALL_URL_POSTFIX.replace('/','_')
272 INSTALL_URL_POSTFIX = "%s_%s" % (TOASTER_CLONE_PREFIX,INSTALL_URL_POSTFIX)
273
274 # get the set of available layer:layer_versions
275 lv_dict = self.find_layer_dir_versions(INSTALL_URL_PREFIX)
276
277 # compute the layer matches
278 layers_list = []
279 for line in bblayer_str.split(' '):
280 if not line:
281 continue
282 if line.endswith('/local'):
283 continue
284
285 # isolate the repo
286 layer_path = line
287 line = line.replace(INSTALL_URL_POSTFIX,'').replace(INSTALL_CLONE_PREFIX,'').replace('/layers/','/').replace('/poky/','/')
288
289 # isolate the sub-path
290 path_index = line.rfind('/')
291 if path_index > 0:
292 sub_path = line[path_index+1:]
293 line = line[0:path_index]
294 else:
295 sub_path = ''
296
297 # isolate the version
298 if TOASTER_CLONE_PREFIX in layer_path:
299 is_toaster_clone = True
300 # extract version from name syntax
301 version_index = line.find('_')
302 if version_index > 0:
303 version = line[version_index+1:]
304 line = line[0:version_index]
305 else:
306 version = ''
307 _log("TOASTER_CLONE(%s/%s), version=%s" % (line,sub_path,version))
308 else:
309 is_toaster_clone = False
310 # version is from the installation
311 version = self.find_layer_dir_version(layer_path)
312 _log("LOCAL_CLONE(%s/%s), version=%s" % (line,sub_path,version))
313
314 # capture the layer information into layers_list
315 layers_list.append( (line,sub_path,version,layer_path,is_toaster_clone) )
316 return layers_list,lv_dict
317
318 #
319 def find_import_release(self,layers_list,lv_dict,default_release):
320 # poky,meta,rocko => 4;openembedded-core
321 release = default_release
322 for line,path,version,layer_path,is_toaster_clone in layers_list:
323 key = "%s,%s,%s" % (line,path,version)
324 if key in lv_dict:
325 lv_id = lv_dict[key]
326 if 'openembedded-core' == lv_id[1]:
327 _log("Find_import_release(%s):version=%s,Toaster=%s" % (lv_id[1],version,is_toaster_clone))
328 # only versions in Toaster managed layers are accepted
329 if not is_toaster_clone:
330 break
331 try:
332 release = Release.objects.get(name=version)
333 except:
334 pass
335 break
336 _log("Find_import_release:RELEASE=%s" % release.name)
337 return release
338
339 # Apply the found conf layers
340 def apply_conf_bblayers(self,layers_list,lv_dict,project,release=None):
341 for line,path,version,layer_path,is_toaster_clone in layers_list:
342 # Assert release promote if present
343 if release:
344 version = release
345 # try to match the key to a layer_version
346 key = "%s,%s,%s" % (line,path,version)
347 key_short = "%s,%s,%s" % (line,path,'')
348 lv_id = ''
349 if key in lv_dict:
350 lv_id = lv_dict[key]
351 lv = Layer_Version.objects.get(pk=int(lv_id[0]))
352 pl,created = ProjectLayer.objects.get_or_create(project=project,
353 layercommit=lv)
354 pl.optional=False
355 pl.save()
356 _log(" %s => %s;%s" % (key,lv_id[0],lv_id[1]))
357 elif key_short in lv_dict:
358 lv_id = lv_dict[key_short]
359 lv = Layer_Version.objects.get(pk=int(lv_id[0]))
360 pl,created = ProjectLayer.objects.get_or_create(project=project,
361 layercommit=lv)
362 pl.optional=False
363 pl.save()
364 _log(" %s ?> %s" % (key,lv_dict[key_short]))
365 else:
366 _log("%s <= %s" % (key,layer_path))
367 found = False
368 # does local layer already exist in this project?
369 try:
370 for pl in ProjectLayer.objects.filter(project=project):
371 if pl.layercommit.layer.local_source_dir == layer_path:
372 found = True
373 _log(" Project Local Layer found!")
374 except Exception as e:
375 _log("ERROR: Local Layer '%s'" % e)
376 pass
377
378 if not found:
379 # Does Layer name+path already exist?
380 try:
381 layer_name_base = os.path.basename(layer_path)
382 _log("Layer_lookup: try '%s','%s'" % (layer_name_base,layer_path))
383 layer = Layer.objects.get(name=layer_name_base,local_source_dir = layer_path)
384 # Found! Attach layer_version and ProjectLayer
385 layer_version = Layer_Version.objects.create(
386 layer=layer,
387 project=project,
388 layer_source=LayerSource.TYPE_IMPORTED)
389 layer_version.save()
390 pl,created = ProjectLayer.objects.get_or_create(project=project,
391 layercommit=layer_version)
392 pl.optional=False
393 pl.save()
394 found = True
395 # add layer contents to this layer version
396 scan_layer_content(layer,layer_version)
397 _log(" Parent Local Layer found in db!")
398 except Exception as e:
399 _log("Layer_exists_test_failed: Local Layer '%s'" % e)
400 pass
401
402 if not found:
403 # Insure that layer path exists, in case of user typo
404 if not os.path.isdir(layer_path):
405 _log("ERROR:Layer path '%s' not found" % layer_path)
406 continue
407 # Add layer to db and attach project to it
408 layer_name_base = os.path.basename(layer_path)
409 # generate a unique layer name
410 layer_name_matches = {}
411 for layer in Layer.objects.filter(name__contains=layer_name_base):
412 layer_name_matches[layer.name] = '1'
413 layer_name_idx = 0
414 layer_name_test = layer_name_base
415 while layer_name_test in layer_name_matches.keys():
416 layer_name_idx += 1
417 layer_name_test = "%s_%d" % (layer_name_base,layer_name_idx)
418 # create the layer and layer_verion objects
419 layer = Layer.objects.create(name=layer_name_test)
420 layer.local_source_dir = layer_path
421 layer_version = Layer_Version.objects.create(
422 layer=layer,
423 project=project,
424 layer_source=LayerSource.TYPE_IMPORTED)
425 layer.save()
426 layer_version.save()
427 pl,created = ProjectLayer.objects.get_or_create(project=project,
428 layercommit=layer_version)
429 pl.optional=False
430 pl.save()
431 # register the layer's content
432 _log(" Local Layer Add content")
433 scan_layer_content(layer,layer_version)
434 _log(" Local Layer Added '%s'!" % layer_name_test)
435
436 # Scan the project's conf files (if any)
437 def scan_conf_variables(self,project_path):
438 # scan the project's settings, add any new layers or variables
439 if os.path.isfile("%s/conf/local.conf" % project_path):
440 self.scan_conf("%s/conf/local.conf" % project_path)
441 self.scan_conf("%s/conf/bblayers.conf" % project_path)
442 # Import then disable old style Toaster conf files (before 'merged_attr')
443 old_toaster_local = "%s/conf/toaster.conf" % project_path
444 if os.path.isfile(old_toaster_local):
445 self.scan_conf(old_toaster_local)
446 shutil.move(old_toaster_local, old_toaster_local+"_old")
447 old_toaster_layer = "%s/conf/toaster-bblayers.conf" % project_path
448 if os.path.isfile(old_toaster_layer):
449 self.scan_conf(old_toaster_layer)
450 shutil.move(old_toaster_layer, old_toaster_layer+"_old")
451
452 # Scan the found conf variables (if any)
453 def apply_conf_variables(self,project,layers_list,lv_dict,release=None):
454 if self.vars:
455 # Catch vars relevant to Toaster (in case no Toaster section)
456 self.update_project_vars(project,'DISTRO')
457 self.update_project_vars(project,'MACHINE')
458 self.update_project_vars(project,'IMAGE_INSTALL_append')
459 self.update_project_vars(project,'IMAGE_FSTYPES')
460 self.update_project_vars(project,'PACKAGE_CLASSES')
461 # These vars are typically only assigned by Toaster
462 #self.update_project_vars(project,'DL_DIR')
463 #self.update_project_vars(project,'SSTATE_DIR')
464
465 # Assert found Toaster vars
466 for var in self.toaster_vars.keys():
467 pv, create = ProjectVariable.objects.get_or_create(project = project, name = var)
468 pv.value = self.toaster_vars[var]
469 _log("* Add/update Toaster var '%s' = '%s'" % (pv.name,pv.value))
470 pv.save()
471
472 # Assert found BBLAYERS
473 if 0 < verbose:
474 for pl in ProjectLayer.objects.filter(project=project):
475 release_name = 'None' if not pl.layercommit.release else pl.layercommit.release.name
476 print(" BEFORE:ProjectLayer=%s,%s,%s,%s" % (pl.layercommit.layer.name,release_name,pl.layercommit.branch,pl.layercommit.commit))
477 self.apply_conf_bblayers(layers_list,lv_dict,project,release)
478 if 0 < verbose:
479 for pl in ProjectLayer.objects.filter(project=project):
480 release_name = 'None' if not pl.layercommit.release else pl.layercommit.release.name
481 print(" AFTER :ProjectLayer=%s,%s,%s,%s" % (pl.layercommit.layer.name,release_name,pl.layercommit.branch,pl.layercommit.commit))
482
483
484 def handle(self, *args, **options):
485 project_name = options['name']
486 project_path = options['path']
487 project_callback = options['callback']
488 if options['release']:
489 release_name = options['release']
490 else:
491 release_name = ''
492
493 #
494 # Delete project
495 #
496
497 if options['delete_project']:
498 try:
499 print("Project '%s' delete from Toaster database" % (project_name))
500 project = Project.objects.get(name=project_name)
501 # TODO: deep project delete
502 project.delete()
503 print("Project '%s' Deleted" % (project_name))
504 return
505 except Exception as e:
506 print("Project '%s' not found, not deleted (%s)" % (project_name,e))
507 return
508
509 #
510 # Create/Update/Import project
511 #
512
513 # See if project (by name) exists
514 project = None
515 try:
516 # Project already exists
517 project = Project.objects.get(name=project_name)
518 except Exception as e:
519 pass
520
521 # Find the installation's default release
522 default_release = Release.objects.get(id=1)
523
524 # SANITY: if 'reconfig' but project does not exist (deleted externally), switch to 'import'
525 if ("reconfigure" == options['command']) and (None == project):
526 options['command'] = 'import'
527
528 # 'Configure':
529 if "configure" == options['command']:
530 # Note: ignore any existing conf files
531 # create project, SANITY: reuse any project of same name
532 project = Project.objects.create_project(project_name,default_release,project)
533
534 # 'Re-configure':
535 if "reconfigure" == options['command']:
536 # Scan the directory's conf files
537 self.scan_conf_variables(project_path)
538 # Scan the layer list
539 layers_list,lv_dict = self.extract_bblayers()
540 # Apply any new layers or variables
541 self.apply_conf_variables(project,layers_list,lv_dict)
542
543 # 'Import':
544 if "import" == options['command']:
545 # Scan the directory's conf files
546 self.scan_conf_variables(project_path)
547 # Remove these Toaster controlled variables
548 for var in ('DL_DIR','SSTATE_DIR'):
549 self.vars.pop(var, None)
550 self.toaster_vars.pop(var, None)
551 # Scan the layer list
552 layers_list,lv_dict = self.extract_bblayers()
553 # Find the directory's release, and promote to default_release if local paths
554 release = self.find_import_release(layers_list,lv_dict,default_release)
555 # create project, SANITY: reuse any project of same name
556 project = Project.objects.create_project(project_name,release,project)
557 # Apply any new layers or variables
558 self.apply_conf_variables(project,layers_list,lv_dict,release)
559 # WORKAROUND: since we now derive the release, redirect 'newproject_specific' to 'project_specific'
560 project.set_variable('INTERNAL_PROJECT_SPECIFIC_SKIPRELEASE','1')
561
562 # Set up the project's meta data
563 project.builddir = project_path
564 project.merged_attr = True
565 project.set_variable(Project.PROJECT_SPECIFIC_CALLBACK,project_callback)
566 project.set_variable(Project.PROJECT_SPECIFIC_STATUS,Project.PROJECT_SPECIFIC_EDIT)
567 if ("configure" == options['command']) or ("import" == options['command']):
568 # preset the mode and default image recipe
569 project.set_variable(Project.PROJECT_SPECIFIC_ISNEW,Project.PROJECT_SPECIFIC_NEW)
570 project.set_variable(Project.PROJECT_SPECIFIC_DEFAULTIMAGE,"core-image-minimal")
571 # Assert any extended/custom actions or variables for new non-Toaster projects
572 if not len(self.toaster_vars):
573 pass
574 else:
575 project.set_variable(Project.PROJECT_SPECIFIC_ISNEW,Project.PROJECT_SPECIFIC_NONE)
576
577 # Save the updated Project
578 project.save()
579
580 _log("Buildimport:project='%s' at '%d'" % (project_name,project.id))
581
582 if ('DEFAULT_IMAGE' in self.vars) and (self.vars['DEFAULT_IMAGE']):
583 print("|Default_image=%s|Project_id=%d" % (self.vars['DEFAULT_IMAGE'],project.id))
584 else:
585 print("|Project_id=%d" % (project.id))
586