sticks 0.3.1

A tool for managing C and C++ projects
Documentation
use anyhow::{Context, Result};
use std::fs;
use std::path::Path;

pub fn add_dependencies(dependency_names: &[String]) -> Result<()> {
	if !Path::new("Makefile").exists() {
		anyhow::bail!("Makefile not found in the current directory");
	}

	let mut makefile_content = fs::read_to_string("Makefile").context("Failed to read Makefile")?;

	if !makefile_content.contains("all: clean install-deps") {
		makefile_content = makefile_content.replace("all: clean", "all: clean install-deps");
	}

	let install_deps_prefix = "sudo apt install -y";

	let install_deps_line =
		if let Some(install_deps_pos) = makefile_content.find(install_deps_prefix) {
			let existing_deps_start = install_deps_pos + install_deps_prefix.len();
			let existing_deps = &makefile_content[existing_deps_start..]
				.lines()
				.next()
				.unwrap_or("")
				.trim();
			existing_deps.to_string()
		} else {
			String::new()
		};

	let mut current_deps: Vec<String> = install_deps_line
		.split_whitespace()
		.map(|s| s.to_string())
		.collect();

	let mut added_deps = Vec::new();

	for dep in dependency_names {
		if !current_deps.contains(dep) {
			current_deps.push(dep.clone());
			added_deps.push(dep);
		}
	}

	if added_deps.is_empty() {
		println!("All dependencies are already present.");
		return Ok(());
	}

	let new_install_deps_line = format!("{} {}", install_deps_prefix, current_deps.join(" "));

	if makefile_content.contains(install_deps_prefix) {
		makefile_content = makefile_content.replace(install_deps_prefix, &new_install_deps_line);
	} else {
		makefile_content.push_str(&format!("\ninstall-deps:\n\t{}\n", new_install_deps_line));
	}

	fs::write("Makefile", makefile_content).context("Failed to write updated Makefile")?;

	println!("Added dependencies: {:?}", added_deps);

	Ok(())
}

pub fn remove_dependencies(dependency_names: &[String]) -> Result<()> {
	const MAKEFILE: &str = "Makefile";
	const INSTALL_DEPS_PREFIX: &str = "sudo apt install -y";

	if !Path::new(MAKEFILE).exists() {
		anyhow::bail!("Makefile not found in the current directory");
	}

	let makefile_content = fs::read_to_string(MAKEFILE)?;
	let lines: Vec<&str> = makefile_content.lines().collect();
	let mut updated_lines: Vec<String> = Vec::new();
	let mut i = 0;
	let mut install_deps_found = false;
	let mut dependencies_removed = false;

	while i < lines.len() {
		let line = lines[i];

		if line.starts_with("all:") {
			let parts: Vec<&str> = line.split(':').collect();
			if parts.len() >= 2 {
				let targets: Vec<&str> = parts[1]
					.split_whitespace()
					.filter(|t| *t != "install-deps")
					.collect();
				if !targets.is_empty() {
					updated_lines.push(format!("all: {}", targets.join(" ")));
				} else {
					updated_lines.push("all: clean".to_string());
				}
			} else {
				updated_lines.push(line.to_string());
			}
		} else if line.starts_with("install-deps:") {
			install_deps_found = true;
			if i + 1 < lines.len() {
				let cmd_line = lines[i + 1];
				if cmd_line.trim_start().starts_with(INSTALL_DEPS_PREFIX) {
					let deps_str = cmd_line.trim_start()[INSTALL_DEPS_PREFIX.len()..].trim();
					let mut current_deps: Vec<String> =
						deps_str.split_whitespace().map(String::from).collect();
					let original_len = current_deps.len();
					current_deps.retain(|dep| !dependency_names.contains(dep));
					let removed = original_len - current_deps.len();

					if removed > 0 {
						dependencies_removed = true;
						if !current_deps.is_empty() {
							updated_lines.push("install-deps:".to_string());
							updated_lines.push(format!(
								"\t{} {}",
								INSTALL_DEPS_PREFIX,
								current_deps.join(" ")
							));
						} else {
							println!(
								"All specified dependencies removed. Removing install-deps rule."
							);
						}
					} else {
						updated_lines.push(line.to_string());
						if i + 1 < lines.len() {
							updated_lines.push(lines[i + 1].to_string());
						}
					}
				} else {
					updated_lines.push(line.to_string());
				}
				i += 1;
			} else {
				updated_lines.push(line.to_string());
			}
		} else {
			updated_lines.push(line.to_string());
		}

		i += 1;
	}

	if dependencies_removed && install_deps_found {
		println!("Dependencies {:?} removed from Makefile.", dependency_names);
	} else {
		println!("Dependencies {:?} not found in Makefile.", dependency_names);
	}

	fs::write(MAKEFILE, updated_lines.join("\n")).context("Failed to write updated Makefile")?;
	Ok(())
}