diff options
-rwxr-xr-x | cmd2/cmd2.py | 122 | ||||
-rw-r--r-- | tests/test_transcript.py | 18 | ||||
-rw-r--r-- | tests/transcripts/expected_history.txt | 20 |
3 files changed, 71 insertions, 89 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index b463ff48..ad2038d4 100755 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -3002,65 +3002,7 @@ a..b, a:b, a:, ..b items by indices (inclusive) except Exception as e: self.perror('Saving {!r} - {}'.format(args.output_file, e), traceback_war=False) elif args.transcript: - # Save the current echo state, and turn it off. We inject commands into the - # output using a different mechanism - saved_echo = self.echo - self.echo = False - - # Redirect stdout to the transcript file - saved_self_stdout = self.stdout - - # The problem with supporting regular expressions in transcripts - # is that they shouldn't be processed in the command, just the output. - # In addition, when we generate a transcript, any slashes in the output - # are not really intended to indicate regular expressions, so they should - # be escaped. - # - # We have to jump through some hoops here in order to catch the commands - # separately from the output and escape the slashes in the output. - transcript = '' - for history_item in history: - # build the command, complete with prompts. When we replay - # the transcript, it looks for the prompts to separate - # the command from the output - first = True - command = '' - for line in history_item.splitlines(): - if first: - command += '{}{}\n'.format(self.prompt, line) - first = False - else: - command += '{}{}\n'.format(self.continuation_prompt, line) - transcript += command - # create a new string buffer and set it to stdout to catch the output - # of the command - membuf = io.StringIO() - self.stdout = membuf - # then run the command and let the output go into our buffer - self.onecmd_plus_hooks(history_item) - # rewind the buffer to the beginning - membuf.seek(0) - # get the output out of the buffer - output = membuf.read() - # and add the regex-escaped output to the transcript - transcript += output.replace('/', '\/') - - # Restore stdout to its original state - self.stdout = saved_self_stdout - # Set echo back to its original state - self.echo = saved_echo - - # finally, we can write the transcript out to the file - with open(args.transcript, 'w') as fout: - fout.write(transcript) - - # and let the user know what we did - if len(history) > 1: - plural = 'commands and their outputs' - else: - plural = 'command and its output' - msg = '{} {} saved to transcript file {!r}' - self.pfeedback(msg.format(len(history), plural, args.transcript)) + self._generate_transcript(history, args.transcript) else: # Display the history items retrieved for hi in history: @@ -3069,6 +3011,68 @@ a..b, a:b, a:, ..b items by indices (inclusive) else: self.poutput(hi.pr()) + def _generate_transcript(self, history, transcript_file): + """Generate a transcript file from a given history of commands.""" + # Save the current echo state, and turn it off. We inject commands into the + # output using a different mechanism + saved_echo = self.echo + self.echo = False + + # Redirect stdout to the transcript file + saved_self_stdout = self.stdout + + # The problem with supporting regular expressions in transcripts + # is that they shouldn't be processed in the command, just the output. + # In addition, when we generate a transcript, any slashes in the output + # are not really intended to indicate regular expressions, so they should + # be escaped. + # + # We have to jump through some hoops here in order to catch the commands + # separately from the output and escape the slashes in the output. + transcript = '' + for history_item in history: + # build the command, complete with prompts. When we replay + # the transcript, we look for the prompts to separate + # the command from the output + first = True + command = '' + for line in history_item.splitlines(): + if first: + command += '{}{}\n'.format(self.prompt, line) + first = False + else: + command += '{}{}\n'.format(self.continuation_prompt, line) + transcript += command + # create a new string buffer and set it to stdout to catch the output + # of the command + membuf = io.StringIO() + self.stdout = membuf + # then run the command and let the output go into our buffer + self.onecmd_plus_hooks(history_item) + # rewind the buffer to the beginning + membuf.seek(0) + # get the output out of the buffer + output = membuf.read() + # and add the regex-escaped output to the transcript + transcript += output.replace('/', '\/') + + # Restore stdout to its original state + self.stdout = saved_self_stdout + # Set echo back to its original state + self.echo = saved_echo + + # finally, we can write the transcript out to the file + with open(transcript_file, 'w') as fout: + fout.write(transcript) + + # and let the user know what we did + if len(history) > 1: + plural = 'commands and their outputs' + else: + plural = 'command and its output' + msg = '{} {} saved to transcript file {!r}' + self.pfeedback(msg.format(len(history), plural, transcript_file)) + @with_argument_list def do_edit(self, arglist): """Edit a file in a text editor. diff --git a/tests/test_transcript.py b/tests/test_transcript.py index 5fee1363..70658161 100644 --- a/tests/test_transcript.py +++ b/tests/test_transcript.py @@ -129,18 +129,16 @@ def test_transcript(request, capsys, filename, feedback_to_output): def test_history_transcript(request, capsys): app = CmdLineApp() app.stdout = StdOut() - run_cmd(app, 'help') - run_cmd(app, 'orate this is\na multiline\ncommand;\n') + run_cmd(app, 'orate this is\na /multiline/\ncommand;\n') run_cmd(app, 'speak /tmp/file.txt is not a regex') - # Get location of the expected transcript - test_dir = os.path.dirname(request.module.__file__) - expected_fname = os.path.join(test_dir, 'transcripts', 'expected_history.txt') - with open(expected_fname) as f: - lines = f.readlines() - # trim off the first 7 lines so we can have a comment in the - # expected_history.txt file explaining what it is - expected = ''.join(lines[7:]) + expected = r"""(Cmd) orate this is +> a /multiline/ +> command; +this is a \/multiline\/ command +(Cmd) speak /tmp/file.txt is not a regex +\/tmp\/file.txt is not a regex +""" # make a tmp file fd, history_fname = tempfile.mkstemp(prefix='', suffix='.txt') diff --git a/tests/transcripts/expected_history.txt b/tests/transcripts/expected_history.txt deleted file mode 100644 index ba2d94ce..00000000 --- a/tests/transcripts/expected_history.txt +++ /dev/null @@ -1,20 +0,0 @@ -# this file contains the expected output of a 'history -t' command. -# Because the help command outputs trailing spaces, this file -# contains trailing spaces. Don't mess it up with your editor -# which may be configured to trim trailing spaces -# The first 7 lines of this file are stripped out by the -# test case before comparing the actual output with -# the contents of this file. -(Cmd) help - -Documented commands (type help <topic>): -======================================== -alias help load orate pyscript say shell speak -edit history mumble py quit set shortcuts unalias - -(Cmd) orate this is -> a multiline -> command; -this is a multiline command -(Cmd) speak /tmp/file.txt is not a regex -\/tmp\/file.txt is not a regex |