poky/scripts/oe-setup-layers
Alexander Kanavin c390b2e615 oe-setup-build: add a tool for discovering config templates and setting up builds
This is another piece of the puzzle in setting up builds from nothing
without having to write custom scripts or use external tools.

After layers have been fetched and placed into their respective locations by
oe-setup-layers, one would surely want to proceed to the actual build, and here's how:

1. Without arguments the tool reads available layers
from .oe-layers.json file (written out by oe-setup-layers or a fallback under scripts/),
prints what templates it has found, and asks the user to select one, as seen below.
This will land the user in a shell ready to run bitbake:

=============================================
alex@Zen2:/srv/work/alex$ ./setup-build
Available build configurations:

1. alex-configuration-gadget
This configuration will set up a build for the purposes of supporting gadget.

2. alex-configuration-gizmo
This configuration allows building a gizmo.

3. poky-default
This is the default build configuration for the Poky reference distribution.

Re-run with 'list -v' to see additional information.
Please choose a configuration by its number: 1
Running: TEMPLATECONF=/srv/work/alex/meta-alex/conf/templates/configuration-gadget . /srv/work/alex/poky/oe-init-build-env /srv/work/alex/build-alex-configuration-gadget && /bin/bash
You had no conf/local.conf file. This configuration file has therefore been
created for you from /srv/work/alex/meta-alex/conf/templates/configuration-gadget/local.conf.sample
You may wish to edit it to, for example, select a different MACHINE (target
hardware).

You had no conf/bblayers.conf file. This configuration file has therefore been
created for you from /srv/work/alex/meta-alex/conf/templates/configuration-gadget/bblayers.conf.sample
To add additional metadata layers into your configuration please add entries
to conf/bblayers.conf.

The Yocto Project has extensive documentation about OE including a reference
manual which can be found at:
    https://docs.yoctoproject.org

For more information about OpenEmbedded see the website:
    https://www.openembedded.org/

This configuration will set up a build for the purposes of supporting gadget.
Please refer to meta-alex/README for additional details and available bitbake targets.
==============================================

2. It is also possible to list available configurations without selecting one using
'setup-build list' or to select and setup one non-interactively with 'setup-build setup'.

3. The full set of command line options is:

$ ./setup-build --help
usage: setup-build [-h] [--layerlist LAYERLIST] {list,setup} ...

A script that discovers available build configurations and sets up a build environment based on one of them. Run without arguments to choose one interactively.

positional arguments:
  {list,setup}
    list                List available configurations
    setup               Set up a build environment and open a shell session with it, ready to run builds.

optional arguments:
  -h, --help            show this help message and exit
  --layerlist LAYERLIST
                        Where to look for available layers (as written out by setup-layers script) (default is /srv/work/alex/.oe-layers.json).

$ ./setup-build list --help
usage: setup-build list [-h] [-v]

optional arguments:
  -h, --help  show this help message and exit
  -v          Print detailed information and usage notes for each available build configuration.

$ ./setup-build setup --help
usage: setup-build setup [-h] [-c configuration_name] [-b build_path] [--no-shell]

optional arguments:
  -h, --help            show this help message and exit
  -c configuration_name
                        Use a build configuration configuration_name to set up a build environment (run this script with 'list' to see what is available)
  -b build_path         Set up a build directory in build_path (run this script with 'list -v' to see where it would be by default)
  --no-shell            Create a build directory but do not start a shell session with the build environment from it.

4. There's an an added hint in oe-setup-layers about how to proceed (as it is really not user-friendly
to fetch the layer repos successfully and then exit without a word), and a symlink to the script
from the top level layer checkout directory.

5. The selftest to check layer setup has been adjusted to run a basic check for template
discovery and build setup. The revision of poky to be cloned has been bumped to 4.1,
as that's the first version with a default template in a standard location.

(From OE-Core rev: 1360b64e88cda7dddfb0eca6a64f70c13dafb890)

Signed-off-by: Alexander Kanavin <alex@linutronix.de>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2024-02-19 11:47:53 +00:00

6.4 KiB
Executable File

#!/usr/bin/env python3

Copyright OpenEmbedded Contributors

SPDX-License-Identifier: MIT

This file was copied from poky(or oe-core)/scripts/oe-setup-layers by running

bitbake-layers create-layers-setup destdir

It is recommended that you do not modify this file directly, but rather re-run the above command to get the freshest upstream copy.

This script is idempotent. Subsequent runs only change what is necessary to

ensure your layers match your configuration.

import argparse import json import os import subprocess

def _is_repo_git_repo(repodir): try: curr_toplevel = subprocess.check_output("git -C %s rev-parse --show-toplevel" % repodir, shell=True, stderr=subprocess.DEVNULL) if curr_toplevel.strip().decode("utf-8") == repodir: return True except subprocess.CalledProcessError: pass return False

def _is_repo_at_rev(repodir, rev): try: curr_rev = subprocess.check_output("git -C %s rev-parse HEAD" % repodir, shell=True, stderr=subprocess.DEVNULL) if curr_rev.strip().decode("utf-8") == rev: return True except subprocess.CalledProcessError: pass return False

def _is_repo_at_remote_uri(repodir, remote, uri): try: curr_uri = subprocess.check_output("git -C %s remote get-url %s" % (repodir, remote), shell=True, stderr=subprocess.DEVNULL) if curr_uri.strip().decode("utf-8") == uri: return True except subprocess.CalledProcessError: pass return False

def _contains_submodules(repodir): return os.path.exists(os.path.join(repodir,".gitmodules"))

def _write_layer_list(dest, repodirs): layers = [] for r in repodirs: for root, dirs, files in os.walk(r): if os.path.basename(root) == 'conf' and 'layer.conf' in files: layers.append(os.path.relpath(os.path.dirname(root), dest)) layers_f = os.path.join(dest, ".oe-layers.json") print("Writing list of layers into {}".format(layers_f)) with open(layers_f, 'w') as f: json.dump({"version":"1.0","layers":layers}, f, sort_keys=True, indent=4)

def _do_checkout(args, json): repos = json['sources'] repodirs = [] oesetupbuild = None for r_name in repos: r_data = repos[r_name] repodir = os.path.abspath(os.path.join(args['destdir'], r_data['path'])) repodirs.append(repodir)

    if 'contains_this_file' in r_data.keys():
        force_arg = 'force_bootstraplayer_checkout'
        if not args[force_arg]:
            print('Note: not checking out source {repo}, use {repoflag} to override.'.format(repo=r_name, repoflag='--force-bootstraplayer-checkout'))
            continue
    r_remote = r_data['git-remote']
    rev = r_remote['rev']
    desc = r_remote['describe']
    if not desc:
        desc = rev[:10]
    branch = r_remote['branch']
    remotes = r_remote['remotes']

    print('\nSetting up source {}, revision {}, branch {}'.format(r_name, desc, branch))
    if not _is_repo_git_repo(repodir):
        cmd = 'git init -q {}'.format(repodir)
        print("Running '{}'".format(cmd))
        subprocess.check_output(cmd, shell=True)

    for remote in remotes:
        if not _is_repo_at_remote_uri(repodir, remote, remotes[remote]['uri']):
            cmd = "git remote remove {} > /dev/null 2>&1; git remote add {} {}".format(remote, remote, remotes[remote]['uri'])
            print("Running '{}' in {}".format(cmd, repodir))
            subprocess.check_output(cmd, shell=True, cwd=repodir)

            cmd = "git fetch -q {} || true".format(remote)
            print("Running '{}' in {}".format(cmd, repodir))
            subprocess.check_output(cmd, shell=True, cwd=repodir)

    if not _is_repo_at_rev(repodir, rev):
        cmd = "git fetch -q --all || true"
        print("Running '{}' in {}".format(cmd, repodir))
        subprocess.check_output(cmd, shell=True, cwd=repodir)

        cmd = 'git checkout -q {}'.format(rev)
        print("Running '{}' in {}".format(cmd, repodir))
        subprocess.check_output(cmd, shell=True, cwd=repodir)

        if _contains_submodules(repodir):
            print("Repo {} contains submodules, use 'git submodule update' to ensure they are up to date".format(repodir))
    if os.path.exists(os.path.join(repodir, 'scripts/oe-setup-build')):
        oesetupbuild = os.path.join(repodir, 'scripts/oe-setup-build')

_write_layer_list(args['destdir'], repodirs)

if oesetupbuild:
    oesetupbuild_symlink = os.path.join(args['destdir'], 'setup-build')
    if os.path.exists(oesetupbuild_symlink):
        os.remove(oesetupbuild_symlink)
    os.symlink(os.path.relpath(oesetupbuild,args['destdir']),oesetupbuild_symlink)
    print("\nRun '{}' to list available build configuration templates and set up a build from one of them.".format(oesetupbuild_symlink))

parser = argparse.ArgumentParser(description="A self contained python script that fetches all the needed layers and sets them to correct revisions using data in a json format from a separate file. The json data can be created from an active build directory with 'bitbake-layers create-layers-setup destdir' and there's a sample file and a schema in meta/files/")

parser.add_argument('--force-bootstraplayer-checkout', action='store_true', help='Force the checkout of the layer containing this file (by default it is presumed that as this script is in it, the layer is already in place).')

try: defaultdest = os.path.dirname(subprocess.check_output('git rev-parse --show-toplevel', universal_newlines=True, shell=True, cwd=os.path.dirname(file))) except subprocess.CalledProcessError as e: defaultdest = os.path.abspath(".")

parser.add_argument('--destdir', default=defaultdest, help='Where to check out the layers (default is {defaultdest}).'.format(defaultdest=defaultdest)) parser.add_argument('--jsondata', default=file+".json", help='File containing the layer data in json format (default is {defaultjson}).'.format(defaultjson=file+".json"))

args = parser.parse_args()

with open(args.jsondata) as f: json_f = json.load(f)

supported_versions = ["1.0"] if json_f["version"] not in supported_versions: raise Exception("File {} has version {}, which is not in supported versions: {}".format(args.jsondata, json_f["version"], supported_versions))

_do_checkout(vars(args), json_f)