You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

160 lines
5.5 KiB

  1. """Command line client functionality"""
  2. import nilmdb.client
  3. from nilmdb.utils.printf import *
  4. from nilmdb.utils import datetime_tz
  5. import nilmdb.utils.time
  6. import sys
  7. import os
  8. import argparse
  9. from argparse import ArgumentDefaultsHelpFormatter as def_form
  10. try: # pragma: no cover
  11. import argcomplete
  12. except ImportError: # pragma: no cover
  13. argcomplete = None
  14. # Valid subcommands. Defined in separate files just to break
  15. # things up -- they're still called with Cmdline as self.
  16. subcommands = [ "help", "info", "create", "list", "metadata",
  17. "insert", "extract", "remove", "destroy",
  18. "intervals", "rename" ]
  19. # Import the subcommand modules
  20. subcmd_mods = {}
  21. for cmd in subcommands:
  22. subcmd_mods[cmd] = __import__("nilmdb.cmdline." + cmd, fromlist = [ cmd ])
  23. class JimArgumentParser(argparse.ArgumentParser):
  24. def error(self, message):
  25. self.print_usage(sys.stderr)
  26. self.exit(2, sprintf("error: %s\n", message))
  27. class Complete(object): # pragma: no cover
  28. # Completion helpers, for using argcomplete (see
  29. # extras/nilmtool-bash-completion.sh)
  30. def escape(self, s):
  31. quote_chars = [ "\\", "\"", "'", " " ]
  32. for char in quote_chars:
  33. s = s.replace(char, "\\" + char)
  34. return s
  35. def none(self, prefix, parsed_args, **kwargs):
  36. return []
  37. rate = none
  38. time = none
  39. url = none
  40. def path(self, prefix, parsed_args, **kwargs):
  41. client = nilmdb.client.Client(parsed_args.url)
  42. return ( self.escape(s[0])
  43. for s in client.stream_list()
  44. if s[0].startswith(prefix) )
  45. def layout(self, prefix, parsed_args, **kwargs):
  46. types = [ "int8", "int16", "int32", "int64",
  47. "uint8", "uint16", "uint32", "uint64",
  48. "float32", "float64" ]
  49. layouts = []
  50. for i in range(1,10):
  51. layouts.extend([(t + "_" + str(i)) for t in types])
  52. return ( l for l in layouts if l.startswith(prefix) )
  53. def meta_key(self, prefix, parsed_args, **kwargs):
  54. return (kv.split('=')[0] for kv
  55. in self.meta_keyval(prefix, parsed_args, **kwargs))
  56. def meta_keyval(self, prefix, parsed_args, **kwargs):
  57. client = nilmdb.client.Client(parsed_args.url)
  58. path = parsed_args.path
  59. if not path:
  60. return []
  61. return ( self.escape(k + '=' + v)
  62. for (k,v) in client.stream_get_metadata(path).iteritems()
  63. if k.startswith(prefix) )
  64. class Cmdline(object):
  65. def __init__(self, argv = None):
  66. self.argv = argv or sys.argv[1:]
  67. self.client = None
  68. self.def_url = os.environ.get("NILMDB_URL", "http://localhost:12380")
  69. self.subcmd = {}
  70. self.complete = Complete()
  71. def arg_time(self, toparse):
  72. """Parse a time string argument"""
  73. try:
  74. return nilmdb.utils.time.parse_time(toparse).totimestamp()
  75. except ValueError as e:
  76. raise argparse.ArgumentTypeError(sprintf("%s \"%s\"",
  77. str(e), toparse))
  78. # Set up the parser
  79. def parser_setup(self):
  80. self.parser = JimArgumentParser(add_help = False,
  81. formatter_class = def_form)
  82. group = self.parser.add_argument_group("General options")
  83. group.add_argument("-h", "--help", action='help',
  84. help='show this help message and exit')
  85. group.add_argument("-V", "--version", action="version",
  86. version = nilmdb.__version__)
  87. group = self.parser.add_argument_group("Server")
  88. group.add_argument("-u", "--url", action="store",
  89. default=self.def_url,
  90. help="NilmDB server URL (default: %(default)s)"
  91. ).completer = self.complete.url
  92. sub = self.parser.add_subparsers(
  93. title="Commands", dest="command",
  94. description="Use 'help command' or 'command --help' for more "
  95. "details on a particular command.")
  96. # Set up subcommands (defined in separate files)
  97. for cmd in subcommands:
  98. self.subcmd[cmd] = subcmd_mods[cmd].setup(self, sub)
  99. def die(self, formatstr, *args):
  100. fprintf(sys.stderr, formatstr + "\n", *args)
  101. if self.client:
  102. self.client.close()
  103. sys.exit(-1)
  104. def run(self):
  105. # Clear cached timezone, so that we can pick up timezone changes
  106. # while running this from the test suite.
  107. datetime_tz._localtz = None
  108. # Run parser
  109. self.parser_setup()
  110. if argcomplete: # pragma: no cover
  111. argcomplete.autocomplete(self.parser)
  112. self.args = self.parser.parse_args(self.argv)
  113. # Run arg verify handler if there is one
  114. if "verify" in self.args:
  115. self.args.verify(self)
  116. self.client = nilmdb.client.Client(self.args.url)
  117. # Make a test connection to make sure things work,
  118. # unless the particular command requests that we don't.
  119. if "no_test_connect" not in self.args:
  120. try:
  121. server_version = self.client.version()
  122. except nilmdb.client.Error as e:
  123. self.die("error connecting to server: %s", str(e))
  124. # Now dispatch client request to appropriate function. Parser
  125. # should have ensured that we don't have any unknown commands
  126. # here.
  127. retval = self.args.handler(self) or 0
  128. self.client.close()
  129. sys.exit(retval)