diff options
| author | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-11-07 13:31:53 +0000 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-11-07 13:31:53 +0000 |
| commit | 8c22ff0d8b70d9b12f0487ef696a7e915b9e3173 (patch) | |
| tree | efdc32587159d0050a69009bdf2330a531727d95 /bitbake/lib/layerindexlib | |
| parent | d412d2747595c1cc4a5e3ca975e3adc31b2f7891 (diff) | |
| download | poky-8c22ff0d8b70d9b12f0487ef696a7e915b9e3173.tar.gz | |
The poky repository master branch is no longer being updated.
You can either:
a) switch to individual clones of bitbake, openembedded-core, meta-yocto and yocto-docs
b) use the new bitbake-setup
You can find information about either approach in our documentation:
https://docs.yoctoproject.org/
Note that "poky" the distro setting is still available in meta-yocto as
before and we continue to use and maintain that.
Long live Poky!
Some further information on the background of this change can be found
in: https://lists.openembedded.org/g/openembedded-architecture/message/2179
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/layerindexlib')
| -rw-r--r-- | bitbake/lib/layerindexlib/README | 28 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/__init__.py | 1377 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/cooker.py | 334 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/plugin.py | 46 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/restapi.py | 392 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/__init__.py | 0 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/common.py | 33 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/cooker.py | 110 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/layerindexobj.py | 210 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/restapi.py | 171 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/testdata/README | 11 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/testdata/build/conf/bblayers.conf | 15 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/testdata/layer1/conf/layer.conf | 17 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/testdata/layer2/conf/layer.conf | 20 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/testdata/layer3/conf/layer.conf | 19 | ||||
| -rw-r--r-- | bitbake/lib/layerindexlib/tests/testdata/layer4/conf/layer.conf | 22 |
16 files changed, 0 insertions, 2805 deletions
diff --git a/bitbake/lib/layerindexlib/README b/bitbake/lib/layerindexlib/README deleted file mode 100644 index 5d927afdf7..0000000000 --- a/bitbake/lib/layerindexlib/README +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | The layerindexlib module is designed to permit programs to work directly | ||
| 2 | with layer index information. (See layers.openembedded.org...) | ||
| 3 | |||
| 4 | The layerindexlib module includes a plugin interface that is used to extend | ||
| 5 | the basic functionality. There are two primary plugins available: restapi | ||
| 6 | and cooker. | ||
| 7 | |||
| 8 | The restapi plugin works with a web based REST Api compatible with the | ||
| 9 | layerindex-web project, as well as the ability to store and retried a | ||
| 10 | the information for one or more files on the disk. | ||
| 11 | |||
| 12 | The cooker plugin works by reading the information from the current build | ||
| 13 | project and processing it as if it were a layer index. | ||
| 14 | |||
| 15 | |||
| 16 | TODO: | ||
| 17 | |||
| 18 | __init__.py: | ||
| 19 | Implement local on-disk caching (using the rest api store/load) | ||
| 20 | Implement layer index style query operations on a combined index | ||
| 21 | |||
| 22 | common.py: | ||
| 23 | Stop network access if BB_NO_NETWORK or allowed hosts is restricted | ||
| 24 | |||
| 25 | cooker.py: | ||
| 26 | Cooker - Implement recipe parsing | ||
| 27 | |||
| 28 | |||
diff --git a/bitbake/lib/layerindexlib/__init__.py b/bitbake/lib/layerindexlib/__init__.py deleted file mode 100644 index c3265ddaa1..0000000000 --- a/bitbake/lib/layerindexlib/__init__.py +++ /dev/null | |||
| @@ -1,1377 +0,0 @@ | |||
| 1 | # Copyright (C) 2016-2018 Wind River Systems, Inc. | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 4 | # | ||
| 5 | |||
| 6 | import datetime | ||
| 7 | |||
| 8 | import logging | ||
| 9 | import os | ||
| 10 | |||
| 11 | from collections import OrderedDict | ||
| 12 | from layerindexlib.plugin import LayerIndexPluginUrlError | ||
| 13 | |||
| 14 | logger = logging.getLogger('BitBake.layerindexlib') | ||
| 15 | |||
| 16 | # Exceptions | ||
| 17 | |||
| 18 | class LayerIndexException(Exception): | ||
| 19 | '''LayerIndex Generic Exception''' | ||
| 20 | def __init__(self, message): | ||
| 21 | self.msg = message | ||
| 22 | Exception.__init__(self, message) | ||
| 23 | |||
| 24 | def __str__(self): | ||
| 25 | return self.msg | ||
| 26 | |||
| 27 | class LayerIndexUrlError(LayerIndexException): | ||
| 28 | '''Exception raised when unable to access a URL for some reason''' | ||
| 29 | def __init__(self, url, message=""): | ||
| 30 | if message: | ||
| 31 | msg = "Unable to access layerindex url %s: %s" % (url, message) | ||
| 32 | else: | ||
| 33 | msg = "Unable to access layerindex url %s" % url | ||
| 34 | self.url = url | ||
| 35 | LayerIndexException.__init__(self, msg) | ||
| 36 | |||
| 37 | class LayerIndexFetchError(LayerIndexException): | ||
| 38 | '''General layerindex fetcher exception when something fails''' | ||
| 39 | def __init__(self, url, message=""): | ||
| 40 | if message: | ||
| 41 | msg = "Unable to fetch layerindex url %s: %s" % (url, message) | ||
| 42 | else: | ||
| 43 | msg = "Unable to fetch layerindex url %s" % url | ||
| 44 | self.url = url | ||
| 45 | LayerIndexException.__init__(self, msg) | ||
| 46 | |||
| 47 | |||
| 48 | # Interface to the overall layerindex system | ||
| 49 | # the layer may contain one or more individual indexes | ||
| 50 | class LayerIndex(): | ||
| 51 | def __init__(self, d): | ||
| 52 | if not d: | ||
| 53 | raise LayerIndexException("Must be initialized with bb.data.") | ||
| 54 | |||
| 55 | self.data = d | ||
| 56 | |||
| 57 | # List of LayerIndexObj | ||
| 58 | self.indexes = [] | ||
| 59 | |||
| 60 | self.plugins = [] | ||
| 61 | |||
| 62 | import bb.utils | ||
| 63 | bb.utils.load_plugins(logger, self.plugins, os.path.dirname(__file__)) | ||
| 64 | for plugin in self.plugins: | ||
| 65 | if hasattr(plugin, 'init'): | ||
| 66 | plugin.init(self) | ||
| 67 | |||
| 68 | def __add__(self, other): | ||
| 69 | newIndex = LayerIndex(self.data) | ||
| 70 | |||
| 71 | if self.__class__ != newIndex.__class__ or \ | ||
| 72 | other.__class__ != newIndex.__class__: | ||
| 73 | raise TypeError("Can not add different types.") | ||
| 74 | |||
| 75 | for indexEnt in self.indexes: | ||
| 76 | newIndex.indexes.append(indexEnt) | ||
| 77 | |||
| 78 | for indexEnt in other.indexes: | ||
| 79 | newIndex.indexes.append(indexEnt) | ||
| 80 | |||
| 81 | return newIndex | ||
| 82 | |||
| 83 | def _parse_params(self, params): | ||
| 84 | '''Take a parameter list, return a dictionary of parameters. | ||
| 85 | |||
| 86 | Expected to be called from the data of urllib.parse.urlparse(url).params | ||
| 87 | |||
| 88 | If there are two conflicting parameters, last in wins... | ||
| 89 | ''' | ||
| 90 | |||
| 91 | param_dict = {} | ||
| 92 | for param in params.split(';'): | ||
| 93 | if not param: | ||
| 94 | continue | ||
| 95 | item = param.split('=', 1) | ||
| 96 | logger.debug(item) | ||
| 97 | param_dict[item[0]] = item[1] | ||
| 98 | |||
| 99 | return param_dict | ||
| 100 | |||
| 101 | def _fetch_url(self, url, username=None, password=None, debuglevel=0): | ||
| 102 | '''Fetch data from a specific URL. | ||
| 103 | |||
| 104 | Fetch something from a specific URL. This is specifically designed to | ||
| 105 | fetch data from a layerindex-web instance, but may be useful for other | ||
| 106 | raw fetch actions. | ||
| 107 | |||
| 108 | It is not designed to be used to fetch recipe sources or similar. the | ||
| 109 | regular fetcher class should used for that. | ||
| 110 | |||
| 111 | It is the responsibility of the caller to check BB_NO_NETWORK and related | ||
| 112 | BB_ALLOWED_NETWORKS. | ||
| 113 | ''' | ||
| 114 | |||
| 115 | if not url: | ||
| 116 | raise LayerIndexUrlError(url, "empty url") | ||
| 117 | |||
| 118 | import urllib | ||
| 119 | from urllib.request import urlopen, Request | ||
| 120 | from urllib.parse import urlparse | ||
| 121 | |||
| 122 | up = urlparse(url) | ||
| 123 | |||
| 124 | if username: | ||
| 125 | logger.debug("Configuring authentication for %s..." % url) | ||
| 126 | password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm() | ||
| 127 | password_mgr.add_password(None, "%s://%s" % (up.scheme, up.netloc), username, password) | ||
| 128 | handler = urllib.request.HTTPBasicAuthHandler(password_mgr) | ||
| 129 | opener = urllib.request.build_opener(handler, urllib.request.HTTPSHandler(debuglevel=debuglevel)) | ||
| 130 | else: | ||
| 131 | opener = urllib.request.build_opener(urllib.request.HTTPSHandler(debuglevel=debuglevel)) | ||
| 132 | |||
| 133 | urllib.request.install_opener(opener) | ||
| 134 | |||
| 135 | logger.debug("Fetching %s (%s)..." % (url, ["without authentication", "with authentication"][bool(username)])) | ||
| 136 | |||
| 137 | try: | ||
| 138 | res = urlopen(Request(url, headers={'User-Agent': 'Mozilla/5.0 (bitbake/lib/layerindex)'}, unverifiable=True)) | ||
| 139 | except urllib.error.HTTPError as e: | ||
| 140 | logger.debug("HTTP Error: %s: %s" % (e.code, e.reason)) | ||
| 141 | logger.debug(" Requested: %s" % (url)) | ||
| 142 | logger.debug(" Actual: %s" % (e.geturl())) | ||
| 143 | |||
| 144 | if e.code == 404: | ||
| 145 | logger.debug("Request not found.") | ||
| 146 | raise LayerIndexFetchError(url, e) | ||
| 147 | else: | ||
| 148 | logger.debug("Headers:\n%s" % (e.headers)) | ||
| 149 | raise LayerIndexFetchError(url, e) | ||
| 150 | except OSError as e: | ||
| 151 | error = 0 | ||
| 152 | reason = "" | ||
| 153 | |||
| 154 | # Process base OSError first... | ||
| 155 | if hasattr(e, 'errno'): | ||
| 156 | error = e.errno | ||
| 157 | reason = e.strerror | ||
| 158 | |||
| 159 | # Process gaierror (socket error) subclass if available. | ||
| 160 | if hasattr(e, 'reason') and hasattr(e.reason, 'errno') and hasattr(e.reason, 'strerror'): | ||
| 161 | error = e.reason.errno | ||
| 162 | reason = e.reason.strerror | ||
| 163 | if error == -2: | ||
| 164 | raise LayerIndexFetchError(url, "%s: %s" % (e, reason)) | ||
| 165 | |||
| 166 | if error and error != 0: | ||
| 167 | raise LayerIndexFetchError(url, "Unexpected exception: [Error %s] %s" % (error, reason)) | ||
| 168 | else: | ||
| 169 | raise LayerIndexFetchError(url, "Unable to fetch OSError exception: %s" % e) | ||
| 170 | |||
| 171 | finally: | ||
| 172 | logger.debug("...fetching %s (%s), done." % (url, ["without authentication", "with authentication"][bool(username)])) | ||
| 173 | |||
| 174 | return res | ||
| 175 | |||
| 176 | |||
| 177 | def load_layerindex(self, indexURI, load=['layerDependencies', 'recipes', 'machines', 'distros'], reload=False): | ||
| 178 | '''Load the layerindex. | ||
| 179 | |||
| 180 | indexURI - An index to load. (Use multiple calls to load multiple indexes) | ||
| 181 | |||
| 182 | reload - If reload is True, then any previously loaded indexes will be forgotten. | ||
| 183 | |||
| 184 | load - List of elements to load. Default loads all items. | ||
| 185 | Note: plugs may ignore this. | ||
| 186 | |||
| 187 | The format of the indexURI: | ||
| 188 | |||
| 189 | <url>;branch=<branch>;cache=<cache>;desc=<description> | ||
| 190 | |||
| 191 | Note: the 'branch' parameter if set can select multiple branches by using | ||
| 192 | comma, such as 'branch=master,morty,pyro'. However, many operations only look | ||
| 193 | at the -first- branch specified! | ||
| 194 | |||
| 195 | The cache value may be undefined, in this case a network failure will | ||
| 196 | result in an error, otherwise the system will look for a file of the cache | ||
| 197 | name and load that instead. | ||
| 198 | |||
| 199 | For example: | ||
| 200 | |||
| 201 | https://layers.openembedded.org/layerindex/api/;branch=master;desc=OpenEmbedded%20Layer%20Index | ||
| 202 | cooker:// | ||
| 203 | ''' | ||
| 204 | if reload: | ||
| 205 | self.indexes = [] | ||
| 206 | |||
| 207 | logger.debug('Loading: %s' % indexURI) | ||
| 208 | |||
| 209 | if not self.plugins: | ||
| 210 | raise LayerIndexException("No LayerIndex Plugins available") | ||
| 211 | |||
| 212 | for plugin in self.plugins: | ||
| 213 | # Check if the plugin was initialized | ||
| 214 | logger.debug('Trying %s' % plugin.__class__) | ||
| 215 | if not hasattr(plugin, 'type') or not plugin.type: | ||
| 216 | continue | ||
| 217 | try: | ||
| 218 | # TODO: Implement 'cache', for when the network is not available | ||
| 219 | indexEnt = plugin.load_index(indexURI, load) | ||
| 220 | break | ||
| 221 | except LayerIndexPluginUrlError as e: | ||
| 222 | logger.debug("%s doesn't support %s" % (plugin.type, e.url)) | ||
| 223 | except NotImplementedError: | ||
| 224 | pass | ||
| 225 | else: | ||
| 226 | logger.debug("No plugins support %s" % indexURI) | ||
| 227 | raise LayerIndexException("No plugins support %s" % indexURI) | ||
| 228 | |||
| 229 | # Mark CONFIG data as something we've added... | ||
| 230 | indexEnt.config['local'] = [] | ||
| 231 | indexEnt.config['local'].append('config') | ||
| 232 | |||
| 233 | # No longer permit changes.. | ||
| 234 | indexEnt.lockData() | ||
| 235 | |||
| 236 | self.indexes.append(indexEnt) | ||
| 237 | |||
| 238 | def store_layerindex(self, indexURI, index=None): | ||
| 239 | '''Store one layerindex | ||
| 240 | |||
| 241 | Typically this will be used to create a local cache file of a remote index. | ||
| 242 | |||
| 243 | file://<path>;branch=<branch> | ||
| 244 | |||
| 245 | We can write out in either the restapi or django formats. The split option | ||
| 246 | will write out the individual elements split by layer and related components. | ||
| 247 | ''' | ||
| 248 | if not index: | ||
| 249 | logger.warning('No index to write, nothing to do.') | ||
| 250 | return | ||
| 251 | |||
| 252 | if not self.plugins: | ||
| 253 | raise LayerIndexException("No LayerIndex Plugins available") | ||
| 254 | |||
| 255 | for plugin in self.plugins: | ||
| 256 | # Check if the plugin was initialized | ||
| 257 | logger.debug('Trying %s' % plugin.__class__) | ||
| 258 | if not hasattr(plugin, 'type') or not plugin.type: | ||
| 259 | continue | ||
| 260 | try: | ||
| 261 | plugin.store_index(indexURI, index) | ||
| 262 | break | ||
| 263 | except LayerIndexPluginUrlError as e: | ||
| 264 | logger.debug("%s doesn't support %s" % (plugin.type, e.url)) | ||
| 265 | except NotImplementedError: | ||
| 266 | logger.debug("Store not implemented in %s" % plugin.type) | ||
| 267 | pass | ||
| 268 | else: | ||
| 269 | logger.debug("No plugins support %s" % indexURI) | ||
| 270 | raise LayerIndexException("No plugins support %s" % indexURI) | ||
| 271 | |||
| 272 | |||
| 273 | def is_empty(self): | ||
| 274 | '''Return True or False if the index has any usable data. | ||
| 275 | |||
| 276 | We check the indexes entries to see if they have a branch set, as well as | ||
| 277 | layerBranches set. If not, they are effectively blank.''' | ||
| 278 | |||
| 279 | found = False | ||
| 280 | for index in self.indexes: | ||
| 281 | if index.__bool__(): | ||
| 282 | found = True | ||
| 283 | break | ||
| 284 | return not found | ||
| 285 | |||
| 286 | |||
| 287 | def find_vcs_url(self, vcs_url, branch=None): | ||
| 288 | '''Return the first layerBranch with the given vcs_url | ||
| 289 | |||
| 290 | If a branch has not been specified, we will iterate over the branches in | ||
| 291 | the default configuration until the first vcs_url/branch match.''' | ||
| 292 | |||
| 293 | for index in self.indexes: | ||
| 294 | logger.debug(' searching %s' % index.config['DESCRIPTION']) | ||
| 295 | layerBranch = index.find_vcs_url(vcs_url, [branch]) | ||
| 296 | if layerBranch: | ||
| 297 | return layerBranch | ||
| 298 | return None | ||
| 299 | |||
| 300 | def find_collection(self, collection, version=None, branch=None): | ||
| 301 | '''Return the first layerBranch with the given collection name | ||
| 302 | |||
| 303 | If a branch has not been specified, we will iterate over the branches in | ||
| 304 | the default configuration until the first collection/branch match.''' | ||
| 305 | |||
| 306 | logger.debug('find_collection: %s (%s) %s' % (collection, version, branch)) | ||
| 307 | |||
| 308 | if branch: | ||
| 309 | branches = [branch] | ||
| 310 | else: | ||
| 311 | branches = None | ||
| 312 | |||
| 313 | for index in self.indexes: | ||
| 314 | logger.debug(' searching %s' % index.config['DESCRIPTION']) | ||
| 315 | layerBranch = index.find_collection(collection, version, branches) | ||
| 316 | if layerBranch: | ||
| 317 | return layerBranch | ||
| 318 | else: | ||
| 319 | logger.debug('Collection %s (%s) not found for branch (%s)' % (collection, version, branch)) | ||
| 320 | return None | ||
| 321 | |||
| 322 | def find_layerbranch(self, name, branch=None): | ||
| 323 | '''Return the layerBranch item for a given name and branch | ||
| 324 | |||
| 325 | If a branch has not been specified, we will iterate over the branches in | ||
| 326 | the default configuration until the first name/branch match.''' | ||
| 327 | |||
| 328 | if branch: | ||
| 329 | branches = [branch] | ||
| 330 | else: | ||
| 331 | branches = None | ||
| 332 | |||
| 333 | for index in self.indexes: | ||
| 334 | layerBranch = index.find_layerbranch(name, branches) | ||
| 335 | if layerBranch: | ||
| 336 | return layerBranch | ||
| 337 | return None | ||
| 338 | |||
| 339 | def find_dependencies(self, names=None, layerbranches=None, ignores=None): | ||
| 340 | '''Return a tuple of all dependencies and valid items for the list of (layer) names | ||
| 341 | |||
| 342 | The dependency scanning happens depth-first. The returned | ||
| 343 | dependencies should be in the best order to define bblayers. | ||
| 344 | |||
| 345 | names - list of layer names (searching layerItems) | ||
| 346 | branches - when specified (with names) only this list of branches are evaluated | ||
| 347 | |||
| 348 | layerbranches - list of layerbranches to resolve dependencies | ||
| 349 | |||
| 350 | ignores - list of layer names to ignore | ||
| 351 | |||
| 352 | return: (dependencies, invalid) | ||
| 353 | |||
| 354 | dependencies[LayerItem.name] = [ LayerBranch, LayerDependency1, LayerDependency2, ... ] | ||
| 355 | invalid = [ LayerItem.name1, LayerItem.name2, ... ] | ||
| 356 | ''' | ||
| 357 | |||
| 358 | invalid = [] | ||
| 359 | |||
| 360 | # Convert name/branch to layerbranches | ||
| 361 | if layerbranches is None: | ||
| 362 | layerbranches = [] | ||
| 363 | |||
| 364 | for name in names: | ||
| 365 | if ignores and name in ignores: | ||
| 366 | continue | ||
| 367 | |||
| 368 | for index in self.indexes: | ||
| 369 | layerbranch = index.find_layerbranch(name) | ||
| 370 | if not layerbranch: | ||
| 371 | # Not in this index, hopefully it's in another... | ||
| 372 | continue | ||
| 373 | layerbranches.append(layerbranch) | ||
| 374 | break | ||
| 375 | else: | ||
| 376 | invalid.append(name) | ||
| 377 | |||
| 378 | |||
| 379 | def _resolve_dependencies(layerbranches, ignores, dependencies, invalid, processed=None): | ||
| 380 | for layerbranch in layerbranches: | ||
| 381 | if ignores and layerbranch.layer.name in ignores: | ||
| 382 | continue | ||
| 383 | |||
| 384 | # Get a list of dependencies and then recursively process them | ||
| 385 | for layerdependency in layerbranch.index.layerDependencies_layerBranchId[layerbranch.id]: | ||
| 386 | try: | ||
| 387 | deplayerbranch = layerdependency.dependency_layerBranch | ||
| 388 | except AttributeError as e: | ||
| 389 | logger.error('LayerBranch does not exist for dependent layer {}:{}\n' \ | ||
| 390 | ' Cannot continue successfully.\n' \ | ||
| 391 | ' You might be able to resolve this by checking out the layer locally.\n' \ | ||
| 392 | ' Consider reaching out the to the layer maintainers or the layerindex admins' \ | ||
| 393 | .format(layerdependency.dependency.name, layerbranch.branch.name)) | ||
| 394 | |||
| 395 | if ignores and deplayerbranch.layer.name in ignores: | ||
| 396 | continue | ||
| 397 | |||
| 398 | # Since this is depth first, we need to know what we're currently processing | ||
| 399 | # in order to avoid infinite recursion on a loop. | ||
| 400 | if processed and deplayerbranch.layer.name in processed: | ||
| 401 | # We have found a recursion... | ||
| 402 | logger.warning('Circular layer dependency found: %s -> %s' % (processed, deplayerbranch.layer.name)) | ||
| 403 | continue | ||
| 404 | |||
| 405 | # This little block is why we can't re-use the LayerIndexObj version, | ||
| 406 | # we must be able to satisfy each dependencies across layer indexes and | ||
| 407 | # use the layer index order for priority. (r stands for replacement below) | ||
| 408 | |||
| 409 | # If this is the primary index, we can fast path and skip this | ||
| 410 | if deplayerbranch.index != self.indexes[0]: | ||
| 411 | # Is there an entry in a prior index for this collection/version? | ||
| 412 | rdeplayerbranch = self.find_collection( | ||
| 413 | collection=deplayerbranch.collection, | ||
| 414 | version=deplayerbranch.version | ||
| 415 | ) | ||
| 416 | if rdeplayerbranch != deplayerbranch: | ||
| 417 | logger.debug('Replaced %s:%s:%s with %s:%s:%s' % \ | ||
| 418 | (deplayerbranch.index.config['DESCRIPTION'], | ||
| 419 | deplayerbranch.branch.name, | ||
| 420 | deplayerbranch.layer.name, | ||
| 421 | rdeplayerbranch.index.config['DESCRIPTION'], | ||
| 422 | rdeplayerbranch.branch.name, | ||
| 423 | rdeplayerbranch.layer.name)) | ||
| 424 | deplayerbranch = rdeplayerbranch | ||
| 425 | |||
| 426 | # New dependency, we need to resolve it now... depth-first | ||
| 427 | if deplayerbranch.layer.name not in dependencies: | ||
| 428 | # Avoid recursion on this branch. | ||
| 429 | # We copy so we don't end up polluting the depth-first branch with other | ||
| 430 | # branches. Duplication between individual branches IS expected and | ||
| 431 | # handled by 'dependencies' processing. | ||
| 432 | if not processed: | ||
| 433 | local_processed = [] | ||
| 434 | else: | ||
| 435 | local_processed = processed.copy() | ||
| 436 | local_processed.append(deplayerbranch.layer.name) | ||
| 437 | |||
| 438 | (dependencies, invalid) = _resolve_dependencies([deplayerbranch], ignores, dependencies, invalid, local_processed) | ||
| 439 | |||
| 440 | if deplayerbranch.layer.name not in dependencies: | ||
| 441 | dependencies[deplayerbranch.layer.name] = [deplayerbranch, layerdependency] | ||
| 442 | else: | ||
| 443 | if layerdependency not in dependencies[deplayerbranch.layer.name]: | ||
| 444 | dependencies[deplayerbranch.layer.name].append(layerdependency) | ||
| 445 | |||
| 446 | return (dependencies, invalid) | ||
| 447 | |||
| 448 | # OK, resolve this one... | ||
| 449 | dependencies = OrderedDict() | ||
| 450 | (dependencies, invalid) = _resolve_dependencies(layerbranches, ignores, dependencies, invalid) | ||
| 451 | |||
| 452 | for layerbranch in layerbranches: | ||
| 453 | if layerbranch.layer.name not in dependencies: | ||
| 454 | dependencies[layerbranch.layer.name] = [layerbranch] | ||
| 455 | |||
| 456 | return (dependencies, invalid) | ||
| 457 | |||
| 458 | |||
| 459 | def list_obj(self, object): | ||
| 460 | '''Print via the plain logger object information | ||
| 461 | |||
| 462 | This function is used to implement debugging and provide the user info. | ||
| 463 | ''' | ||
| 464 | for lix in self.indexes: | ||
| 465 | if not hasattr(lix, object): | ||
| 466 | continue | ||
| 467 | |||
| 468 | logger.plain ('') | ||
| 469 | logger.plain ('Index: %s' % lix.config['DESCRIPTION']) | ||
| 470 | |||
| 471 | output = [] | ||
| 472 | |||
| 473 | if object == 'branches': | ||
| 474 | logger.plain ('%s %s %s' % ('{:26}'.format('branch'), '{:34}'.format('description'), '{:22}'.format('bitbake branch'))) | ||
| 475 | logger.plain ('{:-^80}'.format("")) | ||
| 476 | for branchid in lix.branches: | ||
| 477 | output.append('%s %s %s' % ( | ||
| 478 | '{:26}'.format(lix.branches[branchid].name), | ||
| 479 | '{:34}'.format(lix.branches[branchid].short_description), | ||
| 480 | '{:22}'.format(lix.branches[branchid].bitbake_branch) | ||
| 481 | )) | ||
| 482 | for line in sorted(output): | ||
| 483 | logger.plain (line) | ||
| 484 | |||
| 485 | continue | ||
| 486 | |||
| 487 | if object == 'layerItems': | ||
| 488 | logger.plain ('%s %s' % ('{:26}'.format('layer'), '{:34}'.format('description'))) | ||
| 489 | logger.plain ('{:-^80}'.format("")) | ||
| 490 | for layerid in lix.layerItems: | ||
| 491 | output.append('%s %s' % ( | ||
| 492 | '{:26}'.format(lix.layerItems[layerid].name), | ||
| 493 | '{:34}'.format(lix.layerItems[layerid].summary) | ||
| 494 | )) | ||
| 495 | for line in sorted(output): | ||
| 496 | logger.plain (line) | ||
| 497 | |||
| 498 | continue | ||
| 499 | |||
| 500 | if object == 'layerBranches': | ||
| 501 | logger.plain ('%s %s %s' % ('{:26}'.format('layer'), '{:34}'.format('description'), '{:19}'.format('collection:version'))) | ||
| 502 | logger.plain ('{:-^80}'.format("")) | ||
| 503 | for layerbranchid in lix.layerBranches: | ||
| 504 | output.append('%s %s %s' % ( | ||
| 505 | '{:26}'.format(lix.layerBranches[layerbranchid].layer.name), | ||
| 506 | '{:34}'.format(lix.layerBranches[layerbranchid].layer.summary), | ||
| 507 | '{:19}'.format("%s:%s" % | ||
| 508 | (lix.layerBranches[layerbranchid].collection, | ||
| 509 | lix.layerBranches[layerbranchid].version) | ||
| 510 | ) | ||
| 511 | )) | ||
| 512 | for line in sorted(output): | ||
| 513 | logger.plain (line) | ||
| 514 | |||
| 515 | continue | ||
| 516 | |||
| 517 | if object == 'layerDependencies': | ||
| 518 | logger.plain ('%s %s %s %s' % ('{:19}'.format('branch'), '{:26}'.format('layer'), '{:11}'.format('dependency'), '{:26}'.format('layer'))) | ||
| 519 | logger.plain ('{:-^80}'.format("")) | ||
| 520 | for layerDependency in lix.layerDependencies: | ||
| 521 | if not lix.layerDependencies[layerDependency].dependency_layerBranch: | ||
| 522 | continue | ||
| 523 | |||
| 524 | output.append('%s %s %s %s' % ( | ||
| 525 | '{:19}'.format(lix.layerDependencies[layerDependency].layerbranch.branch.name), | ||
| 526 | '{:26}'.format(lix.layerDependencies[layerDependency].layerbranch.layer.name), | ||
| 527 | '{:11}'.format('requires' if lix.layerDependencies[layerDependency].required else 'recommends'), | ||
| 528 | '{:26}'.format(lix.layerDependencies[layerDependency].dependency_layerBranch.layer.name) | ||
| 529 | )) | ||
| 530 | for line in sorted(output): | ||
| 531 | logger.plain (line) | ||
| 532 | |||
| 533 | continue | ||
| 534 | |||
| 535 | if object == 'recipes': | ||
| 536 | logger.plain ('%s %s %s' % ('{:20}'.format('recipe'), '{:10}'.format('version'), 'layer')) | ||
| 537 | logger.plain ('{:-^80}'.format("")) | ||
| 538 | output = [] | ||
| 539 | for recipe in lix.recipes: | ||
| 540 | output.append('%s %s %s' % ( | ||
| 541 | '{:30}'.format(lix.recipes[recipe].pn), | ||
| 542 | '{:30}'.format(lix.recipes[recipe].pv), | ||
| 543 | lix.recipes[recipe].layer.name | ||
| 544 | )) | ||
| 545 | for line in sorted(output): | ||
| 546 | logger.plain (line) | ||
| 547 | |||
| 548 | continue | ||
| 549 | |||
| 550 | if object == 'machines': | ||
| 551 | logger.plain ('%s %s %s' % ('{:24}'.format('machine'), '{:34}'.format('description'), '{:19}'.format('layer'))) | ||
| 552 | logger.plain ('{:-^80}'.format("")) | ||
| 553 | for machine in lix.machines: | ||
| 554 | output.append('%s %s %s' % ( | ||
| 555 | '{:24}'.format(lix.machines[machine].name), | ||
| 556 | '{:34}'.format(lix.machines[machine].description)[:34], | ||
| 557 | '{:19}'.format(lix.machines[machine].layerbranch.layer.name) | ||
| 558 | )) | ||
| 559 | for line in sorted(output): | ||
| 560 | logger.plain (line) | ||
| 561 | |||
| 562 | continue | ||
| 563 | |||
| 564 | if object == 'distros': | ||
| 565 | logger.plain ('%s %s %s' % ('{:24}'.format('distro'), '{:34}'.format('description'), '{:19}'.format('layer'))) | ||
| 566 | logger.plain ('{:-^80}'.format("")) | ||
| 567 | for distro in lix.distros: | ||
| 568 | output.append('%s %s %s' % ( | ||
| 569 | '{:24}'.format(lix.distros[distro].name), | ||
| 570 | '{:34}'.format(lix.distros[distro].description)[:34], | ||
| 571 | '{:19}'.format(lix.distros[distro].layerbranch.layer.name) | ||
| 572 | )) | ||
| 573 | for line in sorted(output): | ||
| 574 | logger.plain (line) | ||
| 575 | |||
| 576 | continue | ||
| 577 | |||
| 578 | logger.plain ('') | ||
| 579 | |||
| 580 | |||
| 581 | # This class holds a single layer index instance | ||
| 582 | # The LayerIndexObj is made up of dictionary of elements, such as: | ||
| 583 | # index['config'] - configuration data for this index | ||
| 584 | # index['branches'] - dictionary of Branch objects, by id number | ||
| 585 | # index['layerItems'] - dictionary of layerItem objects, by id number | ||
| 586 | # ...etc... (See: https://layers.openembedded.org/layerindex/api/) | ||
| 587 | # | ||
| 588 | # The class needs to manage the 'index' entries and allow easily adding | ||
| 589 | # of new items, as well as simply loading of the items. | ||
| 590 | class LayerIndexObj(): | ||
| 591 | def __init__(self): | ||
| 592 | super().__setattr__('_index', {}) | ||
| 593 | super().__setattr__('_lock', False) | ||
| 594 | |||
| 595 | def __bool__(self): | ||
| 596 | '''False if the index is effectively empty | ||
| 597 | |||
| 598 | We check the index to see if it has a branch set, as well as | ||
| 599 | layerbranches set. If not, it is effectively blank.''' | ||
| 600 | |||
| 601 | if not bool(self._index): | ||
| 602 | return False | ||
| 603 | |||
| 604 | try: | ||
| 605 | if self.branches and self.layerBranches: | ||
| 606 | return True | ||
| 607 | except AttributeError: | ||
| 608 | pass | ||
| 609 | |||
| 610 | return False | ||
| 611 | |||
| 612 | def __getattr__(self, name): | ||
| 613 | if name.startswith('_'): | ||
| 614 | return super().__getattribute__(name) | ||
| 615 | |||
| 616 | if name not in self._index: | ||
| 617 | raise AttributeError('%s not in index datastore' % name) | ||
| 618 | |||
| 619 | return self._index[name] | ||
| 620 | |||
| 621 | def __setattr__(self, name, value): | ||
| 622 | if self.isLocked(): | ||
| 623 | raise TypeError("Can not set attribute '%s': index is locked" % name) | ||
| 624 | |||
| 625 | if name.startswith('_'): | ||
| 626 | super().__setattr__(name, value) | ||
| 627 | return | ||
| 628 | |||
| 629 | self._index[name] = value | ||
| 630 | |||
| 631 | def __delattr__(self, name): | ||
| 632 | if self.isLocked(): | ||
| 633 | raise TypeError("Can not delete attribute '%s': index is locked" % name) | ||
| 634 | |||
| 635 | if name.startswith('_'): | ||
| 636 | super().__delattr__(name) | ||
| 637 | |||
| 638 | self._index.pop(name) | ||
| 639 | |||
| 640 | def lockData(self): | ||
| 641 | '''Lock data object (make it readonly)''' | ||
| 642 | super().__setattr__("_lock", True) | ||
| 643 | |||
| 644 | def unlockData(self): | ||
| 645 | '''unlock data object (make it readonly)''' | ||
| 646 | super().__setattr__("_lock", False) | ||
| 647 | |||
| 648 | # When the data is unlocked, we have to clear the caches, as | ||
| 649 | # modification is allowed! | ||
| 650 | del(self._layerBranches_layerId_branchId) | ||
| 651 | del(self._layerDependencies_layerBranchId) | ||
| 652 | del(self._layerBranches_vcsUrl) | ||
| 653 | |||
| 654 | def isLocked(self): | ||
| 655 | '''Is this object locked (readonly)?''' | ||
| 656 | return self._lock | ||
| 657 | |||
| 658 | def add_element(self, indexname, objs): | ||
| 659 | '''Add a layer index object to index.<indexname>''' | ||
| 660 | if indexname not in self._index: | ||
| 661 | self._index[indexname] = {} | ||
| 662 | |||
| 663 | for obj in objs: | ||
| 664 | if obj.id in self._index[indexname]: | ||
| 665 | if self._index[indexname][obj.id] == obj: | ||
| 666 | continue | ||
| 667 | raise LayerIndexException('Conflict adding object %s(%s) to index' % (indexname, obj.id)) | ||
| 668 | self._index[indexname][obj.id] = obj | ||
| 669 | |||
| 670 | def add_raw_element(self, indexname, objtype, rawobjs): | ||
| 671 | '''Convert a raw layer index data item to a layer index item object and add to the index''' | ||
| 672 | objs = [] | ||
| 673 | for entry in rawobjs: | ||
| 674 | objs.append(objtype(self, entry)) | ||
| 675 | self.add_element(indexname, objs) | ||
| 676 | |||
| 677 | # Quick lookup table for searching layerId and branchID combos | ||
| 678 | @property | ||
| 679 | def layerBranches_layerId_branchId(self): | ||
| 680 | def createCache(self): | ||
| 681 | cache = {} | ||
| 682 | for layerbranchid in self.layerBranches: | ||
| 683 | layerbranch = self.layerBranches[layerbranchid] | ||
| 684 | cache["%s:%s" % (layerbranch.layer_id, layerbranch.branch_id)] = layerbranch | ||
| 685 | return cache | ||
| 686 | |||
| 687 | if self.isLocked(): | ||
| 688 | cache = getattr(self, '_layerBranches_layerId_branchId', None) | ||
| 689 | else: | ||
| 690 | cache = None | ||
| 691 | |||
| 692 | if not cache: | ||
| 693 | cache = createCache(self) | ||
| 694 | |||
| 695 | if self.isLocked(): | ||
| 696 | super().__setattr__('_layerBranches_layerId_branchId', cache) | ||
| 697 | |||
| 698 | return cache | ||
| 699 | |||
| 700 | # Quick lookup table for finding all dependencies of a layerBranch | ||
| 701 | @property | ||
| 702 | def layerDependencies_layerBranchId(self): | ||
| 703 | def createCache(self): | ||
| 704 | cache = {} | ||
| 705 | # This ensures empty lists for all branchids | ||
| 706 | for layerbranchid in self.layerBranches: | ||
| 707 | cache[layerbranchid] = [] | ||
| 708 | |||
| 709 | for layerdependencyid in self.layerDependencies: | ||
| 710 | layerdependency = self.layerDependencies[layerdependencyid] | ||
| 711 | cache[layerdependency.layerbranch_id].append(layerdependency) | ||
| 712 | return cache | ||
| 713 | |||
| 714 | if self.isLocked(): | ||
| 715 | cache = getattr(self, '_layerDependencies_layerBranchId', None) | ||
| 716 | else: | ||
| 717 | cache = None | ||
| 718 | |||
| 719 | if not cache: | ||
| 720 | cache = createCache(self) | ||
| 721 | |||
| 722 | if self.isLocked(): | ||
| 723 | super().__setattr__('_layerDependencies_layerBranchId', cache) | ||
| 724 | |||
| 725 | return cache | ||
| 726 | |||
| 727 | # Quick lookup table for finding all instances of a vcs_url | ||
| 728 | @property | ||
| 729 | def layerBranches_vcsUrl(self): | ||
| 730 | def createCache(self): | ||
| 731 | cache = {} | ||
| 732 | for layerbranchid in self.layerBranches: | ||
| 733 | layerbranch = self.layerBranches[layerbranchid] | ||
| 734 | if layerbranch.layer.vcs_url not in cache: | ||
| 735 | cache[layerbranch.layer.vcs_url] = [layerbranch] | ||
| 736 | else: | ||
| 737 | cache[layerbranch.layer.vcs_url].append(layerbranch) | ||
| 738 | return cache | ||
| 739 | |||
| 740 | if self.isLocked(): | ||
| 741 | cache = getattr(self, '_layerBranches_vcsUrl', None) | ||
| 742 | else: | ||
| 743 | cache = None | ||
| 744 | |||
| 745 | if not cache: | ||
| 746 | cache = createCache(self) | ||
| 747 | |||
| 748 | if self.isLocked(): | ||
| 749 | super().__setattr__('_layerBranches_vcsUrl', cache) | ||
| 750 | |||
| 751 | return cache | ||
| 752 | |||
| 753 | |||
| 754 | def find_vcs_url(self, vcs_url, branches=None): | ||
| 755 | ''''Return the first layerBranch with the given vcs_url | ||
| 756 | |||
| 757 | If a list of branches has not been specified, we will iterate on | ||
| 758 | all branches until the first vcs_url is found.''' | ||
| 759 | |||
| 760 | if not self.__bool__(): | ||
| 761 | return None | ||
| 762 | |||
| 763 | for layerbranch in self.layerBranches_vcsUrl: | ||
| 764 | if branches and layerbranch.branch.name not in branches: | ||
| 765 | continue | ||
| 766 | |||
| 767 | return layerbranch | ||
| 768 | |||
| 769 | return None | ||
| 770 | |||
| 771 | |||
| 772 | def find_collection(self, collection, version=None, branches=None): | ||
| 773 | '''Return the first layerBranch with the given collection name | ||
| 774 | |||
| 775 | If a list of branches has not been specified, we will iterate on | ||
| 776 | all branches until the first collection is found.''' | ||
| 777 | |||
| 778 | if not self.__bool__(): | ||
| 779 | return None | ||
| 780 | |||
| 781 | for layerbranchid in self.layerBranches: | ||
| 782 | layerbranch = self.layerBranches[layerbranchid] | ||
| 783 | if branches and layerbranch.branch.name not in branches: | ||
| 784 | continue | ||
| 785 | |||
| 786 | if layerbranch.collection == collection and \ | ||
| 787 | (version is None or version == layerbranch.version): | ||
| 788 | return layerbranch | ||
| 789 | |||
| 790 | return None | ||
| 791 | |||
| 792 | |||
| 793 | def find_layerbranch(self, name, branches=None): | ||
| 794 | '''Return the first layerbranch whose layer name matches | ||
| 795 | |||
| 796 | If a list of branches has not been specified, we will iterate on | ||
| 797 | all branches until the first layer with that name is found.''' | ||
| 798 | |||
| 799 | if not self.__bool__(): | ||
| 800 | return None | ||
| 801 | |||
| 802 | for layerbranchid in self.layerBranches: | ||
| 803 | layerbranch = self.layerBranches[layerbranchid] | ||
| 804 | if branches and layerbranch.branch.name not in branches: | ||
| 805 | continue | ||
| 806 | |||
| 807 | if layerbranch.layer.name == name: | ||
| 808 | return layerbranch | ||
| 809 | |||
| 810 | return None | ||
| 811 | |||
| 812 | def find_dependencies(self, names=None, branches=None, layerBranches=None, ignores=None): | ||
| 813 | '''Return a tuple of all dependencies and valid items for the list of (layer) names | ||
| 814 | |||
| 815 | The dependency scanning happens depth-first. The returned | ||
| 816 | dependencies should be in the best order to define bblayers. | ||
| 817 | |||
| 818 | names - list of layer names (searching layerItems) | ||
| 819 | branches - when specified (with names) only this list of branches are evaluated | ||
| 820 | |||
| 821 | layerBranches - list of layerBranches to resolve dependencies | ||
| 822 | |||
| 823 | ignores - list of layer names to ignore | ||
| 824 | |||
| 825 | return: (dependencies, invalid) | ||
| 826 | |||
| 827 | dependencies[LayerItem.name] = [ LayerBranch, LayerDependency1, LayerDependency2, ... ] | ||
| 828 | invalid = [ LayerItem.name1, LayerItem.name2, ... ]''' | ||
| 829 | |||
| 830 | invalid = [] | ||
| 831 | |||
| 832 | # Convert name/branch to layerBranches | ||
| 833 | if layerbranches is None: | ||
| 834 | layerbranches = [] | ||
| 835 | |||
| 836 | for name in names: | ||
| 837 | if ignores and name in ignores: | ||
| 838 | continue | ||
| 839 | |||
| 840 | layerbranch = self.find_layerbranch(name, branches) | ||
| 841 | if not layerbranch: | ||
| 842 | invalid.append(name) | ||
| 843 | else: | ||
| 844 | layerbranches.append(layerbranch) | ||
| 845 | |||
| 846 | for layerbranch in layerbranches: | ||
| 847 | if layerbranch.index != self: | ||
| 848 | raise LayerIndexException("Can not resolve dependencies across indexes with this class function!") | ||
| 849 | |||
| 850 | def _resolve_dependencies(layerbranches, ignores, dependencies, invalid): | ||
| 851 | for layerbranch in layerbranches: | ||
| 852 | if ignores and layerbranch.layer.name in ignores: | ||
| 853 | continue | ||
| 854 | |||
| 855 | for layerdependency in layerbranch.index.layerDependencies_layerBranchId[layerbranch.id]: | ||
| 856 | deplayerbranch = layerdependency.dependency_layerBranch or None | ||
| 857 | |||
| 858 | if ignores and deplayerbranch.layer.name in ignores: | ||
| 859 | continue | ||
| 860 | |||
| 861 | # New dependency, we need to resolve it now... depth-first | ||
| 862 | if deplayerbranch.layer.name not in dependencies: | ||
| 863 | (dependencies, invalid) = _resolve_dependencies([deplayerbranch], ignores, dependencies, invalid) | ||
| 864 | |||
| 865 | if deplayerbranch.layer.name not in dependencies: | ||
| 866 | dependencies[deplayerbranch.layer.name] = [deplayerbranch, layerdependency] | ||
| 867 | else: | ||
| 868 | if layerdependency not in dependencies[deplayerbranch.layer.name]: | ||
| 869 | dependencies[deplayerbranch.layer.name].append(layerdependency) | ||
| 870 | |||
| 871 | return (dependencies, invalid) | ||
| 872 | |||
| 873 | # OK, resolve this one... | ||
| 874 | dependencies = OrderedDict() | ||
| 875 | (dependencies, invalid) = _resolve_dependencies(layerbranches, ignores, dependencies, invalid) | ||
| 876 | |||
| 877 | # Is this item already in the list, if not add it | ||
| 878 | for layerbranch in layerbranches: | ||
| 879 | if layerbranch.layer.name not in dependencies: | ||
| 880 | dependencies[layerbranch.layer.name] = [layerbranch] | ||
| 881 | |||
| 882 | return (dependencies, invalid) | ||
| 883 | |||
| 884 | |||
| 885 | # Define a basic LayerIndexItemObj. This object forms the basis for all other | ||
| 886 | # objects. The raw Layer Index data is stored in the _data element, but we | ||
| 887 | # do not want users to access data directly. So wrap this and protect it | ||
| 888 | # from direct manipulation. | ||
| 889 | # | ||
| 890 | # It is up to the insantiators of the objects to fill them out, and once done | ||
| 891 | # lock the objects to prevent further accidently manipulation. | ||
| 892 | # | ||
| 893 | # Using the getattr, setattr and properties we can access and manipulate | ||
| 894 | # the data within the data element. | ||
| 895 | class LayerIndexItemObj(): | ||
| 896 | def __init__(self, index, data=None, lock=False): | ||
| 897 | if data is None: | ||
| 898 | data = {} | ||
| 899 | |||
| 900 | if type(data) != type(dict()): | ||
| 901 | raise TypeError('data (%s) is not a dict' % type(data)) | ||
| 902 | |||
| 903 | super().__setattr__('_lock', lock) | ||
| 904 | super().__setattr__('index', index) | ||
| 905 | super().__setattr__('_data', data) | ||
| 906 | |||
| 907 | def __eq__(self, other): | ||
| 908 | if self.__class__ != other.__class__: | ||
| 909 | return False | ||
| 910 | res=(self._data == other._data) | ||
| 911 | return res | ||
| 912 | |||
| 913 | def __bool__(self): | ||
| 914 | return bool(self._data) | ||
| 915 | |||
| 916 | def __getattr__(self, name): | ||
| 917 | # These are internal to THIS class, and not part of data | ||
| 918 | if name == "index" or name.startswith('_'): | ||
| 919 | return super().__getattribute__(name) | ||
| 920 | |||
| 921 | if name not in self._data: | ||
| 922 | raise AttributeError('%s not in datastore' % name) | ||
| 923 | |||
| 924 | return self._data[name] | ||
| 925 | |||
| 926 | def _setattr(self, name, value, prop=True): | ||
| 927 | '''__setattr__ like function, but with control over property object behavior''' | ||
| 928 | if self.isLocked(): | ||
| 929 | raise TypeError("Can not set attribute '%s': Object data is locked" % name) | ||
| 930 | |||
| 931 | if name.startswith('_'): | ||
| 932 | super().__setattr__(name, value) | ||
| 933 | return | ||
| 934 | |||
| 935 | # Since __setattr__ runs before properties, we need to check if | ||
| 936 | # there is a setter property and then execute it | ||
| 937 | # ... or return self._data[name] | ||
| 938 | propertyobj = getattr(self.__class__, name, None) | ||
| 939 | if prop and isinstance(propertyobj, property): | ||
| 940 | if propertyobj.fset: | ||
| 941 | propertyobj.fset(self, value) | ||
| 942 | else: | ||
| 943 | raise AttributeError('Attribute %s is readonly, and may not be set' % name) | ||
| 944 | else: | ||
| 945 | self._data[name] = value | ||
| 946 | |||
| 947 | def __setattr__(self, name, value): | ||
| 948 | self._setattr(name, value, prop=True) | ||
| 949 | |||
| 950 | def _delattr(self, name, prop=True): | ||
| 951 | # Since __delattr__ runs before properties, we need to check if | ||
| 952 | # there is a deleter property and then execute it | ||
| 953 | # ... or we pop it ourselves.. | ||
| 954 | propertyobj = getattr(self.__class__, name, None) | ||
| 955 | if prop and isinstance(propertyobj, property): | ||
| 956 | if propertyobj.fdel: | ||
| 957 | propertyobj.fdel(self) | ||
| 958 | else: | ||
| 959 | raise AttributeError('Attribute %s is readonly, and may not be deleted' % name) | ||
| 960 | else: | ||
| 961 | self._data.pop(name) | ||
| 962 | |||
| 963 | def __delattr__(self, name): | ||
| 964 | self._delattr(name, prop=True) | ||
| 965 | |||
| 966 | def lockData(self): | ||
| 967 | '''Lock data object (make it readonly)''' | ||
| 968 | super().__setattr__("_lock", True) | ||
| 969 | |||
| 970 | def unlockData(self): | ||
| 971 | '''unlock data object (make it readonly)''' | ||
| 972 | super().__setattr__("_lock", False) | ||
| 973 | |||
| 974 | def isLocked(self): | ||
| 975 | '''Is this object locked (readonly)?''' | ||
| 976 | return self._lock | ||
| 977 | |||
| 978 | # Branch object | ||
| 979 | class Branch(LayerIndexItemObj): | ||
| 980 | def define_data(self, id, name, bitbake_branch, | ||
| 981 | short_description=None, sort_priority=1, | ||
| 982 | updates_enabled=True, updated=None, | ||
| 983 | update_environment=None): | ||
| 984 | self.id = id | ||
| 985 | self.name = name | ||
| 986 | self.bitbake_branch = bitbake_branch | ||
| 987 | self.short_description = short_description or name | ||
| 988 | self.sort_priority = sort_priority | ||
| 989 | self.updates_enabled = updates_enabled | ||
| 990 | self.updated = updated or datetime.datetime.today().isoformat() | ||
| 991 | self.update_environment = update_environment | ||
| 992 | |||
| 993 | @property | ||
| 994 | def name(self): | ||
| 995 | return self.__getattr__('name') | ||
| 996 | |||
| 997 | @name.setter | ||
| 998 | def name(self, value): | ||
| 999 | self._data['name'] = value | ||
| 1000 | |||
| 1001 | if self.bitbake_branch == value: | ||
| 1002 | self.bitbake_branch = "" | ||
| 1003 | |||
| 1004 | @name.deleter | ||
| 1005 | def name(self): | ||
| 1006 | self._delattr('name', prop=False) | ||
| 1007 | |||
| 1008 | @property | ||
| 1009 | def bitbake_branch(self): | ||
| 1010 | try: | ||
| 1011 | return self.__getattr__('bitbake_branch') | ||
| 1012 | except AttributeError: | ||
| 1013 | return self.name | ||
| 1014 | |||
| 1015 | @bitbake_branch.setter | ||
| 1016 | def bitbake_branch(self, value): | ||
| 1017 | if self.name == value: | ||
| 1018 | self._data['bitbake_branch'] = "" | ||
| 1019 | else: | ||
| 1020 | self._data['bitbake_branch'] = value | ||
| 1021 | |||
| 1022 | @bitbake_branch.deleter | ||
| 1023 | def bitbake_branch(self): | ||
| 1024 | self._delattr('bitbake_branch', prop=False) | ||
| 1025 | |||
| 1026 | |||
| 1027 | class LayerItem(LayerIndexItemObj): | ||
| 1028 | def define_data(self, id, name, status='P', | ||
| 1029 | layer_type='A', summary=None, | ||
| 1030 | description=None, | ||
| 1031 | vcs_url=None, vcs_web_url=None, | ||
| 1032 | vcs_web_tree_base_url=None, | ||
| 1033 | vcs_web_file_base_url=None, | ||
| 1034 | usage_url=None, | ||
| 1035 | mailing_list_url=None, | ||
| 1036 | index_preference=1, | ||
| 1037 | classic=False, | ||
| 1038 | updated=None): | ||
| 1039 | self.id = id | ||
| 1040 | self.name = name | ||
| 1041 | self.status = status | ||
| 1042 | self.layer_type = layer_type | ||
| 1043 | self.summary = summary or name | ||
| 1044 | self.description = description or summary or name | ||
| 1045 | self.vcs_url = vcs_url | ||
| 1046 | self.vcs_web_url = vcs_web_url | ||
| 1047 | self.vcs_web_tree_base_url = vcs_web_tree_base_url | ||
| 1048 | self.vcs_web_file_base_url = vcs_web_file_base_url | ||
| 1049 | self.index_preference = index_preference | ||
| 1050 | self.classic = classic | ||
| 1051 | self.updated = updated or datetime.datetime.today().isoformat() | ||
| 1052 | |||
| 1053 | |||
| 1054 | class LayerBranch(LayerIndexItemObj): | ||
| 1055 | def define_data(self, id, collection, version, layer, branch, | ||
| 1056 | vcs_subdir="", vcs_last_fetch=None, | ||
| 1057 | vcs_last_rev=None, vcs_last_commit=None, | ||
| 1058 | actual_branch="", | ||
| 1059 | updated=None): | ||
| 1060 | self.id = id | ||
| 1061 | self.collection = collection | ||
| 1062 | self.version = version | ||
| 1063 | if isinstance(layer, LayerItem): | ||
| 1064 | self.layer = layer | ||
| 1065 | else: | ||
| 1066 | self.layer_id = layer | ||
| 1067 | |||
| 1068 | if isinstance(branch, Branch): | ||
| 1069 | self.branch = branch | ||
| 1070 | else: | ||
| 1071 | self.branch_id = branch | ||
| 1072 | |||
| 1073 | self.vcs_subdir = vcs_subdir | ||
| 1074 | self.vcs_last_fetch = vcs_last_fetch | ||
| 1075 | self.vcs_last_rev = vcs_last_rev | ||
| 1076 | self.vcs_last_commit = vcs_last_commit | ||
| 1077 | self.actual_branch = actual_branch | ||
| 1078 | self.updated = updated or datetime.datetime.today().isoformat() | ||
| 1079 | |||
| 1080 | # This is a little odd, the _data attribute is 'layer', but it's really | ||
| 1081 | # referring to the layer id.. so lets adjust this to make it useful | ||
| 1082 | @property | ||
| 1083 | def layer_id(self): | ||
| 1084 | return self.__getattr__('layer') | ||
| 1085 | |||
| 1086 | @layer_id.setter | ||
| 1087 | def layer_id(self, value): | ||
| 1088 | self._setattr('layer', value, prop=False) | ||
| 1089 | |||
| 1090 | @layer_id.deleter | ||
| 1091 | def layer_id(self): | ||
| 1092 | self._delattr('layer', prop=False) | ||
| 1093 | |||
| 1094 | @property | ||
| 1095 | def layer(self): | ||
| 1096 | try: | ||
| 1097 | return self.index.layerItems[self.layer_id] | ||
| 1098 | except KeyError: | ||
| 1099 | raise AttributeError('Unable to find layerItems in index to map layer_id %s' % self.layer_id) | ||
| 1100 | except IndexError: | ||
| 1101 | raise AttributeError('Unable to find layer_id %s in index layerItems' % self.layer_id) | ||
| 1102 | |||
| 1103 | @layer.setter | ||
| 1104 | def layer(self, value): | ||
| 1105 | if not isinstance(value, LayerItem): | ||
| 1106 | raise TypeError('value is not a LayerItem') | ||
| 1107 | if self.index != value.index: | ||
| 1108 | raise AttributeError('Object and value do not share the same index and thus key set.') | ||
| 1109 | self.layer_id = value.id | ||
| 1110 | |||
| 1111 | @layer.deleter | ||
| 1112 | def layer(self): | ||
| 1113 | del self.layer_id | ||
| 1114 | |||
| 1115 | @property | ||
| 1116 | def branch_id(self): | ||
| 1117 | return self.__getattr__('branch') | ||
| 1118 | |||
| 1119 | @branch_id.setter | ||
| 1120 | def branch_id(self, value): | ||
| 1121 | self._setattr('branch', value, prop=False) | ||
| 1122 | |||
| 1123 | @branch_id.deleter | ||
| 1124 | def branch_id(self): | ||
| 1125 | self._delattr('branch', prop=False) | ||
| 1126 | |||
| 1127 | @property | ||
| 1128 | def branch(self): | ||
| 1129 | try: | ||
| 1130 | logger.debug("Get branch object from branches[%s]" % (self.branch_id)) | ||
| 1131 | return self.index.branches[self.branch_id] | ||
| 1132 | except KeyError: | ||
| 1133 | raise AttributeError('Unable to find branches in index to map branch_id %s' % self.branch_id) | ||
| 1134 | except IndexError: | ||
| 1135 | raise AttributeError('Unable to find branch_id %s in index branches' % self.branch_id) | ||
| 1136 | |||
| 1137 | @branch.setter | ||
| 1138 | def branch(self, value): | ||
| 1139 | if not isinstance(value, LayerItem): | ||
| 1140 | raise TypeError('value is not a LayerItem') | ||
| 1141 | if self.index != value.index: | ||
| 1142 | raise AttributeError('Object and value do not share the same index and thus key set.') | ||
| 1143 | self.branch_id = value.id | ||
| 1144 | |||
| 1145 | @branch.deleter | ||
| 1146 | def branch(self): | ||
| 1147 | del self.branch_id | ||
| 1148 | |||
| 1149 | @property | ||
| 1150 | def actual_branch(self): | ||
| 1151 | if self.__getattr__('actual_branch'): | ||
| 1152 | return self.__getattr__('actual_branch') | ||
| 1153 | else: | ||
| 1154 | return self.branch.name | ||
| 1155 | |||
| 1156 | @actual_branch.setter | ||
| 1157 | def actual_branch(self, value): | ||
| 1158 | logger.debug("Set actual_branch to %s .. name is %s" % (value, self.branch.name)) | ||
| 1159 | if value != self.branch.name: | ||
| 1160 | self._setattr('actual_branch', value, prop=False) | ||
| 1161 | else: | ||
| 1162 | self._setattr('actual_branch', '', prop=False) | ||
| 1163 | |||
| 1164 | @actual_branch.deleter | ||
| 1165 | def actual_branch(self): | ||
| 1166 | self._delattr('actual_branch', prop=False) | ||
| 1167 | |||
| 1168 | # Extend LayerIndexItemObj with common LayerBranch manipulations | ||
| 1169 | # All of the remaining LayerIndex objects refer to layerbranch, and it is | ||
| 1170 | # up to the user to follow that back through the LayerBranch object into | ||
| 1171 | # the layer object to get various attributes. So add an intermediate set | ||
| 1172 | # of attributes that can easily get us the layerbranch as well as layer. | ||
| 1173 | |||
| 1174 | class LayerIndexItemObj_LayerBranch(LayerIndexItemObj): | ||
| 1175 | @property | ||
| 1176 | def layerbranch_id(self): | ||
| 1177 | return self.__getattr__('layerbranch') | ||
| 1178 | |||
| 1179 | @layerbranch_id.setter | ||
| 1180 | def layerbranch_id(self, value): | ||
| 1181 | self._setattr('layerbranch', value, prop=False) | ||
| 1182 | |||
| 1183 | @layerbranch_id.deleter | ||
| 1184 | def layerbranch_id(self): | ||
| 1185 | self._delattr('layerbranch', prop=False) | ||
| 1186 | |||
| 1187 | @property | ||
| 1188 | def layerbranch(self): | ||
| 1189 | try: | ||
| 1190 | return self.index.layerBranches[self.layerbranch_id] | ||
| 1191 | except KeyError: | ||
| 1192 | raise AttributeError('Unable to find layerBranches in index to map layerbranch_id %s' % self.layerbranch_id) | ||
| 1193 | except IndexError: | ||
| 1194 | raise AttributeError('Unable to find layerbranch_id %s in index branches' % self.layerbranch_id) | ||
| 1195 | |||
| 1196 | @layerbranch.setter | ||
| 1197 | def layerbranch(self, value): | ||
| 1198 | if not isinstance(value, LayerBranch): | ||
| 1199 | raise TypeError('value (%s) is not a layerBranch' % type(value)) | ||
| 1200 | if self.index != value.index: | ||
| 1201 | raise AttributeError('Object and value do not share the same index and thus key set.') | ||
| 1202 | self.layerbranch_id = value.id | ||
| 1203 | |||
| 1204 | @layerbranch.deleter | ||
| 1205 | def layerbranch(self): | ||
| 1206 | del self.layerbranch_id | ||
| 1207 | |||
| 1208 | @property | ||
| 1209 | def layer_id(self): | ||
| 1210 | return self.layerbranch.layer_id | ||
| 1211 | |||
| 1212 | # Doesn't make sense to set or delete layer_id | ||
| 1213 | |||
| 1214 | @property | ||
| 1215 | def layer(self): | ||
| 1216 | return self.layerbranch.layer | ||
| 1217 | |||
| 1218 | # Doesn't make sense to set or delete layer | ||
| 1219 | |||
| 1220 | |||
| 1221 | class LayerDependency(LayerIndexItemObj_LayerBranch): | ||
| 1222 | def define_data(self, id, layerbranch, dependency, required=True): | ||
| 1223 | self.id = id | ||
| 1224 | if isinstance(layerbranch, LayerBranch): | ||
| 1225 | self.layerbranch = layerbranch | ||
| 1226 | else: | ||
| 1227 | self.layerbranch_id = layerbranch | ||
| 1228 | if isinstance(dependency, LayerDependency): | ||
| 1229 | self.dependency = dependency | ||
| 1230 | else: | ||
| 1231 | self.dependency_id = dependency | ||
| 1232 | self.required = required | ||
| 1233 | |||
| 1234 | @property | ||
| 1235 | def dependency_id(self): | ||
| 1236 | return self.__getattr__('dependency') | ||
| 1237 | |||
| 1238 | @dependency_id.setter | ||
| 1239 | def dependency_id(self, value): | ||
| 1240 | self._setattr('dependency', value, prop=False) | ||
| 1241 | |||
| 1242 | @dependency_id.deleter | ||
| 1243 | def dependency_id(self): | ||
| 1244 | self._delattr('dependency', prop=False) | ||
| 1245 | |||
| 1246 | @property | ||
| 1247 | def dependency(self): | ||
| 1248 | try: | ||
| 1249 | return self.index.layerItems[self.dependency_id] | ||
| 1250 | except KeyError: | ||
| 1251 | raise AttributeError('Unable to find layerItems in index to map layerbranch_id %s' % self.dependency_id) | ||
| 1252 | except IndexError: | ||
| 1253 | raise AttributeError('Unable to find dependency_id %s in index layerItems' % self.dependency_id) | ||
| 1254 | |||
| 1255 | @dependency.setter | ||
| 1256 | def dependency(self, value): | ||
| 1257 | if not isinstance(value, LayerDependency): | ||
| 1258 | raise TypeError('value (%s) is not a dependency' % type(value)) | ||
| 1259 | if self.index != value.index: | ||
| 1260 | raise AttributeError('Object and value do not share the same index and thus key set.') | ||
| 1261 | self.dependency_id = value.id | ||
| 1262 | |||
| 1263 | @dependency.deleter | ||
| 1264 | def dependency(self): | ||
| 1265 | self._delattr('dependency', prop=False) | ||
| 1266 | |||
| 1267 | @property | ||
| 1268 | def dependency_layerBranch(self): | ||
| 1269 | layerid = self.dependency_id | ||
| 1270 | branchid = self.layerbranch.branch_id | ||
| 1271 | |||
| 1272 | try: | ||
| 1273 | return self.index.layerBranches_layerId_branchId["%s:%s" % (layerid, branchid)] | ||
| 1274 | except IndexError: | ||
| 1275 | # layerBranches_layerId_branchId -- but not layerId:branchId | ||
| 1276 | raise AttributeError('Unable to find layerId:branchId %s:%s in index layerBranches_layerId_branchId' % (layerid, branchid)) | ||
| 1277 | except KeyError: | ||
| 1278 | raise AttributeError('Unable to find layerId:branchId %s:%s in layerItems and layerBranches' % (layerid, branchid)) | ||
| 1279 | |||
| 1280 | # dependency_layerBranch doesn't make sense to set or del | ||
| 1281 | |||
| 1282 | |||
| 1283 | class Recipe(LayerIndexItemObj_LayerBranch): | ||
| 1284 | def define_data(self, id, | ||
| 1285 | filename, filepath, pn, pv, layerbranch, | ||
| 1286 | summary="", description="", section="", license="", | ||
| 1287 | homepage="", bugtracker="", provides="", bbclassextend="", | ||
| 1288 | inherits="", disallowed="", updated=None): | ||
| 1289 | self.id = id | ||
| 1290 | self.filename = filename | ||
| 1291 | self.filepath = filepath | ||
| 1292 | self.pn = pn | ||
| 1293 | self.pv = pv | ||
| 1294 | self.summary = summary | ||
| 1295 | self.description = description | ||
| 1296 | self.section = section | ||
| 1297 | self.license = license | ||
| 1298 | self.homepage = homepage | ||
| 1299 | self.bugtracker = bugtracker | ||
| 1300 | self.provides = provides | ||
| 1301 | self.bbclassextend = bbclassextend | ||
| 1302 | self.inherits = inherits | ||
| 1303 | self.updated = updated or datetime.datetime.today().isoformat() | ||
| 1304 | self.disallowed = disallowed | ||
| 1305 | if isinstance(layerbranch, LayerBranch): | ||
| 1306 | self.layerbranch = layerbranch | ||
| 1307 | else: | ||
| 1308 | self.layerbranch_id = layerbranch | ||
| 1309 | |||
| 1310 | @property | ||
| 1311 | def fullpath(self): | ||
| 1312 | return os.path.join(self.filepath, self.filename) | ||
| 1313 | |||
| 1314 | # Set would need to understand how to split it | ||
| 1315 | # del would we del both parts? | ||
| 1316 | |||
| 1317 | @property | ||
| 1318 | def inherits(self): | ||
| 1319 | if 'inherits' not in self._data: | ||
| 1320 | # Older indexes may not have this, so emulate it | ||
| 1321 | if '-image-' in self.pn: | ||
| 1322 | return 'image' | ||
| 1323 | return self.__getattr__('inherits') | ||
| 1324 | |||
| 1325 | @inherits.setter | ||
| 1326 | def inherits(self, value): | ||
| 1327 | return self._setattr('inherits', value, prop=False) | ||
| 1328 | |||
| 1329 | @inherits.deleter | ||
| 1330 | def inherits(self): | ||
| 1331 | return self._delattr('inherits', prop=False) | ||
| 1332 | |||
| 1333 | |||
| 1334 | class Machine(LayerIndexItemObj_LayerBranch): | ||
| 1335 | def define_data(self, id, | ||
| 1336 | name, description, layerbranch, | ||
| 1337 | updated=None): | ||
| 1338 | self.id = id | ||
| 1339 | self.name = name | ||
| 1340 | self.description = description | ||
| 1341 | if isinstance(layerbranch, LayerBranch): | ||
| 1342 | self.layerbranch = layerbranch | ||
| 1343 | else: | ||
| 1344 | self.layerbranch_id = layerbranch | ||
| 1345 | self.updated = updated or datetime.datetime.today().isoformat() | ||
| 1346 | |||
| 1347 | class Distro(LayerIndexItemObj_LayerBranch): | ||
| 1348 | def define_data(self, id, | ||
| 1349 | name, description, layerbranch, | ||
| 1350 | updated=None): | ||
| 1351 | self.id = id | ||
| 1352 | self.name = name | ||
| 1353 | self.description = description | ||
| 1354 | if isinstance(layerbranch, LayerBranch): | ||
| 1355 | self.layerbranch = layerbranch | ||
| 1356 | else: | ||
| 1357 | self.layerbranch_id = layerbranch | ||
| 1358 | self.updated = updated or datetime.datetime.today().isoformat() | ||
| 1359 | |||
| 1360 | # When performing certain actions, we may need to sort the data. | ||
| 1361 | # This will allow us to keep it consistent from run to run. | ||
| 1362 | def sort_entry(item): | ||
| 1363 | newitem = item | ||
| 1364 | try: | ||
| 1365 | if type(newitem) == type(dict()): | ||
| 1366 | newitem = OrderedDict(sorted(newitem.items(), key=lambda t: t[0])) | ||
| 1367 | for index in newitem: | ||
| 1368 | newitem[index] = sort_entry(newitem[index]) | ||
| 1369 | elif type(newitem) == type(list()): | ||
| 1370 | newitem.sort(key=lambda obj: obj['id']) | ||
| 1371 | for index, _ in enumerate(newitem): | ||
| 1372 | newitem[index] = sort_entry(newitem[index]) | ||
| 1373 | except: | ||
| 1374 | logger.error('Sort failed for item %s' % type(item)) | ||
| 1375 | pass | ||
| 1376 | |||
| 1377 | return newitem | ||
diff --git a/bitbake/lib/layerindexlib/cooker.py b/bitbake/lib/layerindexlib/cooker.py deleted file mode 100644 index ced3e06360..0000000000 --- a/bitbake/lib/layerindexlib/cooker.py +++ /dev/null | |||
| @@ -1,334 +0,0 @@ | |||
| 1 | # Copyright (C) 2016-2018 Wind River Systems, Inc. | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 4 | # | ||
| 5 | |||
| 6 | import logging | ||
| 7 | import os | ||
| 8 | |||
| 9 | from collections import defaultdict | ||
| 10 | |||
| 11 | from urllib.parse import unquote, urlparse | ||
| 12 | |||
| 13 | import layerindexlib | ||
| 14 | |||
| 15 | import layerindexlib.plugin | ||
| 16 | |||
| 17 | logger = logging.getLogger('BitBake.layerindexlib.cooker') | ||
| 18 | |||
| 19 | import bb.utils | ||
| 20 | |||
| 21 | def plugin_init(plugins): | ||
| 22 | return CookerPlugin() | ||
| 23 | |||
| 24 | class CookerPlugin(layerindexlib.plugin.IndexPlugin): | ||
| 25 | def __init__(self): | ||
| 26 | self.type = "cooker" | ||
| 27 | |||
| 28 | self.server_connection = None | ||
| 29 | self.ui_module = None | ||
| 30 | self.server = None | ||
| 31 | |||
| 32 | def _run_command(self, command, path, default=None): | ||
| 33 | try: | ||
| 34 | result, _ = bb.process.run(command, cwd=path) | ||
| 35 | result = result.strip() | ||
| 36 | except bb.process.ExecutionError: | ||
| 37 | result = default | ||
| 38 | return result | ||
| 39 | |||
| 40 | def _handle_git_remote(self, remote): | ||
| 41 | if "://" not in remote: | ||
| 42 | if ':' in remote: | ||
| 43 | # This is assumed to be ssh | ||
| 44 | remote = "ssh://" + remote | ||
| 45 | else: | ||
| 46 | # This is assumed to be a file path | ||
| 47 | remote = "file://" + remote | ||
| 48 | return remote | ||
| 49 | |||
| 50 | def _get_bitbake_info(self): | ||
| 51 | """Return a tuple of bitbake information""" | ||
| 52 | |||
| 53 | # Our path SHOULD be .../bitbake/lib/layerindex/cooker.py | ||
| 54 | bb_path = os.path.dirname(__file__) # .../bitbake/lib/layerindex/cooker.py | ||
| 55 | bb_path = os.path.dirname(bb_path) # .../bitbake/lib/layerindex | ||
| 56 | bb_path = os.path.dirname(bb_path) # .../bitbake/lib | ||
| 57 | bb_path = os.path.dirname(bb_path) # .../bitbake | ||
| 58 | bb_path = self._run_command('git rev-parse --show-toplevel', os.path.dirname(__file__), default=bb_path) | ||
| 59 | bb_branch = self._run_command('git rev-parse --abbrev-ref HEAD', bb_path, default="<unknown>") | ||
| 60 | bb_rev = self._run_command('git rev-parse HEAD', bb_path, default="<unknown>") | ||
| 61 | for remotes in self._run_command('git remote -v', bb_path, default="").split("\n"): | ||
| 62 | remote = remotes.split("\t")[1].split(" ")[0] | ||
| 63 | if "(fetch)" == remotes.split("\t")[1].split(" ")[1]: | ||
| 64 | bb_remote = self._handle_git_remote(remote) | ||
| 65 | break | ||
| 66 | else: | ||
| 67 | bb_remote = self._handle_git_remote(bb_path) | ||
| 68 | |||
| 69 | return (bb_remote, bb_branch, bb_rev, bb_path) | ||
| 70 | |||
| 71 | def _load_bblayers(self, branches=None): | ||
| 72 | """Load the BBLAYERS and related collection information""" | ||
| 73 | |||
| 74 | d = self.layerindex.data | ||
| 75 | |||
| 76 | if not branches: | ||
| 77 | raise layerindexlib.LayerIndexFetchError("No branches specified for _load_bblayers!") | ||
| 78 | |||
| 79 | index = layerindexlib.LayerIndexObj() | ||
| 80 | |||
| 81 | branchId = 0 | ||
| 82 | index.branches = {} | ||
| 83 | |||
| 84 | layerItemId = 0 | ||
| 85 | index.layerItems = {} | ||
| 86 | |||
| 87 | layerBranchId = 0 | ||
| 88 | index.layerBranches = {} | ||
| 89 | |||
| 90 | bblayers = d.getVar('BBLAYERS').split() | ||
| 91 | |||
| 92 | if not bblayers: | ||
| 93 | # It's blank! Nothing to process... | ||
| 94 | return index | ||
| 95 | |||
| 96 | collections = d.getVar('BBFILE_COLLECTIONS') | ||
| 97 | layerconfs = d.varhistory.get_variable_items_files('BBFILE_COLLECTIONS') | ||
| 98 | bbfile_collections = {layer: os.path.dirname(os.path.dirname(path)) for layer, path in layerconfs.items()} | ||
| 99 | |||
| 100 | (_, bb_branch, _, _) = self._get_bitbake_info() | ||
| 101 | |||
| 102 | for branch in branches: | ||
| 103 | branchId += 1 | ||
| 104 | index.branches[branchId] = layerindexlib.Branch(index, None) | ||
| 105 | index.branches[branchId].define_data(branchId, branch, bb_branch) | ||
| 106 | |||
| 107 | for entry in collections.split(): | ||
| 108 | layerpath = entry | ||
| 109 | if entry in bbfile_collections: | ||
| 110 | layerpath = bbfile_collections[entry] | ||
| 111 | |||
| 112 | layername = d.getVar('BBLAYERS_LAYERINDEX_NAME_%s' % entry) or os.path.basename(layerpath) | ||
| 113 | layerversion = d.getVar('LAYERVERSION_%s' % entry) or "" | ||
| 114 | layerurl = self._handle_git_remote(layerpath) | ||
| 115 | |||
| 116 | layersubdir = "" | ||
| 117 | layerrev = "<unknown>" | ||
| 118 | layerbranch = "<unknown>" | ||
| 119 | |||
| 120 | if os.path.isdir(layerpath): | ||
| 121 | layerbasepath = self._run_command('git rev-parse --show-toplevel', layerpath, default=layerpath) | ||
| 122 | if os.path.abspath(layerpath) != os.path.abspath(layerbasepath): | ||
| 123 | layersubdir = os.path.abspath(layerpath)[len(layerbasepath) + 1:] | ||
| 124 | |||
| 125 | layerbranch = self._run_command('git rev-parse --abbrev-ref HEAD', layerpath, default="<unknown>") | ||
| 126 | layerrev = self._run_command('git rev-parse HEAD', layerpath, default="<unknown>") | ||
| 127 | |||
| 128 | for remotes in self._run_command('git remote -v', layerpath, default="").split("\n"): | ||
| 129 | if not remotes: | ||
| 130 | layerurl = self._handle_git_remote(layerpath) | ||
| 131 | else: | ||
| 132 | remote = remotes.split("\t")[1].split(" ")[0] | ||
| 133 | if "(fetch)" == remotes.split("\t")[1].split(" ")[1]: | ||
| 134 | layerurl = self._handle_git_remote(remote) | ||
| 135 | break | ||
| 136 | |||
| 137 | layerItemId += 1 | ||
| 138 | index.layerItems[layerItemId] = layerindexlib.LayerItem(index, None) | ||
| 139 | index.layerItems[layerItemId].define_data(layerItemId, layername, description=layerpath, vcs_url=layerurl) | ||
| 140 | |||
| 141 | for branchId in index.branches: | ||
| 142 | layerBranchId += 1 | ||
| 143 | index.layerBranches[layerBranchId] = layerindexlib.LayerBranch(index, None) | ||
| 144 | index.layerBranches[layerBranchId].define_data(layerBranchId, entry, layerversion, layerItemId, branchId, | ||
| 145 | vcs_subdir=layersubdir, vcs_last_rev=layerrev, actual_branch=layerbranch) | ||
| 146 | |||
| 147 | return index | ||
| 148 | |||
| 149 | |||
| 150 | def load_index(self, url, load): | ||
| 151 | """ | ||
| 152 | Fetches layer information from a build configuration. | ||
| 153 | |||
| 154 | The return value is a dictionary containing API, | ||
| 155 | layer, branch, dependency, recipe, machine, distro, information. | ||
| 156 | |||
| 157 | url type should be 'cooker'. | ||
| 158 | url path is ignored | ||
| 159 | """ | ||
| 160 | |||
| 161 | up = urlparse(url) | ||
| 162 | |||
| 163 | if up.scheme != 'cooker': | ||
| 164 | raise layerindexlib.plugin.LayerIndexPluginUrlError(self.type, url) | ||
| 165 | |||
| 166 | d = self.layerindex.data | ||
| 167 | |||
| 168 | params = self.layerindex._parse_params(up.params) | ||
| 169 | |||
| 170 | # Only reason to pass a branch is to emulate them... | ||
| 171 | if 'branch' in params: | ||
| 172 | branches = params['branch'].split(',') | ||
| 173 | else: | ||
| 174 | branches = ['HEAD'] | ||
| 175 | |||
| 176 | logger.debug("Loading cooker data branches %s" % branches) | ||
| 177 | |||
| 178 | index = self._load_bblayers(branches=branches) | ||
| 179 | |||
| 180 | index.config = {} | ||
| 181 | index.config['TYPE'] = self.type | ||
| 182 | index.config['URL'] = url | ||
| 183 | |||
| 184 | if 'desc' in params: | ||
| 185 | index.config['DESCRIPTION'] = unquote(params['desc']) | ||
| 186 | else: | ||
| 187 | index.config['DESCRIPTION'] = 'local' | ||
| 188 | |||
| 189 | if 'cache' in params: | ||
| 190 | index.config['CACHE'] = params['cache'] | ||
| 191 | |||
| 192 | index.config['BRANCH'] = branches | ||
| 193 | |||
| 194 | # ("layerDependencies", layerindexlib.LayerDependency) | ||
| 195 | layerDependencyId = 0 | ||
| 196 | if "layerDependencies" in load: | ||
| 197 | index.layerDependencies = {} | ||
| 198 | for layerBranchId in index.layerBranches: | ||
| 199 | branchName = index.layerBranches[layerBranchId].branch.name | ||
| 200 | collection = index.layerBranches[layerBranchId].collection | ||
| 201 | |||
| 202 | def add_dependency(layerDependencyId, index, deps, required): | ||
| 203 | try: | ||
| 204 | depDict = bb.utils.explode_dep_versions2(deps) | ||
| 205 | except bb.utils.VersionStringException as vse: | ||
| 206 | bb.fatal('Error parsing LAYERDEPENDS_%s: %s' % (collection, str(vse))) | ||
| 207 | |||
| 208 | for dep, oplist in list(depDict.items()): | ||
| 209 | # We need to search ourselves, so use the _ version... | ||
| 210 | depLayerBranch = index.find_collection(dep, branches=[branchName]) | ||
| 211 | if not depLayerBranch: | ||
| 212 | # Missing dependency?! | ||
| 213 | logger.error('Missing dependency %s (%s)' % (dep, branchName)) | ||
| 214 | continue | ||
| 215 | |||
| 216 | # We assume that the oplist matches... | ||
| 217 | layerDependencyId += 1 | ||
| 218 | layerDependency = layerindexlib.LayerDependency(index, None) | ||
| 219 | layerDependency.define_data(id=layerDependencyId, | ||
| 220 | required=required, layerbranch=layerBranchId, | ||
| 221 | dependency=depLayerBranch.layer_id) | ||
| 222 | |||
| 223 | logger.debug('%s requires %s' % (layerDependency.layer.name, layerDependency.dependency.name)) | ||
| 224 | index.add_element("layerDependencies", [layerDependency]) | ||
| 225 | |||
| 226 | return layerDependencyId | ||
| 227 | |||
| 228 | deps = d.getVar("LAYERDEPENDS_%s" % collection) | ||
| 229 | if deps: | ||
| 230 | layerDependencyId = add_dependency(layerDependencyId, index, deps, True) | ||
| 231 | |||
| 232 | deps = d.getVar("LAYERRECOMMENDS_%s" % collection) | ||
| 233 | if deps: | ||
| 234 | layerDependencyId = add_dependency(layerDependencyId, index, deps, False) | ||
| 235 | |||
| 236 | # Need to load recipes here (requires cooker access) | ||
| 237 | recipeId = 0 | ||
| 238 | ## TODO: NOT IMPLEMENTED | ||
| 239 | # The code following this is an example of what needs to be | ||
| 240 | # implemented. However, it does not work as-is. | ||
| 241 | if False and 'recipes' in load: | ||
| 242 | index.recipes = {} | ||
| 243 | |||
| 244 | ret = self.ui_module.main(self.server_connection.connection, self.server_connection.events, config_params) | ||
| 245 | |||
| 246 | all_versions = self._run_command('allProviders') | ||
| 247 | |||
| 248 | all_versions_list = defaultdict(list, all_versions) | ||
| 249 | for pn in all_versions_list: | ||
| 250 | for ((pe, pv, pr), fpath) in all_versions_list[pn]: | ||
| 251 | realfn = bb.cache.virtualfn2realfn(fpath) | ||
| 252 | |||
| 253 | filepath = os.path.dirname(realfn[0]) | ||
| 254 | filename = os.path.basename(realfn[0]) | ||
| 255 | |||
| 256 | # This is all HORRIBLY slow, and likely unnecessary | ||
| 257 | #dscon = self._run_command('parseRecipeFile', fpath, False, []) | ||
| 258 | #connector = myDataStoreConnector(self, dscon.dsindex) | ||
| 259 | #recipe_data = bb.data.init() | ||
| 260 | #recipe_data.setVar('_remote_data', connector) | ||
| 261 | |||
| 262 | #summary = recipe_data.getVar('SUMMARY') | ||
| 263 | #description = recipe_data.getVar('DESCRIPTION') | ||
| 264 | #section = recipe_data.getVar('SECTION') | ||
| 265 | #license = recipe_data.getVar('LICENSE') | ||
| 266 | #homepage = recipe_data.getVar('HOMEPAGE') | ||
| 267 | #bugtracker = recipe_data.getVar('BUGTRACKER') | ||
| 268 | #provides = recipe_data.getVar('PROVIDES') | ||
| 269 | |||
| 270 | layer = bb.utils.get_file_layer(realfn[0], self.config_data) | ||
| 271 | |||
| 272 | depBranchId = collection[layer] | ||
| 273 | |||
| 274 | recipeId += 1 | ||
| 275 | recipe = layerindexlib.Recipe(index, None) | ||
| 276 | recipe.define_data(id=recipeId, | ||
| 277 | filename=filename, filepath=filepath, | ||
| 278 | pn=pn, pv=pv, | ||
| 279 | summary=pn, description=pn, section='?', | ||
| 280 | license='?', homepage='?', bugtracker='?', | ||
| 281 | provides='?', bbclassextend='?', inherits='?', | ||
| 282 | disallowed='?', layerbranch=depBranchId) | ||
| 283 | |||
| 284 | index = addElement("recipes", [recipe], index) | ||
| 285 | |||
| 286 | # ("machines", layerindexlib.Machine) | ||
| 287 | machineId = 0 | ||
| 288 | if 'machines' in load: | ||
| 289 | index.machines = {} | ||
| 290 | |||
| 291 | for layerBranchId in index.layerBranches: | ||
| 292 | # load_bblayers uses the description to cache the actual path... | ||
| 293 | machine_path = index.layerBranches[layerBranchId].layer.description | ||
| 294 | machine_path = os.path.join(machine_path, 'conf/machine') | ||
| 295 | if os.path.isdir(machine_path): | ||
| 296 | for (dirpath, _, filenames) in os.walk(machine_path): | ||
| 297 | # Ignore subdirs... | ||
| 298 | if not dirpath.endswith('conf/machine'): | ||
| 299 | continue | ||
| 300 | for fname in filenames: | ||
| 301 | if fname.endswith('.conf'): | ||
| 302 | machineId += 1 | ||
| 303 | machine = layerindexlib.Machine(index, None) | ||
| 304 | machine.define_data(id=machineId, name=fname[:-5], | ||
| 305 | description=fname[:-5], | ||
| 306 | layerbranch=index.layerBranches[layerBranchId]) | ||
| 307 | |||
| 308 | index.add_element("machines", [machine]) | ||
| 309 | |||
| 310 | # ("distros", layerindexlib.Distro) | ||
| 311 | distroId = 0 | ||
| 312 | if 'distros' in load: | ||
| 313 | index.distros = {} | ||
| 314 | |||
| 315 | for layerBranchId in index.layerBranches: | ||
| 316 | # load_bblayers uses the description to cache the actual path... | ||
| 317 | distro_path = index.layerBranches[layerBranchId].layer.description | ||
| 318 | distro_path = os.path.join(distro_path, 'conf/distro') | ||
| 319 | if os.path.isdir(distro_path): | ||
| 320 | for (dirpath, _, filenames) in os.walk(distro_path): | ||
| 321 | # Ignore subdirs... | ||
| 322 | if not dirpath.endswith('conf/distro'): | ||
| 323 | continue | ||
| 324 | for fname in filenames: | ||
| 325 | if fname.endswith('.conf'): | ||
| 326 | distroId += 1 | ||
| 327 | distro = layerindexlib.Distro(index, None) | ||
| 328 | distro.define_data(id=distroId, name=fname[:-5], | ||
| 329 | description=fname[:-5], | ||
| 330 | layerbranch=index.layerBranches[layerBranchId]) | ||
| 331 | |||
| 332 | index.add_element("distros", [distro]) | ||
| 333 | |||
| 334 | return index | ||
diff --git a/bitbake/lib/layerindexlib/plugin.py b/bitbake/lib/layerindexlib/plugin.py deleted file mode 100644 index cadda36c74..0000000000 --- a/bitbake/lib/layerindexlib/plugin.py +++ /dev/null | |||
| @@ -1,46 +0,0 @@ | |||
| 1 | # Copyright (C) 2016-2018 Wind River Systems, Inc. | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 4 | # | ||
| 5 | # The file contains: | ||
| 6 | # LayerIndex exceptions | ||
| 7 | # Plugin base class | ||
| 8 | # Utility Functions for working on layerindex data | ||
| 9 | |||
| 10 | import logging | ||
| 11 | |||
| 12 | logger = logging.getLogger('BitBake.layerindexlib.plugin') | ||
| 13 | |||
| 14 | class LayerIndexPluginException(Exception): | ||
| 15 | """LayerIndex Generic Exception""" | ||
| 16 | def __init__(self, message): | ||
| 17 | self.msg = message | ||
| 18 | Exception.__init__(self, message) | ||
| 19 | |||
| 20 | def __str__(self): | ||
| 21 | return self.msg | ||
| 22 | |||
| 23 | class LayerIndexPluginUrlError(LayerIndexPluginException): | ||
| 24 | """Exception raised when a plugin does not support a given URL type""" | ||
| 25 | def __init__(self, plugin, url): | ||
| 26 | msg = "%s does not support %s:" % (plugin, url) | ||
| 27 | self.plugin = plugin | ||
| 28 | self.url = url | ||
| 29 | LayerIndexPluginException.__init__(self, msg) | ||
| 30 | |||
| 31 | class IndexPlugin(): | ||
| 32 | def __init__(self): | ||
| 33 | self.type = None | ||
| 34 | |||
| 35 | def init(self, layerindex): | ||
| 36 | self.layerindex = layerindex | ||
| 37 | |||
| 38 | def plugin_type(self): | ||
| 39 | return self.type | ||
| 40 | |||
| 41 | def load_index(self, uri): | ||
| 42 | raise NotImplementedError('load_index is not implemented') | ||
| 43 | |||
| 44 | def store_index(self, uri, index): | ||
| 45 | raise NotImplementedError('store_index is not implemented') | ||
| 46 | |||
diff --git a/bitbake/lib/layerindexlib/restapi.py b/bitbake/lib/layerindexlib/restapi.py deleted file mode 100644 index 81d99b02ea..0000000000 --- a/bitbake/lib/layerindexlib/restapi.py +++ /dev/null | |||
| @@ -1,392 +0,0 @@ | |||
| 1 | # Copyright (C) 2016-2018 Wind River Systems, Inc. | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 4 | # | ||
| 5 | |||
| 6 | import logging | ||
| 7 | import json | ||
| 8 | import os | ||
| 9 | |||
| 10 | from urllib.parse import unquote | ||
| 11 | from urllib.parse import urlparse | ||
| 12 | |||
| 13 | import bb | ||
| 14 | |||
| 15 | import layerindexlib | ||
| 16 | import layerindexlib.plugin | ||
| 17 | |||
| 18 | logger = logging.getLogger('BitBake.layerindexlib.restapi') | ||
| 19 | |||
| 20 | def plugin_init(plugins): | ||
| 21 | return RestApiPlugin() | ||
| 22 | |||
| 23 | class RestApiPlugin(layerindexlib.plugin.IndexPlugin): | ||
| 24 | def __init__(self): | ||
| 25 | self.type = "restapi" | ||
| 26 | |||
| 27 | def load_index(self, url, load): | ||
| 28 | """ | ||
| 29 | Fetches layer information from a local or remote layer index. | ||
| 30 | |||
| 31 | The return value is a LayerIndexObj. | ||
| 32 | |||
| 33 | url is the url to the rest api of the layer index, such as: | ||
| 34 | https://layers.openembedded.org/layerindex/api/ | ||
| 35 | |||
| 36 | Or a local file... | ||
| 37 | """ | ||
| 38 | |||
| 39 | up = urlparse(url) | ||
| 40 | |||
| 41 | if up.scheme == 'file': | ||
| 42 | return self.load_index_file(up, url, load) | ||
| 43 | |||
| 44 | if up.scheme == 'http' or up.scheme == 'https': | ||
| 45 | return self.load_index_web(up, url, load) | ||
| 46 | |||
| 47 | raise layerindexlib.plugin.LayerIndexPluginUrlError(self.type, url) | ||
| 48 | |||
| 49 | |||
| 50 | def load_index_file(self, up, url, load): | ||
| 51 | """ | ||
| 52 | Fetches layer information from a local file or directory. | ||
| 53 | |||
| 54 | The return value is a LayerIndexObj. | ||
| 55 | |||
| 56 | ud is the parsed url to the local file or directory. | ||
| 57 | """ | ||
| 58 | if not os.path.exists(up.path): | ||
| 59 | raise FileNotFoundError(up.path) | ||
| 60 | |||
| 61 | index = layerindexlib.LayerIndexObj() | ||
| 62 | |||
| 63 | index.config = {} | ||
| 64 | index.config['TYPE'] = self.type | ||
| 65 | index.config['URL'] = url | ||
| 66 | |||
| 67 | params = self.layerindex._parse_params(up.params) | ||
| 68 | |||
| 69 | if 'desc' in params: | ||
| 70 | index.config['DESCRIPTION'] = unquote(params['desc']) | ||
| 71 | else: | ||
| 72 | index.config['DESCRIPTION'] = up.path | ||
| 73 | |||
| 74 | if 'cache' in params: | ||
| 75 | index.config['CACHE'] = params['cache'] | ||
| 76 | |||
| 77 | if 'branch' in params: | ||
| 78 | branches = params['branch'].split(',') | ||
| 79 | index.config['BRANCH'] = branches | ||
| 80 | else: | ||
| 81 | branches = ['*'] | ||
| 82 | |||
| 83 | |||
| 84 | def load_cache(path, index, branches=[]): | ||
| 85 | logger.debug('Loading json file %s' % path) | ||
| 86 | with open(path, 'rt', encoding='utf-8') as f: | ||
| 87 | pindex = json.load(f) | ||
| 88 | |||
| 89 | # Filter the branches on loaded files... | ||
| 90 | newpBranch = [] | ||
| 91 | for branch in branches: | ||
| 92 | if branch != '*': | ||
| 93 | if 'branches' in pindex: | ||
| 94 | for br in pindex['branches']: | ||
| 95 | if br['name'] == branch: | ||
| 96 | newpBranch.append(br) | ||
| 97 | else: | ||
| 98 | if 'branches' in pindex: | ||
| 99 | for br in pindex['branches']: | ||
| 100 | newpBranch.append(br) | ||
| 101 | |||
| 102 | if newpBranch: | ||
| 103 | index.add_raw_element('branches', layerindexlib.Branch, newpBranch) | ||
| 104 | else: | ||
| 105 | logger.debug('No matching branches (%s) in index file(s)' % branches) | ||
| 106 | # No matching branches.. return nothing... | ||
| 107 | return | ||
| 108 | |||
| 109 | for (lName, lType) in [("layerItems", layerindexlib.LayerItem), | ||
| 110 | ("layerBranches", layerindexlib.LayerBranch), | ||
| 111 | ("layerDependencies", layerindexlib.LayerDependency), | ||
| 112 | ("recipes", layerindexlib.Recipe), | ||
| 113 | ("machines", layerindexlib.Machine), | ||
| 114 | ("distros", layerindexlib.Distro)]: | ||
| 115 | if lName in pindex: | ||
| 116 | index.add_raw_element(lName, lType, pindex[lName]) | ||
| 117 | |||
| 118 | |||
| 119 | if not os.path.isdir(up.path): | ||
| 120 | load_cache(up.path, index, branches) | ||
| 121 | return index | ||
| 122 | |||
| 123 | logger.debug('Loading from dir %s...' % (up.path)) | ||
| 124 | for (dirpath, _, filenames) in os.walk(up.path): | ||
| 125 | for filename in filenames: | ||
| 126 | if not filename.endswith('.json'): | ||
| 127 | continue | ||
| 128 | fpath = os.path.join(dirpath, filename) | ||
| 129 | load_cache(fpath, index, branches) | ||
| 130 | |||
| 131 | return index | ||
| 132 | |||
| 133 | |||
| 134 | def load_index_web(self, up, url, load): | ||
| 135 | """ | ||
| 136 | Fetches layer information from a remote layer index. | ||
| 137 | |||
| 138 | The return value is a LayerIndexObj. | ||
| 139 | |||
| 140 | ud is the parsed url to the rest api of the layer index, such as: | ||
| 141 | https://layers.openembedded.org/layerindex/api/ | ||
| 142 | """ | ||
| 143 | |||
| 144 | def _get_json_response(apiurl=None, username=None, password=None, retry=True): | ||
| 145 | assert apiurl is not None | ||
| 146 | |||
| 147 | logger.debug("fetching %s" % apiurl) | ||
| 148 | |||
| 149 | up = urlparse(apiurl) | ||
| 150 | |||
| 151 | username=up.username | ||
| 152 | password=up.password | ||
| 153 | |||
| 154 | # Strip username/password and params | ||
| 155 | if up.port: | ||
| 156 | up_stripped = up._replace(params="", netloc="%s:%s" % (up.hostname, up.port)) | ||
| 157 | else: | ||
| 158 | up_stripped = up._replace(params="", netloc=up.hostname) | ||
| 159 | |||
| 160 | res = self.layerindex._fetch_url(up_stripped.geturl(), username=username, password=password) | ||
| 161 | |||
| 162 | try: | ||
| 163 | parsed = json.loads(res.read().decode('utf-8')) | ||
| 164 | except ConnectionResetError: | ||
| 165 | if retry: | ||
| 166 | logger.debug("%s: Connection reset by peer. Retrying..." % url) | ||
| 167 | parsed = _get_json_response(apiurl=up_stripped.geturl(), username=username, password=password, retry=False) | ||
| 168 | logger.debug("%s: retry successful.") | ||
| 169 | else: | ||
| 170 | raise layerindexlib.LayerIndexFetchError('%s: Connection reset by peer. Is there a firewall blocking your connection?' % apiurl) | ||
| 171 | |||
| 172 | return parsed | ||
| 173 | |||
| 174 | index = layerindexlib.LayerIndexObj() | ||
| 175 | |||
| 176 | index.config = {} | ||
| 177 | index.config['TYPE'] = self.type | ||
| 178 | index.config['URL'] = url | ||
| 179 | |||
| 180 | params = self.layerindex._parse_params(up.params) | ||
| 181 | |||
| 182 | if 'desc' in params: | ||
| 183 | index.config['DESCRIPTION'] = unquote(params['desc']) | ||
| 184 | else: | ||
| 185 | index.config['DESCRIPTION'] = up.hostname | ||
| 186 | |||
| 187 | if 'cache' in params: | ||
| 188 | index.config['CACHE'] = params['cache'] | ||
| 189 | |||
| 190 | if 'branch' in params: | ||
| 191 | branches = params['branch'].split(',') | ||
| 192 | index.config['BRANCH'] = branches | ||
| 193 | else: | ||
| 194 | branches = ['*'] | ||
| 195 | |||
| 196 | try: | ||
| 197 | index.apilinks = _get_json_response(apiurl=url, username=up.username, password=up.password) | ||
| 198 | except Exception as e: | ||
| 199 | raise layerindexlib.LayerIndexFetchError(url, e) | ||
| 200 | |||
| 201 | # Local raw index set... | ||
| 202 | pindex = {} | ||
| 203 | |||
| 204 | # Load all the requested branches at the same time time, | ||
| 205 | # a special branch of '*' means load all branches | ||
| 206 | filter = "" | ||
| 207 | if "*" not in branches: | ||
| 208 | filter = "?filter=name:%s" % "OR".join(branches) | ||
| 209 | |||
| 210 | logger.debug("Loading %s from %s" % (branches, index.apilinks['branches'])) | ||
| 211 | |||
| 212 | # The link won't include username/password, so pull it from the original url | ||
| 213 | pindex['branches'] = _get_json_response(index.apilinks['branches'] + filter, | ||
| 214 | username=up.username, password=up.password) | ||
| 215 | if not pindex['branches']: | ||
| 216 | logger.debug("No valid branches (%s) found at url %s." % (branch, url)) | ||
| 217 | return index | ||
| 218 | index.add_raw_element("branches", layerindexlib.Branch, pindex['branches']) | ||
| 219 | |||
| 220 | # Load all of the layerItems (these can not be easily filtered) | ||
| 221 | logger.debug("Loading %s from %s" % ('layerItems', index.apilinks['layerItems'])) | ||
| 222 | |||
| 223 | |||
| 224 | # The link won't include username/password, so pull it from the original url | ||
| 225 | pindex['layerItems'] = _get_json_response(index.apilinks['layerItems'], | ||
| 226 | username=up.username, password=up.password) | ||
| 227 | if not pindex['layerItems']: | ||
| 228 | logger.debug("No layers were found at url %s." % (url)) | ||
| 229 | return index | ||
| 230 | index.add_raw_element("layerItems", layerindexlib.LayerItem, pindex['layerItems']) | ||
| 231 | |||
| 232 | |||
| 233 | # From this point on load the contents for each branch. Otherwise we | ||
| 234 | # could run into a timeout. | ||
| 235 | for branch in index.branches: | ||
| 236 | filter = "?filter=branch__name:%s" % index.branches[branch].name | ||
| 237 | |||
| 238 | logger.debug("Loading %s from %s" % ('layerBranches', index.apilinks['layerBranches'])) | ||
| 239 | |||
| 240 | # The link won't include username/password, so pull it from the original url | ||
| 241 | pindex['layerBranches'] = _get_json_response(index.apilinks['layerBranches'] + filter, | ||
| 242 | username=up.username, password=up.password) | ||
| 243 | if not pindex['layerBranches']: | ||
| 244 | logger.debug("No valid layer branches (%s) found at url %s." % (branches or "*", url)) | ||
| 245 | return index | ||
| 246 | index.add_raw_element("layerBranches", layerindexlib.LayerBranch, pindex['layerBranches']) | ||
| 247 | |||
| 248 | |||
| 249 | # Load the rest, they all have a similar format | ||
| 250 | # Note: the layer index has a few more items, we can add them if necessary | ||
| 251 | # in the future. | ||
| 252 | filter = "?filter=layerbranch__branch__name:%s" % index.branches[branch].name | ||
| 253 | for (lName, lType) in [("layerDependencies", layerindexlib.LayerDependency), | ||
| 254 | ("recipes", layerindexlib.Recipe), | ||
| 255 | ("machines", layerindexlib.Machine), | ||
| 256 | ("distros", layerindexlib.Distro)]: | ||
| 257 | if lName not in load: | ||
| 258 | continue | ||
| 259 | logger.debug("Loading %s from %s" % (lName, index.apilinks[lName])) | ||
| 260 | |||
| 261 | # The link won't include username/password, so pull it from the original url | ||
| 262 | pindex[lName] = _get_json_response(index.apilinks[lName] + filter, | ||
| 263 | username=up.username, password=up.password) | ||
| 264 | index.add_raw_element(lName, lType, pindex[lName]) | ||
| 265 | |||
| 266 | return index | ||
| 267 | |||
| 268 | def store_index(self, url, index): | ||
| 269 | """ | ||
| 270 | Store layer information into a local file/dir. | ||
| 271 | |||
| 272 | The return value is a dictionary containing API, | ||
| 273 | layer, branch, dependency, recipe, machine, distro, information. | ||
| 274 | |||
| 275 | ud is a parsed url to a directory or file. If the path is a | ||
| 276 | directory, we will split the files into one file per layer. | ||
| 277 | If the path is to a file (exists or not) the entire DB will be | ||
| 278 | dumped into that one file. | ||
| 279 | """ | ||
| 280 | |||
| 281 | up = urlparse(url) | ||
| 282 | |||
| 283 | if up.scheme != 'file': | ||
| 284 | raise layerindexlib.plugin.LayerIndexPluginUrlError(self.type, url) | ||
| 285 | |||
| 286 | logger.debug("Storing to %s..." % up.path) | ||
| 287 | |||
| 288 | try: | ||
| 289 | layerbranches = index.layerBranches | ||
| 290 | except KeyError: | ||
| 291 | logger.error('No layerBranches to write.') | ||
| 292 | return | ||
| 293 | |||
| 294 | |||
| 295 | def filter_item(layerbranchid, objects): | ||
| 296 | filtered = [] | ||
| 297 | for obj in getattr(index, objects, None): | ||
| 298 | try: | ||
| 299 | if getattr(index, objects)[obj].layerbranch_id == layerbranchid: | ||
| 300 | filtered.append(getattr(index, objects)[obj]._data) | ||
| 301 | except AttributeError: | ||
| 302 | logger.debug('No obj.layerbranch_id: %s' % objects) | ||
| 303 | # No simple filter method, just include it... | ||
| 304 | try: | ||
| 305 | filtered.append(getattr(index, objects)[obj]._data) | ||
| 306 | except AttributeError: | ||
| 307 | logger.debug('No obj._data: %s %s' % (objects, type(obj))) | ||
| 308 | filtered.append(obj) | ||
| 309 | return filtered | ||
| 310 | |||
| 311 | |||
| 312 | # Write out to a single file. | ||
| 313 | # Filter out unnecessary items, then sort as we write for determinism | ||
| 314 | if not os.path.isdir(up.path): | ||
| 315 | pindex = {} | ||
| 316 | |||
| 317 | pindex['branches'] = [] | ||
| 318 | pindex['layerItems'] = [] | ||
| 319 | pindex['layerBranches'] = [] | ||
| 320 | |||
| 321 | for layerbranchid in layerbranches: | ||
| 322 | if layerbranches[layerbranchid].branch._data not in pindex['branches']: | ||
| 323 | pindex['branches'].append(layerbranches[layerbranchid].branch._data) | ||
| 324 | |||
| 325 | if layerbranches[layerbranchid].layer._data not in pindex['layerItems']: | ||
| 326 | pindex['layerItems'].append(layerbranches[layerbranchid].layer._data) | ||
| 327 | |||
| 328 | if layerbranches[layerbranchid]._data not in pindex['layerBranches']: | ||
| 329 | pindex['layerBranches'].append(layerbranches[layerbranchid]._data) | ||
| 330 | |||
| 331 | for entry in index._index: | ||
| 332 | # Skip local items, apilinks and items already processed | ||
| 333 | if entry in index.config['local'] or \ | ||
| 334 | entry == 'apilinks' or \ | ||
| 335 | entry == 'branches' or \ | ||
| 336 | entry == 'layerBranches' or \ | ||
| 337 | entry == 'layerItems': | ||
| 338 | continue | ||
| 339 | if entry not in pindex: | ||
| 340 | pindex[entry] = [] | ||
| 341 | pindex[entry].extend(filter_item(layerbranchid, entry)) | ||
| 342 | |||
| 343 | bb.debug(1, 'Writing index to %s' % up.path) | ||
| 344 | with open(up.path, 'wt') as f: | ||
| 345 | json.dump(layerindexlib.sort_entry(pindex), f, indent=4) | ||
| 346 | return | ||
| 347 | |||
| 348 | |||
| 349 | # Write out to a directory one file per layerBranch | ||
| 350 | # Prepare all layer related items, to create a minimal file. | ||
| 351 | # We have to sort the entries as we write so they are deterministic | ||
| 352 | for layerbranchid in layerbranches: | ||
| 353 | pindex = {} | ||
| 354 | |||
| 355 | for entry in index._index: | ||
| 356 | # Skip local items, apilinks and items already processed | ||
| 357 | if entry in index.config['local'] or \ | ||
| 358 | entry == 'apilinks' or \ | ||
| 359 | entry == 'branches' or \ | ||
| 360 | entry == 'layerBranches' or \ | ||
| 361 | entry == 'layerItems': | ||
| 362 | continue | ||
| 363 | pindex[entry] = filter_item(layerbranchid, entry) | ||
| 364 | |||
| 365 | # Add the layer we're processing as the first one... | ||
| 366 | pindex['branches'] = [layerbranches[layerbranchid].branch._data] | ||
| 367 | pindex['layerItems'] = [layerbranches[layerbranchid].layer._data] | ||
| 368 | pindex['layerBranches'] = [layerbranches[layerbranchid]._data] | ||
| 369 | |||
| 370 | # We also need to include the layerbranch for any dependencies... | ||
| 371 | for layerdep in pindex['layerDependencies']: | ||
| 372 | layerdependency = layerindexlib.LayerDependency(index, layerdep) | ||
| 373 | |||
| 374 | layeritem = layerdependency.dependency | ||
| 375 | layerbranch = layerdependency.dependency_layerBranch | ||
| 376 | |||
| 377 | # We need to avoid duplicates... | ||
| 378 | if layeritem._data not in pindex['layerItems']: | ||
| 379 | pindex['layerItems'].append(layeritem._data) | ||
| 380 | |||
| 381 | if layerbranch._data not in pindex['layerBranches']: | ||
| 382 | pindex['layerBranches'].append(layerbranch._data) | ||
| 383 | |||
| 384 | # apply mirroring adjustments here.... | ||
| 385 | |||
| 386 | fname = index.config['DESCRIPTION'] + '__' + pindex['branches'][0]['name'] + '__' + pindex['layerItems'][0]['name'] | ||
| 387 | fname = fname.translate(str.maketrans('/ ', '__')) | ||
| 388 | fpath = os.path.join(up.path, fname) | ||
| 389 | |||
| 390 | bb.debug(1, 'Writing index to %s' % fpath + '.json') | ||
| 391 | with open(fpath + '.json', 'wt') as f: | ||
| 392 | json.dump(layerindexlib.sort_entry(pindex), f, indent=4) | ||
diff --git a/bitbake/lib/layerindexlib/tests/__init__.py b/bitbake/lib/layerindexlib/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/bitbake/lib/layerindexlib/tests/__init__.py +++ /dev/null | |||
diff --git a/bitbake/lib/layerindexlib/tests/common.py b/bitbake/lib/layerindexlib/tests/common.py deleted file mode 100644 index 077382f11d..0000000000 --- a/bitbake/lib/layerindexlib/tests/common.py +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | # Copyright (C) 2017-2018 Wind River Systems, Inc. | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 4 | # | ||
| 5 | |||
| 6 | import unittest | ||
| 7 | import tempfile | ||
| 8 | import os | ||
| 9 | import bb | ||
| 10 | |||
| 11 | import logging | ||
| 12 | |||
| 13 | class LayersTest(unittest.TestCase): | ||
| 14 | |||
| 15 | def setUp(self): | ||
| 16 | self.origdir = os.getcwd() | ||
| 17 | self.d = bb.data.init() | ||
| 18 | # At least one variable needs to be set | ||
| 19 | self.d.setVar('DL_DIR', os.getcwd()) | ||
| 20 | |||
| 21 | if os.environ.get("BB_SKIP_NETTESTS") == "yes": | ||
| 22 | self.d.setVar('BB_NO_NETWORK', '1') | ||
| 23 | |||
| 24 | self.tempdir = tempfile.mkdtemp() | ||
| 25 | self.logger = logging.getLogger("BitBake") | ||
| 26 | |||
| 27 | def tearDown(self): | ||
| 28 | os.chdir(self.origdir) | ||
| 29 | if os.environ.get("BB_TMPDIR_NOCLEAN") == "yes": | ||
| 30 | print("Not cleaning up %s. Please remove manually." % self.tempdir) | ||
| 31 | else: | ||
| 32 | bb.utils.prunedir(self.tempdir) | ||
| 33 | |||
diff --git a/bitbake/lib/layerindexlib/tests/cooker.py b/bitbake/lib/layerindexlib/tests/cooker.py deleted file mode 100644 index 5ddf89aa21..0000000000 --- a/bitbake/lib/layerindexlib/tests/cooker.py +++ /dev/null | |||
| @@ -1,110 +0,0 @@ | |||
| 1 | # Copyright (C) 2018 Wind River Systems, Inc. | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 4 | # | ||
| 5 | |||
| 6 | import os | ||
| 7 | import bb | ||
| 8 | |||
| 9 | import layerindexlib | ||
| 10 | from layerindexlib.tests.common import LayersTest | ||
| 11 | |||
| 12 | |||
| 13 | class LayerIndexCookerTest(LayersTest): | ||
| 14 | |||
| 15 | def setUp(self): | ||
| 16 | LayersTest.setUp(self) | ||
| 17 | |||
| 18 | # Note this is NOT a comprehensive test of cooker, as we can't easily | ||
| 19 | # configure the test data. But we can emulate the basics of the layer.conf | ||
| 20 | # files, so that is what we will do. | ||
| 21 | |||
| 22 | new_topdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "testdata") | ||
| 23 | new_bbpath = os.path.join(new_topdir, "build") | ||
| 24 | |||
| 25 | self.d.setVar('TOPDIR', new_topdir) | ||
| 26 | self.d.setVar('BBPATH', new_bbpath) | ||
| 27 | |||
| 28 | self.d = bb.parse.handle("%s/conf/bblayers.conf" % new_bbpath, self.d, True) | ||
| 29 | for layer in self.d.getVar('BBLAYERS').split(): | ||
| 30 | self.d = bb.parse.handle("%s/conf/layer.conf" % layer, self.d, True) | ||
| 31 | |||
| 32 | self.layerindex = layerindexlib.LayerIndex(self.d) | ||
| 33 | self.layerindex.load_layerindex('cooker://', load=['layerDependencies']) | ||
| 34 | |||
| 35 | def test_layerindex_is_empty(self): | ||
| 36 | self.assertFalse(self.layerindex.is_empty(), msg="Layerindex is not empty!") | ||
| 37 | |||
| 38 | def test_dependency_resolution(self): | ||
| 39 | # Verify depth first searching... | ||
| 40 | (dependencies, invalidnames) = self.layerindex.find_dependencies(names=['meta-python']) | ||
| 41 | |||
| 42 | first = True | ||
| 43 | for deplayerbranch in dependencies: | ||
| 44 | layerBranch = dependencies[deplayerbranch][0] | ||
| 45 | layerDeps = dependencies[deplayerbranch][1:] | ||
| 46 | |||
| 47 | if not first: | ||
| 48 | continue | ||
| 49 | |||
| 50 | first = False | ||
| 51 | |||
| 52 | # Top of the deps should be openembedded-core, since everything depends on it. | ||
| 53 | self.assertEqual(layerBranch.layer.name, "openembedded-core", msg='Top dependency not openembedded-core') | ||
| 54 | |||
| 55 | # meta-python should cause an openembedded-core dependency, if not assert! | ||
| 56 | for dep in layerDeps: | ||
| 57 | if dep.layer.name == 'meta-python': | ||
| 58 | break | ||
| 59 | else: | ||
| 60 | self.assertTrue(False, msg='meta-python was not found') | ||
| 61 | |||
| 62 | # Only check the first element... | ||
| 63 | break | ||
| 64 | else: | ||
| 65 | if first: | ||
| 66 | # Empty list, this is bad. | ||
| 67 | self.assertTrue(False, msg='Empty list of dependencies') | ||
| 68 | |||
| 69 | # Last dep should be the requested item | ||
| 70 | layerBranch = dependencies[deplayerbranch][0] | ||
| 71 | self.assertEqual(layerBranch.layer.name, "meta-python", msg='Last dependency not meta-python') | ||
| 72 | |||
| 73 | def test_find_collection(self): | ||
| 74 | def _check(collection, expected): | ||
| 75 | self.logger.debug("Looking for collection %s..." % collection) | ||
| 76 | result = self.layerindex.find_collection(collection) | ||
| 77 | if expected: | ||
| 78 | self.assertIsNotNone(result, msg="Did not find %s when it shouldn't be there" % collection) | ||
| 79 | else: | ||
| 80 | self.assertIsNone(result, msg="Found %s when it should be there" % collection) | ||
| 81 | |||
| 82 | tests = [ ('core', True), | ||
| 83 | ('openembedded-core', False), | ||
| 84 | ('networking-layer', True), | ||
| 85 | ('meta-python', True), | ||
| 86 | ('openembedded-layer', True), | ||
| 87 | ('notpresent', False) ] | ||
| 88 | |||
| 89 | for collection,result in tests: | ||
| 90 | _check(collection, result) | ||
| 91 | |||
| 92 | def test_find_layerbranch(self): | ||
| 93 | def _check(name, expected): | ||
| 94 | self.logger.debug("Looking for layerbranch %s..." % name) | ||
| 95 | result = self.layerindex.find_layerbranch(name) | ||
| 96 | if expected: | ||
| 97 | self.assertIsNotNone(result, msg="Did not find %s when it shouldn't be there" % collection) | ||
| 98 | else: | ||
| 99 | self.assertIsNone(result, msg="Found %s when it should be there" % collection) | ||
| 100 | |||
| 101 | tests = [ ('openembedded-core', True), | ||
| 102 | ('core', False), | ||
| 103 | ('networking-layer', True), | ||
| 104 | ('meta-python', True), | ||
| 105 | ('openembedded-layer', True), | ||
| 106 | ('notpresent', False) ] | ||
| 107 | |||
| 108 | for collection,result in tests: | ||
| 109 | _check(collection, result) | ||
| 110 | |||
diff --git a/bitbake/lib/layerindexlib/tests/layerindexobj.py b/bitbake/lib/layerindexlib/tests/layerindexobj.py deleted file mode 100644 index de1e474687..0000000000 --- a/bitbake/lib/layerindexlib/tests/layerindexobj.py +++ /dev/null | |||
| @@ -1,210 +0,0 @@ | |||
| 1 | # Copyright (C) 2017-2018 Wind River Systems, Inc. | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 4 | # | ||
| 5 | |||
| 6 | from layerindexlib.tests.common import LayersTest | ||
| 7 | |||
| 8 | |||
| 9 | class LayerIndexObjectsTest(LayersTest): | ||
| 10 | def setUp(self): | ||
| 11 | from layerindexlib import LayerIndexObj, Branch, LayerItem, LayerBranch, LayerDependency, Recipe, Machine, Distro | ||
| 12 | |||
| 13 | LayersTest.setUp(self) | ||
| 14 | |||
| 15 | self.index = LayerIndexObj() | ||
| 16 | |||
| 17 | branchId = 0 | ||
| 18 | layerItemId = 0 | ||
| 19 | layerBranchId = 0 | ||
| 20 | layerDependencyId = 0 | ||
| 21 | recipeId = 0 | ||
| 22 | machineId = 0 | ||
| 23 | distroId = 0 | ||
| 24 | |||
| 25 | self.index.branches = {} | ||
| 26 | self.index.layerItems = {} | ||
| 27 | self.index.layerBranches = {} | ||
| 28 | self.index.layerDependencies = {} | ||
| 29 | self.index.recipes = {} | ||
| 30 | self.index.machines = {} | ||
| 31 | self.index.distros = {} | ||
| 32 | |||
| 33 | branchId += 1 | ||
| 34 | self.index.branches[branchId] = Branch(self.index) | ||
| 35 | self.index.branches[branchId].define_data(branchId, | ||
| 36 | 'test_branch', 'bb_test_branch') | ||
| 37 | self.index.branches[branchId].lockData() | ||
| 38 | |||
| 39 | layerItemId +=1 | ||
| 40 | self.index.layerItems[layerItemId] = LayerItem(self.index) | ||
| 41 | self.index.layerItems[layerItemId].define_data(layerItemId, | ||
| 42 | 'test_layerItem', vcs_url='git://git_test_url/test_layerItem') | ||
| 43 | self.index.layerItems[layerItemId].lockData() | ||
| 44 | |||
| 45 | layerBranchId +=1 | ||
| 46 | self.index.layerBranches[layerBranchId] = LayerBranch(self.index) | ||
| 47 | self.index.layerBranches[layerBranchId].define_data(layerBranchId, | ||
| 48 | 'test_collection', '99', layerItemId, | ||
| 49 | branchId) | ||
| 50 | |||
| 51 | recipeId += 1 | ||
| 52 | self.index.recipes[recipeId] = Recipe(self.index) | ||
| 53 | self.index.recipes[recipeId].define_data(recipeId, 'test_git.bb', | ||
| 54 | 'recipes-test', 'test', 'git', | ||
| 55 | layerBranchId) | ||
| 56 | |||
| 57 | machineId += 1 | ||
| 58 | self.index.machines[machineId] = Machine(self.index) | ||
| 59 | self.index.machines[machineId].define_data(machineId, | ||
| 60 | 'test_machine', 'test_machine', | ||
| 61 | layerBranchId) | ||
| 62 | |||
| 63 | distroId += 1 | ||
| 64 | self.index.distros[distroId] = Distro(self.index) | ||
| 65 | self.index.distros[distroId].define_data(distroId, | ||
| 66 | 'test_distro', 'test_distro', | ||
| 67 | layerBranchId) | ||
| 68 | |||
| 69 | layerItemId +=1 | ||
| 70 | self.index.layerItems[layerItemId] = LayerItem(self.index) | ||
| 71 | self.index.layerItems[layerItemId].define_data(layerItemId, 'test_layerItem 2', | ||
| 72 | vcs_url='git://git_test_url/test_layerItem') | ||
| 73 | |||
| 74 | layerBranchId +=1 | ||
| 75 | self.index.layerBranches[layerBranchId] = LayerBranch(self.index) | ||
| 76 | self.index.layerBranches[layerBranchId].define_data(layerBranchId, | ||
| 77 | 'test_collection_2', '72', layerItemId, | ||
| 78 | branchId, actual_branch='some_other_branch') | ||
| 79 | |||
| 80 | layerDependencyId += 1 | ||
| 81 | self.index.layerDependencies[layerDependencyId] = LayerDependency(self.index) | ||
| 82 | self.index.layerDependencies[layerDependencyId].define_data(layerDependencyId, | ||
| 83 | layerBranchId, 1) | ||
| 84 | |||
| 85 | layerDependencyId += 1 | ||
| 86 | self.index.layerDependencies[layerDependencyId] = LayerDependency(self.index) | ||
| 87 | self.index.layerDependencies[layerDependencyId].define_data(layerDependencyId, | ||
| 88 | layerBranchId, 1, required=False) | ||
| 89 | |||
| 90 | def test_branch(self): | ||
| 91 | branch = self.index.branches[1] | ||
| 92 | self.assertEqual(branch.id, 1) | ||
| 93 | self.assertEqual(branch.name, 'test_branch') | ||
| 94 | self.assertEqual(branch.short_description, 'test_branch') | ||
| 95 | self.assertEqual(branch.bitbake_branch, 'bb_test_branch') | ||
| 96 | |||
| 97 | def test_layerItem(self): | ||
| 98 | layerItem = self.index.layerItems[1] | ||
| 99 | self.assertEqual(layerItem.id, 1) | ||
| 100 | self.assertEqual(layerItem.name, 'test_layerItem') | ||
| 101 | self.assertEqual(layerItem.summary, 'test_layerItem') | ||
| 102 | self.assertEqual(layerItem.description, 'test_layerItem') | ||
| 103 | self.assertEqual(layerItem.vcs_url, 'git://git_test_url/test_layerItem') | ||
| 104 | self.assertEqual(layerItem.vcs_web_url, None) | ||
| 105 | self.assertIsNone(layerItem.vcs_web_tree_base_url) | ||
| 106 | self.assertIsNone(layerItem.vcs_web_file_base_url) | ||
| 107 | self.assertIsNotNone(layerItem.updated) | ||
| 108 | |||
| 109 | layerItem = self.index.layerItems[2] | ||
| 110 | self.assertEqual(layerItem.id, 2) | ||
| 111 | self.assertEqual(layerItem.name, 'test_layerItem 2') | ||
| 112 | self.assertEqual(layerItem.summary, 'test_layerItem 2') | ||
| 113 | self.assertEqual(layerItem.description, 'test_layerItem 2') | ||
| 114 | self.assertEqual(layerItem.vcs_url, 'git://git_test_url/test_layerItem') | ||
| 115 | self.assertIsNone(layerItem.vcs_web_url) | ||
| 116 | self.assertIsNone(layerItem.vcs_web_tree_base_url) | ||
| 117 | self.assertIsNone(layerItem.vcs_web_file_base_url) | ||
| 118 | self.assertIsNotNone(layerItem.updated) | ||
| 119 | |||
| 120 | def test_layerBranch(self): | ||
| 121 | layerBranch = self.index.layerBranches[1] | ||
| 122 | self.assertEqual(layerBranch.id, 1) | ||
| 123 | self.assertEqual(layerBranch.collection, 'test_collection') | ||
| 124 | self.assertEqual(layerBranch.version, '99') | ||
| 125 | self.assertEqual(layerBranch.vcs_subdir, '') | ||
| 126 | self.assertEqual(layerBranch.actual_branch, 'test_branch') | ||
| 127 | self.assertIsNotNone(layerBranch.updated) | ||
| 128 | self.assertEqual(layerBranch.layer_id, 1) | ||
| 129 | self.assertEqual(layerBranch.branch_id, 1) | ||
| 130 | self.assertEqual(layerBranch.layer, self.index.layerItems[1]) | ||
| 131 | self.assertEqual(layerBranch.branch, self.index.branches[1]) | ||
| 132 | |||
| 133 | layerBranch = self.index.layerBranches[2] | ||
| 134 | self.assertEqual(layerBranch.id, 2) | ||
| 135 | self.assertEqual(layerBranch.collection, 'test_collection_2') | ||
| 136 | self.assertEqual(layerBranch.version, '72') | ||
| 137 | self.assertEqual(layerBranch.vcs_subdir, '') | ||
| 138 | self.assertEqual(layerBranch.actual_branch, 'some_other_branch') | ||
| 139 | self.assertIsNotNone(layerBranch.updated) | ||
| 140 | self.assertEqual(layerBranch.layer_id, 2) | ||
| 141 | self.assertEqual(layerBranch.branch_id, 1) | ||
| 142 | self.assertEqual(layerBranch.layer, self.index.layerItems[2]) | ||
| 143 | self.assertEqual(layerBranch.branch, self.index.branches[1]) | ||
| 144 | |||
| 145 | def test_layerDependency(self): | ||
| 146 | layerDependency = self.index.layerDependencies[1] | ||
| 147 | self.assertEqual(layerDependency.id, 1) | ||
| 148 | self.assertEqual(layerDependency.layerbranch_id, 2) | ||
| 149 | self.assertEqual(layerDependency.layerbranch, self.index.layerBranches[2]) | ||
| 150 | self.assertEqual(layerDependency.layer_id, 2) | ||
| 151 | self.assertEqual(layerDependency.layer, self.index.layerItems[2]) | ||
| 152 | self.assertTrue(layerDependency.required) | ||
| 153 | self.assertEqual(layerDependency.dependency_id, 1) | ||
| 154 | self.assertEqual(layerDependency.dependency, self.index.layerItems[1]) | ||
| 155 | self.assertEqual(layerDependency.dependency_layerBranch, self.index.layerBranches[1]) | ||
| 156 | |||
| 157 | layerDependency = self.index.layerDependencies[2] | ||
| 158 | self.assertEqual(layerDependency.id, 2) | ||
| 159 | self.assertEqual(layerDependency.layerbranch_id, 2) | ||
| 160 | self.assertEqual(layerDependency.layerbranch, self.index.layerBranches[2]) | ||
| 161 | self.assertEqual(layerDependency.layer_id, 2) | ||
| 162 | self.assertEqual(layerDependency.layer, self.index.layerItems[2]) | ||
| 163 | self.assertFalse(layerDependency.required) | ||
| 164 | self.assertEqual(layerDependency.dependency_id, 1) | ||
| 165 | self.assertEqual(layerDependency.dependency, self.index.layerItems[1]) | ||
| 166 | self.assertEqual(layerDependency.dependency_layerBranch, self.index.layerBranches[1]) | ||
| 167 | |||
| 168 | def test_recipe(self): | ||
| 169 | recipe = self.index.recipes[1] | ||
| 170 | self.assertEqual(recipe.id, 1) | ||
| 171 | self.assertEqual(recipe.layerbranch_id, 1) | ||
| 172 | self.assertEqual(recipe.layerbranch, self.index.layerBranches[1]) | ||
| 173 | self.assertEqual(recipe.layer_id, 1) | ||
| 174 | self.assertEqual(recipe.layer, self.index.layerItems[1]) | ||
| 175 | self.assertEqual(recipe.filename, 'test_git.bb') | ||
| 176 | self.assertEqual(recipe.filepath, 'recipes-test') | ||
| 177 | self.assertEqual(recipe.fullpath, 'recipes-test/test_git.bb') | ||
| 178 | self.assertEqual(recipe.summary, "") | ||
| 179 | self.assertEqual(recipe.description, "") | ||
| 180 | self.assertEqual(recipe.section, "") | ||
| 181 | self.assertEqual(recipe.pn, 'test') | ||
| 182 | self.assertEqual(recipe.pv, 'git') | ||
| 183 | self.assertEqual(recipe.license, "") | ||
| 184 | self.assertEqual(recipe.homepage, "") | ||
| 185 | self.assertEqual(recipe.bugtracker, "") | ||
| 186 | self.assertEqual(recipe.provides, "") | ||
| 187 | self.assertIsNotNone(recipe.updated) | ||
| 188 | self.assertEqual(recipe.inherits, "") | ||
| 189 | |||
| 190 | def test_machine(self): | ||
| 191 | machine = self.index.machines[1] | ||
| 192 | self.assertEqual(machine.id, 1) | ||
| 193 | self.assertEqual(machine.layerbranch_id, 1) | ||
| 194 | self.assertEqual(machine.layerbranch, self.index.layerBranches[1]) | ||
| 195 | self.assertEqual(machine.layer_id, 1) | ||
| 196 | self.assertEqual(machine.layer, self.index.layerItems[1]) | ||
| 197 | self.assertEqual(machine.name, 'test_machine') | ||
| 198 | self.assertEqual(machine.description, 'test_machine') | ||
| 199 | self.assertIsNotNone(machine.updated) | ||
| 200 | |||
| 201 | def test_distro(self): | ||
| 202 | distro = self.index.distros[1] | ||
| 203 | self.assertEqual(distro.id, 1) | ||
| 204 | self.assertEqual(distro.layerbranch_id, 1) | ||
| 205 | self.assertEqual(distro.layerbranch, self.index.layerBranches[1]) | ||
| 206 | self.assertEqual(distro.layer_id, 1) | ||
| 207 | self.assertEqual(distro.layer, self.index.layerItems[1]) | ||
| 208 | self.assertEqual(distro.name, 'test_distro') | ||
| 209 | self.assertEqual(distro.description, 'test_distro') | ||
| 210 | self.assertIsNotNone(distro.updated) | ||
diff --git a/bitbake/lib/layerindexlib/tests/restapi.py b/bitbake/lib/layerindexlib/tests/restapi.py deleted file mode 100644 index 71f0ae8a9d..0000000000 --- a/bitbake/lib/layerindexlib/tests/restapi.py +++ /dev/null | |||
| @@ -1,171 +0,0 @@ | |||
| 1 | # Copyright (C) 2017-2018 Wind River Systems, Inc. | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 4 | # | ||
| 5 | |||
| 6 | import unittest | ||
| 7 | import os | ||
| 8 | |||
| 9 | import layerindexlib | ||
| 10 | from layerindexlib.tests.common import LayersTest | ||
| 11 | |||
| 12 | |||
| 13 | def skipIfNoNetwork(): | ||
| 14 | if os.environ.get("BB_SKIP_NETTESTS") == "yes": | ||
| 15 | return unittest.skip("Network tests being skipped") | ||
| 16 | return lambda f: f | ||
| 17 | |||
| 18 | class LayerIndexWebRestApiTest(LayersTest): | ||
| 19 | |||
| 20 | @skipIfNoNetwork() | ||
| 21 | def setUp(self): | ||
| 22 | self.assertFalse(os.environ.get("BB_SKIP_NETTESTS") == "yes", msg="BB_SKIP_NETTESTS set, but we tried to test anyway") | ||
| 23 | LayersTest.setUp(self) | ||
| 24 | self.layerindex = layerindexlib.LayerIndex(self.d) | ||
| 25 | self.layerindex.load_layerindex('https://layers.openembedded.org/layerindex/api/;branch=sumo', load=['layerDependencies']) | ||
| 26 | |||
| 27 | @skipIfNoNetwork() | ||
| 28 | def test_layerindex_is_empty(self): | ||
| 29 | self.assertFalse(self.layerindex.is_empty(), msg="Layerindex is empty") | ||
| 30 | |||
| 31 | @skipIfNoNetwork() | ||
| 32 | def test_layerindex_store_file(self): | ||
| 33 | self.layerindex.store_layerindex('file://%s/file.json' % self.tempdir, self.layerindex.indexes[0]) | ||
| 34 | |||
| 35 | self.assertTrue(os.path.isfile('%s/file.json' % self.tempdir), msg="Temporary file was not created by store_layerindex") | ||
| 36 | |||
| 37 | reload = layerindexlib.LayerIndex(self.d) | ||
| 38 | reload.load_layerindex('file://%s/file.json' % self.tempdir) | ||
| 39 | |||
| 40 | self.assertFalse(reload.is_empty(), msg="Layerindex is empty") | ||
| 41 | |||
| 42 | # Calculate layerItems in original index that should NOT be in reload | ||
| 43 | layerItemNames = [] | ||
| 44 | for itemId in self.layerindex.indexes[0].layerItems: | ||
| 45 | layerItemNames.append(self.layerindex.indexes[0].layerItems[itemId].name) | ||
| 46 | |||
| 47 | for layerBranchId in self.layerindex.indexes[0].layerBranches: | ||
| 48 | layerItemNames.remove(self.layerindex.indexes[0].layerBranches[layerBranchId].layer.name) | ||
| 49 | |||
| 50 | for itemId in reload.indexes[0].layerItems: | ||
| 51 | self.assertFalse(reload.indexes[0].layerItems[itemId].name in layerItemNames, msg="Item reloaded when it shouldn't have been") | ||
| 52 | |||
| 53 | # Compare the original to what we wrote... | ||
| 54 | for type in self.layerindex.indexes[0]._index: | ||
| 55 | if type == 'apilinks' or \ | ||
| 56 | type == 'layerItems' or \ | ||
| 57 | type in self.layerindex.indexes[0].config['local']: | ||
| 58 | continue | ||
| 59 | for id in getattr(self.layerindex.indexes[0], type): | ||
| 60 | self.logger.debug("type %s" % (type)) | ||
| 61 | |||
| 62 | self.assertTrue(id in getattr(reload.indexes[0], type), msg="Id number not in reloaded index") | ||
| 63 | |||
| 64 | self.logger.debug("%s ? %s" % (getattr(self.layerindex.indexes[0], type)[id], getattr(reload.indexes[0], type)[id])) | ||
| 65 | |||
| 66 | self.assertEqual(getattr(self.layerindex.indexes[0], type)[id], getattr(reload.indexes[0], type)[id], msg="Reloaded contents different") | ||
| 67 | |||
| 68 | @skipIfNoNetwork() | ||
| 69 | def test_layerindex_store_split(self): | ||
| 70 | self.layerindex.store_layerindex('file://%s' % self.tempdir, self.layerindex.indexes[0]) | ||
| 71 | |||
| 72 | reload = layerindexlib.LayerIndex(self.d) | ||
| 73 | reload.load_layerindex('file://%s' % self.tempdir) | ||
| 74 | |||
| 75 | self.assertFalse(reload.is_empty(), msg="Layer index is empty") | ||
| 76 | |||
| 77 | for type in self.layerindex.indexes[0]._index: | ||
| 78 | if type == 'apilinks' or \ | ||
| 79 | type == 'layerItems' or \ | ||
| 80 | type in self.layerindex.indexes[0].config['local']: | ||
| 81 | continue | ||
| 82 | for id in getattr(self.layerindex.indexes[0] ,type): | ||
| 83 | self.logger.debug("type %s" % (type)) | ||
| 84 | |||
| 85 | self.assertTrue(id in getattr(reload.indexes[0], type), msg="Id number missing from reloaded data") | ||
| 86 | |||
| 87 | self.logger.debug("%s ? %s" % (getattr(self.layerindex.indexes[0] ,type)[id], getattr(reload.indexes[0], type)[id])) | ||
| 88 | |||
| 89 | self.assertEqual(getattr(self.layerindex.indexes[0] ,type)[id], getattr(reload.indexes[0], type)[id], msg="reloaded data does not match original") | ||
| 90 | |||
| 91 | @skipIfNoNetwork() | ||
| 92 | def test_dependency_resolution(self): | ||
| 93 | # Verify depth first searching... | ||
| 94 | (dependencies, invalidnames) = self.layerindex.find_dependencies(names=['meta-python']) | ||
| 95 | |||
| 96 | first = True | ||
| 97 | for deplayerbranch in dependencies: | ||
| 98 | layerBranch = dependencies[deplayerbranch][0] | ||
| 99 | layerDeps = dependencies[deplayerbranch][1:] | ||
| 100 | |||
| 101 | if not first: | ||
| 102 | continue | ||
| 103 | |||
| 104 | first = False | ||
| 105 | |||
| 106 | # Top of the deps should be openembedded-core, since everything depends on it. | ||
| 107 | self.assertEqual(layerBranch.layer.name, "openembedded-core", msg='OpenEmbedded-Core is no the first dependency') | ||
| 108 | |||
| 109 | # meta-python should cause an openembedded-core dependency, if not assert! | ||
| 110 | for dep in layerDeps: | ||
| 111 | if dep.layer.name == 'meta-python': | ||
| 112 | break | ||
| 113 | else: | ||
| 114 | self.logger.debug("meta-python was not found") | ||
| 115 | raise self.failureException | ||
| 116 | |||
| 117 | # Only check the first element... | ||
| 118 | break | ||
| 119 | else: | ||
| 120 | # Empty list, this is bad. | ||
| 121 | self.logger.debug("Empty list of dependencies") | ||
| 122 | self.assertIsNotNone(first, msg="Empty list of dependencies") | ||
| 123 | |||
| 124 | # Last dep should be the requested item | ||
| 125 | layerBranch = dependencies[deplayerbranch][0] | ||
| 126 | self.assertEqual(layerBranch.layer.name, "meta-python", msg="Last dependency not meta-python") | ||
| 127 | |||
| 128 | @skipIfNoNetwork() | ||
| 129 | def test_find_collection(self): | ||
| 130 | def _check(collection, expected): | ||
| 131 | self.logger.debug("Looking for collection %s..." % collection) | ||
| 132 | result = self.layerindex.find_collection(collection) | ||
| 133 | if expected: | ||
| 134 | self.assertIsNotNone(result, msg="Did not find %s when it should be there" % collection) | ||
| 135 | else: | ||
| 136 | self.assertIsNone(result, msg="Found %s when it shouldn't be there" % collection) | ||
| 137 | |||
| 138 | tests = [ ('core', True), | ||
| 139 | ('openembedded-core', False), | ||
| 140 | ('networking-layer', True), | ||
| 141 | ('meta-python', True), | ||
| 142 | ('openembedded-layer', True), | ||
| 143 | ('notpresent', False) ] | ||
| 144 | |||
| 145 | for collection,result in tests: | ||
| 146 | _check(collection, result) | ||
| 147 | |||
| 148 | @skipIfNoNetwork() | ||
| 149 | def test_find_layerbranch(self): | ||
| 150 | def _check(name, expected): | ||
| 151 | self.logger.debug("Looking for layerbranch %s..." % name) | ||
| 152 | |||
| 153 | for index in self.layerindex.indexes: | ||
| 154 | for layerbranchid in index.layerBranches: | ||
| 155 | self.logger.debug("Present: %s" % index.layerBranches[layerbranchid].layer.name) | ||
| 156 | result = self.layerindex.find_layerbranch(name) | ||
| 157 | if expected: | ||
| 158 | self.assertIsNotNone(result, msg="Did not find %s when it should be there" % collection) | ||
| 159 | else: | ||
| 160 | self.assertIsNone(result, msg="Found %s when it shouldn't be there" % collection) | ||
| 161 | |||
| 162 | tests = [ ('openembedded-core', True), | ||
| 163 | ('core', False), | ||
| 164 | ('meta-networking', True), | ||
| 165 | ('meta-python', True), | ||
| 166 | ('meta-oe', True), | ||
| 167 | ('notpresent', False) ] | ||
| 168 | |||
| 169 | for collection,result in tests: | ||
| 170 | _check(collection, result) | ||
| 171 | |||
diff --git a/bitbake/lib/layerindexlib/tests/testdata/README b/bitbake/lib/layerindexlib/tests/testdata/README deleted file mode 100644 index 36ab40bebe..0000000000 --- a/bitbake/lib/layerindexlib/tests/testdata/README +++ /dev/null | |||
| @@ -1,11 +0,0 @@ | |||
| 1 | This test data is used to verify the 'cooker' module of the layerindex. | ||
| 2 | |||
| 3 | The module consists of a faux project bblayers.conf with four layers defined. | ||
| 4 | |||
| 5 | layer1 - openembedded-core | ||
| 6 | layer2 - networking-layer | ||
| 7 | layer3 - meta-python | ||
| 8 | layer4 - openembedded-layer (meta-oe) | ||
| 9 | |||
| 10 | Since we do not have a fully populated cooker, we use this to test the | ||
| 11 | basic index generation, and not any deep recipe based contents. | ||
diff --git a/bitbake/lib/layerindexlib/tests/testdata/build/conf/bblayers.conf b/bitbake/lib/layerindexlib/tests/testdata/build/conf/bblayers.conf deleted file mode 100644 index 40429b2f66..0000000000 --- a/bitbake/lib/layerindexlib/tests/testdata/build/conf/bblayers.conf +++ /dev/null | |||
| @@ -1,15 +0,0 @@ | |||
| 1 | LAYERSERIES_CORENAMES = "sumo" | ||
| 2 | |||
| 3 | # LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf | ||
| 4 | # changes incompatibly | ||
| 5 | LCONF_VERSION = "7" | ||
| 6 | |||
| 7 | BBPATH = "${TOPDIR}" | ||
| 8 | BBFILES ?= "" | ||
| 9 | |||
| 10 | BBLAYERS ?= " \ | ||
| 11 | ${TOPDIR}/layer1 \ | ||
| 12 | ${TOPDIR}/layer2 \ | ||
| 13 | ${TOPDIR}/layer3 \ | ||
| 14 | ${TOPDIR}/layer4 \ | ||
| 15 | " | ||
diff --git a/bitbake/lib/layerindexlib/tests/testdata/layer1/conf/layer.conf b/bitbake/lib/layerindexlib/tests/testdata/layer1/conf/layer.conf deleted file mode 100644 index 966d531959..0000000000 --- a/bitbake/lib/layerindexlib/tests/testdata/layer1/conf/layer.conf +++ /dev/null | |||
| @@ -1,17 +0,0 @@ | |||
| 1 | # We have a conf and classes directory, add to BBPATH | ||
| 2 | BBPATH .= ":${LAYERDIR}" | ||
| 3 | # We have recipes-* directories, add to BBFILES | ||
| 4 | BBFILES += "${LAYERDIR}/recipes-*/*/*.bb" | ||
| 5 | |||
| 6 | BBFILE_COLLECTIONS += "core" | ||
| 7 | BBFILE_PATTERN_core = "^${LAYERDIR}/" | ||
| 8 | BBFILE_PRIORITY_core = "5" | ||
| 9 | |||
| 10 | LAYERSERIES_CORENAMES = "sumo" | ||
| 11 | |||
| 12 | # This should only be incremented on significant changes that will | ||
| 13 | # cause compatibility issues with other layers | ||
| 14 | LAYERVERSION_core = "11" | ||
| 15 | LAYERSERIES_COMPAT_core = "sumo" | ||
| 16 | |||
| 17 | BBLAYERS_LAYERINDEX_NAME_core = "openembedded-core" | ||
diff --git a/bitbake/lib/layerindexlib/tests/testdata/layer2/conf/layer.conf b/bitbake/lib/layerindexlib/tests/testdata/layer2/conf/layer.conf deleted file mode 100644 index 7569d1c217..0000000000 --- a/bitbake/lib/layerindexlib/tests/testdata/layer2/conf/layer.conf +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | # We have a conf and classes directory, add to BBPATH | ||
| 2 | BBPATH .= ":${LAYERDIR}" | ||
| 3 | |||
| 4 | # We have a packages directory, add to BBFILES | ||
| 5 | BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ | ||
| 6 | ${LAYERDIR}/recipes-*/*/*.bbappend" | ||
| 7 | |||
| 8 | BBFILE_COLLECTIONS += "networking-layer" | ||
| 9 | BBFILE_PATTERN_networking-layer := "^${LAYERDIR}/" | ||
| 10 | BBFILE_PRIORITY_networking-layer = "5" | ||
| 11 | |||
| 12 | # This should only be incremented on significant changes that will | ||
| 13 | # cause compatibility issues with other layers | ||
| 14 | LAYERVERSION_networking-layer = "1" | ||
| 15 | |||
| 16 | LAYERDEPENDS_networking-layer = "core" | ||
| 17 | LAYERDEPENDS_networking-layer += "openembedded-layer" | ||
| 18 | LAYERDEPENDS_networking-layer += "meta-python" | ||
| 19 | |||
| 20 | LAYERSERIES_COMPAT_networking-layer = "sumo" | ||
diff --git a/bitbake/lib/layerindexlib/tests/testdata/layer3/conf/layer.conf b/bitbake/lib/layerindexlib/tests/testdata/layer3/conf/layer.conf deleted file mode 100644 index 7089071faf..0000000000 --- a/bitbake/lib/layerindexlib/tests/testdata/layer3/conf/layer.conf +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | # We might have a conf and classes directory, append to BBPATH | ||
| 2 | BBPATH .= ":${LAYERDIR}" | ||
| 3 | |||
| 4 | # We have recipes directories, add to BBFILES | ||
| 5 | BBFILES += "${LAYERDIR}/recipes*/*/*.bb ${LAYERDIR}/recipes*/*/*.bbappend" | ||
| 6 | |||
| 7 | BBFILE_COLLECTIONS += "meta-python" | ||
| 8 | BBFILE_PATTERN_meta-python := "^${LAYERDIR}/" | ||
| 9 | BBFILE_PRIORITY_meta-python = "7" | ||
| 10 | |||
| 11 | # This should only be incremented on significant changes that will | ||
| 12 | # cause compatibility issues with other layers | ||
| 13 | LAYERVERSION_meta-python = "1" | ||
| 14 | |||
| 15 | LAYERDEPENDS_meta-python = "core openembedded-layer" | ||
| 16 | |||
| 17 | LAYERSERIES_COMPAT_meta-python = "sumo" | ||
| 18 | |||
| 19 | LICENSE_PATH += "${LAYERDIR}/licenses" | ||
diff --git a/bitbake/lib/layerindexlib/tests/testdata/layer4/conf/layer.conf b/bitbake/lib/layerindexlib/tests/testdata/layer4/conf/layer.conf deleted file mode 100644 index 6649ee0208..0000000000 --- a/bitbake/lib/layerindexlib/tests/testdata/layer4/conf/layer.conf +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | # We have a conf and classes directory, append to BBPATH | ||
| 2 | BBPATH .= ":${LAYERDIR}" | ||
| 3 | |||
| 4 | # We have a recipes directory, add to BBFILES | ||
| 5 | BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend" | ||
| 6 | |||
| 7 | BBFILE_COLLECTIONS += "openembedded-layer" | ||
| 8 | BBFILE_PATTERN_openembedded-layer := "^${LAYERDIR}/" | ||
| 9 | |||
| 10 | # Define the priority for recipes (.bb files) from this layer, | ||
| 11 | # choosing carefully how this layer interacts with all of the | ||
| 12 | # other layers. | ||
| 13 | |||
| 14 | BBFILE_PRIORITY_openembedded-layer = "6" | ||
| 15 | |||
| 16 | # This should only be incremented on significant changes that will | ||
| 17 | # cause compatibility issues with other layers | ||
| 18 | LAYERVERSION_openembedded-layer = "1" | ||
| 19 | |||
| 20 | LAYERDEPENDS_openembedded-layer = "core" | ||
| 21 | |||
| 22 | LAYERSERIES_COMPAT_openembedded-layer = "sumo" | ||
