blob: 3e0c94c795c1830926c1d1cf9b1fdd01c57163e5 [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.
4"""Common code for servo_parsing operation support"""
5
6import argparse
7import os
8import sys
9import textwrap
10
11if os.getuid():
12 DEFAULT_RC_FILE = '/home/%s/.servodrc' % os.getenv('USER', '')
13else:
14 DEFAULT_RC_FILE = '/home/%s/.servodrc' % os.getenv('SUDO_USER', '')
15
16
17class ServodParserHelpFormatter(argparse.RawDescriptionHelpFormatter,
18 argparse.ArgumentDefaultsHelpFormatter):
19 """Servod help formatter.
20
21 Combines ability for raw description printing (needed to have control over
22 how to print examples) and default argument printing, printing the default
23 which each argument.
24 """
25 pass
26
27
28class ServodParserError(Exception):
29 """Error class for Servod parsing errors."""
30 pass
31
32
33class _BaseServodParser(argparse.ArgumentParser):
34 """Extension to ArgumentParser that allows for examples in the description.
35
36 _BaseServodParser allows for a list of example tuples, where
37 element[0]: is the cmdline invocation
38 element[1]: is a comment to explain what the invocation does.
39
40 For example (loosely based on servod.)
41 ('-b board', 'Start servod with the configuation for board |board|')
42 would print the following help message:
43 ...
44
45 Examples:
46 > servod -b board
47 Start servod with the configuration for board |board|
48
49 Optional Arguments...
50
51 see servod, or dut_control for more examples.
52 """
53
54 def __init__(self, description='', examples=None, *args, **kwargs):
55 """Initialize _BaseServodParser by setting description and formatter.
56
57 Args:
58 args: positional arguments forwarded to ArgumentParser
59 description: description of the program
60 examples: list of tuples where the first element is the cmdline example,
61 and the second element is a comment explaining the example.
62 %(prog)s will be prepended to each example if it does not
63 start with %(prog)s.
64 kwargs: keyword arguments forwarded to ArgumentParser
65 """
66 # Generate description.
67 description_lines = textwrap.wrap(description)
68 # Setting it into the kwargs here ensures that we overwrite an potentially
69 # passed in and undesired formatter class.
70 kwargs['formatter_class'] = ServodParserHelpFormatter
71 if examples:
72 # Extra newline to separate description from examples.
73 description_lines.append('\n')
74 description_lines.append('Examples:')
75 for example, comment in examples:
76 if not example.startswith('%(prog)s'):
77 example = '%(prog)s ' + example
78 example_lines = [' > ' + example]
79 example_lines.extend(textwrap.wrap(comment))
80 description_lines.append('\n\t'.join(example_lines))
81 description = '\n'.join(description_lines)
82 kwargs['description'] = description
83 super(_BaseServodParser, self).__init__(*args, **kwargs)
84
85
86class BaseServodParser(_BaseServodParser):
87 """BaseServodParser handling common arguments in the servod cmdline tools."""
88
89 def __init__(self, *args, **kwargs):
90 """Initialize by adding common arguments.
91
92 Adds:
93 - host/port arguments to find/initialize a servod instance
94 - debug argument to toggle debug message printing
95 - name/rcfile arguments to handle servodrc configurations
96
97 Args:
98 args: positional arguments forwarded to _BaseServodParser
99 kwargs: keyword arguments forwarded to _BaseServodParser
100 """
101 super(BaseServodParser, self).__init__(*args, **kwargs)
102 self.add_argument('-d', '--debug', action='store_true', default=False,
103 help='enable debug messages')
104 self.add_argument('--host', default='localhost', type=str,
105 help='hostname of the servod server.')
106 self.add_argument('-p', '--port', default=None, type=int,
107 help='port of the servod server.')
108
109
110def add_servo_parsing_rc_options(parser):
111 """Add common options descriptors to the parser object
112
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):
126 """Parse servodrc configuration file
127
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):
144 for rc_line in open(rc_file, 'r').readlines():
145 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):
166 """Look for non-defined options in the environment
167
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)
183 if not options.name:
184 options.name = os.getenv('SERVOD_NAME')