blob: 15ec190c4ab113398246d7c7b371740389cd05bb [file] [log] [blame]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001# Copyright (C) 2016 Intel Corporation
2#
Brad Bishopc342db32019-05-15 21:57:59 -04003# SPDX-License-Identifier: MIT
Brad Bishop6e60e8b2018-02-01 10:27:11 -05004#
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
Brad Bishopd7bf8c12018-02-25 22:55:05 -050013from oe.lsb import get_os_release
Brad Bishop6e60e8b2018-02-01 10:27:11 -050014from oeqa.utils.commands import runCmd, get_bb_vars
15
Brad Bishop6e60e8b2018-02-01 10:27:11 -050016
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
Patrick Williams8e7b46e2023-05-01 14:19:06 -050030 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'))}
Brad Bishop6e60e8b2018-02-01 10:27:11 -050033
34 # Host distro information
35 os_release = get_os_release()
36 if os_release:
37 info_dict['host_distro'] = OrderedDict()
Brad Bishopd7bf8c12018-02-25 22:55:05 -050038 for key in ('ID', 'VERSION_ID', 'PRETTY_NAME'):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050039 if key in os_release:
Brad Bishopd7bf8c12018-02-25 22:55:05 -050040 info_dict['host_distro'][key.lower()] = os_release[key]
Brad Bishop6e60e8b2018-02-01 10:27:11 -050041
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"""
Brad Bishop6e60e8b2018-02-01 10:27:11 -050061 info = OrderedDict()
Brad Bishopf86d0552018-12-04 14:18:15 -080062
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
Brad Bishop19323692019-04-05 15:28:33 -040075 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
Brad Bishopf86d0552018-12-04 14:18:15 -080079 return info
Brad Bishop6e60e8b2018-02-01 10:27:11 -050080 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