Simplify par Launcher

Instead of copying some of Py_Main and changing it, use Py_Main
directly, paired with a __main__.py script that uses the runpy module to
trampoline into the user code.

Test: build/soong/python/tests/runtest.sh
Change-Id: I7f5e1e38b63b4e2ce83a85c08953a5e67c7b8788
diff --git a/Launcher/launcher_main.cpp b/Launcher/launcher_main.cpp
index a49998c..09a9d39 100644
--- a/Launcher/launcher_main.cpp
+++ b/Launcher/launcher_main.cpp
@@ -12,8 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "launcher_internal.h"
-
 #include <Python.h>
 #include <android-base/file.h>
 #include <osdefs.h>
@@ -22,103 +20,39 @@
 #include <string>
 
 int main(int argc, char *argv[]) {
-  int result = 0 /* Used to mark if current program runs with success/failure. */;
-
-  // Clear PYTHONPATH and PYTHONHOME so Python doesn't attempt to check the local
-  // disk for Python modules to load. The value of PYTHONHOME will replace "prefix"
-  // and "exe_prefix" based on the description in getpath.c.
-  // Please don't use PYTHONPATH and PYTHONHOME within user program.
-  // TODO(nanzhang): figure out if unsetenv("PYTHONPATH") is better.
-  unsetenv(const_cast<char *>("PYTHONPATH"));
-  // TODO(nanzhang): figure out if Py_SetPythonHome() is better.
-  unsetenv(const_cast<char *>("PYTHONHOME"));
   // PYTHONEXECUTABLE is only used on MacOs X, when the Python interpreter
   // embedded in an application bundle. It is not sure that we have this use case
-  // for Android hermetic Python. So override this environment variable to empty
-  // for now to make our self-contained environment more strict.
+  // for Android hermetic Python. So remove this environment variable to make
+  // our self-contained environment more strict.
   // For user (.py) program, it can access hermetic .par file path through
   // sys.argv[0].
   unsetenv(const_cast<char *>("PYTHONEXECUTABLE"));
 
+  // Always enable Python "-s" option. We don't need user-site directories,
+  // everything's supposed to be hermetic.
+  Py_NoUserSiteDirectory = 1;
+
+  // Ignore PYTHONPATH and PYTHONHOME from the environment.
+  Py_IgnoreEnvironmentFlag = 1;
+
+  Py_DontWriteBytecodeFlag = 1;
+
   // Resolving absolute path based on argv[0] is not reliable since it may
   // include something unusable, too bad.
   // android::base::GetExecutablePath() also handles for Darwin/Windows.
   std::string executable_path = android::base::GetExecutablePath();
 
-  argv[0] = strdup(executable_path.c_str());
-  // argv[0] is used for setting internal path, and Python sys.argv[0]. It
-  // should not exceed MAXPATHLEN defined for CPython.
-  if (!argv[0] || strlen(argv[0]) > MAXPATHLEN) {
-    fprintf(stderr, "The executable path %s is NULL or of invalid length.\n", argv[0]);
-    return 1;
+  int new_argc = argc + 1;
+  char **new_argv = reinterpret_cast<char**>(calloc(new_argc, sizeof(*argv)));
+
+  // Inject the path to our binary into argv[1] so the Py_Main won't parse any
+  // other options, and will execute the __main__.py script inside the zip file
+  // attached to our executable.
+  new_argv[0] = argv[0];
+  new_argv[1] = strdup(executable_path.c_str());
+  for (int i = 1; i < argc; i++) {
+    new_argv[i+1] = argv[i];
   }
 
-  // For debugging/logging purpose, set stdin/stdout/stderr unbuffered through
-  // environment variable.
-  // TODO(nanzhang): Set Py_VerboseFlag if more debugging requests needed.
-  const char *unbuffered_env = getenv("PYTHONUNBUFFERED");
-  if (unbuffered_env && unbuffered_env[0]) {
-    #if defined(MS_WINDOWS) || defined(__CYGWIN__)
-      _setmode(fileno(stdin), O_BINARY);
-      _setmode(fileno(stdout), O_BINARY);
-    #endif
-    #ifdef HAVE_SETVBUF
-      setvbuf(stdin,  (char *)NULL, _IONBF, BUFSIZ);
-      setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
-      setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
-    #else /* !HAVE_SETVBUF */
-      setbuf(stdin,  (char *)NULL);
-      setbuf(stdout, (char *)NULL);
-      setbuf(stderr, (char *)NULL);
-    #endif /* !HAVE_SETVBUF */
-  }
-  //For debugging/logging purpose, Warning control.
-  //Python’s warning machinery by default prints warning messages to sys.stderr.
-  //The full form of argument is:action:message:category:module:line
-  char *warnings_env = getenv("PYTHONWARNINGS");
-  if (warnings_env && warnings_env[0]) {
-      char *warnings_buf, *warning;
-
-      // Note: "new" operation; we need free this chuck of data after use.
-      warnings_buf = new char[strlen(warnings_env) + 1];
-      if (warnings_buf == NULL)
-          Py_FatalError(
-             "not enough memory to copy PYTHONWARNINGS");
-      strcpy(warnings_buf, warnings_env);
-      for (warning = strtok(warnings_buf, ",");
-           warning != NULL;
-           warning = strtok(NULL, ","))
-          PySys_AddWarnOption(warning);
-      delete[] warnings_buf;
-  }
-
-  // Always enable Python "-s" option. We don't need user-site directories,
-  // everything's supposed to be hermetic.
-  Py_NoUserSiteDirectory = 1;
-
-  Py_SetProgramName(argv[0]);
-  Py_Initialize();
-  PySys_SetArgvEx(argc, argv, 0);
-
-  // Set sys.executable to None. The real executable is available as
-  // sys.argv[0], and too many things assume sys.executable is a regular Python
-  // binary, which isn't available. By setting it to None we get clear errors
-  // when people try to use it.
-  if (PySys_SetObject(const_cast<char *>("executable"), Py_None) < 0) {
-    PyErr_Print();
-    result = 1;
-    goto error;
-  }
-
-  result = android::cpython2::python_launcher::RunEntryPointOrMainModule(argv[0]);
-  if (result < 0) {
-    PyErr_Print();
-    goto error;
-  }
-
-error:
-  Py_Finalize();
-
-  free(argv[0]);
-  exit(abs(result));
+  return Py_Main(new_argc, new_argv);
 }