use pyo3::exceptions::{PyRuntimeError, PyValueError};
use pyo3::prelude::*;
use running_process::{ContainedProcessGroup, DaemonChild, SpawnStdio, SpawnedChild};
use crate::helpers::to_py_err;
#[pyclass(name = "ContainedProcessGroup")]
pub(crate) struct PyContainedProcessGroup {
pub(crate) inner: Option<ContainedProcessGroup>,
pub(crate) wrapped_children: Vec<SpawnedChild>,
pub(crate) daemon_children: Vec<DaemonChild>,
}
#[pymethods]
impl PyContainedProcessGroup {
#[new]
#[pyo3(signature = (originator=None))]
fn new(originator: Option<String>) -> PyResult<Self> {
let group = match originator {
Some(ref orig) => ContainedProcessGroup::with_originator(orig).map_err(to_py_err)?,
None => ContainedProcessGroup::new().map_err(to_py_err)?,
};
Ok(Self {
inner: Some(group),
wrapped_children: Vec::new(),
daemon_children: Vec::new(),
})
}
#[getter]
fn originator(&self) -> Option<String> {
self.inner.as_ref()?.originator().map(String::from)
}
#[getter]
fn originator_value(&self) -> Option<String> {
self.inner.as_ref()?.originator_value()
}
fn spawn(&mut self, argv: Vec<String>) -> PyResult<u32> {
let group = self
.inner
.as_ref()
.ok_or_else(|| PyRuntimeError::new_err("group already closed"))?;
if argv.is_empty() {
return Err(PyValueError::new_err("argv must not be empty"));
}
let mut cmd = std::process::Command::new(&argv[0]);
if argv.len() > 1 {
cmd.args(&argv[1..]);
}
let child = group
.spawn(&mut cmd, SpawnStdio::default())
.map_err(to_py_err)?;
let pid = child.id();
self.wrapped_children.push(child);
Ok(pid)
}
fn spawn_daemon(&mut self, argv: Vec<String>) -> PyResult<u32> {
let group = self
.inner
.as_ref()
.ok_or_else(|| PyRuntimeError::new_err("group already closed"))?;
if argv.is_empty() {
return Err(PyValueError::new_err("argv must not be empty"));
}
let mut cmd = std::process::Command::new(&argv[0]);
if argv.len() > 1 {
cmd.args(&argv[1..]);
}
let child = group.spawn_daemon(&mut cmd).map_err(to_py_err)?;
let pid = child.id();
self.daemon_children.push(child);
Ok(pid)
}
fn close(&mut self) {
self.inner.take();
self.wrapped_children.clear();
self.daemon_children.clear();
}
fn __enter__(slf: Py<Self>) -> Py<Self> {
slf
}
#[pyo3(signature = (_exc_type=None, _exc_val=None, _exc_tb=None))]
fn __exit__(
&mut self,
_exc_type: Option<&Bound<'_, PyAny>>,
_exc_val: Option<&Bound<'_, PyAny>>,
_exc_tb: Option<&Bound<'_, PyAny>>,
) {
self.close();
}
}