Allow reusing shell libs in Python 3 code

This simplifies code reuse in the MultiNode Tradefed python runner and
in upcoming changes.

Issue: INFRA-135
Issue: INFRA-137
Change-Id: I6bbf2ca96cc74c2eabf7308c57be07064d81a8e4
Signed-off-by: Karsten Tausche <karsten@fairphone.com>
diff --git a/automated/lib/py_util_lib.py b/automated/lib/py_util_lib.py
new file mode 100644
index 0000000..a3da5eb
--- /dev/null
+++ b/automated/lib/py_util_lib.py
@@ -0,0 +1,45 @@
+"""Shared Python 3 utility code.
+"""
+
+from pathlib import Path
+import subprocess
+from typing import Dict, Optional
+
+AUTOMATED_LIB_DIR = Path(__file__).resolve().parent
+
+
+def call_shell_lib(
+    command: str,
+    environment: Optional[Dict[str, str]] = None,
+    device: Optional[str] = None,
+) -> int:
+    """Python-to-shell adaptor, facilitating code reuse.
+
+    This executes a given command line on a shell with sourced sh-test-lib and
+    android-test-lib.
+
+    Arguments:
+        command: Function or command line including parameters to execute in a
+            shell.
+        environment: Environment to execute the shell command in. This is a
+            mapping of environment variable names to their values.
+        device: ADB identifier (serial or IP and port) of a device. If set, this
+            will be appended as ANDROID_SERIAL to the environment.
+    Return:
+        The exit code of the invoked shell command.
+    """
+    if device:
+        if not environment:
+            environment = {}
+        environment["ANDROID_SERIAL"] = device
+    return subprocess.run(
+        [
+            "sh",
+            "-c",
+            ". {}/sh-test-lib && "
+            ". {}/android-test-lib && {}".format(
+                AUTOMATED_LIB_DIR, AUTOMATED_LIB_DIR, command
+            ),
+        ],
+        env=environment,
+    ).returncode