igniter 0.1.2

A simple process manager written in Rust
Documentation
use monitor::file;
use os;

use std::io;
use std::io::Error;
use std::process::{Command, Child};
use serde_json;

type CmdArgs = Vec<Vec<String>>;

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ProcessData {
    pub name: String,
    pub cmd: String,
    #[serde(default)]
    pub monitor_pid: i32,
    #[serde(default)]
    pub child_pid: i32,
    #[serde(default)]
    pub args: CmdArgs,
    #[serde(default)]
    pub retries: i32,
    #[serde(default)]
    pub max_retries: i32,
}

pub struct Process {
  pub data: ProcessData,
}

impl Process {
  pub fn spawn(&mut self) -> Result<Child, Error> {
    let mut command = Command::new(self.data.cmd.clone());
    let args = self.data.args.clone();

    build_args(&mut command, args);

    match command.spawn() {
      Ok(child) => {
        let child_pid = child.id() as i32;  
        let current_pid = os::current_pid();

        self.monitor_pid(current_pid.clone());
        self.child_pid(child_pid.clone());
        self.save_state()?;

        println!("Started child process with PID: {}", child.id().clone());
        
        Ok(child)
      },
      Err(err) => Err(err),
    } 
  }

  pub fn kill(&self) -> os::Result<()> {
    os::kill(self.data.monitor_pid)
  }

  pub fn monitor_pid(&mut self, pid: i32) {
    self.data.monitor_pid = pid;
  }

  pub fn child_pid(&mut self, pid: i32) {
    self.data.child_pid = pid;
  }

  pub fn increment_retries(&mut self) {
    self.data.retries = self.data.retries + 1;
  }

  pub fn should_retry(&self) -> bool {
    self.data.retries <= self.data.max_retries
  }

  pub fn is_active(&self) -> bool {
    match os::ps(self.data.monitor_pid) {
      Some(_) => true,
      None => false
    }
  }

  pub fn save_state(&self) -> io::Result<()> {
    println!("saving state");
    file::save(file::path_from_name(self.data.name.clone()), &self)
  }

  pub fn serialize(&self) -> serde_json::Result<String> {
    serde_json::to_string(&self.data.clone())
  }
}

impl From<String> for Process {
  fn from(data: String) -> Process {
     Process::from(data.as_str())
  }
}

impl<'a> From<&'a str> for Process {
  fn from(data: &'a str) -> Process {
    let process_data: ProcessData = serde_json::from_str(&data).unwrap();

    Process{
      data: process_data,
    }
  }
}

fn build_args(cmd: &mut Command, args: CmdArgs) {
  for a in args {
    cmd.args(&a);
  }
}