[PATCH] osmo-gsm-tester[master]: fix prompt()

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Sat May 6 20:27:46 UTC 2017


Review at  https://gerrit.osmocom.org/2491

fix prompt()

The prompt() is useful for supervisor (user) interaction during tests.

However it had numerous problems:
- closed stdin, so second prompt() didn't work
- no editing
- no utf-8 multichar
- unflexible poll interval (poll often to stay responsive to input)
and unrelated:
- stdin was hijacked by subprocess.Popen

Firstly pass stdin=PIPE to all subprocesses to leave the tester's stdin
untouched.

Secondly use python input() to read the user entry (instead of mucking about
with the stdin fd), and import readline for history and editing features.

The old approach was put in place to allow polling DBus and processes
regularly. Instead, allow this by running input() in a separate thread while
polling regularly and slowly in the main thread.

The prompt code is now simpler, cleaner and works better.
Will be used in the upcoming 'debug' suite.

Change-Id: I580aca52cd038b59418055259d0d09e9aab49124
---
M src/osmo_gsm_tester/process.py
M src/osmo_gsm_tester/suite.py
M src/osmo_gsm_tester/util.py
3 files changed, 24 insertions(+), 40 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-gsm-tester refs/changes/91/2491/1

diff --git a/src/osmo_gsm_tester/process.py b/src/osmo_gsm_tester/process.py
index 16f7905..a687de6 100644
--- a/src/osmo_gsm_tester/process.py
+++ b/src/osmo_gsm_tester/process.py
@@ -73,6 +73,7 @@
                 self.popen_args,
                 stdout=self.make_output_log('stdout'),
                 stderr=self.make_output_log('stderr'),
+                stdin=subprocess.PIPE,
                 shell=False,
                 cwd=self.run_dir.path,
                 **self.popen_kwargs)
diff --git a/src/osmo_gsm_tester/suite.py b/src/osmo_gsm_tester/suite.py
index e3feede..a886de4 100644
--- a/src/osmo_gsm_tester/suite.py
+++ b/src/osmo_gsm_tester/suite.py
@@ -286,11 +286,12 @@
                                     for k,v in sorted(msg_details.items())])))
         msg = ' '.join(msgs) or 'Hit Enter to continue'
         self.log('prompt:', msg)
+        sys.__stdout__.write('\n\n--- PROMPT ---\n')
         sys.__stdout__.write(msg)
-        sys.__stdout__.write('\n> ')
+        sys.__stdout__.write('\n')
         sys.__stdout__.flush()
-        entered = util.input_polling(self.poll)
-        self.log('prompt entered:', entered)
+        entered = util.input_polling('> ', self.poll)
+        self.log('prompt entered:', repr(entered))
         return entered
 
 loaded_suite_definitions = {}
diff --git a/src/osmo_gsm_tester/util.py b/src/osmo_gsm_tester/util.py
index e132e21..335e3ba 100644
--- a/src/osmo_gsm_tester/util.py
+++ b/src/osmo_gsm_tester/util.py
@@ -29,7 +29,7 @@
 import importlib.util
 import fcntl
 import tty
-import termios
+import readline
 
 
 class listdict:
@@ -282,42 +282,24 @@
     'add 1 and preserve leading zeros'
     return ('%%0%dd' % len(msisdn_str)) % (int(msisdn_str) + 1)
 
-class polling_stdin:
-    def __init__(self, stream):
-        self.stream = stream
-        self.fd = self.stream.fileno()
-    def __enter__(self):
-        self.original_stty = termios.tcgetattr(self.stream)
-        tty.setcbreak(self.stream)
-        self.orig_fl = fcntl.fcntl(self.fd, fcntl.F_GETFL)
-        fcntl.fcntl(self.fd, fcntl.F_SETFL, self.orig_fl | os.O_NONBLOCK)
-    def __exit__(self, *args):
-        fcntl.fcntl(self.fd, fcntl.F_SETFL, self.orig_fl)
-        termios.tcsetattr(self.stream, termios.TCSANOW, self.original_stty)
+class InputThread(threading.Thread):
+    def __init__(self, prompt):
+        super().__init__()
+        self.prompt = prompt
+        self.result = None
 
-def input_polling(poll_func, stream=None):
-    if stream is None:
-        stream = sys.stdin
-    unbuffered_stdin = os.fdopen(stream.fileno(), 'rb', buffering=0)
-    try:
-        with polling_stdin(unbuffered_stdin):
-            acc = []
-            while True:
-                poll_func()
-                got = unbuffered_stdin.read(1)
-                if got and len(got):
-                    try:
-                        # this is hacky: can't deal with multibyte sequences
-                        got_str = got.decode('utf-8')
-                    except:
-                        got_str = '?'
-                    acc.append(got_str)
-                    sys.__stdout__.write(got_str)
-                    sys.__stdout__.flush()
-                    if '\n' in got_str:
-                        return ''.join(acc)
-                time.sleep(.1)
-    finally:
-        unbuffered_stdin.close()
+    def run(self):
+        self.result = input(self.prompt)
+
+def input_polling(prompt, poll_func):
+    input_thread = InputThread(prompt)
+    input_thread.start()
+
+    while input_thread.is_alive():
+        poll_func()
+        time.sleep(1)
+
+    input_thread.join()
+    return input_thread.result
 
 # vim: expandtab tabstop=4 shiftwidth=4

-- 
To view, visit https://gerrit.osmocom.org/2491
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I580aca52cd038b59418055259d0d09e9aab49124
Gerrit-PatchSet: 1
Gerrit-Project: osmo-gsm-tester
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>



More information about the gerrit-log mailing list