<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Sep 16, 2015 at 8:21 AM, Paul Eggleton <span dir="ltr">&lt;<a href="mailto:paul.eggleton@linux.intel.com" target="_blank">paul.eggleton@linux.intel.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div id=":2yp" class="a3s" style="overflow:hidden">Hi Chris,<br>
<div><div class="h5"><br>
On Tuesday 15 September 2015 20:57:46 Christopher Larson wrote:<br>
&gt; This sub-command creates a bbappend for the specified target and prints the<br>
&gt; path to the bbappend. The -w argument, as with some of the other recipetool<br>
&gt; commands, will make a version-independent bbappend.<br>
&gt;<br>
&gt; Example usage: recipetool newappend meta-mylayer virtual/kernel<br>
&gt;<br>
&gt; [YOCTO #7964]<br>
&gt;<br>
&gt; Signed-off-by: Christopher Larson &lt;<a href="mailto:kergoth@gmail.com">kergoth@gmail.com</a>&gt;<br>
&gt; ---<br>
&gt;  scripts/lib/recipetool/newappend.py | 126<br>
&gt; ++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+)<br>
&gt;  create mode 100644 scripts/lib/recipetool/newappend.py<br>
&gt;<br>
&gt; diff --git a/scripts/lib/recipetool/newappend.py<br>
&gt; b/scripts/lib/recipetool/newappend.py new file mode 100644<br>
&gt; index 0000000..be9077c<br>
&gt; --- /dev/null<br>
&gt; +++ b/scripts/lib/recipetool/newappend.py<br>
&gt; @@ -0,0 +1,126 @@<br>
&gt; +# Recipe creation tool - newappend plugin<br>
&gt; +#<br>
&gt; +# This sub-command creates a bbappend for the specified target and prints<br>
&gt; the +# path to the bbappend.<br>
&gt; +#<br>
&gt; +# Example: recipetool newappend meta-mylayer busybox<br>
&gt; +#<br>
&gt; +# Copyright (C) 2015 Christopher Larson &lt;<a href="mailto:kergoth@gmail.com">kergoth@gmail.com</a>&gt;<br>
&gt; +#<br>
&gt; +# This program is free software; you can redistribute it and/or modify<br>
&gt; +# it under the terms of the GNU General Public License version 2 as<br>
&gt; +# published by the Free Software Foundation.<br>
&gt; +#<br>
&gt; +# This program is distributed in the hope that it will be useful,<br>
&gt; +# but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
&gt; +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>
&gt; +# GNU General Public License for more details.<br>
&gt; +#<br>
&gt; +# You should have received a copy of the GNU General Public License along<br>
&gt; +# with this program; if not, write to the Free Software Foundation, Inc.,<br>
&gt; +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.<br>
&gt; +<br>
&gt; +import argparse<br>
&gt; +import errno<br>
&gt; +import logging<br>
&gt; +import os<br>
&gt; +import re<br>
&gt; +<br>
&gt; +<br>
&gt; +logger = logging.getLogger(&#39;recipetool&#39;)<br>
&gt; +tinfoil = None<br>
&gt; +<br>
&gt; +<br>
&gt; +def plugin_init(pluginlist):<br>
&gt; +    # Don&#39;t need to do anything here right now, but plugins must have this<br>
&gt; function defined +    pass<br>
&gt; +<br>
&gt; +<br>
&gt; +def tinfoil_init(instance):<br>
&gt; +    global tinfoil<br>
&gt; +    tinfoil = instance<br>
&gt; +<br>
&gt; +<br>
&gt; +def _provide_to_pn(cooker, provide):<br>
&gt; +    &quot;&quot;&quot;Get the name of the preferred recipe for the specified provide.&quot;&quot;&quot;<br>
&gt; +    import bb.providers<br>
&gt; +    filenames = cooker.recipecache.providers[provide]<br>
&gt; +    eligible, foundUnique = bb.providers.filterProviders(filenames,<br>
&gt; provide, cooker.expanded_data, cooker.recipecache) +    filename =<br>
&gt; eligible[0]<br>
&gt; +    pn = cooker.recipecache.pkg_fn[filename]<br>
&gt; +    return pn<br>
&gt; +<br>
&gt; +<br>
&gt; +def _get_recipe_file(cooker, pn):<br>
&gt; +    import oe.recipeutils<br>
&gt; +    recipefile = oe.recipeutils.pn_to_recipe(cooker, pn)<br>
&gt; +    if not recipefile:<br>
&gt; +        skipreasons = oe.recipeutils.get_unavailable_reasons(cooker, pn)<br>
&gt; +        if skipreasons:<br>
&gt; +            logger.error(&#39;\n&#39;.join(skipreasons))<br>
&gt; +        else:<br>
&gt; +            logger.error(&quot;Unable to find any recipe file matching %s&quot; % pn)<br>
&gt; +    return recipefile<br>
&gt; +<br>
&gt; +<br>
&gt; +def layer(layerpath):<br>
&gt; +    if not os.path.exists(os.path.join(layerpath, &#39;conf&#39;, &#39;layer.conf&#39;)):<br>
&gt; +        raise argparse.ArgumentTypeError(&#39;{0!r} must be a path to a valid<br>
&gt; layer&#39;.format(layerpath)) +    return layerpath<br>
&gt; +<br>
&gt; +<br>
&gt; +def newappend(args):<br>
&gt; +    pn = _provide_to_pn(tinfoil.cooker, args.target)<br>
&gt; +    recipe_path = _get_recipe_file(tinfoil.cooker, pn)<br>
&gt; +<br>
&gt; +    # Map recipe path to the layer it&#39;s in<br>
&gt; +    for layerpath in tinfoil.config_data.getVar(&#39;BBLAYERS&#39;, True).split():<br>
&gt; +        layerconf = os.path.join(layerpath, &#39;conf&#39;, &#39;layer.conf&#39;)<br>
&gt; +        l = bb.data.init()<br>
&gt; +        l.setVar(&#39;LAYERDIR&#39;, layerpath)<br>
&gt; +        l = bb.parse.handle(layerconf, l)<br>
&gt; +        l.expandVarref(&#39;LAYERDIR&#39;)<br>
&gt; +<br>
&gt; +        for layername in l.getVar(&#39;BBFILE_COLLECTIONS&#39;, True).split():<br>
&gt; +            pattern = l.getVar(&#39;BBFILE_PATTERN_&#39; + layername, True)<br>
&gt; +            if pattern and re.match(pattern, recipe_path):<br>
&gt; +                recipe_layer_path = layerpath<br>
&gt; +                break<br>
&gt; +        else:<br>
&gt; +            continue<br>
&gt; +        break<br>
&gt; +    else:<br>
&gt; +        recipe_layer_path =<br>
&gt; os.path.dirname(os.path.dirname(os.path.dirname(recipe_path))) +<br>
&gt; +    recipe_relpath = os.path.relpath(recipe_path, recipe_layer_path)<br>
&gt; +    append_relpath = recipe_relpath + &#39;append&#39;<br>
&gt; +    append_path = os.path.join(args.destlayer, append_relpath)<br>
&gt; +<br>
&gt; +    if args.wildcard_version and &#39;_&#39; in os.path.basename(append_path):<br>
&gt; +        base, _ = os.path.splitext(append_path)<br>
&gt; +        base, _ = base.rsplit(&#39;_&#39;, 1)<br>
&gt; +        append_path = base + &#39;_%.bbappend&#39;<br>
&gt; +<br>
&gt; +    if not os.path.exists(append_path):<br>
&gt; +        try:<br>
&gt; +            os.makedirs(os.path.dirname(append_path))<br>
&gt; +        except OSError as exc:<br>
&gt; +            if exc.errno != errno.EEXIST:<br>
&gt; +                raise<br>
&gt; +<br>
&gt; +        try:<br>
&gt; +            open(append_path, &#39;a&#39;)<br>
&gt; +        except (OSError, IOError) as exc:<br>
&gt; +            logger.critical(str(exc))<br>
&gt; +            return 1<br>
&gt; +<br>
&gt; +    print(append_path)<br>
&gt; +<br>
&gt; +<br>
&gt; +def register_command(subparsers):<br>
&gt; +    parser = subparsers.add_parser(&#39;newappend&#39;,<br>
&gt; +                                   help=&#39;Create a bbappend for the<br>
&gt; specified target in the specified layer&#39;) +    parser.add_argument(&#39;-w&#39;,<br>
&gt; &#39;--wildcard-version&#39;, help=&#39;Use wildcard to make the bbappend apply to any<br>
&gt; recipe version&#39;, action=&#39;store_true&#39;) +    parser.add_argument(&#39;destlayer&#39;,<br>
&gt; help=&#39;Base directory of the destination layer to write the bbappend to&#39;,<br>
&gt; type=layer) +    parser.add_argument(&#39;target&#39;, help=&#39;Target recipe/provide<br>
&gt; to append&#39;) +    parser.set_defaults(func=newappend, parserecipes=True)<br>
<br>
</div></div>So the first thing that springs to mind here is that there&#39;s a bunch of code to<br>
do the major part of this in recipeutils (e.g. finding the correct name and<br>
location for a bbappend file is done by get_bbappend_path()) - shouldn&#39;t we be<br>
using that here?</div></blockquote></div><br>Probably, I had no idea that function existed :) Thanks, will take a look.<br>-- <br><div class="gmail_signature"><div dir="ltr">Christopher Larson<br>kergoth at gmail dot com<br>Founder - BitBake, OpenEmbedded, OpenZaurus<br>Maintainer - Tslib<br>Senior Software Engineer, Mentor Graphics</div></div>
</div></div>