OGS
ApplicationsLib::anonymous_namespace{ogs_embedded_python.cpp} Namespace Reference

Classes

struct  PipeCloser
 Custom deleter for FILE handles from popen. More...

Functions

std::optional< std::string > executeCommand (std::string_view command)
 Executes a command and captures its stdout output using popen.
std::optional< std::pair< int, int > > getPythonVersionFromVenv (std::filesystem::path const &venv_path)
 Gets Python version by executing the venv's python executable.
std::filesystem::path findSitePackagesPath (std::filesystem::path const &venv_path)
 Finds site-packages path in the virtual environment.

Function Documentation

◆ executeCommand()

std::optional< std::string > ApplicationsLib::anonymous_namespace{ogs_embedded_python.cpp}::executeCommand ( std::string_view command)

Executes a command and captures its stdout output using popen.

Definition at line 55 of file ogs_embedded_python.cpp.

56{
57 std::array<char, 256> buffer;
58 std::string result;
59
60#ifdef _WIN32
61 std::unique_ptr<FILE, PipeCloser> pipe(_popen(command.data(), "r"));
62#else
63 std::unique_ptr<FILE, PipeCloser> pipe(popen(command.data(), "r"));
64#endif // _WIN32
65
66 if (!pipe)
67 {
68 DBUG("Failed to execute command: {}", command);
69 return std::nullopt;
70 }
71
72 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
73 {
74 result += buffer.data();
75 }
76
77 return result;
78}
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22

References DBUG(), and executeCommand().

Referenced by executeCommand(), and getPythonVersionFromVenv().

◆ findSitePackagesPath()

std::filesystem::path ApplicationsLib::anonymous_namespace{ogs_embedded_python.cpp}::findSitePackagesPath ( std::filesystem::path const & venv_path)

Finds site-packages path in the virtual environment.

Definition at line 140 of file ogs_embedded_python.cpp.

142{
143 namespace fs = std::filesystem;
144
145#ifdef _WIN32
146 // On Windows: venv/Lib/site-packages
147 fs::path const site_packages = venv_path / "Lib" / "site-packages";
148#else
149 // On Unix: venv/lib/pythonX.Y/site-packages
150 auto const version = getPythonVersionFromVenv(venv_path);
151 if (!version.has_value())
152 {
153 OGS_FATAL(
154 "Failed to determine Python version of the virtual environment.");
155 }
156 fs::path const site_packages = venv_path / "lib" /
157 ("python" + std::to_string(version->first) +
158 "." + std::to_string(version->second)) /
159 "site-packages";
160#endif // _WIN32
161
162 if (!fs::exists(site_packages))
163 {
164 OGS_FATAL("site-packages directory not found at '{}'",
165 site_packages.string());
166 }
167
168 return site_packages;
169}
#define OGS_FATAL(...)
Definition Error.h:19
std::optional< std::pair< int, int > > getPythonVersionFromVenv(std::filesystem::path const &venv_path)
Gets Python version by executing the venv's python executable.

References findSitePackagesPath(), getPythonVersionFromVenv(), and OGS_FATAL.

Referenced by findSitePackagesPath().

◆ getPythonVersionFromVenv()

std::optional< std::pair< int, int > > ApplicationsLib::anonymous_namespace{ogs_embedded_python.cpp}::getPythonVersionFromVenv ( std::filesystem::path const & venv_path)

Gets Python version by executing the venv's python executable.

Definition at line 81 of file ogs_embedded_python.cpp.

83{
84 namespace fs = std::filesystem;
85
86 fs::path python_exe;
87#ifdef _WIN32
88 python_exe = venv_path / "Scripts" / "python.exe";
89#else
90 python_exe = venv_path / "bin" / "python";
91#endif // _WIN32
92
93 if (!fs::exists(python_exe))
94 {
95 DBUG("Python executable not found at: {}", python_exe.string());
96 return std::nullopt;
97 }
98
99 std::string const command = "\"" + python_exe.string() + "\" --version";
100 auto const output = executeCommand(command);
101
102 if (!output.has_value())
103 {
104 DBUG("Failed to get Python version from: {}", python_exe.string());
105 return std::nullopt;
106 }
107
108 // Parse output like "Python 3.11.5"
109 std::string_view const out_view(output.value());
110 constexpr std::string_view prefix = "Python ";
111 std::string_view version_part = out_view.substr(prefix.size());
112 int major = 0, minor = 0;
113
114 auto dot = version_part.find('.');
115 if (dot == std::string_view::npos)
116 {
117 DBUG("Failed to parse Python version from: {}", out_view);
118 return std::nullopt;
119 }
120
121 auto parse = [](std::string_view sv, int& value)
122 {
123 auto [ptr, ec] =
124 std::from_chars(sv.data(), sv.data() + sv.size(), value);
125 return ec == std::errc{} && ptr != sv.data();
126 };
127
128 if (!parse(version_part.substr(0, dot), major) ||
129 !parse(version_part.substr(dot + 1), minor))
130 {
131 DBUG("Failed to parse Python version from: {}", out_view);
132 return std::nullopt;
133 }
134
135 DBUG("Detected Python version {}.{} from venv", major, minor);
136 return std::make_pair(major, minor);
137}
std::optional< std::string > executeCommand(std::string_view command)
Executes a command and captures its stdout output using popen.

References DBUG(), executeCommand(), and getPythonVersionFromVenv().

Referenced by findSitePackagesPath(), and getPythonVersionFromVenv().