Soft Patch Panel
 help / color / mirror / Atom feed
From: ogawa.yasufumi@lab.ntt.co.jp
To: ferruh.yigit@intel.com, spp@dpdk.org
Cc: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
Subject: [spp] [PATCH 07/13] controller: refactor shell.py
Date: Tue,  6 Mar 2018 19:50:49 +0900	[thread overview]
Message-ID: <20180306105055.65210-8-ogawa.yasufumi@lab.ntt.co.jp> (raw)
In-Reply-To: <20180306105055.65210-1-ogawa.yasufumi@lab.ntt.co.jp>

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

Change loading command plugin from usign setattr() to directly assigning
it to Shell class. It is because Shell object provides completion and
showing help only for class methods and does not for methods added with
setattr() mehtod.

This update also includes misc refactoring of whole of shell.py.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/controller/command/hello.py |   2 +-
 src/controller/shell.py         | 246 +++++++++++++++++++++++-----------------
 2 files changed, 141 insertions(+), 107 deletions(-)

diff --git a/src/controller/command/hello.py b/src/controller/command/hello.py
index f898234..e3d974b 100644
--- a/src/controller/command/hello.py
+++ b/src/controller/command/hello.py
@@ -10,7 +10,7 @@ class Hello(object):
         print("Hello, %s!" % self.name)
 
 
-def do_hello(name):
+def do_hello(self, name):
     """Say hello to given user
 
     spp > hello alice
diff --git a/src/controller/shell.py b/src/controller/shell.py
index 3cb5f96..c5ef82d 100644
--- a/src/controller/shell.py
+++ b/src/controller/shell.py
@@ -28,6 +28,8 @@ class Shell(cmd.Cmd, object):
     SEC_SUBCMDS = ['vhost', 'ring', 'pcap', 'nullpmd']
     BYE_CMDS = ['sec', 'all']
 
+    PLUGIN_DIR = 'command'
+
     def default(self, line):
         """Define defualt behaviour
 
@@ -159,18 +161,6 @@ class Shell(cmd.Cmd, object):
 
         return valid
 
-    def complete_pri(self, text, line, begidx, endidx):
-        """Completion for primary process commands"""
-
-        if not text:
-            completions = self.PRI_CMDS[:]
-        else:
-            completions = [p
-                           for p in self.PRI_CMDS
-                           if p.startswith(text)
-                           ]
-        return completions
-
     def clean_sec_cmd(self, cmdstr):
         """remove unwanted spaces to avoid invalid command error"""
 
@@ -178,64 +168,6 @@ class Shell(cmd.Cmd, object):
         res = re.sub(r'\s?;\s?', ";", tmparg)
         return res
 
-    def complete_sec(self, text, line, begidx, endidx):
-        """Completion for secondary process commands"""
-
-        try:
-            cleaned_line = self.clean_sec_cmd(line)
-            if len(cleaned_line.split()) == 1:
-                completions = [str(i)+";" for i in spp_common.SECONDARY_LIST]
-            elif len(cleaned_line.split()) == 2:
-                if not (";" in cleaned_line):
-                    tmplist = [str(i) for i in spp_common.SECONDARY_LIST]
-                    completions = [p+";"
-                                   for p in tmplist
-                                   if p.startswith(text)
-                                   ]
-                elif cleaned_line[-1] == ";":
-                    completions = self.SEC_CMDS[:]
-                else:
-                    seccmd = cleaned_line.split(";")[1]
-                    if cleaned_line[-1] != " ":
-                        completions = [p
-                                       for p in self.SEC_CMDS
-                                       if p.startswith(seccmd)
-                                       ]
-                    elif ("add" in seccmd) or ("del" in seccmd):
-                        completions = self.SEC_SUBCMDS[:]
-                    else:
-                        completions = []
-            elif len(cleaned_line.split()) == 3:
-                subcmd = cleaned_line.split()[-1]
-                if ("add" == subcmd) or ("del" == subcmd):
-                    completions = self.SEC_SUBCMDS[:]
-                else:
-                    if cleaned_line[-1] == " ":
-                        completions = []
-                    else:
-                        completions = [p
-                                       for p in self.SEC_SUBCMDS
-                                       if p.startswith(subcmd)
-                                       ]
-            else:
-                completions = []
-            return completions
-        except Exception as e:
-            print(len(cleaned_line.split()))
-            print(e)
-
-    def complete_bye(self, text, line, begidx, endidx):
-        """Completion for bye commands"""
-
-        if not text:
-            completions = self.BYE_CMDS[:]
-        else:
-            completions = [p
-                           for p in self.BYE_CMDS
-                           if p.startswith(text)
-                           ]
-        return completions
-
     def response(self, result, message):
         """Enqueue message from other than CLI"""
 
@@ -251,6 +183,28 @@ class Shell(cmd.Cmd, object):
             if logger is not None:
                 logger.debug("unknown remote command = %s" % rcmd)
 
+    def precmd(self, line):
+        """Called before running a command
+
+        It is called for checking a contents of command line.
+        """
+
+        if self.recorded_file:
+            if not (
+                    ('playback' in line) or
+                    ('bye' in line) or
+                    ('exit' in line)):
+                self.recorded_file.write("%s\n" % line)
+        return line
+
+    def close(self):
+        """Close record file"""
+
+        if self.recorded_file:
+            print("closing file")
+            self.recorded_file.close()
+            self.recorded_file = None
+
     def do_status(self, _):
         """Display status info of SPP processes
 
@@ -278,6 +232,18 @@ class Shell(cmd.Cmd, object):
             print(message)
             self.response(self.CMD_ERROR, message)
 
+    def complete_pri(self, text, line, begidx, endidx):
+        """Completion for primary process commands"""
+
+        if not text:
+            completions = self.PRI_CMDS[:]
+        else:
+            completions = [p
+                           for p in self.PRI_CMDS
+                           if p.startswith(text)
+                           ]
+        return completions
+
     def do_sec(self, arg):
         """Send command to secondary process
 
@@ -310,8 +276,51 @@ class Shell(cmd.Cmd, object):
             print ("first %s" % cmds[1])
             self.response(self.CMD_ERROR, "invalid format")
 
-    def complete_record(self, text, line, begidx, endidx):
-        return common.compl_common(text, line)
+    def complete_sec(self, text, line, begidx, endidx):
+        """Completion for secondary process commands"""
+
+        try:
+            cleaned_line = self.clean_sec_cmd(line)
+            if len(cleaned_line.split()) == 1:
+                completions = [str(i)+";" for i in spp_common.SECONDARY_LIST]
+            elif len(cleaned_line.split()) == 2:
+                if not (";" in cleaned_line):
+                    tmplist = [str(i) for i in spp_common.SECONDARY_LIST]
+                    completions = [p+";"
+                                   for p in tmplist
+                                   if p.startswith(text)
+                                   ]
+                elif cleaned_line[-1] == ";":
+                    completions = self.SEC_CMDS[:]
+                else:
+                    seccmd = cleaned_line.split(";")[1]
+                    if cleaned_line[-1] != " ":
+                        completions = [p
+                                       for p in self.SEC_CMDS
+                                       if p.startswith(seccmd)
+                                       ]
+                    elif ("add" in seccmd) or ("del" in seccmd):
+                        completions = self.SEC_SUBCMDS[:]
+                    else:
+                        completions = []
+            elif len(cleaned_line.split()) == 3:
+                subcmd = cleaned_line.split()[-1]
+                if ("add" == subcmd) or ("del" == subcmd):
+                    completions = self.SEC_SUBCMDS[:]
+                else:
+                    if cleaned_line[-1] == " ":
+                        completions = []
+                    else:
+                        completions = [p
+                                       for p in self.SEC_SUBCMDS
+                                       if p.startswith(subcmd)
+                                       ]
+            else:
+                completions = []
+            return completions
+        except Exception as e:
+            print(len(cleaned_line.split()))
+            print(e)
 
     def do_record(self, fname):
         """Save commands to a log file
@@ -330,7 +339,7 @@ class Shell(cmd.Cmd, object):
             self.recorded_file = open(fname, 'w')
             self.response(self.CMD_OK, "record")
 
-    def complete_playback(self, text, line, begidx, endidx):
+    def complete_record(self, text, line, begidx, endidx):
         return common.compl_common(text, line)
 
     def do_playback(self, fname):
@@ -360,27 +369,8 @@ class Shell(cmd.Cmd, object):
                 print(message)
                 self.response(self.CMD_NG, message)
 
-    def precmd(self, line):
-        """Called before running a command
-
-        It is called for checking a contents of command line.
-        """
-
-        if self.recorded_file:
-            if not (
-                    ('playback' in line) or
-                    ('bye' in line) or
-                    ('exit' in line)):
-                self.recorded_file.write("%s\n" % line)
-        return line
-
-    def close(self):
-        """Close record file"""
-
-        if self.recorded_file:
-            print("closing file")
-            self.recorded_file.close()
-            self.recorded_file = None
+    def complete_playback(self, text, line, begidx, endidx):
+        return common.compl_common(text, line)
 
     def do_pwd(self, args):
         """Show corrent directory
@@ -392,9 +382,6 @@ class Shell(cmd.Cmd, object):
 
         print(os.getcwd())
 
-    def complete_ls(self, text, line, begidx, endidx):
-        return common.compl_common(text, line)
-
     def do_ls(self, args):
         """Show a list of specified directory
 
@@ -409,8 +396,8 @@ class Shell(cmd.Cmd, object):
         else:
             print("No such a directory.")
 
-    def complete_cd(self, text, line, begidx, endidx):
-        return common.compl_common(text, line, 'directory')
+    def complete_ls(self, text, line, begidx, endidx):
+        return common.compl_common(text, line)
 
     def do_cd(self, args):
         """Change current directory
@@ -424,8 +411,8 @@ class Shell(cmd.Cmd, object):
         else:
             print("No such a directory.")
 
-    def complete_mkdir(self, text, line, begidx, endidx):
-        return common.compl_common(text, line)
+    def complete_cd(self, text, line, begidx, endidx):
+        return common.compl_common(text, line, 'directory')
 
     def do_mkdir(self, args):
         """Create a new directory
@@ -438,6 +425,9 @@ class Shell(cmd.Cmd, object):
         c = 'mkdir -p %s' % args
         subprocess.call(c, shell=True)
 
+    def complete_mkdir(self, text, line, begidx, endidx):
+        return common.compl_common(text, line)
+
     def do_bye(self, arg):
         """Terminate SPP processes and controller
 
@@ -464,6 +454,18 @@ class Shell(cmd.Cmd, object):
             self.close()
             return True
 
+    def complete_bye(self, text, line, begidx, endidx):
+        """Completion for bye commands"""
+
+        if not text:
+            completions = self.BYE_CMDS[:]
+        else:
+            completions = [p
+                           for p in self.BYE_CMDS
+                           if p.startswith(text)
+                           ]
+        return completions
+
     def do_exit(self, args):
         """Terminate SPP controller
 
@@ -475,7 +477,13 @@ class Shell(cmd.Cmd, object):
         print('Thank you for using Soft Patch Panel')
         return True
 
-    def do_load(self, args):
+    def do_inspect(self, args):
+        from pprint import pprint
+        if args == '':
+            pprint(vars(self))
+            pprint(self.__class__.__name__)
+
+    def do_load_cmd(self, args):
         """Load command plugin
 
         Path of plugin file is 'spp/src/controller/command'.
@@ -488,9 +496,35 @@ class Shell(cmd.Cmd, object):
         list_args = args.split(' ')
 
         libdir = 'command'
-        loaded = '%s.%s' % (libdir, list_args[0])
-        # importlib.import_module(loaded)
+        mod_name = list_args[0]
+        method_name = 'do_%s' % mod_name
+        loaded = '%s.%s' % (libdir, mod_name)
         exec('import %s' % loaded)
-        do_cmd = '%s.do_%s' % (loaded, list_args[0])
-        setattr(self, 'do_%s' % list_args[0], eval(do_cmd))
+        do_cmd = '%s.%s' % (loaded, method_name)
+        exec('Shell.%s = %s' % (method_name, do_cmd))
+
         print("Module '%s' loaded." % loaded)
+
+    def complete_load_cmd(self, text, line, begidx, endidx):
+        """Complete command plugins
+
+        Search under PLUGIN_DIR with compl_common() method.
+        This method is intended to be used for searching current
+        directory, but not in this case. If text is not '',
+        compl_common() does not work correctly and do filtering
+        for the result by self.
+        """
+
+        curdir = os.path.dirname(__file__)
+        res = common.compl_common(
+            '', '%s/%s' % (curdir, self.PLUGIN_DIR), 'py')
+
+        completions = []
+        for t in res:
+            if text == '':
+                if t[:2] != '__':
+                    completions.append(t[:-3])
+            else:
+                if t[:len(text)] == text:
+                    completions.append(t[:-3])
+        return completions
-- 
2.13.1

  parent reply	other threads:[~2018-03-06 10:51 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-06 10:50 [spp] [PATCH 00/13] Change structure of SPP controller ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 01/13] spp: move controller to sub directory ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 02/13] controller: move connection threads ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 03/13] controller: aggregate logger to spp_common.py ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 04/13] controller: add load command ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 05/13] controller: move common methods to shell_lib ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 06/13] controller: add filter for py to compl_common ogawa.yasufumi
2018-03-06 10:50 ` ogawa.yasufumi [this message]
2018-03-06 10:50 ` [spp] [PATCH 08/13] controller: change logger output to logfile ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 09/13] controller: add do_topo to shell.py ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 10/13] controller: add topo.py ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 11/13] controller: add topo_subgraph command ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 12/13] controller: add cat and less command ogawa.yasufumi
2018-03-06 10:50 ` [spp] [PATCH 13/13] controller: create log directory ogawa.yasufumi
2018-03-27 23:41 ` [spp] [PATCH 00/13] Change structure of SPP controller Ferruh Yigit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180306105055.65210-8-ogawa.yasufumi@lab.ntt.co.jp \
    --to=ogawa.yasufumi@lab.ntt.co.jp \
    --cc=ferruh.yigit@intel.com \
    --cc=spp@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).