blob: 57cd9027f6ae8d8e4db79e2fb968ba72a975f9d4 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
2# SPDX-License-Identifier: GPL-2.0-only
3#
4
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08005import layerindexlib
6
Patrick Williamsc0f7c042017-02-23 20:41:17 -06007import argparse
Patrick Williamsc0f7c042017-02-23 20:41:17 -06008import logging
9import os
10import subprocess
Patrick Williamsc0f7c042017-02-23 20:41:17 -060011
12from bblayers.action import ActionPlugin
13
14logger = logging.getLogger('bitbake-layers')
15
16
17def plugin_init(plugins):
18 return LayerIndexPlugin()
19
20
21class LayerIndexPlugin(ActionPlugin):
22 """Subcommands for interacting with the layer index.
23
24 This class inherits ActionPlugin to get do_add_layer.
25 """
26
Patrick Williamsc0f7c042017-02-23 20:41:17 -060027 def get_fetch_layer(self, fetchdir, url, subdir, fetch_layer):
28 layername = self.get_layer_name(url)
29 if os.path.splitext(layername)[1] == '.git':
30 layername = os.path.splitext(layername)[0]
31 repodir = os.path.join(fetchdir, layername)
32 layerdir = os.path.join(repodir, subdir)
33 if not os.path.exists(repodir):
34 if fetch_layer:
Brad Bishopa5c52ff2018-11-23 10:55:50 +130035 result = subprocess.call(['git', 'clone', url, repodir])
Patrick Williamsc0f7c042017-02-23 20:41:17 -060036 if result:
37 logger.error("Failed to download %s" % url)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080038 return None, None, None
Patrick Williamsc0f7c042017-02-23 20:41:17 -060039 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080040 return subdir, layername, layerdir
Patrick Williamsc0f7c042017-02-23 20:41:17 -060041 else:
42 logger.plain("Repository %s needs to be fetched" % url)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080043 return subdir, layername, layerdir
Patrick Williamsc0f7c042017-02-23 20:41:17 -060044 elif os.path.exists(layerdir):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080045 return subdir, layername, layerdir
Patrick Williamsc0f7c042017-02-23 20:41:17 -060046 else:
47 logger.error("%s is not in %s" % (url, subdir))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080048 return None, None, None
Patrick Williamsc0f7c042017-02-23 20:41:17 -060049
50 def do_layerindex_fetch(self, args):
51 """Fetches a layer from a layer index along with its dependent layers, and adds them to conf/bblayers.conf.
52"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -060053
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080054 def _construct_url(baseurls, branches):
55 urls = []
56 for baseurl in baseurls:
57 if baseurl[-1] != '/':
58 baseurl += '/'
59
60 if not baseurl.startswith('cooker'):
61 baseurl += "api/"
62
63 if branches:
64 baseurl += ";branch=%s" % ','.join(branches)
65
66 urls.append(baseurl)
67
68 return urls
69
70
71 # Set the default...
72 if args.branch:
73 branches = [args.branch]
74 else:
75 branches = (self.tinfoil.config_data.getVar('LAYERSERIES_CORENAMES') or 'master').split()
76 logger.debug(1, 'Trying branches: %s' % branches)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060077
78 ignore_layers = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -060079 if args.ignore:
80 ignore_layers.extend(args.ignore.split(','))
81
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080082 # Load the cooker DB
83 cookerIndex = layerindexlib.LayerIndex(self.tinfoil.config_data)
84 cookerIndex.load_layerindex('cooker://', load='layerDependencies')
Patrick Williamsc0f7c042017-02-23 20:41:17 -060085
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080086 # Fast path, check if we already have what has been requested!
87 (dependencies, invalidnames) = cookerIndex.find_dependencies(names=args.layername, ignores=ignore_layers)
88 if not args.show_only and not invalidnames:
89 logger.plain("You already have the requested layer(s): %s" % args.layername)
90 return 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -060091
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080092 # The information to show is already in the cookerIndex
93 if invalidnames:
94 # General URL to use to access the layer index
95 # While there is ONE right now, we're expect users could enter several
96 apiurl = self.tinfoil.config_data.getVar('BBLAYERS_LAYERINDEX_URL').split()
97 if not apiurl:
98 logger.error("Cannot get BBLAYERS_LAYERINDEX_URL")
99 return 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600100
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800101 remoteIndex = layerindexlib.LayerIndex(self.tinfoil.config_data)
102
103 for remoteurl in _construct_url(apiurl, branches):
104 logger.plain("Loading %s..." % remoteurl)
105 remoteIndex.load_layerindex(remoteurl)
106
107 if remoteIndex.is_empty():
108 logger.error("Remote layer index %s is empty for branches %s" % (apiurl, branches))
109 return 1
110
111 lIndex = cookerIndex + remoteIndex
112
113 (dependencies, invalidnames) = lIndex.find_dependencies(names=args.layername, ignores=ignore_layers)
114
115 if invalidnames:
116 for invaluename in invalidnames:
117 logger.error('Layer "%s" not found in layer index' % invaluename)
118 return 1
119
120 logger.plain("%s %s %s" % ("Layer".ljust(49), "Git repository (branch)".ljust(54), "Subdirectory"))
121 logger.plain('=' * 125)
122
123 for deplayerbranch in dependencies:
124 layerBranch = dependencies[deplayerbranch][0]
125
126 # TODO: Determine display behavior
127 # This is the local content, uncomment to hide local
128 # layers from the display.
129 #if layerBranch.index.config['TYPE'] == 'cooker':
130 # continue
131
132 layerDeps = dependencies[deplayerbranch][1:]
133
134 requiredby = []
135 recommendedby = []
136 for dep in layerDeps:
137 if dep.required:
138 requiredby.append(dep.layer.name)
139 else:
140 recommendedby.append(dep.layer.name)
141
142 logger.plain('%s %s %s' % (("%s:%s:%s" %
143 (layerBranch.index.config['DESCRIPTION'],
144 layerBranch.branch.name,
145 layerBranch.layer.name)).ljust(50),
146 ("%s (%s)" % (layerBranch.layer.vcs_url,
147 layerBranch.actual_branch)).ljust(55),
148 layerBranch.vcs_subdir
149 ))
150 if requiredby:
151 logger.plain(' required by: %s' % ' '.join(requiredby))
152 if recommendedby:
153 logger.plain(' recommended by: %s' % ' '.join(recommendedby))
154
155 if dependencies:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500156 fetchdir = self.tinfoil.config_data.getVar('BBLAYERS_FETCH_DIR')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600157 if not fetchdir:
158 logger.error("Cannot get BBLAYERS_FETCH_DIR")
159 return 1
160 if not os.path.exists(fetchdir):
161 os.makedirs(fetchdir)
162 addlayers = []
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800163
164 for deplayerbranch in dependencies:
165 layerBranch = dependencies[deplayerbranch][0]
166
167 if layerBranch.index.config['TYPE'] == 'cooker':
168 # Anything loaded via cooker is already local, skip it
169 continue
170
171 subdir, name, layerdir = self.get_fetch_layer(fetchdir,
172 layerBranch.layer.vcs_url,
173 layerBranch.vcs_subdir,
174 not args.show_only)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600175 if not name:
176 # Error already shown
177 return 1
178 addlayers.append((subdir, name, layerdir))
179 if not args.show_only:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800180 localargs = argparse.Namespace()
181 localargs.layerdir = []
182 localargs.force = args.force
183 for subdir, name, layerdir in addlayers:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600184 if os.path.exists(layerdir):
185 if subdir:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800186 logger.plain("Adding layer \"%s\" (%s) to conf/bblayers.conf" % (subdir, layerdir))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600187 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800188 logger.plain("Adding layer \"%s\" (%s) to conf/bblayers.conf" % (name, layerdir))
189 localargs.layerdir.append(layerdir)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600190 else:
191 break
192
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800193 if localargs.layerdir:
194 self.do_add_layer(localargs)
195
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600196 def do_layerindex_show_depends(self, args):
197 """Find layer dependencies from layer index.
198"""
199 args.show_only = True
200 args.ignore = []
201 self.do_layerindex_fetch(args)
202
203 def register_commands(self, sp):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800204 parser_layerindex_fetch = self.add_command(sp, 'layerindex-fetch', self.do_layerindex_fetch, parserecipes=False)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600205 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 -0800206 parser_layerindex_fetch.add_argument('-b', '--branch', help='branch name to fetch')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600207 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')
208 parser_layerindex_fetch.add_argument('layername', nargs='+', help='layer to fetch')
209
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800210 parser_layerindex_show_depends = self.add_command(sp, 'layerindex-show-depends', self.do_layerindex_show_depends, parserecipes=False)
211 parser_layerindex_show_depends.add_argument('-b', '--branch', help='branch name to fetch')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600212 parser_layerindex_show_depends.add_argument('layername', nargs='+', help='layer to query')