summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorChuck Wolber <chuck.wolber@boeing.com>2023-01-16 17:59:30 -0800
committerRichard Purdie <richard.purdie@linuxfoundation.org>2023-01-18 16:42:28 +0000
commitb57d4de337b59a1959f486abee1821df614b6333 (patch)
tree578f3c5ad0fd197ae89660cd0b9dbea66477fd87 /scripts
parentf3d4ee6477739027fd21a8208dbd80097e8e54cb (diff)
downloadpoky-b57d4de337b59a1959f486abee1821df614b6333.tar.gz
scripts/oe-setup-layers: Make efficiently idempotent
The effect of subsequent setup-layers executions is now either a NOOP or the minimal set of changes required to ensure layers precisely match the JSON configuration. This change allows setup-layers to be incorporated into a team's configuration management strategy. In particular, the configuration JSON manages a "pinning policy" that documents the oversight of sources of change (a requirement for embedded development in highly regulated industries). One model for this strategy would work as follows. Team level policy is developed to regularly review upstream commits that occur between the current upstream HEAD and the previously pinned revision. The JSON configuration is periodically updated after a review, test, and approval process. In the rare instance that an upstream change is considered problematic, the bbappend mechanism can be used to make relevant changes in the team's project repository. This approach also requires that team developers regularly run the project repository copy of setup-layers. This is most easily accomplished by including setup-layers in a wrapper script that all team developers use to interact with the bitbake tool suite (e.g. "bb bitbake foo-image"). Project level policy and oversight is effectively "contained" within this wrapper script, thereby reducing a significant source of human error. Left unstated, but acknowledged here, are a number of nuances required to successfully implement the above strategy. The details are out of scope for this explanation. What should be clear is that a larger configuration management strategy can now benefit from the utility provided by setup-layers. Note: Neither the above configuration management strategy example nor the change itself is intended to alter the original intent to use "bitbake-layers create-layers-setup destdir" to keep pace with upstream activity for those who wish to use it that way. (From OE-Core rev: da2e01cacd98715318a5307fe0618dbca0cf1fe7) Signed-off-by: Chuck Wolber <chuck.wolber@boeing.com> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/oe-setup-layers55
1 files changed, 46 insertions, 9 deletions
diff --git a/scripts/oe-setup-layers b/scripts/oe-setup-layers
index 6ecaffed75..d0bc9f1667 100755
--- a/scripts/oe-setup-layers
+++ b/scripts/oe-setup-layers
@@ -10,12 +10,42 @@
10# bitbake-layers create-layers-setup destdir 10# bitbake-layers create-layers-setup destdir
11# 11#
12# It is recommended that you do not modify this file directly, but rather re-run the above command to get the freshest upstream copy. 12# It is recommended that you do not modify this file directly, but rather re-run the above command to get the freshest upstream copy.
13#
14# This script is idempotent. Subsequent runs only change what is necessary to
15# ensure your layers match your configuration.
13 16
14import argparse 17import argparse
15import json 18import json
16import os 19import os
17import subprocess 20import subprocess
18 21
22def _is_layer_git_repo(layerdir):
23 git_dir = os.path.join(layerdir, ".git")
24 if not os.access(git_dir, os.R_OK):
25 return False
26 try:
27 return subprocess.check_output("git -C %s rev-parse --is-inside-git-dir" % git_dir, shell=True, stderr=subprocess.DEVNULL)
28 except subprocess.CalledProcessError:
29 return False
30
31def _is_layer_at_rev(layerdir, rev):
32 try:
33 curr_rev = subprocess.check_output("git -C %s rev-parse HEAD" % layerdir, shell=True, stderr=subprocess.DEVNULL)
34 if curr_rev.strip().decode("utf-8") == rev:
35 return True
36 except subprocess.CalledProcessError:
37 pass
38 return False
39
40def _is_layer_at_remote_uri(layerdir, remote, uri):
41 try:
42 curr_uri = subprocess.check_output("git -C %s remote get-url %s" % (layerdir, remote), shell=True, stderr=subprocess.DEVNULL)
43 if curr_uri.strip().decode("utf-8") == uri:
44 return True
45 except subprocess.CalledProcessError:
46 pass
47 return False
48
19def _do_checkout(args, json): 49def _do_checkout(args, json):
20 layers = json['sources'] 50 layers = json['sources']
21 for l_name in layers: 51 for l_name in layers:
@@ -36,23 +66,30 @@ def _do_checkout(args, json):
36 remotes = l_remote['remotes'] 66 remotes = l_remote['remotes']
37 67
38 print('\nSetting up source {}, revision {}, branch {}'.format(l_name, desc, branch)) 68 print('\nSetting up source {}, revision {}, branch {}'.format(l_name, desc, branch))
39 cmd = 'git init -q {}'.format(layerdir) 69 if not _is_layer_git_repo(layerdir):
40 print("Running '{}'".format(cmd)) 70 cmd = 'git init -q {}'.format(layerdir)
41 subprocess.check_output(cmd, shell=True) 71 print("Running '{}'".format(cmd))
72 subprocess.check_output(cmd, shell=True)
42 73
43 for remote in remotes: 74 for remote in remotes:
44 cmd = "git remote remove {} > /dev/null 2>&1; git remote add {} {}".format(remote, remote, remotes[remote]['uri']) 75 if not _is_layer_at_remote_uri(layerdir, remote, remotes[remote]['uri']):
76 cmd = "git remote remove {} > /dev/null 2>&1; git remote add {} {}".format(remote, remote, remotes[remote]['uri'])
77 print("Running '{}' in {}".format(cmd, layerdir))
78 subprocess.check_output(cmd, shell=True, cwd=layerdir)
79
80 cmd = "git fetch -q {} || true".format(remote)
81 print("Running '{}' in {}".format(cmd, layerdir))
82 subprocess.check_output(cmd, shell=True, cwd=layerdir)
83
84 if not _is_layer_at_rev(layerdir, rev):
85 cmd = "git fetch -q --all || true"
45 print("Running '{}' in {}".format(cmd, layerdir)) 86 print("Running '{}' in {}".format(cmd, layerdir))
46 subprocess.check_output(cmd, shell=True, cwd=layerdir) 87 subprocess.check_output(cmd, shell=True, cwd=layerdir)
47 88
48 cmd = "git fetch -q {} || true".format(remote) 89 cmd = 'git checkout -q {}'.format(rev)
49 print("Running '{}' in {}".format(cmd, layerdir)) 90 print("Running '{}' in {}".format(cmd, layerdir))
50 subprocess.check_output(cmd, shell=True, cwd=layerdir) 91 subprocess.check_output(cmd, shell=True, cwd=layerdir)
51 92
52 cmd = 'git checkout -q {}'.format(rev)
53 print("Running '{}' in {}".format(cmd, layerdir))
54 subprocess.check_output(cmd, shell=True, cwd=layerdir)
55
56parser = 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/") 93parser = 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/")
57 94
58parser.add_argument('--force-bootstraplayer-checkout', action='store_true', 95parser.add_argument('--force-bootstraplayer-checkout', action='store_true',