blob: b1d02a2c7ca385982e5ea7261bb27b0a46f4a883 [file] [log] [blame]
Imre Kis124f0e32021-02-12 18:03:24 +01001#!/usr/bin/env python3
2# Copyright (c) 2020-2021, Arm Limited. All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5
6"""
7This module wraps the c-picker functionality into a command line interface.
8"""
9
10import argparse
11import json
12import sys
13import yaml
14
15from c_picker import __version__ as CPICKER_VERSION
16from c_picker.picker import CPicker
17from c_picker.picker import __doc__ as c_picker_doc
18
19class CPickerRunner:
20 """ Command line wrapper for CPicker """
21
22 def __init__(self):
23 self.root = ""
24 self.args = []
25 self.options = []
26
27 self.parser = argparse.ArgumentParser(prog="c-picker", description=c_picker_doc)
28
29 self.parser.add_argument("--root", help="Root source directory")
30 self.parser.add_argument("--config", help="Configuration file (.json|.yml)", required=True)
31 self.parser.add_argument("--output", help="Output file")
32 self.parser.add_argument("--print-dependencies", help="Print dependencies",
33 action="store_true")
34 self.parser.add_argument("--version", action="version", version=CPICKER_VERSION)
35 self.parser.add_argument("--args", help="clang arguments", nargs=argparse.REMAINDER)
36
37 @staticmethod
38 def error(message):
39 """ Print error message to stderr """
40 print("c-picker error\n" + message, file=sys.stderr)
41
42 def generate_element_descriptors(self, elements):
43 """ Converts the structure of the config file to a list of ElementDescriptors """
44 element_descriptors = []
45
46 for element in elements:
47 file_name = self.root + element["file"]
48 element_name = element["name"] if "name" in element else None
49 element_type = CPicker.Type[element["type"]]
50 element_args = self.args + element.get("args", [])
51 element_options = [
52 CPicker.Option[opt]
53 for opt in self.options + element.get("options", [])]
54
55 descriptor = CPicker.ElementDescriptor(file_name, element_type, element_name)
56 descriptor.set_args(element_args)
57 descriptor.set_options(element_options)
58
59 element_descriptors.append(descriptor)
60
61 return element_descriptors
62
63 @staticmethod
64 def create_config(args):
65 """ Create a configuration object from the command line arguments and config files. """
66 try:
67 if args.config.endswith(".json"):
68 with open(args.config) as json_file:
69 return json.load(json_file)
70 elif args.config.endswith(".yml"):
71 with open(args.config) as yml_file:
72 return yaml.safe_load(yml_file)
73 else:
74 raise Exception("Invalid configuration file %s" % args.config)
75 except json.decoder.JSONDecodeError as exception:
76 raise Exception("Invalid JSON format: " + str(exception))
77 except yaml.YAMLError as exception:
78 raise Exception("Invalid YAML format: " + str(exception))
79 except FileNotFoundError as exception:
80 raise Exception("File not found: " + str(exception))
81
82 def main(self):
83 """ Runs CPicker configured by the command line arguments """
84 try:
85 args = self.parser.parse_args()
86 config = self.create_config(args)
87
88 output_fp = open(args.output, "w") if args.output else None
89
90 self.root = args.root + "/" if args.root else ""
91 self.args = args.args if args.args else [] + config.get("args", [])
92 self.options = config.get("options", [])
93
94 elements = self.generate_element_descriptors(config.get("elements", []))
95
96 c_picker = CPicker(output_fp, args.print_dependencies)
97 c_picker.process(elements)
98
99 if output_fp:
100 output_fp.close()
101
102 return 0
103 except KeyError as exception:
104 self.error("Key error: " + str(exception))
105 except Exception as exception: # pylint: disable=broad-except
106 self.error("Error: " + str(exception))
107
108 return 1
109
110def main():
111 """ Command line main function """
112 c_picker_runner = CPickerRunner()
113 result = c_picker_runner.main()
114 sys.exit(result)
115
116if __name__ == '__main__':
117 main()