23#include <wx/process.h>
39 PYTHON_PROCESS( std::function<
void(
int,
const wxString&,
const wxString&)> aCallback ) :
47 wxLog::GetActiveTarget()->Flush();
52 wxInputStream* processOut = GetInputStream();
58 buffer[ processOut->Read( buffer,
sizeof( buffer ) - 1 ).LastRead() ] =
'\0';
59 output.append( buffer, processOut->LastRead() );
60 bytesRead += processOut->LastRead();
63 processOut = GetErrorStream();
69 buffer[ processOut->Read( buffer,
sizeof( buffer ) - 1 ).LastRead() ] =
'\0';
70 error.append( buffer, processOut->LastRead() );
71 bytesRead += processOut->LastRead();
81 std::function<void(
int,
const wxString&,
const wxString&)>
m_callback;
87 wxFileName
path( aInterpreterPath );
94 const std::function<
void(
int,
const wxString&,
const wxString&)>& aCallback,
95 const wxExecuteEnv* aEnv,
bool aSaveOutput )
103 wxInputStream* processOut = aProcess->GetInputStream();
105 while( aProcess->IsInputOpened() )
107 if( processOut->CanRead() )
110 buffer[processOut->Read( buffer,
sizeof( buffer ) - 1 ).LastRead()] =
'\0';
111 wxString stdOut( buffer, processOut->LastRead() );
112 stdOut = stdOut.BeforeLast(
'\n' );
113 wxLogTrace(
traceApi, wxString::Format(
"Python: %s", stdOut ) );
121 for(
const wxString& arg : aArgs )
123 args.emplace_back( arg.wc_str() );
124 argsStr << arg <<
" ";
127 args.emplace_back(
nullptr );
129 if( wxTheApp->UsesEventLoop() )
132 long pid = wxExecute( args.data(), wxEXEC_ASYNC,
process, aEnv );
136 wxLogTrace(
traceApi, wxString::Format(
"Execute error: process could not be created" ) );
138 aCallback( -1, wxEmptyString,
_(
"Process could not be created" ) );
142 wxLogTrace(
traceApi, wxString::Format(
"Execute: pid %ld", pid ) );
164 wxArrayString out, err;
166 long ret = wxExecute( cmd, out, err, wxEXEC_BLOCK, aEnv );
168 wxString strOut, strErr;
170 for(
const wxString& line : out )
171 strOut << line <<
"\n";
173 for(
const wxString& line : err )
174 strErr << line <<
"\n";
176 aCallback( ret, strOut, strErr );
184 wxString* aStdout, wxString* aStderr,
185 const wxExecuteEnv* aEnv )
189 for(
const wxString& arg : aArgs )
190 argsStr << arg <<
" ";
193 wxArrayString out, err;
195 long ret = wxExecute( cmd, out, err, wxEXEC_BLOCK, aEnv );
197 wxString strOut, strErr;
201 for(
const wxString& line : out )
202 *aStdout << line <<
"\n";
207 for(
const wxString& line : err )
208 *aStderr << line <<
"\n";
218#if defined( __WINDOWS__ )
221 if( pythonExe.IsFileExecutable() )
222 return pythonExe.GetFullPath();
224 wxFileName pythonExe;
228 pythonExe.Assign( wxString::FromUTF8Unchecked( PYTHON_EXECUTABLE ) );
230 if( pythonExe.IsFileExecutable() )
231 return pythonExe.GetFullPath();
238 if( 0 == wxExecute( wxS(
"where pythonw.exe" ),
output, wxEXEC_SYNC ) )
246 if( 0 == wxExecute( wxS(
"which -a python3" ),
output, wxEXEC_SYNC ) )
252 if( 0 == wxExecute( wxS(
"which -a python" ),
output, wxEXEC_SYNC ) )
259 return wxEmptyString;
266 path.AppendDir( wxS(
"python-environments" ) );
267 path.AppendDir( aNamespace );
272 return path.GetPath();
283 wxFileName python( *envPath, wxEmptyString );
286 python.AppendDir(
"Scripts" );
287 python.SetFullName(
"pythonw.exe" );
289 python.AppendDir(
"bin" );
290 python.SetFullName(
"python" );
293 if( !python.IsFileExecutable() )
296 return python.GetFullPath();
static bool EnsurePathExists(const wxString &aPath, bool aPathToFile=false)
Attempts to create a given path if it does not exist.
static wxString GetUserCachePath()
Gets the stock (install) 3d viewer plugins path.
static std::optional< wxString > GetPythonEnvironment(const wxString &aNamespace)
static wxString FindPythonInterpreter()
Searches for a Python intepreter on the user's system.
long Execute(const std::vector< wxString > &aArgs, const std::function< void(int, const wxString &, const wxString &)> &aCallback, const wxExecuteEnv *aEnv=nullptr, bool aSaveOutput=false)
Launches the Python interpreter with the given arguments.
static std::optional< wxString > GetVirtualPython(const wxString &aNamespace)
Returns a full path to the python binary in a venv, if it exists.
long ExecuteSync(const std::vector< wxString > &aArgs, wxString *aStdout=nullptr, wxString *aStderr=nullptr, const wxExecuteEnv *aEnv=nullptr)
wxString m_interpreterPath
PYTHON_MANAGER(const wxString &aInterpreterPath)
static constexpr size_t MAX_OUTPUT_LEN
PYTHON_PROCESS(std::function< void(int, const wxString &, const wxString &)> aCallback)
std::function< void(int, const wxString &, const wxString &)> m_callback
void OnTerminate(int aPid, int aStatus) override
wxString FindKicadFile(const wxString &shortname)
Search the executable file shortname in KiCad binary path and return full file name if found or short...
const wxChar *const traceApi
Flag to enable debug output related to the IPC API and its plugin system.
static PGM_BASE * process
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().