| # Copyright (C) 2016 Intel Corporation |
| # |
| # SPDX-License-Identifier: MIT |
| # |
| # Functions to get metadata from the testing host used |
| # for analytics of test results. |
| |
| from collections import OrderedDict |
| from collections.abc import MutableMapping |
| from xml.dom.minidom import parseString |
| from xml.etree.ElementTree import Element, tostring |
| |
| from oe.lsb import get_os_release |
| from oeqa.utils.commands import runCmd, get_bb_vars |
| |
| |
| def metadata_from_bb(): |
| """ Returns test's metadata as OrderedDict. |
| |
| Data will be gathered using bitbake -e thanks to get_bb_vars. |
| """ |
| metadata_config_vars = ('MACHINE', 'BB_NUMBER_THREADS', 'PARALLEL_MAKE') |
| |
| info_dict = OrderedDict() |
| hostname = runCmd('hostname') |
| info_dict['hostname'] = hostname.output |
| data_dict = get_bb_vars() |
| |
| # Distro information |
| info_dict['distro'] = {'id': data_dict['DISTRO'], |
| 'version_id': data_dict['DISTRO_VERSION'], |
| 'pretty_name': '%s %s' % (data_dict['DISTRO'], data_dict['DISTRO_VERSION'])} |
| |
| # Host distro information |
| os_release = get_os_release() |
| if os_release: |
| info_dict['host_distro'] = OrderedDict() |
| for key in ('ID', 'VERSION_ID', 'PRETTY_NAME'): |
| if key in os_release: |
| info_dict['host_distro'][key.lower()] = os_release[key] |
| |
| info_dict['layers'] = get_layers(data_dict['BBLAYERS']) |
| info_dict['bitbake'] = git_rev_info(os.path.dirname(bb.__file__)) |
| |
| info_dict['config'] = OrderedDict() |
| for var in sorted(metadata_config_vars): |
| info_dict['config'][var] = data_dict[var] |
| return info_dict |
| |
| def metadata_from_data_store(d): |
| """ Returns test's metadata as OrderedDict. |
| |
| Data will be collected from the provided data store. |
| """ |
| # TODO: Getting metadata from the data store would |
| # be useful when running within bitbake. |
| pass |
| |
| def git_rev_info(path): |
| """Get git revision information as a dict""" |
| info = OrderedDict() |
| |
| try: |
| from git import Repo, InvalidGitRepositoryError, NoSuchPathError |
| except ImportError: |
| import subprocess |
| try: |
| info['branch'] = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=path).decode('utf-8').strip() |
| except subprocess.CalledProcessError: |
| pass |
| try: |
| info['commit'] = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=path).decode('utf-8').strip() |
| except subprocess.CalledProcessError: |
| pass |
| try: |
| info['commit_count'] = int(subprocess.check_output(["git", "rev-list", "--count", "HEAD"], cwd=path).decode('utf-8').strip()) |
| except subprocess.CalledProcessError: |
| pass |
| return info |
| try: |
| repo = Repo(path, search_parent_directories=True) |
| except (InvalidGitRepositoryError, NoSuchPathError): |
| return info |
| info['commit'] = repo.head.commit.hexsha |
| info['commit_count'] = repo.head.commit.count() |
| try: |
| info['branch'] = repo.active_branch.name |
| except TypeError: |
| info['branch'] = '(nobranch)' |
| return info |
| |
| def get_layers(layers): |
| """Returns layer information in dict format""" |
| layer_dict = OrderedDict() |
| for layer in layers.split(): |
| layer_name = os.path.basename(layer) |
| layer_dict[layer_name] = git_rev_info(layer) |
| return layer_dict |
| |
| def write_metadata_file(file_path, metadata): |
| """ Writes metadata to a XML file in directory. """ |
| |
| xml = dict_to_XML('metadata', metadata) |
| xml_doc = parseString(tostring(xml).decode('UTF-8')) |
| with open(file_path, 'w') as f: |
| f.write(xml_doc.toprettyxml()) |
| |
| def dict_to_XML(tag, dictionary, **kwargs): |
| """ Return XML element converting dicts recursively. """ |
| |
| elem = Element(tag, **kwargs) |
| for key, val in dictionary.items(): |
| if tag == 'layers': |
| child = (dict_to_XML('layer', val, name=key)) |
| elif isinstance(val, MutableMapping): |
| child = (dict_to_XML(key, val)) |
| else: |
| if tag == 'config': |
| child = Element('variable', name=key) |
| else: |
| child = Element(key) |
| child.text = str(val) |
| elem.append(child) |
| return elem |