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