Skip to content

Commit e4d13c7

Browse files
authored
Merge branch 'master' into autocompleter
2 parents dde5207 + d0e71c8 commit e4d13c7

File tree

4 files changed

+86
-11
lines changed

4 files changed

+86
-11
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.8.8 (TBD, 2018)
2+
* Bug Fixes
3+
* Prevent crashes that could occur attempting to open a file in non-existent directory or with very long filename
4+
15
## 0.9.1 (May 28, 2018)
26
* Bug Fixes
37
* fix packaging error for 0.8.x versions (yes we had to deploy a new version

cmd2/cmd2.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,7 +1710,7 @@ def onecmd_plus_hooks(self, line):
17101710
if self.timing:
17111711
self.pfeedback('Elapsed: %s' % str(datetime.datetime.now() - timestart))
17121712
finally:
1713-
if self.allow_redirection:
1713+
if self.allow_redirection and self.redirecting:
17141714
self._restore_output(statement)
17151715
except EmptyStatement:
17161716
pass
@@ -1854,7 +1854,11 @@ def _redirect_output(self, statement):
18541854
# REDIRECTION_APPEND or REDIRECTION_OUTPUT
18551855
if statement.output == constants.REDIRECTION_APPEND:
18561856
mode = 'a'
1857-
sys.stdout = self.stdout = open(os.path.expanduser(statement.output_to), mode)
1857+
try:
1858+
sys.stdout = self.stdout = open(os.path.expanduser(statement.output_to), mode)
1859+
except OSError as ex:
1860+
self.perror('Not Redirecting because - {}'.format(ex), traceback_war=False)
1861+
self.redirecting = False
18581862
else:
18591863
# going to a paste buffer
18601864
sys.stdout = self.stdout = tempfile.TemporaryFile(mode="w+")
@@ -2892,16 +2896,19 @@ def _generate_transcript(self, history, transcript_file):
28922896
self.echo = saved_echo
28932897

28942898
# finally, we can write the transcript out to the file
2895-
with open(transcript_file, 'w') as fout:
2896-
fout.write(transcript)
2897-
2898-
# and let the user know what we did
2899-
if len(history) > 1:
2900-
plural = 'commands and their outputs'
2899+
try:
2900+
with open(transcript_file, 'w') as fout:
2901+
fout.write(transcript)
2902+
except OSError as ex:
2903+
self.perror('Failed to save transcript: {}'.format(ex), traceback_war=False)
29012904
else:
2902-
plural = 'command and its output'
2903-
msg = '{} {} saved to transcript file {!r}'
2904-
self.pfeedback(msg.format(len(history), plural, transcript_file))
2905+
# and let the user know what we did
2906+
if len(history) > 1:
2907+
plural = 'commands and their outputs'
2908+
else:
2909+
plural = 'command and its output'
2910+
msg = '{} {} saved to transcript file {!r}'
2911+
self.pfeedback(msg.format(len(history), plural, transcript_file))
29052912

29062913
@with_argument_list
29072914
def do_edit(self, arglist):

tests/test_cmd2.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,44 @@ def test_output_redirection(base_app):
615615
finally:
616616
os.remove(filename)
617617

618+
def test_output_redirection_to_nonexistent_directory(base_app):
619+
filename = '~/fakedir/this_does_not_exist.txt'
620+
621+
# Verify that writing to a file in a non-existent directory doesn't work
622+
run_cmd(base_app, 'help > {}'.format(filename))
623+
expected = normalize(BASE_HELP)
624+
with pytest.raises(FileNotFoundError):
625+
with open(filename) as f:
626+
content = normalize(f.read())
627+
assert content == expected
628+
629+
# Verify that appending to a file also works
630+
run_cmd(base_app, 'help history >> {}'.format(filename))
631+
expected = normalize(BASE_HELP + '\n' + HELP_HISTORY)
632+
with pytest.raises(FileNotFoundError):
633+
with open(filename) as f:
634+
content = normalize(f.read())
635+
assert content == expected
636+
637+
def test_output_redirection_to_too_long_filename(base_app):
638+
filename = '~/sdkfhksdjfhkjdshfkjsdhfkjsdhfkjdshfkjdshfkjshdfkhdsfkjhewfuihewiufhweiufhiweufhiuewhiuewhfiuwehfiuewhfiuewhfiuewhfiuewhiuewhfiuewhfiuewfhiuwehewiufhewiuhfiweuhfiuwehfiuewfhiuwehiuewfhiuewhiewuhfiuewhfiuwefhewiuhewiufhewiufhewiufhewiufhewiufhewiufhewiufhewiuhewiufhewiufhewiuheiufhiuewheiwufhewiufheiufheiufhieuwhfewiuhfeiufhiuewfhiuewheiwuhfiuewhfiuewhfeiuwfhewiufhiuewhiuewhfeiuwhfiuwehfuiwehfiuehiuewhfieuwfhieufhiuewhfeiuwfhiuefhueiwhfw'
639+
640+
# Verify that writing to a file in a non-existent directory doesn't work
641+
run_cmd(base_app, 'help > {}'.format(filename))
642+
expected = normalize(BASE_HELP)
643+
with pytest.raises(OSError):
644+
with open(filename) as f:
645+
content = normalize(f.read())
646+
assert content == expected
647+
648+
# Verify that appending to a file also works
649+
run_cmd(base_app, 'help history >> {}'.format(filename))
650+
expected = normalize(BASE_HELP + '\n' + HELP_HISTORY)
651+
with pytest.raises(OSError):
652+
with open(filename) as f:
653+
content = normalize(f.read())
654+
assert content == expected
655+
618656

619657
def test_feedback_to_output_true(base_app):
620658
base_app.feedback_to_output = True

tests/test_transcript.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,32 @@ def test_history_transcript(request, capsys):
154154

155155
assert transcript == expected
156156

157+
def test_history_transcript_bad_filename(request, capsys):
158+
app = CmdLineApp()
159+
app.stdout = StdOut()
160+
run_cmd(app, 'orate this is\na /multiline/\ncommand;\n')
161+
run_cmd(app, 'speak /tmp/file.txt is not a regex')
162+
163+
expected = r"""(Cmd) orate this is
164+
> a /multiline/
165+
> command;
166+
this is a \/multiline\/ command
167+
(Cmd) speak /tmp/file.txt is not a regex
168+
\/tmp\/file.txt is not a regex
169+
"""
170+
171+
# make a tmp file
172+
history_fname = '~/fakedir/this_does_not_exist.txt'
173+
174+
# tell the history command to create a transcript
175+
run_cmd(app, 'history -t "{}"'.format(history_fname))
176+
177+
# read in the transcript created by the history command
178+
with pytest.raises(FileNotFoundError):
179+
with open(history_fname) as f:
180+
transcript = f.read()
181+
assert transcript == expected
182+
157183
@pytest.mark.parametrize('expected, transformed', [
158184
# strings with zero or one slash or with escaped slashes means no regular
159185
# expression present, so the result should just be what re.escape returns.

0 commit comments

Comments
 (0)