summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Grover <andy@groveronline.com>2013-09-12 10:32:57 -0700
committerAndy Grover <andy@groveronline.com>2013-09-12 10:32:57 -0700
commit93e0d3bfe99d019bf06f009f07cc219ea2a44731 (patch)
treed7d06700cd2498fc156665bc167ee9cc34a55c52
parentfb99f2cdbc91995d31a5eb3416e17b86c9285f14 (diff)
parentd9cbcd0419f62912a5925efdbf556bba603fbeb5 (diff)
downloadconfigshell-fb-93e0d3bfe99d019bf06f009f07cc219ea2a44731.tar.gz
Merge pull request #4 from cvubrugier/pyparsing-v2
Replace simpleparse with pyparsing
-rw-r--r--configshell/shell.py92
-rw-r--r--debian/control4
-rw-r--r--rpm/python-configshell.spec.tmpl4
3 files changed, 50 insertions, 50 deletions
diff --git a/configshell/shell.py b/configshell/shell.py
index a3fbbca..fb82f8d 100644
--- a/configshell/shell.py
+++ b/configshell/shell.py
@@ -17,8 +17,8 @@ under the License.
import os
import sys
-import simpleparse.parser
-import simpleparse.dispatchprocessor
+from pyparsing import Empty, Group, OneOrMore, Optional, ParseResults, Regex, Suppress, Word
+from pyparsing import alphanums
import configshell.log as log
import configshell.prefs as prefs
@@ -49,6 +49,12 @@ if sys.stdout.isatty():
else:
tty=False
+# Pyparsing helper to group the location of a token and its value
+# http://stackoverflow.com/questions/18706631/pyparsing-get-token-location-in-results-name
+locator = Empty().setParseAction(lambda s, l, t: l)
+def locatedExpr(expr):
+ return Group(locator('location') + expr('value'))
+
class ConfigShell(object):
'''
This is a simple CLI command interpreter that can be used both in
@@ -90,23 +96,6 @@ class ConfigShell(object):
_current_token = ''
_current_completions = []
complete_key = 'tab'
- grammar = \
- r'''
- <eol> := '\n'
- <space> := ' '+
- line := (linepath)/(space?, command), parameters?, eol?
- >linepath< := space?, path, space?, command?
- command := [a-zA-Z0-9_]+
- >parameters< := (space, kparam/pparam)+
- pparam := var
- kparam := keyword, '=', value
- >keyword< := [a-zA-Z0-9_\-]+
- >value< := var?
- path := bookmark/pathstd/[0-9]+/'..'/'.'/'*'
- <pathstd> := ([a-zA-Z0-9:_.-]*, '/', [a-zA-Z0-9:_./-]*, '*'?)
- <var> := [a-zA-Z0-9_\\+/.<>~@:-%]+
- <bookmark> := '@', var?
- '''
def __init__(self, preferences_dir=None):
'''
@@ -118,7 +107,21 @@ class ConfigShell(object):
self._root_node = None
self._exit = False
- self._parser = simpleparse.parser.Parser(self.grammar, root='line')
+ # Grammar of the command line
+ command = locatedExpr(Word(alphanums + '_'))('command')
+ var = Word(alphanums + '_\+/.<>()~@:-%]')
+ value = var
+ keyword = Word(alphanums + '_\-')
+ kparam = locatedExpr(keyword + Suppress('=') + Optional(value, default=''))('kparams*')
+ pparam = locatedExpr(var)('pparams*')
+ parameter = kparam | pparam
+ parameters = OneOrMore(parameter)
+ bookmark = Regex('@([A-Za-z0-9:_.]|-)+')
+ pathstd = Regex('([A-Za-z0-9:_.]|-)*' + '/' + '([A-Za-z0-9:_./]|-)*') \
+ | '..' | '.'
+ path = locatedExpr(bookmark | pathstd | '*')('path')
+ parser = Optional(path) + Optional(command) + Optional(parameters)
+ self._parser = parser
if tty:
readline.set_completer_delims('\t\n ~!#$^&()[{]}\|;\'",?')
@@ -676,7 +679,7 @@ class ConfigShell(object):
self._completion_help_topic = ''
self._current_parameter = ''
- (result_trees, path, command, pparams, kparams) = \
+ (parse_results, path, command, pparams, kparams) = \
self._parse_cmdline(cmdline)
beg = readline.get_begidx()
@@ -685,13 +688,17 @@ class ConfigShell(object):
# No text under the cursor, fake it so that the parser
# result_trees gives us a token name on a second parser call
self.log.debug("Faking text entry on commandline.")
- result_trees = self._parse_cmdline(cmdline + 'x')[0]
+ parse_results = self._parse_cmdline(cmdline + 'x')[0]
end += 1
- for tree in result_trees:
- if beg == tree[1] and end == tree[2]:
- current_token = tree[0]
- break
+ if path and beg == parse_results.path.location:
+ current_token = 'path'
+ elif command and beg == parse_results.command.location:
+ current_token = 'command'
+ elif pparams and beg in [p.location for p in parse_results.pparams]:
+ current_token = 'pparam'
+ elif kparams and beg in [k.location for k in parse_results.kparams]:
+ current_token = 'kparam'
self._current_completions = \
self._dispatch_completion(path, command,
@@ -825,41 +832,34 @@ class ConfigShell(object):
def _parse_cmdline(self, line):
'''
Parses the command line entered by the user. This is a wrapper around
- the actual simpleparse parsed that pre-chews the result trees to
+ the actual pyparsing parser that pre-chews the result trees to
cleanly extract the tokens we care for (parameters, path, command).
@param line: The command line to parse.
@type line: str
@return: (result_trees, path, command, pparams, kparams),
pparams being positional parameters and kparams the keyword=value.
- @rtype: (list of tuple, str, str, list, dict) For the exact
- result_trees tuple format, c.f. the simpleparse documentation.
+ @rtype: (pyparsing.ParseResults, str, str, list, dict)
'''
self.log.debug("Parsing commandline.")
path = ''
command = ''
pparams = []
kparams = {}
- (success, result_trees, next_character) = self._parser.parse(line)
- if success:
- self.log.debug(str(result_trees))
- for tree in result_trees:
- token = tree[0]
- value = line[tree[1]:tree[2]]
- self.log.debug("Found %s token %s." % (token, value))
- if token == 'path':
- path = value
- elif token == 'command':
- command = value
- elif token == 'pparam':
- pparams.append(value)
- elif token == 'kparam':
- (keyword, sep, value) = value.partition('=')
- kparams[keyword] = value
+
+ parse_results = self._parser.parseString(line)
+ if isinstance(parse_results.path, ParseResults):
+ path = parse_results.path.value
+ if isinstance(parse_results.command, ParseResults):
+ command = parse_results.command.value
+ if isinstance(parse_results.pparams, ParseResults):
+ pparams = [pparam.value for pparam in parse_results.pparams]
+ if isinstance(parse_results.kparams, ParseResults):
+ kparams = dict([kparam.value for kparam in parse_results.kparams])
self.log.debug("Parse gave path='%s' command='%s' " % (path, command)
+ "pparams=%s " % str(pparams)
+ "kparams=%s" % str(kparams))
- return (result_trees, path, command, pparams, kparams)
+ return (parse_results, path, command, pparams, kparams)
def _execute_command(self, path, command, pparams, kparams):
'''
diff --git a/debian/control b/debian/control
index af9ad15..05bb316 100644
--- a/debian/control
+++ b/debian/control
@@ -2,12 +2,12 @@ Source: configshell
Section: python
Priority: optional
Maintainer: Jerome Martin <jxm@risingtidesystems.com>
-Build-Depends: debhelper(>= 7.0.1), python2.6, python-epydoc, python-simpleparse
+Build-Depends: debhelper(>= 7.0.1), python2.6
Standards-Version: 3.8.1
Package: python-configshell
Architecture: all
-Depends: python (>= 2.6)|python2.6, python-epydoc, python-simpleparse, python-urwid (>=0.9.9)
+Depends: python (>= 2.6)|python2.6, python-epydoc, python-pyparsing, python-urwid (>=0.9.9)
Suggests: configshell-doc
Description: Framework to create CLI interfaces.
.
diff --git a/rpm/python-configshell.spec.tmpl b/rpm/python-configshell.spec.tmpl
index f44722c..ddd3942 100644
--- a/rpm/python-configshell.spec.tmpl
+++ b/rpm/python-configshell.spec.tmpl
@@ -10,8 +10,8 @@ URL: http://www.risingtidesystems.com/git/
Source: %{oname}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-rpmroot
BuildArch: noarch
-BuildRequires: python-devel, epydoc, python-simpleparse
-Requires: python-simpleparse, python-urwid >= 0.9.9, epydoc
+BuildRequires: python-devel
+Requires: pyparsing, python-urwid >= 0.9.9, epydoc
Vendor: Datera, Inc.
%description