blob: 830bbd405b3833fee0f72cc0eaed658ab455eae8 [file] [log] [blame]
# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Common code for servo parsing support."""
import argparse
import os
import textwrap
if os.getuid():
DEFAULT_RC_FILE = '/home/%s/.servodrc' % os.getenv('USER', '')
DEFAULT_RC_FILE = '/home/%s/.servodrc' % os.getenv('SUDO_USER', '')
class ServodParserHelpFormatter(argparse.RawDescriptionHelpFormatter,
"""Servod help formatter.
Combines ability for raw description printing (needed to have control over
how to print examples) and default argument printing, printing the default
which each argument.
class ServodParserError(Exception):
"""Error class for Servod parsing errors."""
class _BaseServodParser(argparse.ArgumentParser):
"""Extension to ArgumentParser that allows for examples in the description.
_BaseServodParser allows for a list of example tuples, where
element[0]: is the cmdline invocation
element[1]: is a comment to explain what the invocation does.
For example (loosely based on servod.)
('-b board', 'Start servod with the configuation for board |board|')
would print the following help message:
> servod -b board
Start servod with the configuration for board |board|
Optional Arguments...
see servod, or dut_control for more examples.
def __init__(self, description='', examples=None, **kwargs):
"""Initialize _BaseServodParser by setting description and formatter.
description: description of the program
examples: list of tuples where the first element is the cmdline example,
and the second element is a comment explaining the example.
%(prog)s will be prepended to each example if it does not
start with %(prog)s.
**kwargs: keyword arguments forwarded to ArgumentParser
# Generate description.
description_lines = textwrap.wrap(description)
# Setting it into the kwargs here ensures that we overwrite an potentially
# passed in and undesired formatter class.
kwargs['formatter_class'] = ServodParserHelpFormatter
if examples:
# Extra newline to separate description from examples.
for example, comment in examples:
if not example.startswith('%(prog)s'):
example = '%(prog)s ' + example
example_lines = [' > ' + example]
description = '\n'.join(description_lines)
kwargs['description'] = description
super(_BaseServodParser, self).__init__(**kwargs)
class BaseServodParser(_BaseServodParser):
"""BaseServodParser handling common arguments in the servod cmdline tools."""
def __init__(self, **kwargs):
"""Initialize by adding common arguments.
- host/port arguments to find/initialize a servod instance
- debug argument to toggle debug message printing
- name/rcfile arguments to handle servodrc configurations
**kwargs: keyword arguments forwarded to _BaseServodParser
super(BaseServodParser, self).__init__(**kwargs)
self.add_argument('-d', '--debug', action='store_true', default=False,
help='enable debug messages')
self.add_argument('--host', default='localhost', type=str,
help='hostname of the servod server.')
self.add_argument('-p', '--port', default=None, type=int,
help='port of the servod server.')
def add_servo_parsing_rc_options(parser):
"""Add common options descriptors to the parser object.
parser: Argumentparser to append arguments to
Both servod and dut-control accept command line options for configuring
servo_parsing operation. This function configures the command line parser
object to accept those options.
parser.add_argument('--rcfile', type=str, default=DEFAULT_RC_FILE,
help='servo description file for multi-servo operation.')
parser.add_argument('-n', '--name', type=str,
help='symbolic name of the servo board, '
'used as a config shortcut, could also be supplied '
'through environment variable SERVOD_NAME')
def parse_rc(logger, rc_file):
"""Parse servodrc configuration file.
The format of the configuration file is described above in comments to
DEFAULT_RC_FILE. I the file is not found or is mis-formatted, a warning is
printed but the program tries to continue.
logger: a logging instance used by this servod driver
rc_file: a string, name of the file storing the configuration
a dictionary, where keys are symbolic servo names, and values are
dictionaries representing servo parameters read from the config file,
keyed by strings 'sn' (for serial number), 'port', 'board', and 'model'.
rcd = {} # Dictionary representing the rc file contents.
if os.path.isfile(rc_file):
for rc_line in open(rc_file, 'r'):
line = rc_line.split('#')[0].strip()
if not line:
elts = [x.strip() for x in line.split(',')]
name = elts[0]
if not name or len(elts) < 2 or [x for x in elts if ' ' in x]:'ignoring rc line "%s"', rc_line.rstrip())
rcd[name] = {'sn': elts[1], 'port': None, 'board': None, 'model': None}
if (len(elts) > 2):
rcd[name]['port'] = int(elts[2])
if len(elts) > 3:
rcd[name]['board'] = elts[3]
if len(elts) > 4:
rcd[name]['model'] = elts[4]
if len(elts) > 5:'discarding %s for for %s', ' '.join(elts[5:]), name)
return rcd
def get_env_options(logger, options):
"""Look for non-defined options in the environment.
SERVOD_PORT and SERVOD_NAME environment variables can be used if --port
and --name command line switches are not set. Set the options values as
logger: a logging instance used by this servod driver
options: the options object returned by opt_parse
if not options.port:
env_port = os.getenv('SERVOD_PORT')
if env_port:
options.port = int(env_port)
except ValueError:
logger.warning('Ignoring environment port definition "%s"', env_port)
if not = os.getenv('SERVOD_NAME')