limp/
files.rs

1use std::{
2    fs::{self, File},
3    io::Write,
4    path::{Path, PathBuf},
5    process::Stdio,
6};
7
8use crate::{error::LimpError, parser::load_from_deps, storage::JsonDependency};
9
10const MAIN_SNIP: &str = r#"fn main() {
11    println!("Hello, limp!");
12}"#;
13
14pub fn username() -> String {
15    std::env::var("USER").unwrap_or(std::env::var("USERNAME").unwrap_or("unknown".to_string()))
16}
17
18pub fn storage_path() -> PathBuf {
19    let uname = username();
20
21    match std::env::consts::OS {
22        "windows" => PathBuf::from(format!("C:\\Users\\{}\\AppData\\Roaming\\limp", &uname)),
23        _ => PathBuf::from(format!("/home/{}/.config/limp/", &uname)),
24    }
25}
26
27pub fn config_path() -> PathBuf {
28    storage_path().join("dependencies.json")
29}
30
31pub fn snippets_dir() -> PathBuf {
32    storage_path().join("snippets")
33}
34
35pub fn find_toml() -> Option<PathBuf> {
36    if let Ok(mut path) = std::env::current_dir() {
37        let pre_toml = path.join("Cargo.toml");
38        if pre_toml.exists() {
39            return Some(pre_toml);
40        }
41        while path.pop() {
42            let pre_toml = path.join("Cargo.toml");
43            if pre_toml.exists() {
44                return Some(pre_toml);
45            }
46        }
47        return None;
48    }
49    None
50}
51
52pub fn open<P: AsRef<Path>>(path: P) -> Result<File, LimpError> {
53    let path = path.as_ref();
54    fs::create_dir_all(path.parent().unwrap_or(Path::new("./")))?;
55    let file = File::options()
56        .read(true)
57        .append(true)
58        .create(true)
59        .open(path)?;
60    Ok(file)
61}
62
63pub fn add_to_snippets_dir(name: &str, content: &str) -> Result<String, LimpError> {
64    let path = snippets_dir().join(format!("{name}.rs"));
65    if path.exists() {
66        return Err(LimpError::SnippetExists(name.to_string()));
67    }
68    let mut file = open(&path)?;
69    file.write_all(content.as_bytes())?;
70    Ok(path.display().to_string())
71}
72
73pub fn remove_from_snippets_dir(name: &str) -> Result<(), LimpError> {
74    let path = snippets_dir().join(format!("{name}.rs"));
75    if !path.exists() {
76        // This means the snippet doesn't provided by the user and nothing to remove
77        return Ok(());
78    }
79    fs::remove_file(path)?;
80    Ok(())
81}
82
83pub fn create_project(name: &str, deps: Option<&[JsonDependency]>) -> Result<(), LimpError> {
84    let project = PathBuf::from(format!("./{}", name));
85    if project.exists() && project.read_dir()?.count() > 0 {
86        return Err(LimpError::CrateExistsNotEmpty(name.to_string()));
87    }
88
89    let mut main_snippet = MAIN_SNIP.to_string();
90    let mut toml = open(project.join("Cargo.toml"))?;
91    writeln!(toml, "[package]")?;
92    writeln!(toml, "name = \"{}\"", name)?;
93    writeln!(toml, "version = \"0.1.0\"")?;
94    writeln!(toml, "edition = \"2021\"")?;
95    writeln!(toml)?;
96    writeln!(toml, "[dependencies]")?;
97    if let Some(deps) = deps {
98        for dep in deps.iter() {
99            writeln!(toml, "{}", dep)?
100        }
101        main_snippet = load_from_deps(deps).unwrap_or(MAIN_SNIP.to_string());
102    }
103
104    let mut main = open(project.join("src").join("main.rs"))?;
105    main.write_all(main_snippet.as_bytes())?;
106
107    if !std::process::Command::new("git")
108        .args(["init", name])
109        .stdout(Stdio::null())
110        .stderr(Stdio::null())
111        .spawn()?
112        .wait()?
113        .success()
114    {
115        return Err(LimpError::GitError(name.to_string()));
116    }
117    let mut gitignore = open(project.join(".gitignore"))?;
118    gitignore.write_all(b"/target")?;
119
120    Ok(())
121}