summaryrefslogtreecommitdiffstats
path: root/scripts/lib/bsp/engine.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/bsp/engine.py')
-rw-r--r--scripts/lib/bsp/engine.py1780
1 files changed, 1780 insertions, 0 deletions
diff --git a/scripts/lib/bsp/engine.py b/scripts/lib/bsp/engine.py
new file mode 100644
index 0000000000..681720d20a
--- /dev/null
+++ b/scripts/lib/bsp/engine.py
@@ -0,0 +1,1780 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3#
4# Copyright (c) 2012, Intel Corporation.
5# All rights reserved.
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 2 as
9# published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program; if not, write to the Free Software Foundation, Inc.,
18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19#
20# DESCRIPTION
21# This module implements the templating engine used by 'yocto-bsp' to
22# create BSPs. The BSP templates are simply the set of files expected
23# to appear in a generated BSP, marked up with a small set of tags
24# used to customize the output. The engine parses through the
25# templates and generates a Python program containing all the logic
26# and input elements needed to display and retrieve BSP-specific
27# information from the user. The resulting program uses those results
28# to generate the final BSP files.
29#
30# AUTHORS
31# Tom Zanussi <tom.zanussi (at] intel.com>
32#
33
34import os
35import sys
36from abc import ABCMeta, abstractmethod
37from tags import *
38import shlex
39import json
40import subprocess
41import shutil
42
43class Line():
44 """
45 Generic (abstract) container representing a line that will appear
46 in the BSP-generating program.
47 """
48 __metaclass__ = ABCMeta
49
50 def __init__(self, line):
51 self.line = line
52 self.generated_line = ""
53 self.prio = sys.maxint
54 self.discard = False
55
56 @abstractmethod
57 def gen(self, context = None):
58 """
59 Generate the final executable line that will appear in the
60 BSP-generation program.
61 """
62 pass
63
64 def escape(self, line):
65 """
66 Escape single and double quotes and backslashes until I find
67 something better (re.escape() escapes way too much).
68 """
69 return line.replace("\\", "\\\\").replace("\"", "\\\"").replace("'", "\\'")
70
71 def parse_error(self, msg, lineno, line):
72 raise SyntaxError("%s: %s" % (msg, line))
73
74
75class NormalLine(Line):
76 """
77 Container for normal (non-tag) lines.
78 """
79 def __init__(self, line):
80 Line.__init__(self, line)
81 self.is_filename = False
82 self.is_dirname = False
83 self.out_filebase = None
84
85 def gen(self, context = None):
86 if self.is_filename:
87 line = "current_file = \"" + os.path.join(self.out_filebase, self.escape(self.line)) + "\"; of = open(current_file, \"w\")"
88 elif self.is_dirname:
89 dirname = os.path.join(self.out_filebase, self.escape(self.line))
90 line = "if not os.path.exists(\"" + dirname + "\"): os.mkdir(\"" + dirname + "\")"
91 else:
92 line = "of.write(\"" + self.escape(self.line) + "\\n\")"
93 return line
94
95
96class CodeLine(Line):
97 """
98 Container for Python code tag lines.
99 """
100 def __init__(self, line):
101 Line.__init__(self, line)
102
103 def gen(self, context = None):
104 return self.line
105
106
107class Assignment:
108 """
109 Representation of everything we know about {{=name }} tags.
110 Instances of these are used by Assignment lines.
111 """
112 def __init__(self, start, end, name):
113 self.start = start
114 self.end = end
115 self.name = name
116
117
118class AssignmentLine(NormalLine):
119 """
120 Container for normal lines containing assignment tags. Assignment
121 tags must be in ascending order of 'start' value.
122 """
123 def __init__(self, line):
124 NormalLine.__init__(self, line)
125 self.assignments = []
126
127 def add_assignment(self, start, end, name):
128 self.assignments.append(Assignment(start, end, name))
129
130 def gen(self, context = None):
131 line = self.escape(self.line)
132
133 for assignment in self.assignments:
134 replacement = "\" + " + assignment.name + " + \""
135 idx = line.find(ASSIGN_TAG)
136 line = line[:idx] + replacement + line[idx + assignment.end - assignment.start:]
137 if self.is_filename:
138 return "current_file = \"" + os.path.join(self.out_filebase, line) + "\"; of = open(current_file, \"w\")"
139 elif self.is_dirname:
140 dirname = os.path.join(self.out_filebase, line)
141 return "if not os.path.exists(\"" + dirname + "\"): os.mkdir(\"" + dirname + "\")"
142 else:
143 return "of.write(\"" + line + "\\n\")"
144
145
146class InputLine(Line):
147 """
148 Base class for Input lines.
149 """
150 def __init__(self, props, tag, lineno):
151 Line.__init__(self, tag)
152 self.props = props
153 self.lineno = lineno
154
155 try:
156 self.prio = int(props["prio"])
157 except KeyError:
158 self.prio = sys.maxint
159
160 def gen(self, context = None):
161 try:
162 depends_on = self.props["depends-on"]
163 try:
164 depends_on_val = self.props["depends-on-val"]
165 except KeyError:
166 self.parse_error("No 'depends-on-val' for 'depends-on' property",
167 self.lineno, self.line)
168 except KeyError:
169 pass
170
171
172class EditBoxInputLine(InputLine):
173 """
174 Base class for 'editbox' Input lines.
175
176 props:
177 name: example - "Load address"
178 msg: example - "Please enter the load address"
179 result:
180 Sets the value of the variable specified by 'name' to
181 whatever the user typed.
182 """
183 def __init__(self, props, tag, lineno):
184 InputLine.__init__(self, props, tag, lineno)
185
186 def gen(self, context = None):
187 InputLine.gen(self, context)
188 name = self.props["name"]
189 if not name:
190 self.parse_error("No input 'name' property found",
191 self.lineno, self.line)
192 msg = self.props["msg"]
193 if not msg:
194 self.parse_error("No input 'msg' property found",
195 self.lineno, self.line)
196
197 try:
198 default_choice = self.props["default"]
199 except KeyError:
200 default_choice = ""
201
202 msg += " [default: " + default_choice + "]"
203
204 line = name + " = default(raw_input(\"" + msg + " \"), " + name + ")"
205
206 return line
207
208
209class GitRepoEditBoxInputLine(EditBoxInputLine):
210 """
211 Base class for 'editbox' Input lines for user input of remote git
212 repos. This class verifies the existence and connectivity of the
213 specified git repo.
214
215 props:
216 name: example - "Load address"
217 msg: example - "Please enter the load address"
218 result:
219 Sets the value of the variable specified by 'name' to
220 whatever the user typed.
221 """
222 def __init__(self, props, tag, lineno):
223 EditBoxInputLine.__init__(self, props, tag, lineno)
224
225 def gen(self, context = None):
226 EditBoxInputLine.gen(self, context)
227 name = self.props["name"]
228 if not name:
229 self.parse_error("No input 'name' property found",
230 self.lineno, self.line)
231 msg = self.props["msg"]
232 if not msg:
233 self.parse_error("No input 'msg' property found",
234 self.lineno, self.line)
235
236 try:
237 default_choice = self.props["default"]
238 except KeyError:
239 default_choice = ""
240
241 msg += " [default: " + default_choice + "]"
242
243 line = name + " = get_verified_git_repo(\"" + msg + "\"," + name + ")"
244
245 return line
246
247
248class FileEditBoxInputLine(EditBoxInputLine):
249 """
250 Base class for 'editbox' Input lines for user input of existing
251 files. This class verifies the existence of the specified file.
252
253 props:
254 name: example - "Load address"
255 msg: example - "Please enter the load address"
256 result:
257 Sets the value of the variable specified by 'name' to
258 whatever the user typed.
259 """
260 def __init__(self, props, tag, lineno):
261 EditBoxInputLine.__init__(self, props, tag, lineno)
262
263 def gen(self, context = None):
264 EditBoxInputLine.gen(self, context)
265 name = self.props["name"]
266 if not name:
267 self.parse_error("No input 'name' property found",
268 self.lineno, self.line)
269 msg = self.props["msg"]
270 if not msg:
271 self.parse_error("No input 'msg' property found",
272 self.lineno, self.line)
273
274 try:
275 default_choice = self.props["default"]
276 except KeyError:
277 default_choice = ""
278
279 msg += " [default: " + default_choice + "]"
280
281 line = name + " = get_verified_file(\"" + msg + "\"," + name + ", True)"
282
283 return line
284
285
286class BooleanInputLine(InputLine):
287 """
288 Base class for boolean Input lines.
289 props:
290 name: example - "keyboard"
291 msg: example - "Got keyboard?"
292 result:
293 Sets the value of the variable specified by 'name' to "yes" or "no"
294 example - keyboard = "yes"
295 """
296 def __init__(self, props, tag, lineno):
297 InputLine.__init__(self, props, tag, lineno)
298
299 def gen(self, context = None):
300 InputLine.gen(self, context)
301 name = self.props["name"]
302 if not name:
303 self.parse_error("No input 'name' property found",
304 self.lineno, self.line)
305 msg = self.props["msg"]
306 if not msg:
307 self.parse_error("No input 'msg' property found",
308 self.lineno, self.line)
309
310 try:
311 default_choice = self.props["default"]
312 except KeyError:
313 default_choice = ""
314
315 msg += " [default: " + default_choice + "]"
316
317 line = name + " = boolean(raw_input(\"" + msg + " \"), " + name + ")"
318
319 return line
320
321
322class ListInputLine(InputLine):
323 """
324 Base class for List-based Input lines. e.g. Choicelist, Checklist.
325 """
326 __metaclass__ = ABCMeta
327
328 def __init__(self, props, tag, lineno):
329 InputLine.__init__(self, props, tag, lineno)
330 self.choices = []
331
332 def gen_choicepair_list(self):
333 """Generate a list of 2-item val:desc lists from self.choices."""
334 if not self.choices:
335 return None
336
337 choicepair_list = list()
338
339 for choice in self.choices:
340 choicepair = []
341 choicepair.append(choice.val)
342 choicepair.append(choice.desc)
343 choicepair_list.append(choicepair)
344
345 return choicepair_list
346
347 def gen_degenerate_choicepair_list(self, choices):
348 """Generate a list of 2-item val:desc with val=desc from passed-in choices."""
349 choicepair_list = list()
350
351 for choice in choices:
352 choicepair = []
353 choicepair.append(choice)
354 choicepair.append(choice)
355 choicepair_list.append(choicepair)
356
357 return choicepair_list
358
359 def exec_listgen_fn(self, context = None):
360 """
361 Execute the list-generating function contained as a string in
362 the "gen" property.
363 """
364 retval = None
365 try:
366 fname = self.props["gen"]
367 modsplit = fname.split('.')
368 mod_fn = modsplit.pop()
369 mod = '.'.join(modsplit)
370
371 __import__(mod)
372 # python 2.7 has a better way to do this using importlib.import_module
373 m = sys.modules[mod]
374
375 fn = getattr(m, mod_fn)
376 if not fn:
377 self.parse_error("couldn't load function specified for 'gen' property ",
378 self.lineno, self.line)
379 retval = fn(context)
380 if not retval:
381 self.parse_error("function specified for 'gen' property returned nothing ",
382 self.lineno, self.line)
383 except KeyError:
384 pass
385
386 return retval
387
388 def gen_choices_str(self, choicepairs):
389 """
390 Generate a numbered list of choices from a list of choicepairs
391 for display to the user.
392 """
393 choices_str = ""
394
395 for i, choicepair in enumerate(choicepairs):
396 choices_str += "\t" + str(i + 1) + ") " + choicepair[1] + "\n"
397
398 return choices_str
399
400 def gen_choices_val_str(self, choicepairs):
401 """
402 Generate an array of choice values corresponding to the
403 numbered list generated by gen_choices_str().
404 """
405 choices_val_list = "["
406
407 for i, choicepair in enumerate(choicepairs):
408 choices_val_list += "\"" + choicepair[0] + "\","
409 choices_val_list += "]"
410
411 return choices_val_list
412
413 def gen_choices_val_list(self, choicepairs):
414 """
415 Generate an array of choice values corresponding to the
416 numbered list generated by gen_choices_str().
417 """
418 choices_val_list = []
419
420 for i, choicepair in enumerate(choicepairs):
421 choices_val_list.append(choicepair[0])
422
423 return choices_val_list
424
425 def gen_choices_list(self, context = None, checklist = False):
426 """
427 Generate an array of choice values corresponding to the
428 numbered list generated by gen_choices_str().
429 """
430 choices = self.exec_listgen_fn(context)
431 if choices:
432 if len(choices) == 0:
433 self.parse_error("No entries available for input list",
434 self.lineno, self.line)
435 choicepairs = self.gen_degenerate_choicepair_list(choices)
436 else:
437 if len(self.choices) == 0:
438 self.parse_error("No entries available for input list",
439 self.lineno, self.line)
440 choicepairs = self.gen_choicepair_list()
441
442 return choicepairs
443
444 def gen_choices(self, context = None, checklist = False):
445 """
446 Generate an array of choice values corresponding to the
447 numbered list generated by gen_choices_str(), display it to
448 the user, and process the result.
449 """
450 msg = self.props["msg"]
451 if not msg:
452 self.parse_error("No input 'msg' property found",
453 self.lineno, self.line)
454
455 try:
456 default_choice = self.props["default"]
457 except KeyError:
458 default_choice = ""
459
460 msg += " [default: " + default_choice + "]"
461
462 choicepairs = self.gen_choices_list(context, checklist)
463
464 choices_str = self.gen_choices_str(choicepairs)
465 choices_val_list = self.gen_choices_val_list(choicepairs)
466 if checklist:
467 choiceval = default(find_choicevals(raw_input(msg + "\n" + choices_str), choices_val_list), default_choice)
468 else:
469 choiceval = default(find_choiceval(raw_input(msg + "\n" + choices_str), choices_val_list), default_choice)
470
471 return choiceval
472
473
474def find_choiceval(choice_str, choice_list):
475 """
476 Take number as string and return val string from choice_list,
477 empty string if oob. choice_list is a simple python list.
478 """
479 choice_val = ""
480
481 try:
482 choice_idx = int(choice_str)
483 if choice_idx <= len(choice_list):
484 choice_idx -= 1
485 choice_val = choice_list[choice_idx]
486 except ValueError:
487 pass
488
489 return choice_val
490
491
492def find_choicevals(choice_str, choice_list):
493 """
494 Take numbers as space-separated string and return vals list from
495 choice_list, empty list if oob. choice_list is a simple python
496 list.
497 """
498 choice_vals = []
499
500 choices = choice_str.split()
501 for choice in choices:
502 choice_vals.append(find_choiceval(choice, choice_list))
503
504 return choice_vals
505
506
507def default(input_str, name):
508 """
509 Return default if no input_str, otherwise stripped input_str.
510 """
511 if not input_str:
512 return name
513
514 return input_str.strip()
515
516
517def verify_git_repo(giturl):
518 """
519 Verify that the giturl passed in can be connected to. This can be
520 used as a check for the existence of the given repo and/or basic
521 git remote connectivity.
522
523 Returns True if the connection was successful, fals otherwise
524 """
525 if not giturl:
526 return False
527
528 gitcmd = "git ls-remote %s > /dev/null 2>&1" % (giturl)
529 rc = subprocess.call(gitcmd, shell=True)
530 if rc == 0:
531 return True
532
533 return False
534
535
536def get_verified_git_repo(input_str, name):
537 """
538 Return git repo if verified, otherwise loop forever asking user
539 for filename.
540 """
541 msg = input_str.strip() + " "
542
543 giturl = default(raw_input(msg), name)
544
545 while True:
546 if verify_git_repo(giturl):
547 return giturl
548 giturl = default(raw_input(msg), name)
549
550
551def get_verified_file(input_str, name, filename_can_be_null):
552 """
553 Return filename if the file exists, otherwise loop forever asking
554 user for filename.
555 """
556 msg = input_str.strip() + " "
557
558 filename = default(raw_input(msg), name)
559
560 while True:
561 if not filename and filename_can_be_null:
562 return filename
563 if os.path.isfile(filename):
564 return filename
565 filename = default(raw_input(msg), name)
566
567
568def replace_file(replace_this, with_this):
569 """
570 Replace the given file with the contents of filename, retaining
571 the original filename.
572 """
573 try:
574 replace_this.close()
575 shutil.copy(with_this, replace_this.name)
576 except IOError:
577 pass
578
579
580def boolean(input_str, name):
581 """
582 Return lowercase version of first char in string, or value in name.
583 """
584 if not input_str:
585 return name
586
587 str = input_str.lower().strip()
588 if str and str[0] == "y" or str[0] == "n":
589 return str[0]
590 else:
591 return name
592
593
594def strip_base(input_str):
595 """
596 strip '/base' off the end of input_str, so we can use 'base' in
597 the branch names we present to the user.
598 """
599 if input_str and input_str.endswith("/base"):
600 return input_str[:-len("/base")]
601 return input_str.strip()
602
603
604deferred_choices = {}
605
606def gen_choices_defer(input_line, context, checklist = False):
607 """
608 Save the context hashed the name of the input item, which will be
609 passed to the gen function later.
610 """
611 name = input_line.props["name"]
612
613 try:
614 nameappend = input_line.props["nameappend"]
615 except KeyError:
616 nameappend = ""
617
618 try:
619 branches_base = input_line.props["branches_base"]
620 except KeyError:
621 branches_base = ""
622
623 filename = input_line.props["filename"]
624
625 closetag_start = filename.find(CLOSE_TAG)
626
627 if closetag_start != -1:
628 filename = filename[closetag_start + len(CLOSE_TAG):]
629
630 filename = filename.strip()
631 filename = os.path.splitext(filename)[0]
632
633 captured_context = capture_context(context)
634 context["filename"] = filename
635 captured_context["filename"] = filename
636 context["nameappend"] = nameappend
637 captured_context["nameappend"] = nameappend
638 context["branches_base"] = branches_base
639 captured_context["branches_base"] = branches_base
640
641 deferred_choice = (input_line, captured_context, checklist)
642 key = name + "_" + filename + "_" + nameappend
643 deferred_choices[key] = deferred_choice
644
645
646def invoke_deferred_choices(name):
647 """
648 Invoke the choice generation function using the context hashed by
649 'name'.
650 """
651 deferred_choice = deferred_choices[name]
652 input_line = deferred_choice[0]
653 context = deferred_choice[1]
654 checklist = deferred_choice[2]
655
656 context["name"] = name
657
658 choices = input_line.gen_choices(context, checklist)
659
660 return choices
661
662
663class ChoicelistInputLine(ListInputLine):
664 """
665 Base class for choicelist Input lines.
666 props:
667 name: example - "xserver_choice"
668 msg: example - "Please select an xserver for this machine"
669 result:
670 Sets the value of the variable specified by 'name' to whichever Choice was chosen
671 example - xserver_choice = "xserver_vesa"
672 """
673 def __init__(self, props, tag, lineno):
674 ListInputLine.__init__(self, props, tag, lineno)
675
676 def gen(self, context = None):
677 InputLine.gen(self, context)
678
679 gen_choices_defer(self, context)
680 name = self.props["name"]
681 nameappend = context["nameappend"]
682 filename = context["filename"]
683
684 try:
685 default_choice = self.props["default"]
686 except KeyError:
687 default_choice = ""
688
689 line = name + " = default(invoke_deferred_choices(\"" + name + "_" + filename + "_" + nameappend + "\"), \"" + default_choice + "\")"
690
691 return line
692
693
694class ListValInputLine(InputLine):
695 """
696 Abstract base class for choice and checkbox Input lines.
697 """
698 def __init__(self, props, tag, lineno):
699 InputLine.__init__(self, props, tag, lineno)
700
701 try:
702 self.val = self.props["val"]
703 except KeyError:
704 self.parse_error("No input 'val' property found", self.lineno, self.line)
705
706 try:
707 self.desc = self.props["msg"]
708 except KeyError:
709 self.parse_error("No input 'msg' property found", self.lineno, self.line)
710
711
712class ChoiceInputLine(ListValInputLine):
713 """
714 Base class for choicelist item Input lines.
715 """
716 def __init__(self, props, tag, lineno):
717 ListValInputLine.__init__(self, props, tag, lineno)
718
719 def gen(self, context = None):
720 return None
721
722
723class ChecklistInputLine(ListInputLine):
724 """
725 Base class for checklist Input lines.
726 """
727 def __init__(self, props, tag, lineno):
728 ListInputLine.__init__(self, props, tag, lineno)
729
730 def gen(self, context = None):
731 InputLine.gen(self, context)
732
733 gen_choices_defer(self, context, True)
734 name = self.props["name"]
735 nameappend = context["nameappend"]
736 filename = context["filename"]
737
738 try:
739 default_choice = self.props["default"]
740 except KeyError:
741 default_choice = ""
742
743 line = name + " = default(invoke_deferred_choices(\"" + name + "_" + filename + "_" + nameappend + "\"), \"" + default_choice + "\")"
744
745 return line
746
747
748class CheckInputLine(ListValInputLine):
749 """
750 Base class for checklist item Input lines.
751 """
752 def __init__(self, props, tag, lineno):
753 ListValInputLine.__init__(self, props, tag, lineno)
754
755 def gen(self, context = None):
756 return None
757
758
759class SubstrateBase(object):
760 """
761 Base class for both expanded and unexpanded file and dir container
762 objects.
763 """
764 def __init__(self, filename, filebase, out_filebase):
765 self.filename = filename
766 self.filebase = filebase
767 self.out_filebase = out_filebase
768 self.raw_lines = []
769 self.expanded_lines = []
770 self.prev_choicelist = None
771
772 def parse_error(self, msg, lineno, line):
773 raise SyntaxError("%s: [%s: %d]: %s" % (msg, self.filename, lineno, line))
774
775 def expand_input_tag(self, tag, lineno):
776 """
777 Input tags consist of the word 'input' at the beginning,
778 followed by name:value property pairs which are converted into
779 a dictionary.
780 """
781 propstr = tag[len(INPUT_TAG):]
782
783 props = dict(prop.split(":", 1) for prop in shlex.split(propstr))
784 props["filename"] = self.filename
785
786 input_type = props[INPUT_TYPE_PROPERTY]
787 if not props[INPUT_TYPE_PROPERTY]:
788 self.parse_error("No input 'type' property found", lineno, tag)
789
790 if input_type == "boolean":
791 return BooleanInputLine(props, tag, lineno)
792 if input_type == "edit":
793 return EditBoxInputLine(props, tag, lineno)
794 if input_type == "edit-git-repo":
795 return GitRepoEditBoxInputLine(props, tag, lineno)
796 if input_type == "edit-file":
797 return FileEditBoxInputLine(props, tag, lineno)
798 elif input_type == "choicelist":
799 self.prev_choicelist = ChoicelistInputLine(props, tag, lineno)
800 return self.prev_choicelist
801 elif input_type == "choice":
802 if not self.prev_choicelist:
803 self.parse_error("Found 'choice' input tag but no previous choicelist",
804 lineno, tag)
805 choice = ChoiceInputLine(props, tag, lineno)
806 self.prev_choicelist.choices.append(choice)
807 return choice
808 elif input_type == "checklist":
809 return ChecklistInputLine(props, tag, lineno)
810 elif input_type == "check":
811 return CheckInputLine(props, tag, lineno)
812
813 def expand_assignment_tag(self, start, line, lineno):
814 """
815 Expand all tags in a line.
816 """
817 expanded_line = AssignmentLine(line.rstrip())
818
819 while start != -1:
820 end = line.find(CLOSE_TAG, start)
821 if end == -1:
822 self.parse_error("No close tag found for assignment tag", lineno, line)
823 else:
824 name = line[start + len(ASSIGN_TAG):end].strip()
825 expanded_line.add_assignment(start, end + len(CLOSE_TAG), name)
826 start = line.find(ASSIGN_TAG, end)
827
828 return expanded_line
829
830 def expand_tag(self, line, lineno):
831 """
832 Returns a processed tag line, or None if there was no tag
833
834 The rules for tags are very simple:
835 - No nested tags
836 - Tags start with {{ and end with }}
837 - An assign tag, {{=, can appear anywhere and will
838 be replaced with what the assignment evaluates to
839 - Any other tag occupies the whole line it is on
840 - if there's anything else on the tag line, it's an error
841 - if it starts with 'input', it's an input tag and
842 will only be used for prompting and setting variables
843 - anything else is straight Python
844 - tags are in effect only until the next blank line or tag or 'pass' tag
845 - we don't have indentation in tags, but we need some way to end a block
846 forcefully without blank lines or other tags - that's the 'pass' tag
847 - todo: implement pass tag
848 - directories and filenames can have tags as well, but only assignment
849 and 'if' code lines
850 - directories and filenames are the only case where normal tags can
851 coexist with normal text on the same 'line'
852 """
853 start = line.find(ASSIGN_TAG)
854 if start != -1:
855 return self.expand_assignment_tag(start, line, lineno)
856
857 start = line.find(OPEN_TAG)
858 if start == -1:
859 return None
860
861 end = line.find(CLOSE_TAG, 0)
862 if end == -1:
863 self.parse_error("No close tag found for open tag", lineno, line)
864
865 tag = line[start + len(OPEN_TAG):end].strip()
866
867 if not tag.lstrip().startswith(INPUT_TAG):
868 return CodeLine(tag)
869
870 return self.expand_input_tag(tag, lineno)
871
872 def expand_file_or_dir_name(self):
873 """
874 Expand file or dir names into codeline. Dirnames and
875 filenames can only have assignments or if statements. First
876 translate if statements into CodeLine + (dirname or filename
877 creation).
878 """
879 lineno = 0
880
881 line = self.filename[len(self.filebase):]
882 if line.startswith("/"):
883 line = line[1:]
884 opentag_start = -1
885
886 start = line.find(OPEN_TAG)
887 while start != -1:
888 if not line[start:].startswith(ASSIGN_TAG):
889 opentag_start = start
890 break
891 start += len(ASSIGN_TAG)
892 start = line.find(OPEN_TAG, start)
893
894 if opentag_start != -1:
895 end = line.find(CLOSE_TAG, opentag_start)
896 if end == -1:
897 self.parse_error("No close tag found for open tag", lineno, line)
898 # we have a {{ tag i.e. code
899 tag = line[opentag_start + len(OPEN_TAG):end].strip()
900
901 if not tag.lstrip().startswith(IF_TAG):
902 self.parse_error("Only 'if' tags are allowed in file or directory names",
903 lineno, line)
904 self.expanded_lines.append(CodeLine(tag))
905
906 # everything after }} is the actual filename (possibly with assignments)
907 # everything before is the pathname
908 line = line[:opentag_start] + line[end + len(CLOSE_TAG):].strip()
909
910 assign_start = line.find(ASSIGN_TAG)
911 if assign_start != -1:
912 assignment_tag = self.expand_assignment_tag(assign_start, line, lineno)
913 if isinstance(self, SubstrateFile):
914 assignment_tag.is_filename = True
915 assignment_tag.out_filebase = self.out_filebase
916 elif isinstance(self, SubstrateDir):
917 assignment_tag.is_dirname = True
918 assignment_tag.out_filebase = self.out_filebase
919 self.expanded_lines.append(assignment_tag)
920 return
921
922 normal_line = NormalLine(line)
923 if isinstance(self, SubstrateFile):
924 normal_line.is_filename = True
925 normal_line.out_filebase = self.out_filebase
926 elif isinstance(self, SubstrateDir):
927 normal_line.is_dirname = True
928 normal_line.out_filebase = self.out_filebase
929 self.expanded_lines.append(normal_line)
930
931 def expand(self):
932 """
933 Expand the file or dir name first, eventually this ends up
934 creating the file or dir.
935 """
936 self.expand_file_or_dir_name()
937
938
939class SubstrateFile(SubstrateBase):
940 """
941 Container for both expanded and unexpanded substrate files.
942 """
943 def __init__(self, filename, filebase, out_filebase):
944 SubstrateBase.__init__(self, filename, filebase, out_filebase)
945
946 def read(self):
947 if self.raw_lines:
948 return
949 f = open(self.filename)
950 self.raw_lines = f.readlines()
951
952 def expand(self):
953 """Expand the contents of all template tags in the file."""
954 SubstrateBase.expand(self)
955 self.read()
956
957 for lineno, line in enumerate(self.raw_lines):
958 expanded_line = self.expand_tag(line, lineno + 1) # humans not 0-based
959 if not expanded_line:
960 expanded_line = NormalLine(line.rstrip())
961 self.expanded_lines.append(expanded_line)
962
963 def gen(self, context = None):
964 """Generate the code that generates the BSP."""
965 base_indent = 0
966
967 indent = new_indent = base_indent
968
969 for line in self.expanded_lines:
970 genline = line.gen(context)
971 if not genline:
972 continue
973 if isinstance(line, InputLine):
974 line.generated_line = genline
975 continue
976 if genline.startswith(OPEN_START):
977 if indent == 1:
978 base_indent = 1
979 if indent:
980 if genline == BLANKLINE_STR or (not genline.startswith(NORMAL_START)
981 and not genline.startswith(OPEN_START)):
982 indent = new_indent = base_indent
983 if genline.endswith(":"):
984 new_indent = base_indent + 1
985 line.generated_line = (indent * INDENT_STR) + genline
986 indent = new_indent
987
988
989class SubstrateDir(SubstrateBase):
990 """
991 Container for both expanded and unexpanded substrate dirs.
992 """
993 def __init__(self, filename, filebase, out_filebase):
994 SubstrateBase.__init__(self, filename, filebase, out_filebase)
995
996 def expand(self):
997 SubstrateBase.expand(self)
998
999 def gen(self, context = None):
1000 """Generate the code that generates the BSP."""
1001 indent = new_indent = 0
1002 for line in self.expanded_lines:
1003 genline = line.gen(context)
1004 if not genline:
1005 continue
1006 if genline.endswith(":"):
1007 new_indent = 1
1008 else:
1009 new_indent = 0
1010 line.generated_line = (indent * INDENT_STR) + genline
1011 indent = new_indent
1012
1013
1014def expand_target(target, all_files, out_filebase):
1015 """
1016 Expand the contents of all template tags in the target. This
1017 means removing tags and categorizing or creating lines so that
1018 future passes can process and present input lines and generate the
1019 corresponding lines of the Python program that will be exec'ed to
1020 actually produce the final BSP. 'all_files' includes directories.
1021 """
1022 for root, dirs, files in os.walk(target):
1023 for file in files:
1024 if file.endswith("~") or file.endswith("#"):
1025 continue
1026 f = os.path.join(root, file)
1027 sfile = SubstrateFile(f, target, out_filebase)
1028 sfile.expand()
1029 all_files.append(sfile)
1030
1031 for dir in dirs:
1032 d = os.path.join(root, dir)
1033 sdir = SubstrateDir(d, target, out_filebase)
1034 sdir.expand()
1035 all_files.append(sdir)
1036
1037
1038def gen_program_machine_lines(machine, program_lines):
1039 """
1040 Use the input values we got from the command line.
1041 """
1042 line = "machine = \"" + machine + "\""
1043 program_lines.append(line)
1044
1045 line = "layer_name = \"" + machine + "\""
1046 program_lines.append(line)
1047
1048
1049def sort_inputlines(input_lines):
1050 """Sort input lines according to priority (position)."""
1051 input_lines.sort(key = lambda l: l.prio)
1052
1053
1054def find_parent_dependency(lines, depends_on):
1055 for i, line in lines:
1056 if isinstance(line, CodeLine):
1057 continue
1058 if line.props["name"] == depends_on:
1059 return i
1060
1061 return -1
1062
1063
1064def process_inputline_dependencies(input_lines, all_inputlines):
1065 """If any input lines depend on others, put the others first."""
1066 for line in input_lines:
1067 if isinstance(line, InputLineGroup):
1068 group_inputlines = []
1069 process_inputline_dependencies(line.group, group_inputlines)
1070 line.group = group_inputlines
1071 all_inputlines.append(line)
1072 continue
1073
1074 if isinstance(line, CodeLine) or isinstance(line, NormalLine):
1075 all_inputlines.append(line)
1076 continue
1077
1078 try:
1079 depends_on = line.props["depends-on"]
1080 depends_codeline = "if " + line.props["depends-on"] + " == \"" + line.props["depends-on-val"] + "\":"
1081 all_inputlines.append(CodeLine(depends_codeline))
1082 all_inputlines.append(line)
1083 except KeyError:
1084 all_inputlines.append(line)
1085
1086
1087def conditional_filename(filename):
1088 """
1089 Check if the filename itself contains a conditional statement. If
1090 so, return a codeline for it.
1091 """
1092 opentag_start = filename.find(OPEN_TAG)
1093
1094 if opentag_start != -1:
1095 if filename[opentag_start:].startswith(ASSIGN_TAG):
1096 return None
1097 end = filename.find(CLOSE_TAG, opentag_start)
1098 if end == -1:
1099 print "No close tag found for open tag in filename %s" % filename
1100 sys.exit(1)
1101
1102 # we have a {{ tag i.e. code
1103 tag = filename[opentag_start + len(OPEN_TAG):end].strip()
1104 if not tag.lstrip().startswith(IF_TAG):
1105 print "Only 'if' tags are allowed in file or directory names, filename: %s" % filename
1106 sys.exit(1)
1107
1108 return CodeLine(tag)
1109
1110 return None
1111
1112
1113class InputLineGroup(InputLine):
1114 """
1115 InputLine that does nothing but group other input lines
1116 corresponding to all the input lines in a SubstrateFile so they
1117 can be generated as a group. prio is the only property used.
1118 """
1119 def __init__(self, codeline):
1120 InputLine.__init__(self, {}, "", 0)
1121 self.group = []
1122 self.prio = sys.maxint
1123 self.group.append(codeline)
1124
1125 def append(self, line):
1126 self.group.append(line)
1127 if line.prio < self.prio:
1128 self.prio = line.prio
1129
1130 def len(self):
1131 return len(self.group)
1132
1133
1134def gather_inputlines(files):
1135 """
1136 Gather all the InputLines - we want to generate them first.
1137 """
1138 all_inputlines = []
1139 input_lines = []
1140
1141 for file in files:
1142 if isinstance(file, SubstrateFile):
1143 group = None
1144 basename = os.path.basename(file.filename)
1145
1146 codeline = conditional_filename(basename)
1147 if codeline:
1148 group = InputLineGroup(codeline)
1149
1150 have_condition = False
1151 condition_to_write = None
1152 for line in file.expanded_lines:
1153 if isinstance(line, CodeLine):
1154 have_condition = True
1155 condition_to_write = line
1156 continue
1157 if isinstance(line, InputLine):
1158 if group:
1159 if condition_to_write:
1160 condition_to_write.prio = line.prio
1161 condition_to_write.discard = True
1162 group.append(condition_to_write)
1163 condition_to_write = None
1164 group.append(line)
1165 else:
1166 if condition_to_write:
1167 condition_to_write.prio = line.prio
1168 condition_to_write.discard = True
1169 input_lines.append(condition_to_write)
1170 condition_to_write = None
1171 input_lines.append(line)
1172 else:
1173 if condition_to_write:
1174 condition_to_write = None
1175 if have_condition:
1176 if not line.line.strip():
1177 line.discard = True
1178 input_lines.append(line)
1179 have_condition = False
1180
1181 if group and group.len() > 1:
1182 input_lines.append(group)
1183
1184 sort_inputlines(input_lines)
1185 process_inputline_dependencies(input_lines, all_inputlines)
1186
1187 return all_inputlines
1188
1189
1190def run_program_lines(linelist, codedump):
1191 """
1192 For a single file, print all the python code into a buf and execute it.
1193 """
1194 buf = "\n".join(linelist)
1195
1196 if codedump:
1197 of = open("bspgen.out", "w")
1198 of.write(buf)
1199 of.close()
1200 exec buf
1201
1202
1203def gen_target(files, context = None):
1204 """
1205 Generate the python code for each file.
1206 """
1207 for file in files:
1208 file.gen(context)
1209
1210
1211def gen_program_header_lines(program_lines):
1212 """
1213 Generate any imports we need.
1214 """
1215 program_lines.append("current_file = \"\"")
1216
1217
1218def gen_supplied_property_vals(properties, program_lines):
1219 """
1220 Generate user-specified entries for input values instead of
1221 generating input prompts.
1222 """
1223 for name, val in properties.iteritems():
1224 program_line = name + " = \"" + val + "\""
1225 program_lines.append(program_line)
1226
1227
1228def gen_initial_property_vals(input_lines, program_lines):
1229 """
1230 Generate null or default entries for input values, so we don't
1231 have undefined variables.
1232 """
1233 for line in input_lines:
1234 if isinstance(line, InputLineGroup):
1235 gen_initial_property_vals(line.group, program_lines)
1236 continue
1237
1238 if isinstance(line, InputLine):
1239 try:
1240 name = line.props["name"]
1241 try:
1242 default_val = "\"" + line.props["default"] + "\""
1243 except:
1244 default_val = "\"\""
1245 program_line = name + " = " + default_val
1246 program_lines.append(program_line)
1247 except KeyError:
1248 pass
1249
1250
1251def gen_program_input_lines(input_lines, program_lines, context, in_group = False):
1252 """
1253 Generate only the input lines used for prompting the user. For
1254 that, we only have input lines and CodeLines that affect the next
1255 input line.
1256 """
1257 indent = new_indent = 0
1258
1259 for line in input_lines:
1260 if isinstance(line, InputLineGroup):
1261 gen_program_input_lines(line.group, program_lines, context, True)
1262 continue
1263 if not line.line.strip():
1264 continue
1265
1266 genline = line.gen(context)
1267 if not genline:
1268 continue
1269 if genline.endswith(":"):
1270 new_indent += 1
1271 else:
1272 if indent > 1 or (not in_group and indent):
1273 new_indent -= 1
1274
1275 line.generated_line = (indent * INDENT_STR) + genline
1276 program_lines.append(line.generated_line)
1277
1278 indent = new_indent
1279
1280
1281def gen_program_lines(target_files, program_lines):
1282 """
1283 Generate the program lines that make up the BSP generation
1284 program. This appends the generated lines of all target_files to
1285 program_lines, and skips input lines, which are dealt with
1286 separately, or omitted.
1287 """
1288 for file in target_files:
1289 if file.filename.endswith("noinstall"):
1290 continue
1291
1292 for line in file.expanded_lines:
1293 if isinstance(line, InputLine):
1294 continue
1295 if line.discard:
1296 continue
1297
1298 program_lines.append(line.generated_line)
1299
1300
1301def create_context(machine, arch, scripts_path):
1302 """
1303 Create a context object for use in deferred function invocation.
1304 """
1305 context = {}
1306
1307 context["machine"] = machine
1308 context["arch"] = arch
1309 context["scripts_path"] = scripts_path
1310
1311 return context
1312
1313
1314def capture_context(context):
1315 """
1316 Create a context object for use in deferred function invocation.
1317 """
1318 captured_context = {}
1319
1320 captured_context["machine"] = context["machine"]
1321 captured_context["arch"] = context["arch"]
1322 captured_context["scripts_path"] = context["scripts_path"]
1323
1324 return captured_context
1325
1326
1327def expand_targets(context, bsp_output_dir, expand_common=True):
1328 """
1329 Expand all the tags in both the common and machine-specific
1330 'targets'.
1331
1332 If expand_common is False, don't expand the common target (this
1333 option is used to create special-purpose layers).
1334 """
1335 target_files = []
1336
1337 machine = context["machine"]
1338 arch = context["arch"]
1339 scripts_path = context["scripts_path"]
1340
1341 lib_path = scripts_path + '/lib'
1342 bsp_path = lib_path + '/bsp'
1343 arch_path = bsp_path + '/substrate/target/arch'
1344
1345 if expand_common:
1346 common = os.path.join(arch_path, "common")
1347 expand_target(common, target_files, bsp_output_dir)
1348
1349 arches = os.listdir(arch_path)
1350 if arch not in arches or arch == "common":
1351 print "Invalid karch, exiting\n"
1352 sys.exit(1)
1353
1354 target = os.path.join(arch_path, arch)
1355 expand_target(target, target_files, bsp_output_dir)
1356
1357 gen_target(target_files, context)
1358
1359 return target_files
1360
1361
1362def yocto_common_create(machine, target, scripts_path, layer_output_dir, codedump, properties_file, properties_str="", expand_common=True):
1363 """
1364 Common layer-creation code
1365
1366 machine - user-defined machine name (if needed, will generate 'machine' var)
1367 target - the 'target' the layer will be based on, must be one in
1368 scripts/lib/bsp/substrate/target/arch
1369 scripts_path - absolute path to yocto /scripts dir
1370 layer_output_dir - dirname to create for layer
1371 codedump - dump generated code to bspgen.out
1372 properties_file - use values from this file if nonempty i.e no prompting
1373 properties_str - use values from this string if nonempty i.e no prompting
1374 expand_common - boolean, use the contents of (for bsp layers) arch/common
1375 """
1376 if os.path.exists(layer_output_dir):
1377 print "\nlayer output dir already exists, exiting. (%s)" % layer_output_dir
1378 sys.exit(1)
1379
1380 properties = None
1381
1382 if properties_file:
1383 try:
1384 infile = open(properties_file, "r")
1385 except IOError:
1386 print "Couldn't open properties file %s for reading, exiting" % properties_file
1387 sys.exit(1)
1388
1389 properties = json.load(infile)
1390
1391 if properties_str and not properties:
1392 properties = json.loads(properties_str)
1393
1394 os.mkdir(layer_output_dir)
1395
1396 context = create_context(machine, target, scripts_path)
1397 target_files = expand_targets(context, layer_output_dir, expand_common)
1398
1399 input_lines = gather_inputlines(target_files)
1400
1401 program_lines = []
1402
1403 gen_program_header_lines(program_lines)
1404
1405 gen_initial_property_vals(input_lines, program_lines)
1406
1407 if properties:
1408 gen_supplied_property_vals(properties, program_lines)
1409
1410 gen_program_machine_lines(machine, program_lines)
1411
1412 if not properties:
1413 gen_program_input_lines(input_lines, program_lines, context)
1414
1415 gen_program_lines(target_files, program_lines)
1416
1417 run_program_lines(program_lines, codedump)
1418
1419
1420def yocto_layer_create(layer_name, scripts_path, layer_output_dir, codedump, properties_file, properties=""):
1421 """
1422 Create yocto layer
1423
1424 layer_name - user-defined layer name
1425 scripts_path - absolute path to yocto /scripts dir
1426 layer_output_dir - dirname to create for layer
1427 codedump - dump generated code to bspgen.out
1428 properties_file - use values from this file if nonempty i.e no prompting
1429 properties - use values from this string if nonempty i.e no prompting
1430 """
1431 yocto_common_create(layer_name, "layer", scripts_path, layer_output_dir, codedump, properties_file, properties, False)
1432
1433 print "\nNew layer created in %s.\n" % (layer_output_dir)
1434 print "Don't forget to add it to your BBLAYERS (for details see %s\README)." % (layer_output_dir)
1435
1436
1437def yocto_bsp_create(machine, arch, scripts_path, bsp_output_dir, codedump, properties_file, properties=None):
1438 """
1439 Create bsp
1440
1441 machine - user-defined machine name
1442 arch - the arch the bsp will be based on, must be one in
1443 scripts/lib/bsp/substrate/target/arch
1444 scripts_path - absolute path to yocto /scripts dir
1445 bsp_output_dir - dirname to create for BSP
1446 codedump - dump generated code to bspgen.out
1447 properties_file - use values from this file if nonempty i.e no prompting
1448 properties - use values from this string if nonempty i.e no prompting
1449 """
1450 yocto_common_create(machine, arch, scripts_path, bsp_output_dir, codedump, properties_file, properties)
1451
1452 print "\nNew %s BSP created in %s" % (arch, bsp_output_dir)
1453
1454
1455def print_dict(items, indent = 0):
1456 """
1457 Print the values in a possibly nested dictionary.
1458 """
1459 for key, val in items.iteritems():
1460 print " "*indent + "\"%s\" :" % key,
1461 if type(val) == dict:
1462 print "{"
1463 print_dict(val, indent + 1)
1464 print " "*indent + "}"
1465 else:
1466 print "%s" % val
1467
1468
1469def get_properties(input_lines):
1470 """
1471 Get the complete set of properties for all the input items in the
1472 BSP, as a possibly nested dictionary.
1473 """
1474 properties = {}
1475
1476 for line in input_lines:
1477 if isinstance(line, InputLineGroup):
1478 statement = line.group[0].line
1479 group_properties = get_properties(line.group)
1480 properties[statement] = group_properties
1481 continue
1482
1483 if not isinstance(line, InputLine):
1484 continue
1485
1486 if isinstance(line, ChoiceInputLine):
1487 continue
1488
1489 props = line.props
1490 item = {}
1491 name = props["name"]
1492 for key, val in props.items():
1493 if not key == "name":
1494 item[key] = val
1495 properties[name] = item
1496
1497 return properties
1498
1499
1500def yocto_layer_list_properties(arch, scripts_path, properties_file, expand_common=True):
1501 """
1502 List the complete set of properties for all the input items in the
1503 layer. If properties_file is non-null, write the complete set of
1504 properties as a nested JSON object corresponding to a possibly
1505 nested dictionary.
1506 """
1507 context = create_context("unused", arch, scripts_path)
1508 target_files = expand_targets(context, "unused", expand_common)
1509
1510 input_lines = gather_inputlines(target_files)
1511
1512 properties = get_properties(input_lines)
1513 if properties_file:
1514 try:
1515 of = open(properties_file, "w")
1516 except IOError:
1517 print "Couldn't open properties file %s for writing, exiting" % properties_file
1518 sys.exit(1)
1519
1520 json.dump(properties, of)
1521
1522 print_dict(properties)
1523
1524
1525def split_nested_property(property):
1526 """
1527 A property name of the form x.y describes a nested property
1528 i.e. the property y is contained within x and can be addressed
1529 using standard JSON syntax for nested properties. Note that if a
1530 property name itself contains '.', it should be contained in
1531 double quotes.
1532 """
1533 splittable_property = ""
1534 in_quotes = False
1535 for c in property:
1536 if c == '.' and not in_quotes:
1537 splittable_property += '\n'
1538 continue
1539 if c == '"':
1540 in_quotes = not in_quotes
1541 splittable_property += c
1542
1543 split_properties = splittable_property.split('\n')
1544
1545 if len(split_properties) > 1:
1546 return split_properties
1547
1548 return None
1549
1550
1551def find_input_line_group(substring, input_lines):
1552 """
1553 Find and return the InputLineGroup containing the specified substring.
1554 """
1555 for line in input_lines:
1556 if isinstance(line, InputLineGroup):
1557 if substring in line.group[0].line:
1558 return line
1559
1560 return None
1561
1562
1563def find_input_line(name, input_lines):
1564 """
1565 Find the input line with the specified name.
1566 """
1567 for line in input_lines:
1568 if isinstance(line, InputLineGroup):
1569 l = find_input_line(name, line.group)
1570 if l:
1571 return l
1572
1573 if isinstance(line, InputLine):
1574 try:
1575 if line.props["name"] == name:
1576 return line
1577 if line.props["name"] + "_" + line.props["nameappend"] == name:
1578 return line
1579 except KeyError:
1580 pass
1581
1582 return None
1583
1584
1585def print_values(type, values_list):
1586 """
1587 Print the values in the given list of values.
1588 """
1589 if type == "choicelist":
1590 for value in values_list:
1591 print "[\"%s\", \"%s\"]" % (value[0], value[1])
1592 elif type == "boolean":
1593 for value in values_list:
1594 print "[\"%s\", \"%s\"]" % (value[0], value[1])
1595
1596
1597def yocto_layer_list_property_values(arch, property, scripts_path, properties_file, expand_common=True):
1598 """
1599 List the possible values for a given input property. If
1600 properties_file is non-null, write the complete set of properties
1601 as a JSON object corresponding to an array of possible values.
1602 """
1603 context = create_context("unused", arch, scripts_path)
1604 context["name"] = property
1605
1606 target_files = expand_targets(context, "unused", expand_common)
1607
1608 input_lines = gather_inputlines(target_files)
1609
1610 properties = get_properties(input_lines)
1611
1612 nested_properties = split_nested_property(property)
1613 if nested_properties:
1614 # currently the outer property of a nested property always
1615 # corresponds to an input line group
1616 input_line_group = find_input_line_group(nested_properties[0], input_lines)
1617 if input_line_group:
1618 input_lines[:] = input_line_group.group[1:]
1619 # The inner property of a nested property name is the
1620 # actual property name we want, so reset to that
1621 property = nested_properties[1]
1622
1623 input_line = find_input_line(property, input_lines)
1624 if not input_line:
1625 print "Couldn't find values for property %s" % property
1626 return
1627
1628 values_list = []
1629
1630 type = input_line.props["type"]
1631 if type == "boolean":
1632 values_list.append(["y", "n"])
1633 elif type == "choicelist" or type == "checklist":
1634 try:
1635 gen_fn = input_line.props["gen"]
1636 if nested_properties:
1637 context["filename"] = nested_properties[0]
1638 try:
1639 context["branches_base"] = input_line.props["branches_base"]
1640 except KeyError:
1641 context["branches_base"] = None
1642 values_list = input_line.gen_choices_list(context, False)
1643 except KeyError:
1644 for choice in input_line.choices:
1645 choicepair = []
1646 choicepair.append(choice.val)
1647 choicepair.append(choice.desc)
1648 values_list.append(choicepair)
1649
1650 if properties_file:
1651 try:
1652 of = open(properties_file, "w")
1653 except IOError:
1654 print "Couldn't open properties file %s for writing, exiting" % properties_file
1655 sys.exit(1)
1656
1657 json.dump(values_list, of)
1658
1659 print_values(type, values_list)
1660
1661
1662def yocto_bsp_list(args, scripts_path, properties_file):
1663 """
1664 Print available architectures, or the complete list of properties
1665 defined by the BSP, or the possible values for a particular BSP
1666 property.
1667 """
1668 if len(args) < 1:
1669 return False
1670
1671 if args[0] == "karch":
1672 lib_path = scripts_path + '/lib'
1673 bsp_path = lib_path + '/bsp'
1674 arch_path = bsp_path + '/substrate/target/arch'
1675 print "Architectures available:"
1676 for arch in os.listdir(arch_path):
1677 if arch == "common" or arch == "layer":
1678 continue
1679 print " %s" % arch
1680 return True
1681 else:
1682 arch = args[0]
1683
1684 if len(args) < 2 or len(args) > 3:
1685 return False
1686
1687 if len(args) == 2:
1688 if args[1] == "properties":
1689 yocto_layer_list_properties(arch, scripts_path, properties_file)
1690 else:
1691 return False
1692
1693 if len(args) == 3:
1694 if args[1] == "property":
1695 yocto_layer_list_property_values(arch, args[2], scripts_path, properties_file)
1696 else:
1697 return False
1698
1699 return True
1700
1701
1702def yocto_layer_list(args, scripts_path, properties_file):
1703 """
1704 Print the complete list of input properties defined by the layer,
1705 or the possible values for a particular layer property.
1706 """
1707 if len(args) < 1:
1708 return False
1709
1710 if len(args) < 1 or len(args) > 2:
1711 return False
1712
1713 if len(args) == 1:
1714 if args[0] == "properties":
1715 yocto_layer_list_properties("layer", scripts_path, properties_file, False)
1716 else:
1717 return False
1718
1719 if len(args) == 2:
1720 if args[0] == "property":
1721 yocto_layer_list_property_values("layer", args[1], scripts_path, properties_file, False)
1722 else:
1723 return False
1724
1725 return True
1726
1727
1728def map_standard_kbranch(need_new_kbranch, new_kbranch, existing_kbranch):
1729 """
1730 Return the linux-yocto bsp branch to use with the specified
1731 kbranch. This handles the -standard variants for 3.4 and 3.8; the
1732 other variants don't need mappings.
1733 """
1734 if need_new_kbranch == "y":
1735 kbranch = new_kbranch
1736 else:
1737 kbranch = existing_kbranch
1738
1739 if kbranch.startswith("standard/common-pc-64"):
1740 return "bsp/common-pc-64/common-pc-64-standard.scc"
1741 if kbranch.startswith("standard/common-pc"):
1742 return "bsp/common-pc/common-pc-standard.scc"
1743 else:
1744 return "ktypes/standard/standard.scc"
1745
1746
1747def map_preempt_rt_kbranch(need_new_kbranch, new_kbranch, existing_kbranch):
1748 """
1749 Return the linux-yocto bsp branch to use with the specified
1750 kbranch. This handles the -preempt-rt variants for 3.4 and 3.8;
1751 the other variants don't need mappings.
1752 """
1753 if need_new_kbranch == "y":
1754 kbranch = new_kbranch
1755 else:
1756 kbranch = existing_kbranch
1757
1758 if kbranch.startswith("standard/preempt-rt/common-pc-64"):
1759 return "bsp/common-pc-64/common-pc-64-preempt-rt.scc"
1760 if kbranch.startswith("standard/preempt-rt/common-pc"):
1761 return "bsp/common-pc/common-pc-preempt-rt.scc"
1762 else:
1763 return "ktypes/preempt-rt/preempt-rt.scc"
1764
1765
1766def map_tiny_kbranch(need_new_kbranch, new_kbranch, existing_kbranch):
1767 """
1768 Return the linux-yocto bsp branch to use with the specified
1769 kbranch. This handles the -tiny variants for 3.4 and 3.8; the
1770 other variants don't need mappings.
1771 """
1772 if need_new_kbranch == "y":
1773 kbranch = new_kbranch
1774 else:
1775 kbranch = existing_kbranch
1776
1777 if kbranch.startswith("standard/tiny/common-pc"):
1778 return "bsp/common-pc/common-pc-tiny.scc"
1779 else:
1780 return "ktypes/tiny/tiny.scc"