use eyre::{Context, bail, eyre};
use std::{
env::consts::{DLL_PREFIX, DLL_SUFFIX},
ffi::OsStr,
path::Path,
};
pub use dora_message::{config, uhlc};
#[cfg(feature = "build")]
pub mod build;
pub mod descriptor;
pub mod metadata;
pub mod topics;
pub fn adjust_shared_library_path(path: &Path) -> Result<std::path::PathBuf, eyre::ErrReport> {
let file_name = path
.file_name()
.ok_or_else(|| eyre!("shared library path has no file name"))?
.to_str()
.ok_or_else(|| eyre!("shared library file name is not valid UTF8"))?;
if file_name.starts_with("lib") {
bail!("Shared library file name must not start with `lib`, prefix is added automatically");
}
if path.extension().is_some() {
bail!("Shared library file name must have no extension, it is added automatically");
}
let library_filename = format!("{DLL_PREFIX}{file_name}{DLL_SUFFIX}");
let path = path.with_file_name(library_filename);
Ok(path)
}
pub fn get_python_path() -> Result<std::path::PathBuf, eyre::ErrReport> {
if let Ok(uv_path) = get_uv_path() {
let output = std::process::Command::new(&uv_path)
.args(["python", "find"])
.output();
if let Ok(output) = output {
if output.status.success() {
let python_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !python_path.is_empty() {
let path = std::path::PathBuf::from(&python_path);
if path.exists() {
return Ok(path);
}
}
}
}
}
if let Ok(python) = which::which("python") {
if !is_python2(&python) {
return Ok(python);
}
}
which::which("python3").context(
"failed to find a valid Python 3 installation. Make sure that python3 is available.",
)
}
fn is_python2(python_path: &std::path::Path) -> bool {
let output = std::process::Command::new(python_path)
.args(["--version"])
.output();
match output {
Ok(output) => {
let version = if output.stdout.is_empty() {
String::from_utf8_lossy(&output.stderr)
} else {
String::from_utf8_lossy(&output.stdout)
};
version.starts_with("Python 2")
}
Err(_) => false,
}
}
pub fn get_pip_path() -> Result<std::path::PathBuf, eyre::ErrReport> {
let python = match which::which("pip3") {
Ok(python) => python,
Err(_) => which::which("pip")
.context("failed to find `pip3` or `pip`. Make sure that python is available.")?,
};
Ok(python)
}
pub fn get_uv_path() -> Result<std::path::PathBuf, eyre::ErrReport> {
which::which("uv")
.context("failed to find `uv`. Make sure to install it using: https://docs.astral.sh/uv/getting-started/installation/")
}
pub async fn run<S>(program: S, args: &[&str], pwd: Option<&Path>) -> eyre::Result<()>
where
S: AsRef<OsStr>,
{
let mut run = tokio::process::Command::new(program);
run.args(args);
if let Some(pwd) = pwd {
run.current_dir(pwd);
}
if !run.status().await?.success() {
eyre::bail!("failed to run {args:?}");
};
Ok(())
}