|
- """Command line client functionality"""
-
- import nilmdb
- from nilmdb.utils.printf import *
- from nilmdb.utils import datetime_tz
-
- import sys
- import re
- import argparse
- from argparse import ArgumentDefaultsHelpFormatter as def_form
-
- version = "1.0"
-
- # Valid subcommands. Defined in separate files just to break
- # things up -- they're still called with Cmdline as self.
- subcommands = [ "info", "create", "list", "metadata", "insert", "extract",
- "remove", "destroy" ]
-
- # Import the subcommand modules. Equivalent way of doing this would be
- # from . import info as cmd_info
- subcmd_mods = {}
- for cmd in subcommands:
- subcmd_mods[cmd] = __import__("nilmdb.cmdline." + cmd, fromlist = [ cmd ])
-
- class JimArgumentParser(argparse.ArgumentParser):
- def error(self, message):
- self.print_usage(sys.stderr)
- self.exit(2, sprintf("error: %s\n", message))
-
- class Cmdline(object):
-
- def __init__(self, argv):
- self.argv = argv
- self.client = None
-
- def arg_time(self, toparse):
- """Parse a time string argument"""
- try:
- return self.parse_time(toparse).totimestamp()
- except ValueError as e:
- raise argparse.ArgumentTypeError(sprintf("%s \"%s\"",
- str(e), toparse))
-
- def parse_time(self, toparse):
- """
- Parse a free-form time string and return a datetime_tz object.
- If the string doesn't contain a timestamp, the current local
- timezone is assumed (e.g. from the TZ env var).
- """
- # If string isn't "now" and doesn't contain at least 4 digits,
- # consider it invalid. smartparse might otherwise accept
- # empty strings and strings with just separators.
- if toparse != "now" and len(re.findall(r"\d", toparse)) < 4:
- raise ValueError("not enough digits for a timestamp")
-
- # Try to just parse the time as given
- try:
- return datetime_tz.datetime_tz.smartparse(toparse)
- except ValueError:
- pass
-
- # Try to extract a substring in a condensed format that we expect
- # to see in a filename or header comment
- res = re.search(r"(^|[^\d])(" # non-numeric or SOL
- r"(199\d|2\d\d\d)" # year
- r"[-/]?" # separator
- r"(0[1-9]|1[012])" # month
- r"[-/]?" # separator
- r"([012]\d|3[01])" # day
- r"[-T ]?" # separator
- r"([01]\d|2[0-3])" # hour
- r"[:]?" # separator
- r"([0-5]\d)" # minute
- r"[:]?" # separator
- r"([0-5]\d)?" # second
- r"([-+]\d\d\d\d)?" # timezone
- r")", toparse)
- if res is not None:
- try:
- return datetime_tz.datetime_tz.smartparse(res.group(2))
- except ValueError:
- pass
-
- # Could also try to successively parse substrings, but let's
- # just give up for now.
- raise ValueError("unable to parse timestamp")
-
- def time_string(self, timestamp):
- """
- Convert a Unix timestamp to a string for printing, using the
- local timezone for display (e.g. from the TZ env var).
- """
- dt = datetime_tz.datetime_tz.fromtimestamp(timestamp)
- return dt.strftime("%a, %d %b %Y %H:%M:%S.%f %z")
-
- def parser_setup(self):
- version_string = sprintf("nilmtool %s, client library %s",
- version, nilmdb.Client.client_version)
-
- self.parser = JimArgumentParser(add_help = False,
- formatter_class = def_form)
-
- group = self.parser.add_argument_group("General options")
- group.add_argument("-h", "--help", action='help',
- help='show this help message and exit')
- group.add_argument("-V", "--version", action="version",
- version=version_string)
-
- group = self.parser.add_argument_group("Server")
- group.add_argument("-u", "--url", action="store",
- default="http://localhost:12380/",
- help="NilmDB server URL (default: %(default)s)")
-
- sub = self.parser.add_subparsers(title="Commands",
- dest="command",
- description="Specify --help after "
- "the command for command-specific "
- "options.")
-
- # Set up subcommands (defined in separate files)
- for cmd in subcommands:
- subcmd_mods[cmd].setup(self, sub)
-
- def die(self, formatstr, *args):
- fprintf(sys.stderr, formatstr + "\n", *args)
- if self.client:
- self.client.close()
- sys.exit(-1)
-
- def run(self):
- # Clear cached timezone, so that we can pick up timezone changes
- # while running this from the test suite.
- datetime_tz._localtz = None
-
- # Run parser
- self.parser_setup()
- self.args = self.parser.parse_args(self.argv)
-
- # Run arg verify handler if there is one
- if "verify" in self.args:
- self.args.verify(self)
-
- self.client = nilmdb.Client(self.args.url)
-
- # Make a test connection to make sure things work
- try:
- server_version = self.client.version()
- except nilmdb.client.Error as e:
- self.die("error connecting to server: %s", str(e))
-
- # Now dispatch client request to appropriate function. Parser
- # should have ensured that we don't have any unknown commands
- # here.
- retval = self.args.handler(self) or 0
-
- self.client.close()
- sys.exit(retval)
|