devpane 0.2.0

A terminal-first multi-process workspace and development dashboard
use std::collections::HashMap;
use std::path::PathBuf;
use std::process::{Child, Command, Stdio};
use std::{fs, io};

use super::platform;
use super::session::{ProcessSession, ProcessStatus};
use crate::error::DevboxError;
use crate::storage::get_log_file;
use uuid::Uuid;

pub fn start_process(
    name: String,
    program: String,
    args: Vec<String>,
    cwd: PathBuf,
    env: HashMap<String, String>,
    project_dir: Option<PathBuf>,
) -> Result<(Child, ProcessSession), DevboxError> {
    let id = Uuid::new_v4().to_string();

    let file = fs::OpenOptions::new()
        .create(true)
        .append(true)
        .open(get_log_file(&id)?)
        .map_err(DevboxError::FileOperation)?;

    let stdout_file = file.try_clone().map_err(DevboxError::FileOperation)?;

    let child = Command::new(&program)
        .args(args)
        .current_dir(&cwd)
        .envs(env)
        .stdout(Stdio::from(stdout_file))
        .stderr(Stdio::from(file))
        .spawn()
        .map_err(DevboxError::ProcessLaunch)?;

    let pid = child.id();

    let (start_time_seconds, start_time_useconds) = match platform::get_process_start_time(pid) {
        Ok(value) => value,
        Err(error) => {
            let _ = platform::stop_process(pid);
            return Err(DevboxError::ProcessCheck(error));
        }
    };

    let session = ProcessSession {
        id,
        pid,
        name,
        command: program,
        start_time_seconds,
        start_time_useconds,
        status: ProcessStatus::Running,
        exit_code: None,
        project_dir,
        cwd,
    };

    println!("Started {} with PID {}", session.name, session.pid);

    Ok((child, session))
}

pub use platform::stop_process;

pub fn is_same_process(session: &ProcessSession) -> Result<bool, io::Error> {
    if !platform::is_process_active(session.pid)? {
        return Ok(false);
    }

    let (current_start_time_seconds, current_start_time_useconds) =
        platform::get_process_start_time(session.pid)?;

    Ok(current_start_time_seconds == session.start_time_seconds
        && current_start_time_useconds == session.start_time_useconds)
}