Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 1 | # |
| 2 | # Copyright OpenEmbedded Contributors |
| 3 | # |
| 4 | # SPDX-License-Identifier: GPL-2.0-only |
| 5 | # |
| 6 | |
| 7 | import logging |
| 8 | import os |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 9 | import sys |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 10 | |
| 11 | import bb.utils |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 12 | |
| 13 | from bblayers.common import LayerPlugin |
| 14 | |
| 15 | logger = logging.getLogger('bitbake-layers') |
| 16 | |
| 17 | sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) |
| 18 | |
| 19 | import oe.buildcfg |
| 20 | |
| 21 | def plugin_init(plugins): |
| 22 | return MakeSetupPlugin() |
| 23 | |
| 24 | class MakeSetupPlugin(LayerPlugin): |
| 25 | |
Patrick Williams | 03514f1 | 2024-04-05 07:04:11 -0500 | [diff] [blame] | 26 | def _get_remotes_with_url(self, repo_path): |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 27 | remotes = {} |
Patrick Williams | 03514f1 | 2024-04-05 07:04:11 -0500 | [diff] [blame] | 28 | for r in oe.buildcfg.get_metadata_git_remotes(repo_path): |
| 29 | remotes[r] = {'uri':oe.buildcfg.get_metadata_git_remote_url(repo_path, r)} |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 30 | return remotes |
| 31 | |
Andrew Geissler | 6aa7eec | 2023-03-03 12:41:14 -0600 | [diff] [blame] | 32 | def _is_submodule(self, repo_path): |
| 33 | # This is slightly brittle: git does not offer a way to tell whether |
| 34 | # a given repo dir is a submodule checkout, so we need to rely on .git |
| 35 | # being a file (rather than a dir like it is in standalone checkouts). |
| 36 | # The file typically contains a gitdir pointer to elsewhere. |
| 37 | return os.path.isfile(os.path.join(repo_path,".git")) |
| 38 | |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 39 | def make_repo_config(self, destdir): |
Andrew Geissler | 517393d | 2023-01-13 08:55:19 -0600 | [diff] [blame] | 40 | """ This is a helper function for the writer plugins that discovers currently configured layers. |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 41 | The writers do not have to use it, but it can save a bit of work and avoid duplicated code, hence it is |
| 42 | available here. """ |
| 43 | repos = {} |
| 44 | layers = oe.buildcfg.get_layer_revisions(self.tinfoil.config_data) |
Patrick Williams | 03514f1 | 2024-04-05 07:04:11 -0500 | [diff] [blame] | 45 | destdir_repo = oe.buildcfg.get_metadata_git_toplevel(destdir) |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 46 | |
| 47 | for (l_path, l_name, l_branch, l_rev, l_ismodified) in layers: |
| 48 | if l_name == 'workspace': |
| 49 | continue |
| 50 | if l_ismodified: |
| 51 | logger.error("Layer {name} in {path} has uncommitted modifications or is not in a git repository.".format(name=l_name,path=l_path)) |
| 52 | return |
Patrick Williams | 03514f1 | 2024-04-05 07:04:11 -0500 | [diff] [blame] | 53 | repo_path = oe.buildcfg.get_metadata_git_toplevel(l_path) |
Andrew Geissler | 6aa7eec | 2023-03-03 12:41:14 -0600 | [diff] [blame] | 54 | |
| 55 | if self._is_submodule(repo_path): |
| 56 | continue |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 57 | if repo_path not in repos.keys(): |
Patrick Williams | 03514f1 | 2024-04-05 07:04:11 -0500 | [diff] [blame] | 58 | repos[repo_path] = {'path':os.path.basename(repo_path),'git-remote':{ |
| 59 | 'rev':l_rev, |
| 60 | 'branch':l_branch, |
| 61 | 'remotes':self._get_remotes_with_url(repo_path), |
| 62 | 'describe':oe.buildcfg.get_metadata_git_describe(repo_path)}} |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 63 | if repo_path == destdir_repo: |
| 64 | repos[repo_path]['contains_this_file'] = True |
| 65 | if not repos[repo_path]['git-remote']['remotes'] and not repos[repo_path]['contains_this_file']: |
| 66 | 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)) |
| 67 | return |
| 68 | |
| 69 | top_path = os.path.commonpath([os.path.dirname(r) for r in repos.keys()]) |
| 70 | |
| 71 | repos_nopaths = {} |
| 72 | for r in repos.keys(): |
| 73 | r_nopath = os.path.basename(r) |
| 74 | repos_nopaths[r_nopath] = repos[r] |
| 75 | r_relpath = os.path.relpath(r, top_path) |
| 76 | repos_nopaths[r_nopath]['path'] = r_relpath |
| 77 | return repos_nopaths |
| 78 | |
| 79 | def do_make_setup(self, args): |
| 80 | """ Writes out a configuration file and/or a script that replicate the directory structure and revisions of the layers in a current build. """ |
| 81 | for p in self.plugins: |
| 82 | if str(p) == args.writer: |
| 83 | p.do_write(self, args) |
| 84 | |
| 85 | def register_commands(self, sp): |
| 86 | parser_setup_layers = self.add_command(sp, 'create-layers-setup', self.do_make_setup, parserecipes=False) |
| 87 | parser_setup_layers.add_argument('destdir', |
| 88 | 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).') |
| 89 | parser_setup_layers.add_argument('--output-prefix', '-o', |
| 90 | help='File name prefix for the output files, if the default (setup-layers) is undesirable.') |
| 91 | |
| 92 | self.plugins = [] |
| 93 | |
| 94 | for path in (self.tinfoil.config_data.getVar('BBPATH').split(':')): |
| 95 | pluginpath = os.path.join(path, 'lib', 'bblayers', 'setupwriters') |
| 96 | bb.utils.load_plugins(logger, self.plugins, pluginpath) |
| 97 | |
| 98 | 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") |
| 99 | |
| 100 | for plugin in self.plugins: |
| 101 | if hasattr(plugin, 'register_arguments'): |
| 102 | plugin.register_arguments(parser_setup_layers) |