1# Copyright (C) 2016 Intel Corporation 2# 3# SPDX-License-Identifier: MIT 4# 5# Functions to get metadata from the testing host used 6# for analytics of test results. 7 8from collections import OrderedDict 9from collections.abc import MutableMapping 10from xml.dom.minidom import parseString 11from xml.etree.ElementTree import Element, tostring 12 13from oe.lsb import get_os_release 14from oeqa.utils.commands import runCmd, get_bb_vars 15 16 17def metadata_from_bb(): 18 """ Returns test's metadata as OrderedDict. 19 20 Data will be gathered using bitbake -e thanks to get_bb_vars. 21 """ 22 metadata_config_vars = ('MACHINE', 'BB_NUMBER_THREADS', 'PARALLEL_MAKE') 23 24 info_dict = OrderedDict() 25 hostname = runCmd('hostname') 26 info_dict['hostname'] = hostname.output 27 data_dict = get_bb_vars() 28 29 # Distro information 30 info_dict['distro'] = {'id': data_dict.get('DISTRO', 'NODISTRO'), 31 'version_id': data_dict.get('DISTRO_VERSION', 'NO_DISTRO_VERSION'), 32 'pretty_name': '%s %s' % (data_dict.get('DISTRO', 'NODISTRO'), data_dict.get('DISTRO_VERSION', 'NO_DISTRO_VERSION'))} 33 34 # Host distro information 35 os_release = get_os_release() 36 if os_release: 37 info_dict['host_distro'] = OrderedDict() 38 for key in ('ID', 'VERSION_ID', 'PRETTY_NAME'): 39 if key in os_release: 40 info_dict['host_distro'][key.lower()] = os_release[key] 41 42 info_dict['layers'] = get_layers(data_dict['BBLAYERS']) 43 info_dict['bitbake'] = git_rev_info(os.path.dirname(bb.__file__)) 44 45 info_dict['config'] = OrderedDict() 46 for var in sorted(metadata_config_vars): 47 info_dict['config'][var] = data_dict[var] 48 return info_dict 49 50def metadata_from_data_store(d): 51 """ Returns test's metadata as OrderedDict. 52 53 Data will be collected from the provided data store. 54 """ 55 # TODO: Getting metadata from the data store would 56 # be useful when running within bitbake. 57 pass 58 59def git_rev_info(path): 60 """Get git revision information as a dict""" 61 info = OrderedDict() 62 63 try: 64 from git import Repo, InvalidGitRepositoryError, NoSuchPathError 65 except ImportError: 66 import subprocess 67 try: 68 info['branch'] = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=path).decode('utf-8').strip() 69 except subprocess.CalledProcessError: 70 pass 71 try: 72 info['commit'] = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=path).decode('utf-8').strip() 73 except subprocess.CalledProcessError: 74 pass 75 try: 76 info['commit_count'] = int(subprocess.check_output(["git", "rev-list", "--count", "HEAD"], cwd=path).decode('utf-8').strip()) 77 except subprocess.CalledProcessError: 78 pass 79 return info 80 try: 81 repo = Repo(path, search_parent_directories=True) 82 except (InvalidGitRepositoryError, NoSuchPathError): 83 return info 84 info['commit'] = repo.head.commit.hexsha 85 info['commit_count'] = repo.head.commit.count() 86 try: 87 info['branch'] = repo.active_branch.name 88 except TypeError: 89 info['branch'] = '(nobranch)' 90 return info 91 92def get_layers(layers): 93 """Returns layer information in dict format""" 94 layer_dict = OrderedDict() 95 for layer in layers.split(): 96 layer_name = os.path.basename(layer) 97 layer_dict[layer_name] = git_rev_info(layer) 98 return layer_dict 99 100def write_metadata_file(file_path, metadata): 101 """ Writes metadata to a XML file in directory. """ 102 103 xml = dict_to_XML('metadata', metadata) 104 xml_doc = parseString(tostring(xml).decode('UTF-8')) 105 with open(file_path, 'w') as f: 106 f.write(xml_doc.toprettyxml()) 107 108def dict_to_XML(tag, dictionary, **kwargs): 109 """ Return XML element converting dicts recursively. """ 110 111 elem = Element(tag, **kwargs) 112 for key, val in dictionary.items(): 113 if tag == 'layers': 114 child = (dict_to_XML('layer', val, name=key)) 115 elif isinstance(val, MutableMapping): 116 child = (dict_to_XML(key, val)) 117 else: 118 if tag == 'config': 119 child = Element('variable', name=key) 120 else: 121 child = Element(key) 122 child.text = str(val) 123 elem.append(child) 124 return elem 125