@@ -229,7 +229,7 @@ def pyreadline_remove_history_item(pos):
229
229
pass
230
230
231
231
232
- __version__ = '0.8.7 '
232
+ __version__ = '0.8.8 '
233
233
234
234
# Pyparsing enablePackrat() can greatly speed up parsing, but problems have been seen in Python 3 in the past
235
235
pyparsing .ParserElement .enablePackrat ()
@@ -2470,7 +2470,7 @@ def onecmd_plus_hooks(self, line):
2470
2470
if self .timing :
2471
2471
self .pfeedback ('Elapsed: %s' % str (datetime .datetime .now () - timestart ))
2472
2472
finally :
2473
- if self .allow_redirection :
2473
+ if self .allow_redirection and self . redirecting :
2474
2474
self ._restore_output (statement )
2475
2475
except EmptyStatement :
2476
2476
pass
@@ -2586,7 +2586,11 @@ def _redirect_output(self, statement):
2586
2586
mode = 'w'
2587
2587
if statement .parsed .output == 2 * self .redirector :
2588
2588
mode = 'a'
2589
- sys .stdout = self .stdout = open (os .path .expanduser (statement .parsed .outputTo ), mode )
2589
+ try :
2590
+ sys .stdout = self .stdout = open (os .path .expanduser (statement .parsed .outputTo ), mode )
2591
+ except (FILE_NOT_FOUND_ERROR , IOError ) as ex :
2592
+ self .perror ('Not Redirecting because - {}' .format (ex ), traceback_war = False )
2593
+ self .redirecting = False
2590
2594
else :
2591
2595
sys .stdout = self .stdout = tempfile .TemporaryFile (mode = "w+" )
2592
2596
if statement .parsed .output == '>>' :
@@ -3638,34 +3642,7 @@ def do_history(self, args):
3638
3642
except Exception as e :
3639
3643
self .perror ('Saving {!r} - {}' .format (args .output_file , e ), traceback_war = False )
3640
3644
elif args .transcript :
3641
- # Make sure echo is on so commands print to standard out
3642
- saved_echo = self .echo
3643
- self .echo = True
3644
-
3645
- # Redirect stdout to the transcript file
3646
- saved_self_stdout = self .stdout
3647
- self .stdout = open (args .transcript , 'w' )
3648
-
3649
- # Run all of the commands in the history with output redirected to transcript and echo on
3650
- self .runcmds_plus_hooks (history )
3651
-
3652
- # Restore stdout to its original state
3653
- self .stdout .close ()
3654
- self .stdout = saved_self_stdout
3655
-
3656
- # Set echo back to its original state
3657
- self .echo = saved_echo
3658
-
3659
- # Post-process the file to escape un-escaped "/" regex escapes
3660
- with open (args .transcript , 'r' ) as fin :
3661
- data = fin .read ()
3662
- post_processed_data = data .replace ('/' , '\/' )
3663
- with open (args .transcript , 'w' ) as fout :
3664
- fout .write (post_processed_data )
3665
-
3666
- plural = 's' if len (history ) > 1 else ''
3667
- self .pfeedback ('{} command{} and outputs saved to transcript file {!r}' .format (len (history ), plural ,
3668
- args .transcript ))
3645
+ self ._generate_transcript (history , args .transcript )
3669
3646
else :
3670
3647
# Display the history items retrieved
3671
3648
for hi in history :
@@ -3674,6 +3651,73 @@ def do_history(self, args):
3674
3651
else :
3675
3652
self .poutput (hi .pr ())
3676
3653
3654
+ def _generate_transcript (self , history , transcript_file ):
3655
+ """Generate a transcript file from a given history of commands."""
3656
+ # Save the current echo state, and turn it off. We inject commands into the
3657
+ # output using a different mechanism
3658
+ import io
3659
+
3660
+ saved_echo = self .echo
3661
+ self .echo = False
3662
+
3663
+ # Redirect stdout to the transcript file
3664
+ saved_self_stdout = self .stdout
3665
+
3666
+ # The problem with supporting regular expressions in transcripts
3667
+ # is that they shouldn't be processed in the command, just the output.
3668
+ # In addition, when we generate a transcript, any slashes in the output
3669
+ # are not really intended to indicate regular expressions, so they should
3670
+ # be escaped.
3671
+ #
3672
+ # We have to jump through some hoops here in order to catch the commands
3673
+ # separately from the output and escape the slashes in the output.
3674
+ transcript = ''
3675
+ for history_item in history :
3676
+ # build the command, complete with prompts. When we replay
3677
+ # the transcript, we look for the prompts to separate
3678
+ # the command from the output
3679
+ first = True
3680
+ command = ''
3681
+ for line in history_item .splitlines ():
3682
+ if first :
3683
+ command += '{}{}\n ' .format (self .prompt , line )
3684
+ first = False
3685
+ else :
3686
+ command += '{}{}\n ' .format (self .continuation_prompt , line )
3687
+ transcript += command
3688
+ # create a new string buffer and set it to stdout to catch the output
3689
+ # of the command
3690
+ membuf = io .StringIO ()
3691
+ self .stdout = membuf
3692
+ # then run the command and let the output go into our buffer
3693
+ self .onecmd_plus_hooks (history_item )
3694
+ # rewind the buffer to the beginning
3695
+ membuf .seek (0 )
3696
+ # get the output out of the buffer
3697
+ output = membuf .read ()
3698
+ # and add the regex-escaped output to the transcript
3699
+ transcript += output .replace ('/' , '\/' )
3700
+
3701
+ # Restore stdout to its original state
3702
+ self .stdout = saved_self_stdout
3703
+ # Set echo back to its original state
3704
+ self .echo = saved_echo
3705
+
3706
+ # finally, we can write the transcript out to the file
3707
+ try :
3708
+ with open (transcript_file , 'w' ) as fout :
3709
+ fout .write (transcript )
3710
+ except (FILE_NOT_FOUND_ERROR , IOError ) as ex :
3711
+ self .perror ('Failed to save transcript: {}' .format (ex ), traceback_war = False )
3712
+ else :
3713
+ # and let the user know what we did
3714
+ if len (history ) > 1 :
3715
+ plural = 'commands and their outputs'
3716
+ else :
3717
+ plural = 'command and its output'
3718
+ msg = '{} {} saved to transcript file {!r}'
3719
+ self .pfeedback (msg .format (len (history ), plural , transcript_file ))
3720
+
3677
3721
@with_argument_list
3678
3722
def do_edit (self , arglist ):
3679
3723
"""Edit a file in a text editor.
0 commit comments