blob: 9f02a9da2efb8591a096d258097dda2041f03193 [file] [log] [blame]
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001import layerindexlib
2
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003import argparse
Patrick Williamsc0f7c042017-02-23 20:41:17 -06004import logging
5import os
6import subprocess
Patrick Williamsc0f7c042017-02-23 20:41:17 -06007
8from bblayers.action import ActionPlugin
9
10logger = logging.getLogger('bitbake-layers')
11
12
13def plugin_init(plugins):
14 return LayerIndexPlugin()
15
16
17class LayerIndexPlugin(ActionPlugin):
18 """Subcommands for interacting with the layer index.
19
20 This class inherits ActionPlugin to get do_add_layer.
21 """
22
Patrick Williamsc0f7c042017-02-23 20:41:17 -060023 def get_fetch_layer(self, fetchdir, url, subdir, fetch_layer):
24 layername = self.get_layer_name(url)
25 if os.path.splitext(layername)[1] == '.git':
26 layername = os.path.splitext(layername)[0]
27 repodir = os.path.join(fetchdir, layername)
28 layerdir = os.path.join(repodir, subdir)
29 if not os.path.exists(repodir):
30 if fetch_layer:
31 result = subprocess.call('git clone %s %s' % (url, repodir), shell = True)
32 if result:
33 logger.error("Failed to download %s" % url)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080034 return None, None, None
Patrick Williamsc0f7c042017-02-23 20:41:17 -060035 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080036 return subdir, layername, layerdir
Patrick Williamsc0f7c042017-02-23 20:41:17 -060037 else:
38 logger.plain("Repository %s needs to be fetched" % url)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080039 return subdir, layername, layerdir
Patrick Williamsc0f7c042017-02-23 20:41:17 -060040 elif os.path.exists(layerdir):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080041 return subdir, layername, layerdir
Patrick Williamsc0f7c042017-02-23 20:41:17 -060042 else:
43 logger.error("%s is not in %s" % (url, subdir))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080044 return None, None, None
Patrick Williamsc0f7c042017-02-23 20:41:17 -060045
46 def do_layerindex_fetch(self, args):
47 """Fetches a layer from a layer index along with its dependent layers, and adds them to conf/bblayers.conf.
48"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -060049
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080050 def _construct_url(baseurls, branches):
51 urls = []
52 for baseurl in baseurls:
53 if baseurl[-1] != '/':
54 baseurl += '/'
55
56 if not baseurl.startswith('cooker'):
57 baseurl += "api/"
58
59 if branches:
60 baseurl += ";branch=%s" % ','.join(branches)
61
62 urls.append(baseurl)
63
64 return urls
65
66
67 # Set the default...
68 if args.branch:
69 branches = [args.branch]
70 else:
71 branches = (self.tinfoil.config_data.getVar('LAYERSERIES_CORENAMES') or 'master').split()
72 logger.debug(1, 'Trying branches: %s' % branches)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060073
74 ignore_layers = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -060075 if args.ignore:
76 ignore_layers.extend(args.ignore.split(','))
77
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080078 # Load the cooker DB
79 cookerIndex = layerindexlib.LayerIndex(self.tinfoil.config_data)
80 cookerIndex.load_layerindex('cooker://', load='layerDependencies')
Patrick Williamsc0f7c042017-02-23 20:41:17 -060081
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080082 # Fast path, check if we already have what has been requested!
83 (dependencies, invalidnames) = cookerIndex.find_dependencies(names=args.layername, ignores=ignore_layers)
84 if not args.show_only and not invalidnames:
85 logger.plain("You already have the requested layer(s): %s" % args.layername)
86 return 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -060087
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080088 # The information to show is already in the cookerIndex
89 if invalidnames:
90 # General URL to use to access the layer index
91 # While there is ONE right now, we're expect users could enter several
92 apiurl = self.tinfoil.config_data.getVar('BBLAYERS_LAYERINDEX_URL').split()
93 if not apiurl:
94 logger.error("Cannot get BBLAYERS_LAYERINDEX_URL")
95 return 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -060096
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080097 remoteIndex = layerindexlib.LayerIndex(self.tinfoil.config_data)
98
99 for remoteurl in _construct_url(apiurl, branches):
100 logger.plain("Loading %s..." % remoteurl)
101 remoteIndex.load_layerindex(remoteurl)
102
103 if remoteIndex.is_empty():
104 logger.error("Remote layer index %s is empty for branches %s" % (apiurl, branches))
105 return 1
106
107 lIndex = cookerIndex + remoteIndex
108
109 (dependencies, invalidnames) = lIndex.find_dependencies(names=args.layername, ignores=ignore_layers)
110
111 if invalidnames:
112 for invaluename in invalidnames:
113 logger.error('Layer "%s" not found in layer index' % invaluename)
114 return 1
115
116 logger.plain("%s %s %s" % ("Layer".ljust(49), "Git repository (branch)".ljust(54), "Subdirectory"))
117 logger.plain('=' * 125)
118
119 for deplayerbranch in dependencies:
120 layerBranch = dependencies[deplayerbranch][0]
121
122 # TODO: Determine display behavior
123 # This is the local content, uncomment to hide local
124 # layers from the display.
125 #if layerBranch.index.config['TYPE'] == 'cooker':
126 # continue
127
128 layerDeps = dependencies[deplayerbranch][1:]
129
130 requiredby = []
131 recommendedby = []
132 for dep in layerDeps:
133 if dep.required:
134 requiredby.append(dep.layer.name)
135 else:
136 recommendedby.append(dep.layer.name)
137
138 logger.plain('%s %s %s' % (("%s:%s:%s" %
139 (layerBranch.index.config['DESCRIPTION'],
140 layerBranch.branch.name,
141 layerBranch.layer.name)).ljust(50),
142 ("%s (%s)" % (layerBranch.layer.vcs_url,
143 layerBranch.actual_branch)).ljust(55),
144 layerBranch.vcs_subdir
145 ))
146 if requiredby:
147 logger.plain(' required by: %s' % ' '.join(requiredby))
148 if recommendedby:
149 logger.plain(' recommended by: %s' % ' '.join(recommendedby))
150
151 if dependencies:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500152 fetchdir = self.tinfoil.config_data.getVar('BBLAYERS_FETCH_DIR')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600153 if not fetchdir:
154 logger.error("Cannot get BBLAYERS_FETCH_DIR")
155 return 1
156 if not os.path.exists(fetchdir):
157 os.makedirs(fetchdir)
158 addlayers = []
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800159
160 for deplayerbranch in dependencies:
161 layerBranch = dependencies[deplayerbranch][0]
162
163 if layerBranch.index.config['TYPE'] == 'cooker':
164 # Anything loaded via cooker is already local, skip it
165 continue
166
167 subdir, name, layerdir = self.get_fetch_layer(fetchdir,
168 layerBranch.layer.vcs_url,
169 layerBranch.vcs_subdir,
170 not args.show_only)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600171 if not name:
172 # Error already shown
173 return 1
174 addlayers.append((subdir, name, layerdir))
175 if not args.show_only:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800176 localargs = argparse.Namespace()
177 localargs.layerdir = []
178 localargs.force = args.force
179 for subdir, name, layerdir in addlayers:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600180 if os.path.exists(layerdir):
181 if subdir:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800182 logger.plain("Adding layer \"%s\" (%s) to conf/bblayers.conf" % (subdir, layerdir))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600183 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800184 logger.plain("Adding layer \"%s\" (%s) to conf/bblayers.conf" % (name, layerdir))
185 localargs.layerdir.append(layerdir)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600186 else:
187 break
188
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800189 if localargs.layerdir:
190 self.do_add_layer(localargs)
191
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600192 def do_layerindex_show_depends(self, args):
193 """Find layer dependencies from layer index.
194"""
195 args.show_only = True
196 args.ignore = []
197 self.do_layerindex_fetch(args)
198
199 def register_commands(self, sp):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800200 parser_layerindex_fetch = self.add_command(sp, 'layerindex-fetch', self.do_layerindex_fetch, parserecipes=False)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600201 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 -0800202 parser_layerindex_fetch.add_argument('-b', '--branch', help='branch name to fetch')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600203 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')
204 parser_layerindex_fetch.add_argument('layername', nargs='+', help='layer to fetch')
205
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800206 parser_layerindex_show_depends = self.add_command(sp, 'layerindex-show-depends', self.do_layerindex_show_depends, parserecipes=False)
207 parser_layerindex_show_depends.add_argument('-b', '--branch', help='branch name to fetch')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600208 parser_layerindex_show_depends.add_argument('layername', nargs='+', help='layer to query')