# Copyright (C) 2016 Intel Corporation # # Released under the MIT license (see COPYING.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