#!/usr/bin/env rust-script //! ```cargo //! [dependencies] //! anyhow = "1.0.75" //! dirs = "5.0.1" //! ``` use anyhow::{anyhow, bail, Context}; use std::{ fs::{self, File}, io::{BufRead, BufReader, ErrorKind}, }; const ENV: &str = r#". "$HOME/.cargo/env""#; // until the release of https://github.com/rust-lang/rustup/pull/3506/files const ENV_FISH: &str = r#"set -x PATH "$HOME/.cargo/bin" $PATH"#; fn main() -> anyhow::Result<()> { let home = dirs::home_dir().context("can't find home directory")?; let mut login_path = home.clone(); login_path.push(".bash_login"); let login = match File::open(&login_path) { Ok(file) => { let login = BufReader::new(file); let mut skip = false; let mut new_login = String::new(); let mut removed = false; let mut added = false; for line in login.lines() { let line = line.context("failed to read line in ~/.bash_login")?; if line.is_empty() && skip { continue; } skip = line.is_empty(); if line == ENV { removed = true; } else { new_login.push_str(&line); new_login.push('\n'); } if line == "# custom" && !added { added = true; new_login.push('\n'); new_login.push_str(ENV); new_login.push_str("\n\n"); skip = true; } } if removed && !added { bail!("would remove \"{ENV}\" and not add it back"); } new_login.trim().to_owned() + "\n" } Err(e) if e.kind() == ErrorKind::NotFound => format!("# custom\n\n{ENV}\n"), Err(e) => bail!(anyhow!(e).context("failed to read ~/.bash_login")), }; fs::write(login_path, &login).context("failed to write new ~/.bash_login")?; let mut bashrc_path = home.clone(); bashrc_path.push(".bashrc"); let bashrc = match File::open(&bashrc_path) { Ok(file) => { let bashrc = BufReader::new(file); let mut skip = false; let mut new_bashrc = String::new(); for line in bashrc.lines() { let line = line.context("failed to read line in ~/.bashrc")?; if line.is_empty() && skip { continue; } skip = line.is_empty(); if line != ENV { new_bashrc.push_str(&line); new_bashrc.push('\n'); } } new_bashrc.trim().to_owned() + "\n" } Err(e) if e.kind() == ErrorKind::NotFound => "# custom\n".to_owned(), Err(e) => bail!(anyhow!(e).context("failed to read ~/.bashrc")), }; fs::write(bashrc_path, &bashrc).context("failed to write new ~/.bashrc")?; let mut config_fish_path = dirs::config_dir().context("can't find config directory")?; config_fish_path.push("fish"); fs::create_dir_all(&config_fish_path)?; config_fish_path.push("config.fish"); let config_fish = match File::open(&config_fish_path) { Ok(file) => { let config_fish = BufReader::new(file); let mut skip = false; let mut new_config_fish = String::new(); for line in config_fish.lines() { let line = line.context("failed to read line in config.fish")?; if line.is_empty() && skip { continue; } skip = line.is_empty(); if line != ENV_FISH { new_config_fish.push_str(&line); new_config_fish.push('\n'); } } new_config_fish.trim().to_owned() + "\n" } Err(e) if e.kind() == ErrorKind::NotFound => String::new(), Err(e) => bail!(anyhow!(e).context("failed to read config.fish")), }; fs::write(config_fish_path, &config_fish).context("failed to write new config.fish")?; Ok(()) }