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