diff options
author | Christopher Larson <chris_larson@mentor.com> | 2016-04-30 12:41:00 -0700 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-05-17 21:16:35 +0100 |
commit | 6bbe4fe48c93d1e2b67a36aa82d2ea5e289a219c (patch) | |
tree | 802427823189e16ffcd6560acfda961303873adc /bitbake/lib/bblayers/layerindex.py | |
parent | 07eebc66898b423ea2e04e96c57d3b2b5eabbb26 (diff) | |
download | poky-6bbe4fe48c93d1e2b67a36aa82d2ea5e289a219c.tar.gz |
bitbake: bitbake-layers: convert to plugin-based
This uses bb.utils.load_plugins, based on the plugin handling in recipetool
and devtool in oe-core.
(Bitbake rev: 5e542df9b966a99b5a5b8aa7cf6100174aff54b2)
Signed-off-by: Christopher Larson <chris_larson@mentor.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bblayers/layerindex.py')
-rw-r--r-- | bitbake/lib/bblayers/layerindex.py | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/bitbake/lib/bblayers/layerindex.py b/bitbake/lib/bblayers/layerindex.py new file mode 100644 index 0000000000..3c39d8a79e --- /dev/null +++ b/bitbake/lib/bblayers/layerindex.py | |||
@@ -0,0 +1,270 @@ | |||
1 | import argparse | ||
2 | import httplib | ||
3 | import json | ||
4 | import logging | ||
5 | import os | ||
6 | import subprocess | ||
7 | import urlparse | ||
8 | |||
9 | from bblayers.action import ActionPlugin | ||
10 | |||
11 | logger = logging.getLogger('bitbake-layers') | ||
12 | |||
13 | |||
14 | def plugin_init(plugins): | ||
15 | return LayerIndexPlugin() | ||
16 | |||
17 | |||
18 | class LayerIndexPlugin(ActionPlugin): | ||
19 | """Subcommands for interacting with the layer index. | ||
20 | |||
21 | This class inherits ActionPlugin to get do_add_layer. | ||
22 | """ | ||
23 | |||
24 | def get_json_data(self, apiurl): | ||
25 | proxy_settings = os.environ.get("http_proxy", None) | ||
26 | conn = None | ||
27 | _parsedurl = urlparse.urlparse(apiurl) | ||
28 | path = _parsedurl.path | ||
29 | query = _parsedurl.query | ||
30 | |||
31 | def parse_url(url): | ||
32 | parsedurl = urlparse.urlparse(url) | ||
33 | if parsedurl.netloc[0] == '[': | ||
34 | host, port = parsedurl.netloc[1:].split(']', 1) | ||
35 | if ':' in port: | ||
36 | port = port.rsplit(':', 1)[1] | ||
37 | else: | ||
38 | port = None | ||
39 | else: | ||
40 | if parsedurl.netloc.count(':') == 1: | ||
41 | (host, port) = parsedurl.netloc.split(":") | ||
42 | else: | ||
43 | host = parsedurl.netloc | ||
44 | port = None | ||
45 | return (host, 80 if port is None else int(port)) | ||
46 | |||
47 | if proxy_settings is None: | ||
48 | host, port = parse_url(apiurl) | ||
49 | conn = httplib.HTTPConnection(host, port) | ||
50 | conn.request("GET", path + "?" + query) | ||
51 | else: | ||
52 | host, port = parse_url(proxy_settings) | ||
53 | conn = httplib.HTTPConnection(host, port) | ||
54 | conn.request("GET", apiurl) | ||
55 | |||
56 | r = conn.getresponse() | ||
57 | if r.status != 200: | ||
58 | raise Exception("Failed to read " + path + ": %d %s" % (r.status, r.reason)) | ||
59 | return json.loads(r.read()) | ||
60 | |||
61 | def get_layer_deps(self, layername, layeritems, layerbranches, layerdependencies, branchnum, selfname=False): | ||
62 | def layeritems_info_id(items_name, layeritems): | ||
63 | litems_id = None | ||
64 | for li in layeritems: | ||
65 | if li['name'] == items_name: | ||
66 | litems_id = li['id'] | ||
67 | break | ||
68 | return litems_id | ||
69 | |||
70 | def layerbranches_info(items_id, layerbranches): | ||
71 | lbranch = {} | ||
72 | for lb in layerbranches: | ||
73 | if lb['layer'] == items_id and lb['branch'] == branchnum: | ||
74 | lbranch['id'] = lb['id'] | ||
75 | lbranch['vcs_subdir'] = lb['vcs_subdir'] | ||
76 | break | ||
77 | return lbranch | ||
78 | |||
79 | def layerdependencies_info(lb_id, layerdependencies): | ||
80 | ld_deps = [] | ||
81 | for ld in layerdependencies: | ||
82 | if ld['layerbranch'] == lb_id and not ld['dependency'] in ld_deps: | ||
83 | ld_deps.append(ld['dependency']) | ||
84 | if not ld_deps: | ||
85 | logger.error("The dependency of layerDependencies is not found.") | ||
86 | return ld_deps | ||
87 | |||
88 | def layeritems_info_name_subdir(items_id, layeritems): | ||
89 | litems = {} | ||
90 | for li in layeritems: | ||
91 | if li['id'] == items_id: | ||
92 | litems['vcs_url'] = li['vcs_url'] | ||
93 | litems['name'] = li['name'] | ||
94 | break | ||
95 | return litems | ||
96 | |||
97 | if selfname: | ||
98 | selfid = layeritems_info_id(layername, layeritems) | ||
99 | lbinfo = layerbranches_info(selfid, layerbranches) | ||
100 | if lbinfo: | ||
101 | selfsubdir = lbinfo['vcs_subdir'] | ||
102 | else: | ||
103 | logger.error("%s is not found in the specified branch" % layername) | ||
104 | return | ||
105 | selfurl = layeritems_info_name_subdir(selfid, layeritems)['vcs_url'] | ||
106 | if selfurl: | ||
107 | return selfurl, selfsubdir | ||
108 | else: | ||
109 | logger.error("Cannot get layer %s git repo and subdir" % layername) | ||
110 | return | ||
111 | ldict = {} | ||
112 | itemsid = layeritems_info_id(layername, layeritems) | ||
113 | if not itemsid: | ||
114 | return layername, None | ||
115 | lbid = layerbranches_info(itemsid, layerbranches) | ||
116 | if lbid: | ||
117 | lbid = layerbranches_info(itemsid, layerbranches)['id'] | ||
118 | else: | ||
119 | logger.error("%s is not found in the specified branch" % layername) | ||
120 | return None, None | ||
121 | for dependency in layerdependencies_info(lbid, layerdependencies): | ||
122 | lname = layeritems_info_name_subdir(dependency, layeritems)['name'] | ||
123 | lurl = layeritems_info_name_subdir(dependency, layeritems)['vcs_url'] | ||
124 | lsubdir = layerbranches_info(dependency, layerbranches)['vcs_subdir'] | ||
125 | ldict[lname] = lurl, lsubdir | ||
126 | return None, ldict | ||
127 | |||
128 | def get_fetch_layer(self, fetchdir, url, subdir, fetch_layer): | ||
129 | layername = self.get_layer_name(url) | ||
130 | if os.path.splitext(layername)[1] == '.git': | ||
131 | layername = os.path.splitext(layername)[0] | ||
132 | repodir = os.path.join(fetchdir, layername) | ||
133 | layerdir = os.path.join(repodir, subdir) | ||
134 | if not os.path.exists(repodir): | ||
135 | if fetch_layer: | ||
136 | result = subprocess.call('git clone %s %s' % (url, repodir), shell = True) | ||
137 | if result: | ||
138 | logger.error("Failed to download %s" % url) | ||
139 | return None, None | ||
140 | else: | ||
141 | return layername, layerdir | ||
142 | else: | ||
143 | logger.plain("Repository %s needs to be fetched" % url) | ||
144 | return layername, layerdir | ||
145 | elif os.path.exists(layerdir): | ||
146 | return layername, layerdir | ||
147 | else: | ||
148 | logger.error("%s is not in %s" % (url, subdir)) | ||
149 | return None, None | ||
150 | |||
151 | def do_layerindex_fetch(self, args): | ||
152 | """Fetches a layer from a layer index along with its dependent layers, and adds them to conf/bblayers.conf. | ||
153 | """ | ||
154 | apiurl = self.tinfoil.config_data.getVar('BBLAYERS_LAYERINDEX_URL', True) | ||
155 | if not apiurl: | ||
156 | logger.error("Cannot get BBLAYERS_LAYERINDEX_URL") | ||
157 | return 1 | ||
158 | else: | ||
159 | if apiurl[-1] != '/': | ||
160 | apiurl += '/' | ||
161 | apiurl += "api/" | ||
162 | apilinks = self.get_json_data(apiurl) | ||
163 | branches = self.get_json_data(apilinks['branches']) | ||
164 | |||
165 | branchnum = 0 | ||
166 | for branch in branches: | ||
167 | if branch['name'] == args.branch: | ||
168 | branchnum = branch['id'] | ||
169 | break | ||
170 | if branchnum == 0: | ||
171 | validbranches = ', '.join([branch['name'] for branch in branches]) | ||
172 | logger.error('Invalid layer branch name "%s". Valid branches: %s' % (args.branch, validbranches)) | ||
173 | return 1 | ||
174 | |||
175 | ignore_layers = [] | ||
176 | for collection in self.tinfoil.config_data.getVar('BBFILE_COLLECTIONS', True).split(): | ||
177 | lname = self.tinfoil.config_data.getVar('BBLAYERS_LAYERINDEX_NAME_%s' % collection, True) | ||
178 | if lname: | ||
179 | ignore_layers.append(lname) | ||
180 | |||
181 | if args.ignore: | ||
182 | ignore_layers.extend(args.ignore.split(',')) | ||
183 | |||
184 | layeritems = self.get_json_data(apilinks['layerItems']) | ||
185 | layerbranches = self.get_json_data(apilinks['layerBranches']) | ||
186 | layerdependencies = self.get_json_data(apilinks['layerDependencies']) | ||
187 | invaluenames = [] | ||
188 | repourls = {} | ||
189 | printlayers = [] | ||
190 | |||
191 | def query_dependencies(layers, layeritems, layerbranches, layerdependencies, branchnum): | ||
192 | depslayer = [] | ||
193 | for layername in layers: | ||
194 | invaluename, layerdict = self.get_layer_deps(layername, layeritems, layerbranches, layerdependencies, branchnum) | ||
195 | if layerdict: | ||
196 | repourls[layername] = self.get_layer_deps(layername, layeritems, layerbranches, layerdependencies, branchnum, selfname=True) | ||
197 | for layer in layerdict: | ||
198 | if not layer in ignore_layers: | ||
199 | depslayer.append(layer) | ||
200 | printlayers.append((layername, layer, layerdict[layer][0], layerdict[layer][1])) | ||
201 | if not layer in ignore_layers and not layer in repourls: | ||
202 | repourls[layer] = (layerdict[layer][0], layerdict[layer][1]) | ||
203 | if invaluename and not invaluename in invaluenames: | ||
204 | invaluenames.append(invaluename) | ||
205 | return depslayer | ||
206 | |||
207 | depslayers = query_dependencies(args.layername, layeritems, layerbranches, layerdependencies, branchnum) | ||
208 | while depslayers: | ||
209 | depslayer = query_dependencies(depslayers, layeritems, layerbranches, layerdependencies, branchnum) | ||
210 | depslayers = depslayer | ||
211 | if invaluenames: | ||
212 | for invaluename in invaluenames: | ||
213 | logger.error('Layer "%s" not found in layer index' % invaluename) | ||
214 | return 1 | ||
215 | logger.plain("%s %s %s %s" % ("Layer".ljust(19), "Required by".ljust(19), "Git repository".ljust(54), "Subdirectory")) | ||
216 | logger.plain('=' * 115) | ||
217 | for layername in args.layername: | ||
218 | layerurl = repourls[layername] | ||
219 | logger.plain("%s %s %s %s" % (layername.ljust(20), '-'.ljust(20), layerurl[0].ljust(55), layerurl[1])) | ||
220 | printedlayers = [] | ||
221 | for layer, dependency, gitrepo, subdirectory in printlayers: | ||
222 | if dependency in printedlayers: | ||
223 | continue | ||
224 | logger.plain("%s %s %s %s" % (dependency.ljust(20), layer.ljust(20), gitrepo.ljust(55), subdirectory)) | ||
225 | printedlayers.append(dependency) | ||
226 | |||
227 | if repourls: | ||
228 | fetchdir = self.tinfoil.config_data.getVar('BBLAYERS_FETCH_DIR', True) | ||
229 | if not fetchdir: | ||
230 | logger.error("Cannot get BBLAYERS_FETCH_DIR") | ||
231 | return 1 | ||
232 | if not os.path.exists(fetchdir): | ||
233 | os.makedirs(fetchdir) | ||
234 | addlayers = [] | ||
235 | for repourl, subdir in repourls.values(): | ||
236 | name, layerdir = self.get_fetch_layer(fetchdir, repourl, subdir, not args.show_only) | ||
237 | if not name: | ||
238 | # Error already shown | ||
239 | return 1 | ||
240 | addlayers.append((subdir, name, layerdir)) | ||
241 | if not args.show_only: | ||
242 | for subdir, name, layerdir in set(addlayers): | ||
243 | if os.path.exists(layerdir): | ||
244 | if subdir: | ||
245 | logger.plain("Adding layer \"%s\" to conf/bblayers.conf" % subdir) | ||
246 | else: | ||
247 | logger.plain("Adding layer \"%s\" to conf/bblayers.conf" % name) | ||
248 | localargs = argparse.Namespace() | ||
249 | localargs.layerdir = layerdir | ||
250 | self.do_add_layer(localargs) | ||
251 | else: | ||
252 | break | ||
253 | |||
254 | def do_layerindex_show_depends(self, args): | ||
255 | """Find layer dependencies from layer index. | ||
256 | """ | ||
257 | args.show_only = True | ||
258 | args.ignore = [] | ||
259 | self.do_layerindex_fetch(args) | ||
260 | |||
261 | def register_commands(self, sp): | ||
262 | parser_layerindex_fetch = self.add_command(sp, 'layerindex-fetch', self.do_layerindex_fetch) | ||
263 | parser_layerindex_fetch.add_argument('-n', '--show-only', help='show dependencies and do nothing else', action='store_true') | ||
264 | parser_layerindex_fetch.add_argument('-b', '--branch', help='branch name to fetch (default %(default)s)', default='master') | ||
265 | 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') | ||
266 | parser_layerindex_fetch.add_argument('layername', nargs='+', help='layer to fetch') | ||
267 | |||
268 | parser_layerindex_show_depends = self.add_command(sp, 'layerindex-show-depends', self.do_layerindex_show_depends) | ||
269 | parser_layerindex_show_depends.add_argument('-b', '--branch', help='branch name to fetch (default %(default)s)', default='master') | ||
270 | parser_layerindex_show_depends.add_argument('layername', nargs='+', help='layer to query') | ||