From e0cd11ab21000ec5f3997bcee9aca61ad064f426 Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Thu, 19 Feb 2015 14:54:25 -0800 Subject: [PATCH 1/2] cli: don't read/write readline history more than once Previously, when creating multiple CLI objects, each one would append the ~/.mininet_history file to readline's internal list. When writing the file back it would be duplicated for each CLI object created. So, over a few mininet runs the history file would grow exponentially. This change moves the readline setup code out of the CLI constructor into a class method and adds a flag to prevent it from being executed more than once. --- mininet/cli.py | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/mininet/cli.py b/mininet/cli.py index 23aaac5..cd017e4 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -56,20 +56,12 @@ class CLI( Cmd ): Cmd.__init__( self ) info( '*** Starting CLI:\n' ) - # Set up history if readline is available - try: - import readline - except ImportError: - pass - else: - history_path = os.path.expanduser('~/.mininet_history') - if os.path.isfile(history_path): - readline.read_history_file(history_path) - atexit.register(lambda: readline.write_history_file(history_path)) - if self.inputFile: self.do_source( self.inputFile ) return + + self.setup_readline() + while True: try: # Make sure no nodes are still waiting @@ -84,6 +76,26 @@ class CLI( Cmd ): except KeyboardInterrupt: output( '\nInterrupt\n' ) + has_setup_readline = False + @classmethod + def setup_readline( cls ): + "Set up history if readline is available" + + # Only set up readline once to prevent multiplying the history file + if cls.has_setup_readline: + return + cls.has_setup_readline = True + + try: + import readline + except ImportError: + pass + else: + history_path = os.path.expanduser('~/.mininet_history') + if os.path.isfile(history_path): + readline.read_history_file(history_path) + atexit.register(lambda: readline.write_history_file(history_path)) + def emptyline( self ): "Don't repeat last command when you hit return." pass From 613fac4babdc3c471673842b28ddcac36d9a33e3 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Fri, 20 Feb 2015 16:46:18 -0800 Subject: [PATCH 2/2] Move cmdloop() wrapper into a new run() method I also added another try/catch block so that interrupting the 'Interrupt' message should no longer occur. --- mininet/cli.py | 52 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/mininet/cli.py b/mininet/cli.py index cd017e4..a8c93be 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -45,6 +45,10 @@ class CLI( Cmd ): prompt = 'mininet> ' def __init__( self, mininet, stdin=sys.stdin, script=None ): + """Start and run interactive or batch mode CLI + mininet: Mininet network object + stdin: standard input for CLI + script: script to run in batch mode""" self.mn = mininet # Local variable bindings for py command self.locals = { 'net': mininet } @@ -60,32 +64,17 @@ class CLI( Cmd ): self.do_source( self.inputFile ) return - self.setup_readline() + self.initReadline() + self.run() - while True: - try: - # Make sure no nodes are still waiting - for node in self.mn.values(): - while node.waiting: - node.sendInt() - node.waitOutput() - if self.isatty(): - quietRun( 'stty echo sane intr "^C"' ) - self.cmdloop() - break - except KeyboardInterrupt: - output( '\nInterrupt\n' ) - - has_setup_readline = False + readlineInited = False @classmethod - def setup_readline( cls ): + def initReadline( cls ): "Set up history if readline is available" - # Only set up readline once to prevent multiplying the history file - if cls.has_setup_readline: + if cls.readlineInited: return - cls.has_setup_readline = True - + cls.readlineInited = True try: import readline except ImportError: @@ -96,6 +85,27 @@ class CLI( Cmd ): readline.read_history_file(history_path) atexit.register(lambda: readline.write_history_file(history_path)) + def run( self ): + "Run our cmdloop(), catching KeyboardInterrupt" + while True: + try: + # Make sure no nodes are still waiting + for node in self.mn.values(): + while node.waiting: + info( 'stopping', node, '\n' ) + node.sendInt() + node.waitOutput() + if self.isatty(): + quietRun( 'stty echo sane intr ^C' ) + self.cmdloop() + break + except KeyboardInterrupt: + # Output a message - unless it's also interrupted + try: + output( '\nInterrupt\n' ) + except: + pass + def emptyline( self ): "Don't repeat last command when you hit return." pass