blob: 0ac8fd2ec706998cf84c3d811325cf270ecbd516 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
Patrick Williams92b42cb2022-09-03 06:53:57 -05002# Copyright BitBake Contributors
3#
Brad Bishopc342db32019-05-15 21:57:59 -04004# SPDX-License-Identifier: GPL-2.0-only
5#
6
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08007import layerindexlib
8
Patrick Williamsc0f7c042017-02-23 20:41:17 -06009import argparse
Patrick Williamsc0f7c042017-02-23 20:41:17 -060010import logging
11import os
12import subprocess
Patrick Williamsc0f7c042017-02-23 20:41:17 -060013
14from bblayers.action import ActionPlugin
15
16logger = logging.getLogger('bitbake-layers')
17
18
19def plugin_init(plugins):
20 return LayerIndexPlugin()
21
22
23class LayerIndexPlugin(ActionPlugin):
24 """Subcommands for interacting with the layer index.
25
26 This class inherits ActionPlugin to get do_add_layer.
27 """
28
Andrew Geissler82c905d2020-04-13 13:39:40 -050029 def get_fetch_layer(self, fetchdir, url, subdir, fetch_layer, branch, shallow=False):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060030 layername = self.get_layer_name(url)
31 if os.path.splitext(layername)[1] == '.git':
32 layername = os.path.splitext(layername)[0]
33 repodir = os.path.join(fetchdir, layername)
34 layerdir = os.path.join(repodir, subdir)
35 if not os.path.exists(repodir):
36 if fetch_layer:
Andrew Geissler82c905d2020-04-13 13:39:40 -050037 cmd = ['git', 'clone']
38 if shallow:
39 cmd.extend(['--depth', '1'])
40 if branch:
41 cmd.extend(['-b' , branch])
42 cmd.extend([url, repodir])
43 result = subprocess.call(cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060044 if result:
Andrew Geissler82c905d2020-04-13 13:39:40 -050045 logger.error("Failed to download %s (%s)" % (url, branch))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080046 return None, None, None
Patrick Williamsc0f7c042017-02-23 20:41:17 -060047 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080048 return subdir, layername, layerdir
Patrick Williamsc0f7c042017-02-23 20:41:17 -060049 else:
50 logger.plain("Repository %s needs to be fetched" % url)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080051 return subdir, layername, layerdir
Patrick Williamsc0f7c042017-02-23 20:41:17 -060052 elif os.path.exists(layerdir):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080053 return subdir, layername, layerdir
Patrick Williamsc0f7c042017-02-23 20:41:17 -060054 else:
55 logger.error("%s is not in %s" % (url, subdir))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080056 return None, None, None
Patrick Williamsc0f7c042017-02-23 20:41:17 -060057
58 def do_layerindex_fetch(self, args):
59 """Fetches a layer from a layer index along with its dependent layers, and adds them to conf/bblayers.conf.
60"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -060061
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080062 def _construct_url(baseurls, branches):
63 urls = []
64 for baseurl in baseurls:
65 if baseurl[-1] != '/':
66 baseurl += '/'
67
68 if not baseurl.startswith('cooker'):
69 baseurl += "api/"
70
71 if branches:
72 baseurl += ";branch=%s" % ','.join(branches)
73
74 urls.append(baseurl)
75
76 return urls
77
78
79 # Set the default...
80 if args.branch:
81 branches = [args.branch]
82 else:
83 branches = (self.tinfoil.config_data.getVar('LAYERSERIES_CORENAMES') or 'master').split()
Andrew Geisslerd1e89492021-02-12 15:35:20 -060084 logger.debug('Trying branches: %s' % branches)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060085
86 ignore_layers = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -060087 if args.ignore:
88 ignore_layers.extend(args.ignore.split(','))
89
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080090 # Load the cooker DB
91 cookerIndex = layerindexlib.LayerIndex(self.tinfoil.config_data)
92 cookerIndex.load_layerindex('cooker://', load='layerDependencies')
Patrick Williamsc0f7c042017-02-23 20:41:17 -060093
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080094 # Fast path, check if we already have what has been requested!
95 (dependencies, invalidnames) = cookerIndex.find_dependencies(names=args.layername, ignores=ignore_layers)
96 if not args.show_only and not invalidnames:
97 logger.plain("You already have the requested layer(s): %s" % args.layername)
98 return 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -060099
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800100 # The information to show is already in the cookerIndex
101 if invalidnames:
102 # General URL to use to access the layer index
103 # While there is ONE right now, we're expect users could enter several
104 apiurl = self.tinfoil.config_data.getVar('BBLAYERS_LAYERINDEX_URL').split()
105 if not apiurl:
106 logger.error("Cannot get BBLAYERS_LAYERINDEX_URL")
107 return 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600108
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800109 remoteIndex = layerindexlib.LayerIndex(self.tinfoil.config_data)
110
111 for remoteurl in _construct_url(apiurl, branches):
112 logger.plain("Loading %s..." % remoteurl)
113 remoteIndex.load_layerindex(remoteurl)
114
115 if remoteIndex.is_empty():
116 logger.error("Remote layer index %s is empty for branches %s" % (apiurl, branches))
117 return 1
118
119 lIndex = cookerIndex + remoteIndex
120
121 (dependencies, invalidnames) = lIndex.find_dependencies(names=args.layername, ignores=ignore_layers)
122
123 if invalidnames:
124 for invaluename in invalidnames:
125 logger.error('Layer "%s" not found in layer index' % invaluename)
126 return 1
127
128 logger.plain("%s %s %s" % ("Layer".ljust(49), "Git repository (branch)".ljust(54), "Subdirectory"))
129 logger.plain('=' * 125)
130
131 for deplayerbranch in dependencies:
132 layerBranch = dependencies[deplayerbranch][0]
133
134 # TODO: Determine display behavior
135 # This is the local content, uncomment to hide local
136 # layers from the display.
137 #if layerBranch.index.config['TYPE'] == 'cooker':
138 # continue
139
140 layerDeps = dependencies[deplayerbranch][1:]
141
142 requiredby = []
143 recommendedby = []
144 for dep in layerDeps:
145 if dep.required:
146 requiredby.append(dep.layer.name)
147 else:
148 recommendedby.append(dep.layer.name)
149
150 logger.plain('%s %s %s' % (("%s:%s:%s" %
151 (layerBranch.index.config['DESCRIPTION'],
152 layerBranch.branch.name,
153 layerBranch.layer.name)).ljust(50),
154 ("%s (%s)" % (layerBranch.layer.vcs_url,
155 layerBranch.actual_branch)).ljust(55),
156 layerBranch.vcs_subdir
157 ))
158 if requiredby:
159 logger.plain(' required by: %s' % ' '.join(requiredby))
160 if recommendedby:
161 logger.plain(' recommended by: %s' % ' '.join(recommendedby))
162
163 if dependencies:
Andrew Geisslerc926e172021-05-07 16:11:35 -0500164 if args.fetchdir:
165 fetchdir = args.fetchdir
166 else:
167 fetchdir = self.tinfoil.config_data.getVar('BBLAYERS_FETCH_DIR')
168 if not fetchdir:
169 logger.error("Cannot get BBLAYERS_FETCH_DIR")
170 return 1
171
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600172 if not os.path.exists(fetchdir):
173 os.makedirs(fetchdir)
Andrew Geisslerc926e172021-05-07 16:11:35 -0500174
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600175 addlayers = []
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800176
177 for deplayerbranch in dependencies:
178 layerBranch = dependencies[deplayerbranch][0]
179
180 if layerBranch.index.config['TYPE'] == 'cooker':
181 # Anything loaded via cooker is already local, skip it
182 continue
183
184 subdir, name, layerdir = self.get_fetch_layer(fetchdir,
185 layerBranch.layer.vcs_url,
186 layerBranch.vcs_subdir,
Andrew Geissler82c905d2020-04-13 13:39:40 -0500187 not args.show_only,
188 layerBranch.actual_branch,
189 args.shallow)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600190 if not name:
191 # Error already shown
192 return 1
193 addlayers.append((subdir, name, layerdir))
194 if not args.show_only:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800195 localargs = argparse.Namespace()
196 localargs.layerdir = []
197 localargs.force = args.force
198 for subdir, name, layerdir in addlayers:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600199 if os.path.exists(layerdir):
200 if subdir:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800201 logger.plain("Adding layer \"%s\" (%s) to conf/bblayers.conf" % (subdir, layerdir))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600202 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800203 logger.plain("Adding layer \"%s\" (%s) to conf/bblayers.conf" % (name, layerdir))
204 localargs.layerdir.append(layerdir)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600205 else:
206 break
207
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800208 if localargs.layerdir:
209 self.do_add_layer(localargs)
210
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600211 def do_layerindex_show_depends(self, args):
212 """Find layer dependencies from layer index.
213"""
214 args.show_only = True
215 args.ignore = []
Andrew Geisslerc926e172021-05-07 16:11:35 -0500216 args.fetchdir = ""
217 args.shallow = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600218 self.do_layerindex_fetch(args)
219
220 def register_commands(self, sp):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800221 parser_layerindex_fetch = self.add_command(sp, 'layerindex-fetch', self.do_layerindex_fetch, parserecipes=False)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600222 parser_layerindex_fetch.add_argument('-n', '--show-only', help='show dependencies and do nothing else', action='store_true')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800223 parser_layerindex_fetch.add_argument('-b', '--branch', help='branch name to fetch')
Andrew Geissler82c905d2020-04-13 13:39:40 -0500224 parser_layerindex_fetch.add_argument('-s', '--shallow', help='do only shallow clones (--depth=1)', action='store_true')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600225 parser_layerindex_fetch.add_argument('-i', '--ignore', help='assume the specified layers do not need to be fetched/added (separate multiple layers with commas, no spaces)', metavar='LAYER')
Andrew Geisslerc926e172021-05-07 16:11:35 -0500226 parser_layerindex_fetch.add_argument('-f', '--fetchdir', help='directory to fetch the layer(s) into (will be created if it does not exist)')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600227 parser_layerindex_fetch.add_argument('layername', nargs='+', help='layer to fetch')
228
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800229 parser_layerindex_show_depends = self.add_command(sp, 'layerindex-show-depends', self.do_layerindex_show_depends, parserecipes=False)
230 parser_layerindex_show_depends.add_argument('-b', '--branch', help='branch name to fetch')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600231 parser_layerindex_show_depends.add_argument('layername', nargs='+', help='layer to query')