<commit_before>use std::fs;
use std::path::Path;
use tilde_expand::tilde_expand;

use super::super::results::{BearerResult, BearerError};


pub fn build_path(config_dir: &str, client_name: &str) -> BearerResult<(String, bool)> {

    let config_dir_expanded = tilde_expand(config_dir.as_bytes());
    let config_dir_expanded = String::from_utf8(config_dir_expanded);
    if let Err(err) = config_dir_expanded {
        return Err(BearerError::UTF8EncodingError(
            format!("Cannot build path from config dir {}: {:?}",
                    config_dir,
                    err)));
    }
    let config_dir_expanded = config_dir_expanded.unwrap();
    let path = config_dir_expanded.clone();
    let path = Path::new(path.as_str());
    if !path.exists() {
        debug!("Creating the config dir {}, path not exists", config_dir);
        let res = fs::create_dir_all(&config_dir_expanded);
        if let Err(err) = res {
            return Err(BearerError::IOError(
                format!("Could not create directory {}: {}",
                        config_dir_expanded,
                        err)));
        }
    } else if !path.is_dir() {
        return Err(BearerError::ValueError(
            format!("Path {} is not a directory",
                    config_dir_expanded)));
    }


    let path = path.join(format!("{}.toml", client_name));

    match path.to_str() {
        Some(string) => Ok((string.to_string(), path.is_file())),
        None => {
            Err(BearerError::UTF8EncodingError(
                format!("Could not build path with config dir {} and client {}",
                        config_dir_expanded,
                        client_name)))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::fs;
    use std::path::Path;
    use rand::{thread_rng, Rng};

    #[test]
    fn test_build_path_exists() {
        let (path, exists) = build_path(
            "src/tests/conf", "dummy_with_tokens").unwrap();
        assert_eq!(exists, true);
        assert!(path.ends_with("src/tests/conf/dummy_with_tokens.toml"));
    }

    #[test]
    fn test_build_path_not_exists() {
        let (path, exists) = build_path(
            "src/tests/conf", "not_exists").unwrap();
        assert_eq!(exists, false);
        assert!(path.ends_with("src/tests/conf/not_exists.toml"));
    }

    #[test]
    fn test_build_path_create_dir() {
        let rnd: String = thread_rng().gen_ascii_chars().take(10).collect();

        let tmpdir = format!("/tmp/test-bearer-{}", rnd);

        let dirpath = Path::new(tmpdir.as_str());
        assert_eq!(dirpath.exists(), false);

        let (path, exists) = build_path(
            tmpdir.as_str(), "not_exists").unwrap();
        assert_eq!(exists, false);

        let tmpdir = format!("/tmp/test-bearer-{}", rnd);
        let filepath = format!("{}/not_exists.toml", tmpdir);

        assert_eq!(path, filepath);

        let filepath = Path::new(filepath.as_str());

        assert_eq!(dirpath.exists(), true);
        assert_eq!(filepath.exists(), false);

        fs::remove_dir_all(tmpdir).unwrap();
    }

}<commit_msg>Add the list clients helper<commit_after>use std::fs;
use std::path::Path;
use std::vec::Vec;
use tilde_expand::tilde_expand;

use super::super::results::{BearerResult, BearerError};


fn expand_path(config_dir: &str) -> BearerResult<String> {
    let config_dir_expanded = tilde_expand(config_dir.as_bytes());
    let config_dir_expanded = String::from_utf8(config_dir_expanded);
    if let Err(err) = config_dir_expanded {
        return Err(BearerError::UTF8EncodingError(
            format!("Cannot build path from config dir {}: {:?}",
                    config_dir,
                    err)));
    }
    Ok(config_dir_expanded.unwrap())
}


pub fn build_path(config_dir: &str, client_name: &str) -> BearerResult<(String, bool)> {

    let config_dir_expanded = expand_path(config_dir)?;
    let path = config_dir_expanded.clone();
    let path = Path::new(path.as_str());
    if !path.exists() {
        debug!("Creating the config dir {}, path not exists", config_dir);
        let res = fs::create_dir_all(&config_dir_expanded);
        if let Err(err) = res {
            return Err(BearerError::IOError(
                format!("Could not create directory {}: {}",
                        config_dir_expanded,
                        err)));
        }
    } else if !path.is_dir() {
        return Err(BearerError::ValueError(
            format!("Path {} is not a directory",
                    config_dir_expanded)));
    }


    let path = path.join(format!("{}.toml", client_name));

    match path.to_str() {
        Some(string) => Ok((string.to_string(), path.is_file())),
        None => {
            Err(BearerError::UTF8EncodingError(
                format!("Could not build path with config dir {} and client {}",
                        config_dir_expanded,
                        client_name)))
        }
    }
}


pub fn list_clients(config_dir: &str) -> BearerResult<Vec<String>> {
    let config_dir_expanded = expand_path(config_dir)?;
    let path = config_dir_expanded.clone();
    let path = Path::new(path.as_str());
    if !path.is_dir() {
        return Err(BearerError::ValueError(
            format!("Path {} is not a directory",
                    config_dir_expanded)));
    }
    let paths = fs::read_dir(path).unwrap();
    let mut ret = paths.map(
            |pth| pth.unwrap().path().file_name().unwrap().to_str().unwrap().to_string()
        ).filter(
            |pth| pth.ends_with(".toml")
        ).map(
            |pth| pth.as_str()[..pth.len() - 5].to_string()
        ).collect::<Vec<String>>();
    ret.sort();
    Ok(ret)
}


#[cfg(test)]
mod tests {
    use super::*;

    use std::fs;
    use std::path::Path;
    use rand::{thread_rng, Rng};

    #[test]
    fn test_build_path_exists() {
        let (path, exists) = build_path(
            "src/tests/conf", "dummy_with_tokens").unwrap();
        assert_eq!(exists, true);
        assert!(path.ends_with("src/tests/conf/dummy_with_tokens.toml"));
    }

    #[test]
    fn test_build_path_not_exists() {
        let (path, exists) = build_path(
            "src/tests/conf", "not_exists").unwrap();
        assert_eq!(exists, false);
        assert!(path.ends_with("src/tests/conf/not_exists.toml"));
    }

    #[test]
    fn test_build_path_create_dir() {
        let rnd: String = thread_rng().gen_ascii_chars().take(10).collect();

        let tmpdir = format!("/tmp/test-bearer-{}", rnd);

        let dirpath = Path::new(tmpdir.as_str());
        assert_eq!(dirpath.exists(), false);

        let (path, exists) = build_path(
            tmpdir.as_str(), "not_exists").unwrap();
        assert_eq!(exists, false);

        let tmpdir = format!("/tmp/test-bearer-{}", rnd);
        let filepath = format!("{}/not_exists.toml", tmpdir);

        assert_eq!(path, filepath);

        let filepath = Path::new(filepath.as_str());

        assert_eq!(dirpath.exists(), true);
        assert_eq!(filepath.exists(), false);

        fs::remove_dir_all(tmpdir).unwrap();
    }

    #[test]
    fn test_list_clients_ok() {
        let clients = list_clients("src/tests/conf").unwrap();
        assert_eq!(
            clients.as_slice(),
            &["dummy", "dummy_with_tokens", "invalid"]
        )
    }

    #[test]
    fn test_list_clients_err() {
        let err = list_clients("not/an/existings/directory");
        assert_eq!(err.is_err(), true);
        let err = err.unwrap_err();
        assert_eq!(
            err,
            BearerError::ValueError("".to_string())
        )
    }
}
{'fraction_non_alphanumeric': 0.1530398322851153, 'fraction_numerical': 0.001441299790356394, 'mean_word_length': 2.4290206648697215, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5858820', 'n_tokens_mistral': 2445, 'n_tokens_neox': 2418, 'n_words': 443}