diff options
| author | 2026-02-26 12:40:51 -0500 | |
|---|---|---|
| committer | 2026-02-26 12:40:51 -0500 | |
| commit | 8c411011aadfd96e7189366f20dda87b26a50cbf (patch) | |
| tree | 766b0d2e6d75c63c3fca1ffc0d3359064e83c0fe | |
| parent | updates to add, remove and list (diff) | |
add build support
| -rw-r--r-- | Cargo.lock | 79 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/action.rs | 67 | ||||
| -rw-r--r-- | src/config.rs | 25 | ||||
| -rw-r--r-- | src/main.rs | 1 | ||||
| -rw-r--r-- | src/util.rs | 22 |
6 files changed, 164 insertions, 32 deletions
@@ -38,6 +38,12 @@ dependencies = [ ] [[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -49,6 +55,8 @@ version = "0.1.0" dependencies = [ "git2", "libc", + "serde", + "toml", ] [[package]] @@ -88,6 +96,12 @@ dependencies = [ ] [[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] name = "icu_collections" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -190,6 +204,16 @@ dependencies = [ ] [[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] name = "jobserver" version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -327,6 +351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -350,6 +375,15 @@ dependencies = [ ] [[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + +[[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -400,6 +434,45 @@ dependencies = [ ] [[package]] +name = "toml" +version = "1.0.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7614eaf19ad818347db24addfa201729cf2a9b6fdfd9eb0ab870fcacc606c0c" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.0.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" + +[[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -439,6 +512,12 @@ dependencies = [ ] [[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" + +[[package]] name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6,3 +6,5 @@ edition = "2024" [dependencies] git2 = "0.20.4" libc = "0.2.182" +serde = { version = "1.0.228", features = ["derive"] } +toml = "1.0.3" diff --git a/src/action.rs b/src/action.rs index cd3b32b..b94c8b3 100644 --- a/src/action.rs +++ b/src/action.rs @@ -1,7 +1,11 @@ -use crate::util::{TEMP_CONFIG_PATH, create_config, dir_size, get_editor, is_root, open_in_editor, yn_prompt}; +use crate::config::Config; +use crate::util::{ + TEMP_CONFIG_PATH, create_config, dir_size, get_editor, is_root, open_in_editor, yn_prompt, +}; use git2::Repository; use std::fs; use std::path::{Path, PathBuf}; +use std::process::Command; const BASE_REPO_PATH: &str = "/var/db/forge"; const BASE_CONFIG_PATH: &str = "/etc/forge/packages"; @@ -74,6 +78,32 @@ impl Action { } } +//========================================= +// command helpers +//========================================= + +fn build(config_path: PathBuf, repo_path: PathBuf) -> Result<(), String> { + let config = Config::new(config_path); + if let Some(bld) = config.unwrap().build { + let status = Command::new(bld) + .current_dir(repo_path) + .status() + .map_err(|e| format!("failed to execute editor: {}", e))?; + + if !status.success() { + return Err(format!("editor exited with non-zero status: {}", status)); + } + } else { + return Err("no build command found".to_string()); + } + + Ok(()) +} + +//========================================= +// commands +//========================================= + fn add(url: &str) -> Result<(), String> { if !is_root() { return Err("add must be run as root".to_string()); @@ -85,10 +115,7 @@ fn add(url: &str) -> Result<(), String> { }; let config_name = format!("{repo_name}.toml"); - println!( - "Creating config: {}", - config_name - ); + println!("Creating config: {}", config_name); create_config(repo_name)?; let editor = get_editor(); @@ -96,26 +123,29 @@ fn add(url: &str) -> Result<(), String> { open_in_editor(&editor, &config_temp)?; let clone_path = PathBuf::from(BASE_REPO_PATH).join(repo_name); - let repo = Repository::clone(url, &clone_path).map_err(|e| { - format!("failed to clone {}: {}", repo_name, e) - })?; + let repo = Repository::clone(url, &clone_path) + .map_err(|e| format!("failed to clone {}: {}", repo_name, e))?; let mut config_path = PathBuf::from(BASE_CONFIG_PATH); if !config_path.exists() { - fs::create_dir_all(&config_path).map_err(|e| { - format!("failed to create config directory: {}", e) - })?; + fs::create_dir_all(&config_path) + .map_err(|e| format!("failed to create config directory: {}", e))?; } config_path.push(config_name); - fs::rename(config_temp, config_path).map_err(|e| format!("failed to place config in system directory: {}", e))?; + fs::rename(config_temp, &config_path) + .map_err(|e| format!("failed to place config in system directory: {}", e))?; println!( - "New package initialized at: {}", + "New package initialized at: {}\n", repo.path().to_str().unwrap() ); + if yn_prompt("Run build and install commands?") { + build(config_path, clone_path)?; + } + Ok(()) } @@ -174,12 +204,8 @@ fn remove(packages: Vec<String>) -> Result<(), String> { if yn_prompt("Proceed with removal?") { for (name, path, cfg_path) in package_paths { - fs::remove_dir_all(&path).map_err(|e| { - format!("failed to remove {}: {}", name, e) - })?; - fs::remove_file(&cfg_path).map_err(|e| { - format!("failed to remove {}: {}", name, e) - })?; + fs::remove_dir_all(&path).map_err(|e| format!("failed to remove {}: {}", name, e))?; + fs::remove_file(&cfg_path).map_err(|e| format!("failed to remove {}: {}", name, e))?; println!("Removed {}", name); } } @@ -190,7 +216,8 @@ fn remove(packages: Vec<String>) -> Result<(), String> { fn list() -> Result<(), String> { let config_path = Path::new(BASE_CONFIG_PATH); for entry in fs::read_dir(config_path) - .map_err(|e| format!("failed to iterate package directory: {}", e))? { + .map_err(|e| format!("failed to iterate package directory: {}", e))? + { let entry = entry.map_err(|e| e.to_string())?; let path = entry.path(); if path.is_file() { diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..f168b27 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,25 @@ +use serde::Deserialize; +use std::fs; +use std::path::Path; + +#[derive(Deserialize)] +pub struct Config { + pub update: Option<String>, + pub build: Option<String>, + pub install: Option<String>, + pub dependencies: Option<Vec<String>>, +} + +impl Config { + pub fn new<P: AsRef<Path>>(filepath: P) -> Option<Self> { + let contents = match fs::read_to_string(filepath) { + Ok(c) => c, + Err(_) => { + eprintln!("no package config found"); + return None; + } + }; + let config: Config = toml::from_str(&contents).expect("failed to parse config"); + Some(config) + } +} diff --git a/src/main.rs b/src/main.rs index ff71155..fa0ee11 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use std::{env, fs}; use crate::util::TEMP_CONFIG_PATH; mod action; +mod config; mod util; fn main() { diff --git a/src/util.rs b/src/util.rs index ae114d0..caa2c73 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,3 +1,4 @@ +use libc; use std::env; use std::fs; use std::io; @@ -5,7 +6,6 @@ use std::io::Write; use std::path::Path; use std::path::PathBuf; use std::process::Command; -use libc; pub const TEMP_CONFIG_PATH: &str = "/var/lib/forge/.tmp"; @@ -14,9 +14,8 @@ pub fn create_config(package: &str) -> Result<(), String> { let mut path = PathBuf::from(TEMP_CONFIG_PATH); if !path.exists() { - fs::create_dir_all(&path).map_err(|e| { - format!("failed to create temp config directory: {}", e) - })?; + fs::create_dir_all(&path) + .map_err(|e| format!("failed to create temp config directory: {}", e))?; } path.push(filename); @@ -25,14 +24,12 @@ pub fn create_config(package: &str) -> Result<(), String> { r#"# {package} configuration update = "tagged" # no | live | tagged build = "make" -dependencies = [] install = "make install" +dependencies = [] "# ); - fs::write(path, template).map_err(|e| { - format!("failed to create config: {}", e) - })?; + fs::write(path, template).map_err(|e| format!("failed to create config: {}", e))?; Ok(()) } @@ -60,13 +57,14 @@ pub fn get_editor() -> String { } pub fn is_root() -> bool { - unsafe { libc::geteuid() == 0} + unsafe { libc::geteuid() == 0 } } pub fn open_in_editor(editor: &str, file: &str) -> Result<(), String> { - let status = Command::new(editor).arg(file).status().map_err(|e| { - format!("failed to execute editor: {}", e) - })?; + let status = Command::new(editor) + .arg(file) + .status() + .map_err(|e| format!("failed to execute editor: {}", e))?; if !status.success() { return Err(format!("editor exited with non-zero status: {}", status)); |
