1# 2# Copyright OpenEmbedded Contributors 3# 4# SPDX-License-Identifier: GPL-2.0-only 5# 6 7import logging 8import os 9import sys 10 11import bb.utils 12 13from bblayers.common import LayerPlugin 14 15logger = logging.getLogger('bitbake-layers') 16 17sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) 18 19import oe.buildcfg 20 21def plugin_init(plugins): 22 return MakeSetupPlugin() 23 24class MakeSetupPlugin(LayerPlugin): 25 26 def _get_remotes_with_url(self, repo_path): 27 remotes = {} 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)} 30 return remotes 31 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 39 def make_repo_config(self, destdir): 40 """ This is a helper function for the writer plugins that discovers currently configured layers. 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) 45 destdir_repo = oe.buildcfg.get_metadata_git_toplevel(destdir) 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 53 repo_path = oe.buildcfg.get_metadata_git_toplevel(l_path) 54 55 if self._is_submodule(repo_path): 56 continue 57 if repo_path not in repos.keys(): 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)}} 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) 103