cicada 0.7.2

A simple Unix shell.
Documentation
use std::env;
use std::fs::{self, read_dir};
use std::path::Path;

use parsers;
use shell;

fn in_env() -> bool {
    if let Ok(x) = env::var("VIRTUAL_ENV") {
        if x != "" {
            return true;
        }
    }
    false
}

fn get_envs_home() -> String {
    let home_envs;
    match env::var("VIRTUALENV_HOME") {
        Ok(x) => {
            home_envs = x;
        }
        Err(_) => {
            home_envs = String::new();
        }
    }
    home_envs
}

fn list_envs() -> i32 {
    let home_envs = get_envs_home();
    if home_envs == "" {
        println!("you need to set VIRTUALENV_HOME to use vox");
        return 1;
    }
    if !Path::new(home_envs.as_str()).exists() {
        match fs::create_dir_all(home_envs.as_str()) {
            Ok(_) => {}
            Err(e) => println!("fs create_dir_all failed: {:?}", e),
        }
    }

    println!("Envs under: {}", home_envs);
    let pdir = home_envs.clone();
    if let Ok(list) = read_dir(home_envs) {
        for ent in list {
            if let Ok(ent) = ent {
                let ent_name = ent.file_name();
                if let Ok(path) = ent_name.into_string() {
                    let full_path = format!("{}/{}/bin/activate", pdir, path);
                    if !Path::new(full_path.as_str()).exists() {
                        continue;
                    }
                    println!("{}", path);
                }
            }
        }
    }
    0
}

fn enter_env(sh: &shell::Shell, path: &str) -> i32 {
    if in_env() {
        println!("vox: already in env");
        return 1;
    }
    let home_envs = get_envs_home();
    let full_path = format!("{}/{}/bin/activate", home_envs, path);
    if !Path::new(full_path.as_str()).exists() {
        println!("no such env: {}", full_path);
        return 1;
    }
    let path_env = format!("{}/{}", home_envs, path);
    env::set_var("VIRTUAL_ENV", &path_env);
    let mut path_new = String::from("${VIRTUAL_ENV}/bin:$PATH");
    shell::extend_env(sh, &mut path_new);
    env::set_var("PATH", &path_new);
    0
}

fn exit_env(sh: &shell::Shell) -> i32 {
    if !in_env() {
        println!("vox: not in an env");
        return 0;
    }
    let env_path;
    match env::var("PATH") {
        Ok(x) => env_path = x,
        Err(_) => {
            println!("vox: cannot read PATH env");
            return 1;
        }
    }
    let mut _tokens: Vec<&str> = env_path.split(':').collect();
    let mut path_virtual_env = String::from("${VIRTUAL_ENV}/bin");
    shell::extend_env(sh, &mut path_virtual_env);
    _tokens.iter().position(|&n| n == path_virtual_env).map(
        |e| {
            _tokens.remove(e)
        },
    );
    let env_path_new = _tokens.join(":");
    env::set_var("PATH", &env_path_new);
    env::set_var("VIRTUAL_ENV", "");
    0
}

pub fn run(sh: &shell::Shell, tokens: &Vec<(String, String)>) -> i32 {
    let args = parsers::parser_line::tokens_to_args(&tokens);
    if args.len() == 2 && args[1] == "ls" {
        list_envs()
    } else if args.len() == 3 && args[1] == "enter" {
        enter_env(sh, args[2].as_str())
    } else if args.len() == 2 && args[1] == "exit" {
        exit_env(sh)
    } else {
        println!("vox: invalid command");
        println!("vox (ls | enter <env-name> | exit)");
        1
    }
}