blob: 3ceffd4c03230ee21f7b943f60d9d8db55a2578f [file] [log] [blame]
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +08001# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +08004"""Common code for servo parsing support."""
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +08005
6import argparse
7import os
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +08008import textwrap
9
10if os.getuid():
11 DEFAULT_RC_FILE = '/home/%s/.servodrc' % os.getenv('USER', '')
12else:
13 DEFAULT_RC_FILE = '/home/%s/.servodrc' % os.getenv('SUDO_USER', '')
14
15
16class ServodParserHelpFormatter(argparse.RawDescriptionHelpFormatter,
17 argparse.ArgumentDefaultsHelpFormatter):
18 """Servod help formatter.
19
20 Combines ability for raw description printing (needed to have control over
21 how to print examples) and default argument printing, printing the default
22 which each argument.
23 """
24 pass
25
26
27class ServodParserError(Exception):
28 """Error class for Servod parsing errors."""
29 pass
30
31
32class _BaseServodParser(argparse.ArgumentParser):
33 """Extension to ArgumentParser that allows for examples in the description.
34
35 _BaseServodParser allows for a list of example tuples, where
36 element[0]: is the cmdline invocation
37 element[1]: is a comment to explain what the invocation does.
38
39 For example (loosely based on servod.)
40 ('-b board', 'Start servod with the configuation for board |board|')
41 would print the following help message:
42 ...
43
44 Examples:
45 > servod -b board
46 Start servod with the configuration for board |board|
47
48 Optional Arguments...
49
50 see servod, or dut_control for more examples.
51 """
52
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +080053 def __init__(self, description='', examples=None, **kwargs):
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +080054 """Initialize _BaseServodParser by setting description and formatter.
55
56 Args:
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +080057 description: description of the program
58 examples: list of tuples where the first element is the cmdline example,
59 and the second element is a comment explaining the example.
60 %(prog)s will be prepended to each example if it does not
61 start with %(prog)s.
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +080062 **kwargs: keyword arguments forwarded to ArgumentParser
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +080063 """
64 # Generate description.
65 description_lines = textwrap.wrap(description)
66 # Setting it into the kwargs here ensures that we overwrite an potentially
67 # passed in and undesired formatter class.
68 kwargs['formatter_class'] = ServodParserHelpFormatter
69 if examples:
70 # Extra newline to separate description from examples.
71 description_lines.append('\n')
72 description_lines.append('Examples:')
73 for example, comment in examples:
74 if not example.startswith('%(prog)s'):
75 example = '%(prog)s ' + example
76 example_lines = [' > ' + example]
77 example_lines.extend(textwrap.wrap(comment))
78 description_lines.append('\n\t'.join(example_lines))
79 description = '\n'.join(description_lines)
80 kwargs['description'] = description
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +080081 super(_BaseServodParser, self).__init__(**kwargs)
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +080082
83
84class BaseServodParser(_BaseServodParser):
85 """BaseServodParser handling common arguments in the servod cmdline tools."""
86
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +080087 def __init__(self, **kwargs):
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +080088 """Initialize by adding common arguments.
89
90 Adds:
91 - host/port arguments to find/initialize a servod instance
92 - debug argument to toggle debug message printing
93 - name/rcfile arguments to handle servodrc configurations
94
95 Args:
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +080096 **kwargs: keyword arguments forwarded to _BaseServodParser
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +080097 """
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +080098 super(BaseServodParser, self).__init__(**kwargs)
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +080099 self.add_argument('-d', '--debug', action='store_true', default=False,
100 help='enable debug messages')
101 self.add_argument('--host', default='localhost', type=str,
102 help='hostname of the servod server.')
103 self.add_argument('-p', '--port', default=None, type=int,
104 help='port of the servod server.')
105
106
107def add_servo_parsing_rc_options(parser):
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +0800108 """Add common options descriptors to the parser object.
109
110 Args:
111 parser: Argumentparser to append arguments to
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +0800112
113 Both servod and dut-control accept command line options for configuring
114 servo_parsing operation. This function configures the command line parser
115 object to accept those options.
116 """
117 parser.add_argument('--rcfile', type=str, default=DEFAULT_RC_FILE,
118 help='servo description file for multi-servo operation.')
119 parser.add_argument('-n', '--name', type=str,
120 help='symbolic name of the servo board, '
121 'used as a config shortcut, could also be supplied '
122 'through environment variable SERVOD_NAME')
123
124
125def parse_rc(logger, rc_file):
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +0800126 """Parse servodrc configuration file.
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +0800127
128 The format of the configuration file is described above in comments to
129 DEFAULT_RC_FILE. I the file is not found or is mis-formatted, a warning is
130 printed but the program tries to continue.
131
132 Args:
133 logger: a logging instance used by this servod driver
134 rc_file: a string, name of the file storing the configuration
135
136 Returns:
137 a dictionary, where keys are symbolic servo names, and values are
138 dictionaries representing servo parameters read from the config file,
139 keyed by strings 'sn' (for serial number), 'port', 'board', and 'model'.
140 """
141
142 rcd = {} # Dictionary representing the rc file contents.
143 if os.path.isfile(rc_file):
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +0800144 for rc_line in open(rc_file, 'r'):
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +0800145 line = rc_line.split('#')[0].strip()
146 if not line:
147 continue
148 elts = [x.strip() for x in line.split(',')]
149 name = elts[0]
150 if not name or len(elts) < 2 or [x for x in elts if ' ' in x]:
151 logger.info('ignoring rc line "%s"', rc_line.rstrip())
152 continue
153 rcd[name] = {'sn': elts[1], 'port': None, 'board': None, 'model': None}
154 if (len(elts) > 2):
155 rcd[name]['port'] = int(elts[2])
156 if len(elts) > 3:
157 rcd[name]['board'] = elts[3]
158 if len(elts) > 4:
159 rcd[name]['model'] = elts[4]
160 if len(elts) > 5:
161 logger.info('discarding %s for for %s', ' '.join(elts[5:]), name)
162 return rcd
163
164
165def get_env_options(logger, options):
Ruben Rodriguez Buchillon0902f092018-09-19 15:03:17 +0800166 """Look for non-defined options in the environment.
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +0800167
168 SERVOD_PORT and SERVOD_NAME environment variables can be used if --port
169 and --name command line switches are not set. Set the options values as
170 necessary.
171
172 Args:
173 logger: a logging instance used by this servod driver
174 options: the options object returned by opt_parse
175 """
176 if not options.port:
177 env_port = os.getenv('SERVOD_PORT')
178 if env_port:
179 try:
180 options.port = int(env_port)
181 except ValueError:
182 logger.warning('Ignoring environment port definition "%s"', env_port)
Raul E Rangel2e94ae22018-10-03 10:30:51 -0600183 if hasattr(options, 'name') and not options.name:
Ruben Rodriguez Buchillon63e38602018-09-19 10:36:58 +0800184 options.name = os.getenv('SERVOD_NAME')