192b42cb3SPatrick Williams#!/usr/bin/env python3
292b42cb3SPatrick Williams#
392b42cb3SPatrick Williams# Copyright OpenEmbedded Contributors
492b42cb3SPatrick Williams#
592b42cb3SPatrick Williams# SPDX-License-Identifier: MIT
692b42cb3SPatrick Williams#
792b42cb3SPatrick Williams
892b42cb3SPatrick Williams# This file was copied from poky(or oe-core)/scripts/oe-setup-layers by running
992b42cb3SPatrick Williams#
1092b42cb3SPatrick Williams# bitbake-layers create-layers-setup destdir
1192b42cb3SPatrick Williams#
1292b42cb3SPatrick Williams# It is recommended that you do not modify this file directly, but rather re-run the above command to get the freshest upstream copy.
13c5535c91SAndrew Geissler#
14c5535c91SAndrew Geissler# This script is idempotent. Subsequent runs only change what is necessary to
15c5535c91SAndrew Geissler# ensure your layers match your configuration.
1692b42cb3SPatrick Williams
1792b42cb3SPatrick Williamsimport argparse
1892b42cb3SPatrick Williamsimport json
1992b42cb3SPatrick Williamsimport os
2092b42cb3SPatrick Williamsimport subprocess
2192b42cb3SPatrick Williams
226aa7eec5SAndrew Geisslerdef _is_repo_git_repo(repodir):
23c5535c91SAndrew Geissler    try:
2420137395SAndrew Geissler        curr_toplevel = subprocess.check_output("git -C %s rev-parse --show-toplevel" % repodir, shell=True, stderr=subprocess.DEVNULL)
2520137395SAndrew Geissler        if curr_toplevel.strip().decode("utf-8") == repodir:
2620137395SAndrew Geissler            return True
27c5535c91SAndrew Geissler    except subprocess.CalledProcessError:
2820137395SAndrew Geissler        pass
29c5535c91SAndrew Geissler    return False
30c5535c91SAndrew Geissler
316aa7eec5SAndrew Geisslerdef _is_repo_at_rev(repodir, rev):
32c5535c91SAndrew Geissler    try:
336aa7eec5SAndrew Geissler        curr_rev = subprocess.check_output("git -C %s rev-parse HEAD" % repodir, shell=True, stderr=subprocess.DEVNULL)
34c5535c91SAndrew Geissler        if curr_rev.strip().decode("utf-8") == rev:
35c5535c91SAndrew Geissler            return True
36c5535c91SAndrew Geissler    except subprocess.CalledProcessError:
37c5535c91SAndrew Geissler        pass
38c5535c91SAndrew Geissler    return False
39c5535c91SAndrew Geissler
406aa7eec5SAndrew Geisslerdef _is_repo_at_remote_uri(repodir, remote, uri):
41c5535c91SAndrew Geissler    try:
426aa7eec5SAndrew Geissler        curr_uri = subprocess.check_output("git -C %s remote get-url %s" % (repodir, remote), shell=True, stderr=subprocess.DEVNULL)
43c5535c91SAndrew Geissler        if curr_uri.strip().decode("utf-8") == uri:
44c5535c91SAndrew Geissler            return True
45c5535c91SAndrew Geissler    except subprocess.CalledProcessError:
46c5535c91SAndrew Geissler        pass
47c5535c91SAndrew Geissler    return False
48c5535c91SAndrew Geissler
496aa7eec5SAndrew Geisslerdef _contains_submodules(repodir):
506aa7eec5SAndrew Geissler    return os.path.exists(os.path.join(repodir,".gitmodules"))
5192b42cb3SPatrick Williams
52*73bd93f1SPatrick Williamsdef _write_layer_list(dest, repodirs):
53*73bd93f1SPatrick Williams    layers = []
54*73bd93f1SPatrick Williams    for r in repodirs:
55*73bd93f1SPatrick Williams        for root, dirs, files in os.walk(r):
56*73bd93f1SPatrick Williams            if os.path.basename(root) == 'conf' and 'layer.conf' in files:
57*73bd93f1SPatrick Williams                layers.append(os.path.relpath(os.path.dirname(root), dest))
58*73bd93f1SPatrick Williams    layers_f = os.path.join(dest, ".oe-layers.json")
59*73bd93f1SPatrick Williams    print("Writing list of layers into {}".format(layers_f))
60*73bd93f1SPatrick Williams    with open(layers_f, 'w') as f:
61*73bd93f1SPatrick Williams        json.dump({"version":"1.0","layers":layers}, f, sort_keys=True, indent=4)
62*73bd93f1SPatrick Williams
636aa7eec5SAndrew Geisslerdef _do_checkout(args, json):
646aa7eec5SAndrew Geissler    repos = json['sources']
65*73bd93f1SPatrick Williams    repodirs = []
66*73bd93f1SPatrick Williams    oesetupbuild = None
676aa7eec5SAndrew Geissler    for r_name in repos:
686aa7eec5SAndrew Geissler        r_data = repos[r_name]
696aa7eec5SAndrew Geissler        repodir = os.path.abspath(os.path.join(args['destdir'], r_data['path']))
70*73bd93f1SPatrick Williams        repodirs.append(repodir)
716aa7eec5SAndrew Geissler
726aa7eec5SAndrew Geissler        if 'contains_this_file' in r_data.keys():
7392b42cb3SPatrick Williams            force_arg = 'force_bootstraplayer_checkout'
7492b42cb3SPatrick Williams            if not args[force_arg]:
756aa7eec5SAndrew Geissler                print('Note: not checking out source {repo}, use {repoflag} to override.'.format(repo=r_name, repoflag='--force-bootstraplayer-checkout'))
7692b42cb3SPatrick Williams                continue
776aa7eec5SAndrew Geissler        r_remote = r_data['git-remote']
786aa7eec5SAndrew Geissler        rev = r_remote['rev']
796aa7eec5SAndrew Geissler        desc = r_remote['describe']
8092b42cb3SPatrick Williams        if not desc:
8192b42cb3SPatrick Williams            desc = rev[:10]
826aa7eec5SAndrew Geissler        branch = r_remote['branch']
836aa7eec5SAndrew Geissler        remotes = r_remote['remotes']
8492b42cb3SPatrick Williams
856aa7eec5SAndrew Geissler        print('\nSetting up source {}, revision {}, branch {}'.format(r_name, desc, branch))
866aa7eec5SAndrew Geissler        if not _is_repo_git_repo(repodir):
876aa7eec5SAndrew Geissler            cmd = 'git init -q {}'.format(repodir)
8892b42cb3SPatrick Williams            print("Running '{}'".format(cmd))
8992b42cb3SPatrick Williams            subprocess.check_output(cmd, shell=True)
9092b42cb3SPatrick Williams
9192b42cb3SPatrick Williams        for remote in remotes:
926aa7eec5SAndrew Geissler            if not _is_repo_at_remote_uri(repodir, remote, remotes[remote]['uri']):
9392b42cb3SPatrick Williams                cmd = "git remote remove {} > /dev/null 2>&1; git remote add {} {}".format(remote, remote, remotes[remote]['uri'])
946aa7eec5SAndrew Geissler                print("Running '{}' in {}".format(cmd, repodir))
956aa7eec5SAndrew Geissler                subprocess.check_output(cmd, shell=True, cwd=repodir)
9692b42cb3SPatrick Williams
9792b42cb3SPatrick Williams                cmd = "git fetch -q {} || true".format(remote)
986aa7eec5SAndrew Geissler                print("Running '{}' in {}".format(cmd, repodir))
996aa7eec5SAndrew Geissler                subprocess.check_output(cmd, shell=True, cwd=repodir)
10092b42cb3SPatrick Williams
1016aa7eec5SAndrew Geissler        if not _is_repo_at_rev(repodir, rev):
102c5535c91SAndrew Geissler            cmd = "git fetch -q --all || true"
1036aa7eec5SAndrew Geissler            print("Running '{}' in {}".format(cmd, repodir))
1046aa7eec5SAndrew Geissler            subprocess.check_output(cmd, shell=True, cwd=repodir)
105c5535c91SAndrew Geissler
10692b42cb3SPatrick Williams            cmd = 'git checkout -q {}'.format(rev)
1076aa7eec5SAndrew Geissler            print("Running '{}' in {}".format(cmd, repodir))
1086aa7eec5SAndrew Geissler            subprocess.check_output(cmd, shell=True, cwd=repodir)
1096aa7eec5SAndrew Geissler
1106aa7eec5SAndrew Geissler            if _contains_submodules(repodir):
1116aa7eec5SAndrew Geissler                print("Repo {} contains submodules, use 'git submodule update' to ensure they are up to date".format(repodir))
112*73bd93f1SPatrick Williams        if os.path.exists(os.path.join(repodir, 'scripts/oe-setup-build')):
113*73bd93f1SPatrick Williams            oesetupbuild = os.path.join(repodir, 'scripts/oe-setup-build')
114*73bd93f1SPatrick Williams
115*73bd93f1SPatrick Williams    _write_layer_list(args['destdir'], repodirs)
116*73bd93f1SPatrick Williams
117*73bd93f1SPatrick Williams    if oesetupbuild:
118*73bd93f1SPatrick Williams        oesetupbuild_symlink = os.path.join(args['destdir'], 'setup-build')
119*73bd93f1SPatrick Williams        if os.path.exists(oesetupbuild_symlink):
120*73bd93f1SPatrick Williams            os.remove(oesetupbuild_symlink)
121*73bd93f1SPatrick Williams        os.symlink(os.path.relpath(oesetupbuild,args['destdir']),oesetupbuild_symlink)
122*73bd93f1SPatrick Williams        print("\nRun '{}' to list available build configuration templates and set up a build from one of them.".format(oesetupbuild_symlink))
12392b42cb3SPatrick Williams
12492b42cb3SPatrick Williamsparser = 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/")
12592b42cb3SPatrick Williams
12692b42cb3SPatrick Williamsparser.add_argument('--force-bootstraplayer-checkout', action='store_true',
12792b42cb3SPatrick Williams        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).')
12892b42cb3SPatrick Williams
12992b42cb3SPatrick Williamstry:
13092b42cb3SPatrick Williams    defaultdest = os.path.dirname(subprocess.check_output('git rev-parse --show-toplevel', universal_newlines=True, shell=True, cwd=os.path.dirname(__file__)))
13192b42cb3SPatrick Williamsexcept subprocess.CalledProcessError as e:
13292b42cb3SPatrick Williams    defaultdest = os.path.abspath(".")
13392b42cb3SPatrick Williams
13492b42cb3SPatrick Williamsparser.add_argument('--destdir', default=defaultdest, help='Where to check out the layers (default is {defaultdest}).'.format(defaultdest=defaultdest))
13592b42cb3SPatrick Williamsparser.add_argument('--jsondata', default=__file__+".json", help='File containing the layer data in json format (default is {defaultjson}).'.format(defaultjson=__file__+".json"))
13692b42cb3SPatrick Williams
13792b42cb3SPatrick Williamsargs = parser.parse_args()
13892b42cb3SPatrick Williams
13992b42cb3SPatrick Williamswith open(args.jsondata) as f:
1406aa7eec5SAndrew Geissler    json_f = json.load(f)
14192b42cb3SPatrick Williams
14292b42cb3SPatrick Williamssupported_versions = ["1.0"]
1436aa7eec5SAndrew Geisslerif json_f["version"] not in supported_versions:
1446aa7eec5SAndrew Geissler    raise Exception("File {} has version {}, which is not in supported versions: {}".format(args.jsondata, json_f["version"], supported_versions))
14592b42cb3SPatrick Williams
1466aa7eec5SAndrew Geissler_do_checkout(vars(args), json_f)
147