diff options
Diffstat (limited to 'bitbake/lib/toaster/toastermain/management/commands/buildimport.py')
-rw-r--r-- | bitbake/lib/toaster/toastermain/management/commands/buildimport.py | 586 |
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 | |||
47 | from django.core.management.base import BaseCommand, CommandError | ||
48 | from django.core.exceptions import ObjectDoesNotExist | ||
49 | from orm.models import ProjectManager, Project, Release, ProjectVariable | ||
50 | from orm.models import Layer, Layer_Version, LayerSource, ProjectLayer | ||
51 | from toastergui.api import scan_layer_content | ||
52 | from django.db import OperationalError | ||
53 | |||
54 | import os | ||
55 | import re | ||
56 | import os.path | ||
57 | import subprocess | ||
58 | |||
59 | # Toaster variable section delimiters | ||
60 | TOASTER_PROLOG = '#=== TOASTER_CONFIG_PROLOG ===' | ||
61 | TOASTER_EPILOG = '#=== TOASTER_CONFIG_EPILOG ===' | ||
62 | |||
63 | # quick development/debugging support | ||
64 | verbose = 2 | ||
65 | def _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 | |||
99 | class 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 | |||