Initial commit
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
#
|
||||
# Copyright OpenEmbedded Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import logging
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
import shutil
|
||||
import json
|
||||
|
||||
import bb.utils
|
||||
import bb.process
|
||||
|
||||
from bblayers.common import LayerPlugin
|
||||
|
||||
logger = logging.getLogger('bitbake-layers')
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
import oe.buildcfg
|
||||
|
||||
def plugin_init(plugins):
|
||||
return BuildConfPlugin()
|
||||
|
||||
class BuildConfPlugin(LayerPlugin):
|
||||
notes_fixme = """FIXME: Please place here the description of this build configuration.
|
||||
It will be shown to the users when they set up their builds via TEMPLATECONF.
|
||||
"""
|
||||
|
||||
def _save_conf(self, templatename, templatepath, oecorepath, relpaths_to_oecore):
|
||||
confdir = os.path.join(os.environ["BBPATH"], "conf")
|
||||
destdir = os.path.join(templatepath, "conf", "templates", templatename)
|
||||
os.makedirs(destdir, exist_ok=True)
|
||||
|
||||
with open(os.path.join(confdir, "local.conf")) as src:
|
||||
with open(os.path.join(destdir, "local.conf.sample"), 'w') as dest:
|
||||
dest.write(src.read())
|
||||
|
||||
with open(os.path.join(confdir, "bblayers.conf")) as src:
|
||||
with open(os.path.join(destdir, "bblayers.conf.sample"), 'w') as dest:
|
||||
bblayers_data = src.read()
|
||||
|
||||
for (abspath, relpath) in relpaths_to_oecore:
|
||||
bblayers_data = bblayers_data.replace(abspath, "##OEROOT##/" + relpath)
|
||||
dest.write(bblayers_data)
|
||||
|
||||
with open(os.path.join(destdir, "conf-notes.txt"), 'w') as dest:
|
||||
dest.write(self.notes_fixme)
|
||||
|
||||
logger.info("""Configuration template placed into {}
|
||||
Please review the files in there, and particularly provide a configuration description in {}
|
||||
You can try out the configuration with
|
||||
TEMPLATECONF={} . {}/oe-init-build-env build-try-{}"""
|
||||
.format(destdir, os.path.join(destdir, "conf-notes.txt"), destdir, oecorepath, templatename))
|
||||
|
||||
def do_save_build_conf(self, args):
|
||||
""" Save the currently active build configuration (conf/local.conf, conf/bblayers.conf) as a template into a layer.\n This template can later be used for setting up builds via TEMPLATECONF. """
|
||||
repos = {}
|
||||
layers = oe.buildcfg.get_layer_revisions(self.tinfoil.config_data)
|
||||
targetlayer = None
|
||||
oecore = None
|
||||
|
||||
for l in layers:
|
||||
if os.path.abspath(l[0]) == os.path.abspath(args.layerpath):
|
||||
targetlayer = l[0]
|
||||
if l[1] == 'meta':
|
||||
oecore = os.path.dirname(l[0])
|
||||
|
||||
if not targetlayer:
|
||||
logger.error("Layer {} not in one of the currently enabled layers:\n{}".format(args.layerpath, "\n".join([l[0] for l in layers])))
|
||||
elif not oecore:
|
||||
logger.error("Openembedded-core not in one of the currently enabled layers:\n{}".format("\n".join([l[0] for l in layers])))
|
||||
else:
|
||||
relpaths_to_oecore = [(l[0], os.path.relpath(l[0], start=oecore)) for l in layers]
|
||||
self._save_conf(args.templatename, targetlayer, oecore, relpaths_to_oecore)
|
||||
|
||||
def register_commands(self, sp):
|
||||
parser_build_conf = self.add_command(sp, 'save-build-conf', self.do_save_build_conf, parserecipes=False)
|
||||
parser_build_conf.add_argument('layerpath',
|
||||
help='The path to the layer where the configuration template should be saved.')
|
||||
parser_build_conf.add_argument('templatename',
|
||||
help='The name of the configuration template.')
|
||||
@@ -0,0 +1,90 @@
|
||||
#
|
||||
# Copyright OpenEmbedded Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
import bb.utils
|
||||
|
||||
from bblayers.common import LayerPlugin
|
||||
from bblayers.action import ActionPlugin
|
||||
|
||||
logger = logging.getLogger('bitbake-layers')
|
||||
|
||||
def plugin_init(plugins):
|
||||
return CreatePlugin()
|
||||
|
||||
def read_template(template, template_dir='templates'):
|
||||
lines = str()
|
||||
with open(os.path.join(os.path.dirname(__file__), template_dir, template)) as fd:
|
||||
lines = ''.join(fd.readlines())
|
||||
return lines
|
||||
|
||||
class CreatePlugin(LayerPlugin):
|
||||
def do_create_layer(self, args):
|
||||
"""Create a basic layer"""
|
||||
layerdir = os.path.abspath(args.layerdir)
|
||||
if os.path.exists(layerdir):
|
||||
sys.stderr.write("Specified layer directory exists\n")
|
||||
return 1
|
||||
|
||||
# create dirs
|
||||
conf = os.path.join(layerdir, 'conf')
|
||||
bb.utils.mkdirhier(conf)
|
||||
|
||||
layername = os.path.basename(os.path.normpath(args.layerdir))
|
||||
layerid = args.layerid if args.layerid is not None else layername
|
||||
|
||||
# Create the README from templates/README
|
||||
readme_template = read_template('README').format(layername=layername)
|
||||
readme = os.path.join(layerdir, 'README')
|
||||
with open(readme, 'w') as fd:
|
||||
fd.write(readme_template)
|
||||
|
||||
# Copy the MIT license from meta
|
||||
copying = 'COPYING.MIT'
|
||||
dn = os.path.dirname
|
||||
license_src = os.path.join(dn(dn(dn(__file__))), copying)
|
||||
license_dst = os.path.join(layerdir, copying)
|
||||
shutil.copy(license_src, license_dst)
|
||||
|
||||
# Get the compat value for core layer.
|
||||
compat = self.tinfoil.config_data.getVar('LAYERSERIES_CORENAMES') or ""
|
||||
|
||||
# Create the layer.conf from templates/layer.conf
|
||||
layerconf_template = read_template('layer.conf').format(
|
||||
layerid=layerid, priority=args.priority, compat=compat)
|
||||
layerconf = os.path.join(conf, 'layer.conf')
|
||||
with open(layerconf, 'w') as fd:
|
||||
fd.write(layerconf_template)
|
||||
|
||||
# Create the example from templates/example.bb
|
||||
example_template = read_template('example.bb')
|
||||
example = os.path.join(layerdir, 'recipes-' + args.examplerecipe, args.examplerecipe)
|
||||
bb.utils.mkdirhier(example)
|
||||
with open(os.path.join(example, args.examplerecipe + '_%s.bb') % args.version, 'w') as fd:
|
||||
fd.write(example_template)
|
||||
|
||||
if args.add_layer:
|
||||
# Add the layer to bblayers.conf
|
||||
args.layerdir = [layerdir]
|
||||
ActionPlugin.do_add_layer(self, args)
|
||||
logger.plain('Layer added %s' % args.layerdir)
|
||||
|
||||
else:
|
||||
logger.plain('Add your new layer with \'bitbake-layers add-layer %s\'' % args.layerdir)
|
||||
|
||||
def register_commands(self, sp):
|
||||
parser_create_layer = self.add_command(sp, 'create-layer', self.do_create_layer, parserecipes=False)
|
||||
parser_create_layer.add_argument('layerdir', help='Layer directory to create')
|
||||
parser_create_layer.add_argument('--add-layer', '-a', action='store_true', help='Add the layer to bblayers.conf after creation')
|
||||
parser_create_layer.add_argument('--layerid', '-i', help='Layer id to use if different from layername')
|
||||
parser_create_layer.add_argument('--priority', '-p', default=6, help='Priority of recipes in layer')
|
||||
parser_create_layer.add_argument('--example-recipe-name', '-e', dest='examplerecipe', default='example', help='Filename of the example recipe')
|
||||
parser_create_layer.add_argument('--example-recipe-version', '-v', dest='version', default='0.1', help='Version number for the example recipe')
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
#
|
||||
# Copyright OpenEmbedded Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import logging
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
import bb.utils
|
||||
import bb.process
|
||||
|
||||
from bblayers.common import LayerPlugin
|
||||
|
||||
logger = logging.getLogger('bitbake-layers')
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
import oe.buildcfg
|
||||
|
||||
def plugin_init(plugins):
|
||||
return MakeSetupPlugin()
|
||||
|
||||
class MakeSetupPlugin(LayerPlugin):
|
||||
|
||||
def _get_repo_path(self, layer_path):
|
||||
repo_path, _ = bb.process.run('git rev-parse --show-toplevel', cwd=layer_path)
|
||||
return repo_path.strip()
|
||||
|
||||
def _get_remotes(self, repo_path):
|
||||
remotes = {}
|
||||
remotes_list,_ = bb.process.run('git remote', cwd=repo_path)
|
||||
for r in remotes_list.split():
|
||||
uri,_ = bb.process.run('git remote get-url {r}'.format(r=r), cwd=repo_path)
|
||||
remotes[r] = {'uri':uri.strip()}
|
||||
return remotes
|
||||
|
||||
def _get_describe(self, repo_path):
|
||||
try:
|
||||
describe,_ = bb.process.run('git describe --tags', cwd=repo_path)
|
||||
except bb.process.ExecutionError:
|
||||
return ""
|
||||
return describe.strip()
|
||||
|
||||
def _is_submodule(self, repo_path):
|
||||
# This is slightly brittle: git does not offer a way to tell whether
|
||||
# a given repo dir is a submodule checkout, so we need to rely on .git
|
||||
# being a file (rather than a dir like it is in standalone checkouts).
|
||||
# The file typically contains a gitdir pointer to elsewhere.
|
||||
return os.path.isfile(os.path.join(repo_path,".git"))
|
||||
|
||||
def make_repo_config(self, destdir):
|
||||
""" This is a helper function for the writer plugins that discovers currently configured layers.
|
||||
The writers do not have to use it, but it can save a bit of work and avoid duplicated code, hence it is
|
||||
available here. """
|
||||
repos = {}
|
||||
layers = oe.buildcfg.get_layer_revisions(self.tinfoil.config_data)
|
||||
try:
|
||||
destdir_repo = self._get_repo_path(destdir)
|
||||
except bb.process.ExecutionError:
|
||||
destdir_repo = None
|
||||
|
||||
for (l_path, l_name, l_branch, l_rev, l_ismodified) in layers:
|
||||
if l_name == 'workspace':
|
||||
continue
|
||||
if l_ismodified:
|
||||
logger.error("Layer {name} in {path} has uncommitted modifications or is not in a git repository.".format(name=l_name,path=l_path))
|
||||
return
|
||||
repo_path = self._get_repo_path(l_path)
|
||||
|
||||
if self._is_submodule(repo_path):
|
||||
continue
|
||||
if repo_path not in repos.keys():
|
||||
repos[repo_path] = {'path':os.path.basename(repo_path),'git-remote':{'rev':l_rev, 'branch':l_branch, 'remotes':self._get_remotes(repo_path), 'describe':self._get_describe(repo_path)}}
|
||||
if repo_path == destdir_repo:
|
||||
repos[repo_path]['contains_this_file'] = True
|
||||
if not repos[repo_path]['git-remote']['remotes'] and not repos[repo_path]['contains_this_file']:
|
||||
logger.error("Layer repository in {path} does not have any remotes configured. Please add at least one with 'git remote add'.".format(path=repo_path))
|
||||
return
|
||||
|
||||
top_path = os.path.commonpath([os.path.dirname(r) for r in repos.keys()])
|
||||
|
||||
repos_nopaths = {}
|
||||
for r in repos.keys():
|
||||
r_nopath = os.path.basename(r)
|
||||
repos_nopaths[r_nopath] = repos[r]
|
||||
r_relpath = os.path.relpath(r, top_path)
|
||||
repos_nopaths[r_nopath]['path'] = r_relpath
|
||||
return repos_nopaths
|
||||
|
||||
def do_make_setup(self, args):
|
||||
""" Writes out a configuration file and/or a script that replicate the directory structure and revisions of the layers in a current build. """
|
||||
for p in self.plugins:
|
||||
if str(p) == args.writer:
|
||||
p.do_write(self, args)
|
||||
|
||||
def register_commands(self, sp):
|
||||
parser_setup_layers = self.add_command(sp, 'create-layers-setup', self.do_make_setup, parserecipes=False)
|
||||
parser_setup_layers.add_argument('destdir',
|
||||
help='Directory where to write the output\n(if it is inside one of the layers, the layer becomes a bootstrap repository and thus will be excluded from fetching).')
|
||||
parser_setup_layers.add_argument('--output-prefix', '-o',
|
||||
help='File name prefix for the output files, if the default (setup-layers) is undesirable.')
|
||||
|
||||
self.plugins = []
|
||||
|
||||
for path in (self.tinfoil.config_data.getVar('BBPATH').split(':')):
|
||||
pluginpath = os.path.join(path, 'lib', 'bblayers', 'setupwriters')
|
||||
bb.utils.load_plugins(logger, self.plugins, pluginpath)
|
||||
|
||||
parser_setup_layers.add_argument('--writer', '-w', choices=[str(p) for p in self.plugins], help="Choose the output format (defaults to oe-setup-layers).\n\nCurrently supported options are:\noe-setup-layers - a self-contained python script and a json config for it.\n\n", default="oe-setup-layers")
|
||||
|
||||
for plugin in self.plugins:
|
||||
if hasattr(plugin, 'register_arguments'):
|
||||
plugin.register_arguments(parser_setup_layers)
|
||||
@@ -0,0 +1,52 @@
|
||||
#
|
||||
# Copyright OpenEmbedded Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
import stat
|
||||
|
||||
logger = logging.getLogger('bitbake-layers')
|
||||
|
||||
def plugin_init(plugins):
|
||||
return OeSetupLayersWriter()
|
||||
|
||||
class OeSetupLayersWriter():
|
||||
|
||||
def __str__(self):
|
||||
return "oe-setup-layers"
|
||||
|
||||
def _write_python(self, input, output):
|
||||
with open(input) as f:
|
||||
script = f.read()
|
||||
with open(output, 'w') as f:
|
||||
f.write(script)
|
||||
st = os.stat(output)
|
||||
os.chmod(output, st.st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
|
||||
|
||||
def _write_json(self, repos, output):
|
||||
with open(output, 'w') as f:
|
||||
json.dump(repos, f, sort_keys=True, indent=4)
|
||||
|
||||
def do_write(self, parent, args):
|
||||
""" Writes out a python script and a json config that replicate the directory structure and revisions of the layers in a current build. """
|
||||
if not os.path.exists(args.destdir):
|
||||
os.makedirs(args.destdir)
|
||||
repos = parent.make_repo_config(args.destdir)
|
||||
json = {"version":"1.0","sources":repos}
|
||||
if not repos:
|
||||
raise Exception("Could not determine layer sources")
|
||||
output = args.output_prefix or "setup-layers"
|
||||
output = os.path.join(os.path.abspath(args.destdir),output)
|
||||
self._write_json(json, output + ".json")
|
||||
logger.info('Created {}.json'.format(output))
|
||||
if not args.json_only:
|
||||
self._write_python(os.path.join(os.path.dirname(__file__),'../../../../scripts/oe-setup-layers'), output)
|
||||
logger.info('Created {}'.format(output))
|
||||
|
||||
def register_arguments(self, parser):
|
||||
parser.add_argument('--json-only', action='store_true',
|
||||
help='When using the oe-setup-layers writer, write only the layer configuruation in json format. Otherwise, also a copy of scripts/oe-setup-layers (from oe-core or poky) is provided, which is a self contained python script that fetches all the needed layers and sets them to correct revisions using the data from the json.')
|
||||
@@ -0,0 +1,41 @@
|
||||
This README file contains information on the contents of the {layername} layer.
|
||||
|
||||
Please see the corresponding sections below for details.
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
URI: <first dependency>
|
||||
branch: <branch name>
|
||||
|
||||
URI: <second dependency>
|
||||
branch: <branch name>
|
||||
|
||||
.
|
||||
.
|
||||
.
|
||||
|
||||
Patches
|
||||
=======
|
||||
|
||||
Please submit any patches against the {layername} layer to the xxxx mailing list (xxxx@zzzz.org)
|
||||
and cc: the maintainer:
|
||||
|
||||
Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com>
|
||||
|
||||
Table of Contents
|
||||
=================
|
||||
|
||||
I. Adding the {layername} layer to your build
|
||||
II. Misc
|
||||
|
||||
|
||||
I. Adding the {layername} layer to your build
|
||||
=================================================
|
||||
|
||||
Run 'bitbake-layers add-layer {layername}'
|
||||
|
||||
II. Misc
|
||||
========
|
||||
|
||||
--- replace with specific information about the {layername} layer ---
|
||||
@@ -0,0 +1,13 @@
|
||||
SUMMARY = "bitbake-layers recipe"
|
||||
DESCRIPTION = "Recipe created by bitbake-layers"
|
||||
LICENSE = "MIT"
|
||||
|
||||
python do_display_banner() {
|
||||
bb.plain("***********************************************");
|
||||
bb.plain("* *");
|
||||
bb.plain("* Example recipe created by bitbake-layers *");
|
||||
bb.plain("* *");
|
||||
bb.plain("***********************************************");
|
||||
}
|
||||
|
||||
addtask display_banner before do_build
|
||||
@@ -0,0 +1,13 @@
|
||||
# We have a conf and classes directory, add to BBPATH
|
||||
BBPATH .= ":${{LAYERDIR}}"
|
||||
|
||||
# We have recipes-* directories, add to BBFILES
|
||||
BBFILES += "${{LAYERDIR}}/recipes-*/*/*.bb \
|
||||
${{LAYERDIR}}/recipes-*/*/*.bbappend"
|
||||
|
||||
BBFILE_COLLECTIONS += "{layerid}"
|
||||
BBFILE_PATTERN_{layerid} = "^${{LAYERDIR}}/"
|
||||
BBFILE_PRIORITY_{layerid} = "{priority}"
|
||||
|
||||
LAYERDEPENDS_{layerid} = "core"
|
||||
LAYERSERIES_COMPAT_{layerid} = "{compat}"
|
||||
Reference in New Issue
Block a user