From d503b1f9220dd7d844fbb0a9ff195f55b465feb4 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Wed, 2 Dec 2015 17:25:30 -0800 Subject: [PATCH] describe-tests: add options for json or csv output For simple consumption, use objects with fields in the json output, and list the headers separately in case the original order is useful. Signed-off-by: Josh Durgin --- scripts/describe_tests.py | 1 + teuthology/describe_tests.py | 81 ++++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/scripts/describe_tests.py b/scripts/describe_tests.py index 09924353f0..8f1777445b 100644 --- a/scripts/describe_tests.py +++ b/scripts/describe_tests.py @@ -31,6 +31,7 @@ optional arguments: include [default: desc] --show-facet [yes|no] List the facet of each file [default: yes] + --format [plain|json|csv] Output format (written to stdout) options only for describing combinations represented by a suite: -c, --combinations Describe test combinations rather than diff --git a/teuthology/describe_tests.py b/teuthology/describe_tests.py index afbaceaf91..ff18e118f5 100644 --- a/teuthology/describe_tests.py +++ b/teuthology/describe_tests.py @@ -1,7 +1,10 @@ # -*- coding: utf-8 -*- +import csv +import json from prettytable import PrettyTable, FRAME, ALL import os +import sys import yaml from teuthology.exceptions import ParseError @@ -11,6 +14,7 @@ def main(args): suite_dir = os.path.abspath(args[""]) fields = args["--fields"].split(',') include_facet = args['--show-facet'] == 'yes' + output_format = args['--format'] if args['--combinations']: limit = int(args['--limit']) @@ -23,11 +27,33 @@ def main(args): subset = None if args['--subset']: subset = map(int, args['--subset'].split('/')) - describe_combinations(suite_dir, fields, subset, - limit, filter_in, filter_out, - include_facet) + headers, rows = get_combinations(suite_dir, fields, subset, + limit, filter_in, + filter_out, include_facet) + hrule = ALL else: - describe_suite(suite_dir, fields, include_facet) + headers, rows = describe_suite(suite_dir, fields, include_facet, + output_format) + hrule = FRAME + + output_results(headers, rows, output_format, hrule) + +def output_results(headers, rows, output_format, hrule): + if output_format == 'json': + objects = [{k: v for k, v in zip(headers, row) if v} + for row in rows] + print(json.dumps(dict(headers=headers, data=objects))) + elif output_format == 'csv': + writer = csv.writer(sys.stdout) + writer.writerows([headers] + rows) + else: + table = PrettyTable(headers) + table.align = 'l' + table.vrules = ALL + table.hrules = hrule + for row in rows: + table.add_row(row) + print(table) def get_combinations(suite_dir, fields, subset, limit, filter_in, filter_out, @@ -106,43 +132,17 @@ def get_combinations(suite_dir, fields, subset, return headers, sorted([[row.get(field, '') for field in headers] for row in rows]) -def describe_combinations(suite_dir, fields, subset, - limit, filter_in, filter_out, - include_facet): - headers, rows = get_combinations(suite_dir, fields, subset, - limit, filter_in, filter_out, - include_facet) - - table = PrettyTable(headers) - table.align = 'l' - table.vrules = ALL - table.hrules = ALL - - for row in rows: - table.add_row(row) - - print(table) - -def describe_suite(suite_dir, fields, include_facet): +def describe_suite(suite_dir, fields, include_facet, output_format): try: - rows = tree_with_info(suite_dir, fields, include_facet, '', []) + rows = tree_with_info(suite_dir, fields, include_facet, '', [], + output_format=output_format) except ParseError: return 1 headers = ['path'] if include_facet: headers.append('facet') - - table = PrettyTable(headers + fields) - table.align = 'l' - table.vrules = ALL - table.hrules = FRAME - - for row in rows: - table.add_row(row) - - print(suite_dir) - print(table) + return headers + fields, rows def extract_info(file_name, fields, _isdir=os.path.isdir, _open=open): empty_result = {f: '' for f in fields} @@ -166,9 +166,16 @@ def extract_info(file_name, fields, _isdir=os.path.isdir, _open=open): return {field: description[0].get(field, '') for field in fields} +def path_relative_to_suites(path): + try: + root = os.path.join('ceph-qa-suite', 'suites') + return path[path.index(root) + len(root):] + except ValueError: + return path + def tree_with_info(cur_dir, fields, include_facet, prefix, rows, _listdir=os.listdir, _isdir=os.path.isdir, - _open=open): + _open=open, output_format='plain'): files = sorted(_listdir(cur_dir)) has_yamls = any([x.endswith('.yaml') for x in files]) facet = os.path.basename(cur_dir) if has_yamls else '' @@ -182,6 +189,8 @@ def tree_with_info(cur_dir, fields, include_facet, prefix, rows, dir_pad = '│ ' info = extract_info(path, fields, _isdir, _open) tree_node = prefix + file_pad + f + if output_format != 'plain': + tree_node = path_relative_to_suites(path) meta = [info[f] for f in fields] row = [tree_node] if include_facet: @@ -190,5 +199,5 @@ def tree_with_info(cur_dir, fields, include_facet, prefix, rows, if _isdir(path): tree_with_info(path, fields, include_facet, prefix + dir_pad, rows, - _listdir, _isdir, _open) + _listdir, _isdir, _open, output_format) return rows -- 2.39.5