"""Prints all histogram names."""
from __future__ import print_function
import argparse
import os
import re
import subprocess
import sys
import tempfile
import io
from typing import Iterable, Set
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common'))
import path_util
import xml_utils
import extract_histograms
import histogram_paths
import merge_xml
def get_names(xml_files):
"""Returns all histogram names generated from a list of xml files.
Args:
xml_files: A list of open file objects containing histogram definitions.
Returns:
The set of histogram names.
"""
doc = merge_xml.MergeFiles(files=xml_files)
histograms, had_errors = extract_histograms.ExtractHistogramsFromDom(doc)
if had_errors:
raise ValueError("Error parsing inputs.")
return set(extract_histograms.ExtractNames(histograms))
def get_names_from_contents(contents: Iterable[str]) -> Set[str]:
"""Returns all histogram names from the given contents.
This function is different from get_names() in that it does not make
additional checks against the given contents. Note: it currently doesn't
handle go/patterned-histogram names.
Args:
contents: An iterable of strings from the raw histograms xml file.
Returns:
The set of histogram names.
"""
contents_list = list(contents)
if not contents_list:
return set()
doc = merge_xml.MergeFiles(files=[io.StringIO('\n'.join(contents_list))])
xml_utils.NormalizeAllAttributeValues(doc)
histograms_tree = xml_utils.GetTagSubTree(doc, 'histograms', 2)
histogram_names = set()
for histogram in xml_utils.IterElementsWithTag(histograms_tree, 'histogram'):
histogram_names.add(histogram.getAttribute('name'))
return histogram_names
def histogram_xml_files():
return [open(f, encoding="utf-8") for f in histogram_paths.ALL_XMLS]
def get_histogram_diff(revision):
"""Returns the added / removed histogram names relative to git revision
Args:
revision: A git revision as described in
https://git-scm.com/docs/gitrevisions
Returns:
A tuple of (added names, removed names), where each entry is sorted in
ascending order.
"""
def get_file_at_revision(path):
"""Returns a file-like object containing |path|'s content at |revision|"""
obj = "%s:%s" % (revision, path)
contents = subprocess.check_output(
("git", "cat-file", "--textconv", obj)).decode()
return io.StringIO(contents)
prev_files = []
for p in histogram_paths.ALL_XMLS_RELATIVE:
try:
prev_files.append(get_file_at_revision(p))
except subprocess.CalledProcessError:
continue
current_histogram_names = get_names(histogram_xml_files())
prev_histogram_names = get_names(prev_files)
added_names = sorted(list(current_histogram_names - prev_histogram_names))
removed_names = sorted(list(prev_histogram_names - current_histogram_names))
return (added_names, removed_names)
def _print_diff_names(revision):
added_names, removed_names = get_histogram_diff(revision)
print("%d histograms added:" % len(added_names))
for name in added_names:
print(name)
print("%d histograms removed:" % len(removed_names))
for name in removed_names:
print(name)
def main(argv):
parser = argparse.ArgumentParser(description='Print histogram names.')
parser.add_argument('--diff',
type=str,
help='Git revision to diff against (e.g. HEAD~)')
args = parser.parse_args(argv[1:])
if args.diff is not None:
_print_diff_names(args.diff)
else:
name_set = get_names(histogram_xml_files())
for name in sorted(list(name_set)):
print(name)
if __name__ == '__main__':
main(sys.argv)