[yocto] [PATCH 3/8] yocto-bsp: add templating engine

Tom Zanussi tom.zanussi at intel.com
Fri Mar 2 09:22:34 PST 2012


On Fri, 2012-03-02 at 08:57 -0800, Darren Hart wrote:
> 
> On 03/01/2012 11:01 PM, tom.zanussi at intel.com wrote:
> > From: Tom Zanussi <tom.zanussi at intel.com>
> > 
> > The main implementation of the Yocto BSP templating engine,
> > essentially containing the internal implementation of the 'yocto-bsp
> > create' and yocto-bsp list' commands.
> > 
> > Signed-off-by: Tom Zanussi <tom.zanussi at intel.com>
> > ---
> >  scripts/lib/bsp/engine.py | 1336 +++++++++++++++++++++++++++++++++++++++++++++
> >  1 files changed, 1336 insertions(+), 0 deletions(-)
> >  create mode 100644 scripts/lib/bsp/engine.py
> > 
> > diff --git a/scripts/lib/bsp/engine.py b/scripts/lib/bsp/engine.py
> > new file mode 100644
> > index 0000000..7bf3e92
> > --- /dev/null
> > +++ b/scripts/lib/bsp/engine.py
> > @@ -0,0 +1,1336 @@
> > +# ex:ts=4:sw=4:sts=4:et
> > +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
> > +#
> > +# Copyright 2012 Intel Corporation
> > +# Authored-by:  Tom Zanussi <tom.zanussi at intel.com>
> 
> same comments here...
> 
> > +#
> > +# This program is free software; you can redistribute it and/or modify
> > +# it under the terms of the GNU General Public License version 2 as
> > +# published by the Free Software Foundation.
> > +#
> > +# This program is distributed in the hope that it will be useful,
> > +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > +# GNU General Public License for more details.
> > +#
> > +# You should have received a copy of the GNU General Public License along
> > +# with this program; if not, write to the Free Software Foundation, Inc.,
> > +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> > +
> > +import os
> > +import sys
> > +from abc import ABCMeta, abstractmethod
> > +from tags import *
> > +import shlex
> > +import json
> > +
> 
> 
> This looks like a healthy list of dependencies. Do we need to augment
> the required packages list?
> 

This is all standard Python 2.6 stuff, so nothing special needed if we
have Python.

> 
> > +class Line():
> > +    """
> > +    Generic (abstract) container representing a line that will appear
> > +    in the BSP-generating program.
> > +    """
> > +    __metaclass__ = ABCMeta
> 
> Oh, I didn't know about that. My ABCs have been rather amateur by
> comparison. Nice.
> 
> > +
> > +    def __init__(self, line):
> > +        self.line = line
> > +        self.generated_line = ""
> > +
> > +    @abstractmethod
> > +    def gen(self, context = None):
> > +        """
> > +        Generate the final executable line that will appear in the
> > +        BSP-generation program.
> > +        """
> > +        pass
> > +
> > +    def escape(self, line):
> > +        """
> > +        Escape single and double quotes and backslashes until I find
> > +        something better (re.escape() escapes way too much)
> > +        """
> > +        return line.replace("\\", "\\\\").replace("\"", "\\\"").replace("'", "\\'")
> > +
> > +    def parse_error(self, msg, lineno, line):
> > +         raise SyntaxError("%s: %s" % (msg, line))
> > +
> 
> 
> Very nicely pythonic Tom. Classes, PyDoc, decorators, exceptions. Nice work!
> 

Heh, thanks, and then we have isinstance() everywhere, which is not.
Need to fix that.  ;-)

> > +
> > +class NormalLine(Line):
> > +    """
> > +    Container for normal (non-tag) lines.
> > +    """
> > +    def __init__(self, line):
> > +        Line.__init__(self, line)
> > +        self.is_filename = False
> > +        self.is_dirname = False
> > +        self.out_filebase = None
> > +
> > +    def gen(self, context = None):
> > +        if self.is_filename:
> > +            line = "of = open(\"" + os.path.join(self.out_filebase, self.escape(self.line)) + "\", \"w\")"
> > +        elif self.is_dirname:
> > +            dirname = os.path.join(self.out_filebase, self.escape(self.line))
> > +            line = "if not os.path.exists(\"" + dirname + "\"): os.mkdir(\"" + dirname + "\")"
> > +        else:
> > +            line = "of.write(\"" + self.escape(self.line) + "\\n\")"
> > +        return line
> > +
> > +
> > +class CodeLine(Line):
> > +    """
> > +    Container for Python code tag lines.
> > +    """
> > +    def __init__(self, line):
> > +        Line.__init__(self, line)
> > +
> > +    def gen(self, context = None):
> > +        return self.line
> > +
> > +
> > +class Assignment:
> > +    """
> > +    Representation of everything we know about {{=name }} tags.
> > +    Instances of these are used by Assignment lines.
> > +    """
> > +    def __init__(self, start, end, name):
> > +        self.start = start
> > +        self.end = end
> > +        self.name = name
> > +
> > +
> > +class AssignmentLine(NormalLine):
> > +    """
> > +    Container for normal lines containing assignment tags.  Assignment
> > +    tags must be in ascending order of 'start' value.
> > +    """
> > +    def __init__(self, line):
> > +        NormalLine.__init__(self, line)
> > +        self.assignments = []
> > +
> > +    def add_assignment(self, start, end, name):
> > +        self.assignments.append(Assignment(start, end, name))
> > +
> > +    def gen(self, context = None):
> > +        line = self.escape(self.line)
> > +
> > +        for assignment in self.assignments:
> > +            replacement = "\" + " + assignment.name + " + \""
> > +            idx = line.find(ASSIGN_TAG)
> > +            line = line[:idx] + replacement + line[idx + assignment.end - assignment.start:]
> > +        if self.is_filename:
> > +            return "of = open(\"" + os.path.join(self.out_filebase, line) + "\", \"w\")"
> > +        elif self.is_dirname:
> > +            dirname = os.path.join(self.out_filebase, line)
> > +            return "if not os.path.exists(\"" + dirname + "\"): os.mkdir(\"" + dirname + "\")"
> > +        else:
> > +            return "of.write(\"" + line + "\\n\")"
> > +
> > +
> > +class InputLine(Line):
> > +    """
> > +    Base class for Input lines.
> > +    """
> > +    def __init__(self, props, tag, lineno):
> > +        Line.__init__(self, tag)
> > +        self.props = props
> > +        self.lineno = lineno
> > +
> > +        try:
> > +            self.prio = int(props["prio"])
> > +        except KeyError:
> > +            self.prio = sys.maxint
> > +
> > +    def gen(self, context = None):
> > +        try:
> > +            depends_on = self.props["depends-on"]
> > +            try:
> > +                depends_on_val = self.props["depends-on-val"]
> > +            except KeyError:
> > +                self.parse_error("No 'depends-on-val' for 'depends-on' property",
> > +                                 self.lineno, self.line)
> > +        except KeyError:
> > +            pass
> > +
> > +
> > +class EditBoxInputLine(InputLine):
> > +    """
> > +    Base class for 'editbox' Input lines.
> > +
> > +    props:
> > +        name: example - "Load address"
> > +        msg: example - "Please enter the load address"
> > +    result:
> > +        Sets the value of the variable specified by 'name' to
> > +        whatever the user typed.
> > +    """
> > +    def __init__(self, props, tag, lineno):
> > +        InputLine.__init__(self, props, tag, lineno)
> > +
> > +    def query_user(self):
> > +        msg = self.props["name"]
> > +        if not msg:
> > +            self.parse_error("No input 'msg' property found",
> > +                             self.lineno, self.line)
> > +
> > +        return self.show_prompt(msg)
> > +
> > +    def gen(self, context = None):
> > +        InputLine.gen(self, context)
> > +        name = self.props["name"]
> > +        if not name:
> > +            self.parse_error("No input 'name' property found",
> > +                             self.lineno, self.line)
> > +        msg = self.props["msg"]
> > +        if not msg:
> > +            self.parse_error("No input 'msg' property found",
> > +                             self.lineno, self.line)
> > +
> > +        line = name + " = default(raw_input(" + msg + " ), " + name + ")"
> > +
> > +        return line
> > +
> > +
> > +class BooleanInputLine(InputLine):
> > +    """
> > +    Base class for boolean Input lines.
> > +    props:
> > +        name: example - "keyboard"
> > +        msg:  example - "Got keyboard?"
> > +    result:
> > +        Sets the value of the variable specified by 'name' to "yes" or "no"
> > +        example - keyboard = "yes"
> > +    """
> > +    def __init__(self, props, tag, lineno):
> > +        InputLine.__init__(self, props, tag, lineno)
> > +
> > +    def query_user(self):
> > +        msg = self.props["name"]
> > +        if not msg:
> > +            self.parse_error("No input 'msg' property found",
> > +                             self.lineno, self.line)
> > +
> > +        return self.show_prompt(msg)
> > +
> > +    def gen(self, context = None):
> > +        InputLine.gen(self, context)
> > +        name = self.props["name"]
> > +        if not name:
> > +            self.parse_error("No input 'name' property found",
> > +                             self.lineno, self.line)
> > +        msg = self.props["msg"]
> > +        if not msg:
> > +            self.parse_error("No input 'msg' property found",
> > +                             self.lineno, self.line)
> > +
> > +        line = name + " = boolean(raw_input(\"" + msg + " \"), " + name + ")"
> > +
> > +        return line
> > +
> > +
> > +class ListInputLine(InputLine):
> > +    """
> > +    Base class for List-based Input lines. e.g. Choicelist, Checklist
> > +    """
> > +    __metaclass__ = ABCMeta
> > +
> > +    def __init__(self, props, tag, lineno):
> > +        InputLine.__init__(self, props, tag, lineno)
> > +        self.choices = []
> > +
> > +    def gen_choicepair_list(self):
> > +        """generate a list of 2-item val:desc lists from self.choices"""
> 
> Nitpic, initial caps and period.
> 
> > +        if not self.choices:
> > +            return None
> > +
> > +        choicepair_list = list()
> > +
> > +        for choice in self.choices:
> > +            choicepair = []
> > +            choicepair.append(choice.val)
> > +            choicepair.append(choice.desc)
> > +            choicepair_list.append(choicepair)
> > +
> > +        return choicepair_list
> > +
> > +    def gen_degenerate_choicepair_list(self, choices):
> > +        """generate a list of 2-item val:desc with val=desc from passed-in choices"""
> 
> Nitpic, initial caps and period.
> 
> > +        choicepair_list = list()
> > +
> > +        for choice in choices:
> > +            choicepair = []
> > +            choicepair.append(choice)
> > +            choicepair.append(choice)
> > +            choicepair_list.append(choicepair)
> > +
> > +        return choicepair_list
> > +
> > +    def exec_listgen_fn(self, context = None):
> > +        """
> > +        execute the list-generating function contained as a string in
> > +        the "gen" property.
> 
> Nitpic, initial caps.
> 
> 
> And I'm stopping here. It looks really good, but it is a bit more than I
> can review very closely right now. So I'd only have superficial
> comments, which aren't so helpful right now. Nice work!
> 

Thanks for the comments,

Tom





More information about the yocto mailing list