mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Fix the pause module for python3
* On python3, stdin goes through a buffer that translates from raw bytes to text. this interferes with pause as it (1) performs universal newline conversion and therefore '\r' is turned into '\n' and (2) the buffering prevents us from getting the typed characters immediately (possibly a python3 bug?) Using the raw byte stream that's behind the text decoder fixes these problems. Unrelated cleanups: * Use to_text instead of str for conversion into strings to avoid possible tracebacks * Use either \r or \n as the end of a line. Fixes #26278 Resolves #26446
This commit is contained in:
parent
a94156227d
commit
5ceabe939d
1 changed files with 21 additions and 14 deletions
|
@ -25,6 +25,8 @@ import tty
|
||||||
|
|
||||||
from os import isatty
|
from os import isatty
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils.six import PY3
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -85,7 +87,7 @@ class ActionModule(ActionBase):
|
||||||
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
result['failed'] = True
|
result['failed'] = True
|
||||||
result['msg'] = "non-integer value given for prompt duration:\n%s" % str(e)
|
result['msg'] = u"non-integer value given for prompt duration:\n%s" % to_text(e)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Is 'prompt' a key in 'args'?
|
# Is 'prompt' a key in 'args'?
|
||||||
|
@ -102,8 +104,8 @@ class ActionModule(ActionBase):
|
||||||
# Begin the hard work!
|
# Begin the hard work!
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
result['start'] = str(datetime.datetime.now())
|
result['start'] = to_text(datetime.datetime.now())
|
||||||
result['user_input'] = ''
|
result['user_input'] = b''
|
||||||
|
|
||||||
fd = None
|
fd = None
|
||||||
old_settings = None
|
old_settings = None
|
||||||
|
@ -122,9 +124,13 @@ class ActionModule(ActionBase):
|
||||||
|
|
||||||
# save the attributes on the existing (duped) stdin so
|
# save the attributes on the existing (duped) stdin so
|
||||||
# that we can restore them later after we set raw mode
|
# that we can restore them later after we set raw mode
|
||||||
|
if PY3:
|
||||||
|
stdin = self._connection._new_stdin.buffer
|
||||||
|
else:
|
||||||
|
stdin = self._connection._new_stdin
|
||||||
fd = None
|
fd = None
|
||||||
try:
|
try:
|
||||||
fd = self._connection._new_stdin.fileno()
|
fd = stdin.fileno()
|
||||||
except (ValueError, AttributeError):
|
except (ValueError, AttributeError):
|
||||||
# ValueError: someone is using a closed file descriptor as stdin
|
# ValueError: someone is using a closed file descriptor as stdin
|
||||||
# AttributeError: someone is using a null file descriptor as stdin on windoez
|
# AttributeError: someone is using a null file descriptor as stdin on windoez
|
||||||
|
@ -136,12 +142,12 @@ class ActionModule(ActionBase):
|
||||||
|
|
||||||
# flush the buffer to make sure no previous key presses
|
# flush the buffer to make sure no previous key presses
|
||||||
# are read in below
|
# are read in below
|
||||||
termios.tcflush(self._connection._new_stdin, termios.TCIFLUSH)
|
termios.tcflush(stdin, termios.TCIFLUSH)
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
if fd is not None:
|
if fd is not None:
|
||||||
key_pressed = self._connection._new_stdin.read(1)
|
key_pressed = stdin.read(1)
|
||||||
if key_pressed == '\x03':
|
if key_pressed == b'\x03':
|
||||||
raise KeyboardInterrupt
|
raise KeyboardInterrupt
|
||||||
|
|
||||||
if not seconds:
|
if not seconds:
|
||||||
|
@ -149,7 +155,7 @@ class ActionModule(ActionBase):
|
||||||
display.warning("Not waiting from prompt as stdin is not interactive")
|
display.warning("Not waiting from prompt as stdin is not interactive")
|
||||||
break
|
break
|
||||||
# read key presses and act accordingly
|
# read key presses and act accordingly
|
||||||
if key_pressed == '\r':
|
if key_pressed in (b'\r', b'\n'):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
result['user_input'] += key_pressed
|
result['user_input'] += key_pressed
|
||||||
|
@ -158,7 +164,7 @@ class ActionModule(ActionBase):
|
||||||
if seconds is not None:
|
if seconds is not None:
|
||||||
signal.alarm(0)
|
signal.alarm(0)
|
||||||
display.display("Press 'C' to continue the play or 'A' to abort \r"),
|
display.display("Press 'C' to continue the play or 'A' to abort \r"),
|
||||||
if self._c_or_a():
|
if self._c_or_a(stdin):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise AnsibleError('user requested abort!')
|
raise AnsibleError('user requested abort!')
|
||||||
|
@ -174,7 +180,7 @@ class ActionModule(ActionBase):
|
||||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||||
|
|
||||||
duration = time.time() - start
|
duration = time.time() - start
|
||||||
result['stop'] = str(datetime.datetime.now())
|
result['stop'] = to_text(datetime.datetime.now())
|
||||||
result['delta'] = int(duration)
|
result['delta'] = int(duration)
|
||||||
|
|
||||||
if duration_unit == 'minutes':
|
if duration_unit == 'minutes':
|
||||||
|
@ -183,12 +189,13 @@ class ActionModule(ActionBase):
|
||||||
duration = round(duration, 2)
|
duration = round(duration, 2)
|
||||||
result['stdout'] = "Paused for %s %s" % (duration, duration_unit)
|
result['stdout'] = "Paused for %s %s" % (duration, duration_unit)
|
||||||
|
|
||||||
|
result['user_input'] = to_text(result['user_input'], errors='surrogate_or_strict')
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _c_or_a(self):
|
def _c_or_a(self, stdin):
|
||||||
while True:
|
while True:
|
||||||
key_pressed = self._connection._new_stdin.read(1)
|
key_pressed = stdin.read(1)
|
||||||
if key_pressed.lower() == 'a':
|
if key_pressed.lower() == b'a':
|
||||||
return False
|
return False
|
||||||
elif key_pressed.lower() == 'c':
|
elif key_pressed.lower() == b'c':
|
||||||
return True
|
return True
|
||||||
|
|
Loading…
Add table
Reference in a new issue