Skip to content

Commit

Permalink
fix: run in window
Browse files Browse the repository at this point in the history
  • Loading branch information
nguyenhoangthuan99 committed Oct 17, 2024
1 parent fcbffae commit 51091b6
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 27 deletions.
84 changes: 71 additions & 13 deletions src/python_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

#if defined(_WIN32)
#include <process.h>
#include <processthreadsapi.h>
#include <userenv.h>
#pragma comment(lib, "userenv.lib")
#else
#include <spawn.h>
#include <sys/wait.h>
Expand Down Expand Up @@ -58,40 +61,95 @@ void PythonEngine::HandlePythonFileExecutionRequestImpl(

#if defined(_WIN32)
std::wstring exe_path = python_utils::getCurrentExecutablePath();
std::string exe_args_string = " --run_python_file " + file_execution_path;
if (!python_library_path.empty())
exe_args_string += " --python_library_path " + python_library_path;
std::wstring pyArgs =
exe_path + python_utils::stringToWString(exe_args_string);
std::wstring command_line =
L"\"" + exe_path + L"\" --run_python_file \"" +
python_utils::stringToWString(file_execution_path) + L"\"";

if (!python_library_path.empty()) {
command_line +=
L" \"" + python_utils::stringToWString(python_library_path) + L"\"";
}

STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

if (!CreateProcessW(
const_cast<wchar_t*>(exe_path.c_str()),
const_cast<wchar_t*>(pyArgs.c_str()),
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
LOG_ERROR << "Failed to create child process: " << GetLastError();
// Prepare environment block
LPWCH envBlock = GetEnvironmentStringsW();
if (envBlock == NULL) {
LOG_ERROR << "Failed to get environment block";
json_resp["message"] = "Failed to execute the Python file";
status_resp["status_code"] = k500InternalServerError;
callback(std::move(status_resp), std::move(json_resp));
return;
}

std::wstring env_block;
for (LPCWSTR env = envBlock; *env != L'\0'; env += wcslen(env) + 1) {
env_block += env;
env_block += L'\0';
}
FreeEnvironmentStringsW(envBlock);

// Add or modify PYTHONPATH
std::wstring pythonpath =
L"PYTHONPATH=" + python_utils::stringToWString(python_library_path);
env_block += pythonpath;
env_block += L'\0';
env_block += L'\0'; // Double null-termination

LPVOID pEnv = NULL;
if (!CreateEnvironmentBlock(&pEnv, NULL, FALSE)) {
LOG_ERROR << "Failed to create environment block";
json_resp["message"] = "Failed to execute the Python file";
status_resp["status_code"] = k500InternalServerError;
callback(std::move(status_resp), std::move(json_resp));
return;
}

if (!CreateProcessW(NULL, const_cast<LPWSTR>(command_line.c_str()), NULL,
NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, pEnv, NULL, &si,
&pi)) {
DWORD error = GetLastError();
LOG_ERROR << "Failed to create child process: " << error;
json_resp["message"] = "Failed to execute the Python file. Error code: " +
std::to_string(error);
status_resp["status_code"] = k500InternalServerError;
} else {
LOG_INFO << "Created child process for Python embedding";
WaitForSingleObject(pi.hProcess, INFINITE);

DWORD exit_code;
if (GetExitCodeProcess(pi.hProcess, &exit_code)) {
if (exit_code != 0) {
LOG_ERROR << "Child process exited with status: " << exit_code;
json_resp["message"] = "Python script execution failed";
status_resp["status_code"] = k500InternalServerError;
}
} else {
LOG_ERROR << "Failed to get exit code: " << GetLastError();
json_resp["message"] = "Failed to get Python script execution status";
status_resp["status_code"] = k500InternalServerError;
}

CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}

DestroyEnvironmentBlock(pEnv);
#else
std::string child_process_exe_path = python_utils::getCurrentExecutablePath();
std::vector<char*> child_process_args;
child_process_args.push_back(const_cast<char*>(child_process_exe_path.c_str()));
child_process_args.push_back(
const_cast<char*>(child_process_exe_path.c_str()));
child_process_args.push_back(const_cast<char*>("--run_python_file"));
child_process_args.push_back(const_cast<char*>(file_execution_path.c_str()));

if (!python_library_path.empty()) {
child_process_args.push_back(const_cast<char*>(python_library_path.c_str()));
child_process_args.push_back(
const_cast<char*>(python_library_path.c_str()));
}
child_process_args.push_back(NULL);

Expand All @@ -105,7 +163,7 @@ void PythonEngine::HandlePythonFileExecutionRequestImpl(
for (char** env = environ; *env != nullptr; env++) {
env_strings.push_back(*env);
}

// Add or modify PYTHONPATH
std::string pythonpath = "PYTHONPATH=" + python_library_path;
env_strings.push_back(pythonpath);
Expand Down
61 changes: 48 additions & 13 deletions src/python_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,25 +102,57 @@ inline std::string GetDirectoryPathFromFilePath(const std::string& file_path) {
}
return "./";
}

inline std::string FindPythonDynamicLib(const std::string& lib_dir) {
std::string pattern;
try {
LOG_INFO << "Entering FindPythonDynamicLib, lib_dir: " << lib_dir;

if (lib_dir.empty()) {
LOG_ERROR << "lib_dir is empty";
return "";
}

std::string pattern;
#if defined(_WIN32) || defined(_WIN64)
pattern = "python[0-9][0-9]+\\.dll";
pattern = "python[0-9][0-9]+\\.dll";
#elif defined(__APPLE__) || defined(__MACH__)
pattern = "libpython[0-9]+\\.[0-9]+\\.dylib";
pattern = "libpython[0-9]+\\.[0-9]+\\.dylib";
#else
pattern = "libpython[0-9]+\\.[0-9]+\\.so.*";
pattern = "libpython[0-9]+\\.[0-9]+\\.so.*";
#endif
std::regex regex_pattern(pattern);
for (const auto& entry : std::filesystem::directory_iterator(lib_dir)) {
std::string file_name = entry.path().filename().string();
if (std::regex_match(file_name, regex_pattern)) {
return entry.path().string();
LOG_INFO << "Pattern: " << pattern;

std::regex regex_pattern(pattern);
LOG_INFO << "Regex pattern compiled successfully";

if (!std::filesystem::exists(lib_dir)) {
LOG_ERROR << "Directory does not exist: " << lib_dir;
return "";
}

if (!std::filesystem::is_directory(lib_dir)) {
LOG_ERROR << "Path is not a directory: " << lib_dir;
return "";
}

LOG_INFO << "Starting directory iteration";
for (const auto& entry : std::filesystem::directory_iterator(lib_dir)) {
std::string file_name = entry.path().filename().string();
LOG_INFO << "File name: " << file_name;
if (std::regex_match(file_name, regex_pattern)) {
LOG_INFO << "Match found: " << entry.path().string();
return entry.path().string();
}
}

LOG_ERROR << "No Python dynamic library found in " << lib_dir;
return "";
} catch (const std::exception& e) {
LOG_ERROR << "Exception in FindPythonDynamicLib: " << e.what();
return "";
} catch (...) {
LOG_ERROR << "Unknown exception in FindPythonDynamicLib";
return "";
}
LOG_ERROR << "No Python dynamic library found in " << lib_dir;
return "";
}

inline void ClearAndSetPythonSysPath(const std::string& default_py_lib_path,
Expand Down Expand Up @@ -183,7 +215,10 @@ inline void ExecutePythonFile(const std::string& binary_exec_path,

std::string effective_py_lib_path = py_lib_path;
if (effective_py_lib_path.empty()) {
effective_py_lib_path = binary_dir_path + "engines/cortex.python/python/";
effective_py_lib_path =
(std::filesystem::path(binary_dir_path) /
std::filesystem::path("engines/cortex.python/python/"))
.string();
LOG_WARN << "No specified Python library path, using default: "
<< effective_py_lib_path;
}
Expand Down
2 changes: 1 addition & 1 deletion third-party/install_python.bat
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
cd %INSTALL_DIR%

echo Downloading Python...
curl -o python-installer.exe https://www.python.org/ftp/python/3.10.4/python-3.10.4-amd64.exe
curl -o python-installer.exe https://www.python.org/ftp/python/3.12.7/python-3.12.7-amd64.exe

echo Installing Python to %INSTALL_DIR%
start /wait python-installer.exe /quiet InstallAllUsers=0 PrependPath=0 TargetDir=%INSTALL_DIR% Include_pip=1 Include_test=0
Expand Down

0 comments on commit 51091b6

Please sign in to comment.