diff --git a/pkgr/src/commands.rs b/pkgr/src/commands.rs index 8c7996e..6d8e139 100644 --- a/pkgr/src/commands.rs +++ b/pkgr/src/commands.rs @@ -5,6 +5,8 @@ use clap::{Parser, Subcommand}; use log::{debug, error, info, trace, warn}; use manifest::Manifest; use std::process::exit; +use crate::CONFIG; +use crate::process::Process; #[derive(Parser, Debug)] #[clap(name = "pkgr", version)] @@ -69,7 +71,7 @@ impl Command { } trace!("Starting install..."); - match pkg.install() { + match pkg.install(CONFIG.with(|c| if !*build { c.build_by_default } else { *build })) { Ok(_) => (), Err(e) => { error!("Install failed: {}", e.to_string()); @@ -110,6 +112,12 @@ impl Command { info!("Info message."); warn!("Warning message."); error!("Error message."); + + info!(""); + Process::command(vec!["sh", "-c", "echo whoami: $(whoami)"].iter_mut().map(|s| s.to_string()).collect()) + .spawn() + .unwrap(); + info!(""); info!("PKGR VERSION: {}", env!("CARGO_PKG_VERSION")); info!("PKGR AUTHORS: {}", env!("CARGO_PKG_AUTHORS")); diff --git a/pkgr/src/config/mod.rs b/pkgr/src/config/mod.rs new file mode 100644 index 0000000..29f4936 --- /dev/null +++ b/pkgr/src/config/mod.rs @@ -0,0 +1,27 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Config { + #[serde(default)] + pub build_by_default: bool, +} + +impl Config { + pub fn from_path(path: &str) -> Result { + match std::fs::read_to_string(path) { + Ok(s) => match toml::from_str(&s) { + Ok(c) => Ok(c), + Err(e) => Err(format!("failed to parse config: {}", e)), + }, + Err(e) => Err(format!("failed to read config: {}", e)), + } + } +} + +impl Default for Config { + fn default() -> Config { + Config { + build_by_default: false, + } + } +} \ No newline at end of file diff --git a/pkgr/src/main.rs b/pkgr/src/main.rs index cb73e53..97f721f 100644 --- a/pkgr/src/main.rs +++ b/pkgr/src/main.rs @@ -10,13 +10,18 @@ mod logging; mod package; mod process; mod tmpfs; +mod config; + +thread_local! { + static CONFIG: config::Config = config::Config::from_path("/etc/pkgr.toml") + .unwrap_or(config::Config::default()); +} fn main() { logging::setup_logger().expect("Unable to setup logger."); #[cfg(not(debug_assertions))] { - #[cfg(target_family = "unix")] if unsafe { libc::getuid() } != 0 { use log::error; error!("pkgr must be run as root."); diff --git a/pkgr/src/package/identifier.rs b/pkgr/src/package/identifier.rs index 17064e4..427b775 100644 --- a/pkgr/src/package/identifier.rs +++ b/pkgr/src/package/identifier.rs @@ -128,3 +128,36 @@ impl FromStr for PackageLocator { }) } } + +impl From<(String, String)> for PackageLocator { + fn from((name, locate_str): (String, String)) -> Self { + // name = "pkg" + // locate_str = "1.0.0:tag1,tag2" or "1.0.0" or "tag1,tag2" + let mut version = None; + let mut tags = None; + + let version_re = Regex::new("^([0-9]+)").unwrap(); + let tags_re = Regex::new("^:([a-zA-Z0-9,._]+)").unwrap(); + + if let Some(caps) = version_re.captures(locate_str.as_str()) { + version = Some(caps.get(1).unwrap().as_str().parse::().unwrap()); + } + + if let Some(caps) = tags_re.captures(locate_str.as_str()) { + tags = Some( + caps.get(1) + .unwrap() + .as_str() + .split(",") + .map(|s| s.to_string()) + .collect(), + ); + } + + PackageLocator { + name, + version, + tags, + } + } +} diff --git a/pkgr/src/package/installer/errors.rs b/pkgr/src/package/installer/errors.rs index 46cd402..637e891 100644 --- a/pkgr/src/package/installer/errors.rs +++ b/pkgr/src/package/installer/errors.rs @@ -30,6 +30,7 @@ impl Display for BuildError { pub enum InstallError { BuildError(BuildError), BinError(BinError), + InvalidManifest, Generic, } @@ -38,6 +39,7 @@ impl ToString for InstallError { match self { InstallError::BuildError(e) => format!("Build error: {}", e), InstallError::BinError(e) => format!("Bin error: {}", e), + InstallError::InvalidManifest => "Invalid manifest".to_string(), InstallError::Generic => "Install error".to_string(), } } diff --git a/pkgr/src/package/installer/mod.rs b/pkgr/src/package/installer/mod.rs index 0d474aa..8181ea8 100644 --- a/pkgr/src/package/installer/mod.rs +++ b/pkgr/src/package/installer/mod.rs @@ -1,9 +1,13 @@ use crate::tmpfs::TempDir; use errors::{BinError, BuildError, InstallError}; -use log::{debug, trace}; +use log::{debug, error, info, trace}; use manifest::Manifest; use pkgfile::PKGFile; use std::fmt::Display; +use std::process::exit; +use crate::CONFIG; +use crate::package::identifier::{PackageIdentifier, PackageLocator}; +use crate::package::Package; pub mod errors; @@ -59,14 +63,54 @@ impl PackageInstaller { } let build_manifest = self.manifest.build.clone().unwrap(); // TODO: Check dependencies + for pkg_tuple in build_manifest.dependencies { + let mut pkg = Package::fetch( + PackageIdentifier::PackageLocator( + PackageLocator::from(pkg_tuple) + ) + ).expect("no pkg"); + + if !pkg.is_installed() { + match pkg.install(CONFIG.with(|c| { + c.build_by_default + })) { + Ok(_) => { info!("Installed dependency: \"{}\"", pkg.manifest().package.name) }, + Err(_) => { + error!("Could not install dependency: \"{}\"", pkg.identifier); + exit(1); + } + } + } + } Ok(()) } - pub fn install(&self) -> Result<(), InstallError> { + pub fn install(&mut self) -> Result<(), InstallError> { match self.install_type { - InstallType::Bin => self.bin().map_err(|e| InstallError::BinError(e)), - InstallType::Build => self.build().map_err(|e| InstallError::BuildError(e)), + InstallType::Bin => { + if let None = self.manifest.bin { + self.install_type = InstallType::Build; + if let None = self.manifest.build { + return Err(InstallError::InvalidManifest); + } + } + } + InstallType::Build => { + if let None = self.manifest.build { + self.install_type = InstallType::Bin; + if let None = self.manifest.bin { + return Err(InstallError::InvalidManifest); + } + } + } + } + + match self.install_type { + InstallType::Bin => self.bin() + .map_err(|e| InstallError::BinError(e)), + InstallType::Build => self.build() + .map_err(|e| InstallError::BuildError(e)), } } } diff --git a/pkgr/src/package/mod.rs b/pkgr/src/package/mod.rs index e23a191..79de18d 100644 --- a/pkgr/src/package/mod.rs +++ b/pkgr/src/package/mod.rs @@ -1,4 +1,4 @@ -use log::trace; +use log::{info, trace}; pub mod fetch; pub mod identifier; @@ -51,12 +51,26 @@ impl Package { } /// Install the package. - pub fn install(&mut self) -> Result<(), installer::errors::InstallError> { + pub fn install(&mut self, build: bool) -> Result<(), installer::errors::InstallError> { let manifest = self.manifest(); - let installer = installer::PackageInstaller::new( + let mut installer = installer::PackageInstaller::new( manifest.clone(), self.pkgfile.clone(), - installer::InstallType::Bin, + if build { + info!("building package: {}...", if self.manifest().package.name.is_empty() { + self.identifier.to_string() + } else { + self.manifest().package.name + }); + installer::InstallType::Build + } else { + info!("using binary install for package: {}...", if self.manifest().package.name.is_empty() { + self.identifier.to_string() + } else { + self.manifest().package.name + }); + installer::InstallType::Bin + }, ); match installer.install() { Ok(_) => { diff --git a/pkgr/src/process/mod.rs b/pkgr/src/process.rs similarity index 73% rename from pkgr/src/process/mod.rs rename to pkgr/src/process.rs index 21586c0..727529f 100644 --- a/pkgr/src/process/mod.rs +++ b/pkgr/src/process.rs @@ -1,6 +1,7 @@ +use std::io::{BufRead, BufReader}; use std::process::Command; +use log::info; -pub mod output; pub struct Process { pub command: Vec, @@ -31,7 +32,18 @@ impl Process { .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) .spawn()?; - output::spawn_output_handlers(&mut child); + + let stdout = child.stdout.take().unwrap(); + let stderr = child.stderr.take().unwrap(); + + for line in BufReader::new(stdout).lines() { + info!(target: "command:stdout", "{}", line.unwrap()); + } + + for line in BufReader::new(stderr).lines() { + info!(target: "command:stderr", "{}", line.unwrap()); + } + Ok(child) } } diff --git a/pkgr/src/process/output.rs b/pkgr/src/process/output.rs deleted file mode 100644 index 68d91fd..0000000 --- a/pkgr/src/process/output.rs +++ /dev/null @@ -1,26 +0,0 @@ -// create functions that spawn threads for Stdout and Stderr -// that print the output to info!(target: "command:stdout", ...) and info!(target: "command:stderr", ...) respectively - -use std::io::{BufRead, BufReader}; -use std::process::Child; - -use log::{error, info}; - -pub fn spawn_output_handlers(child: &mut Child) { - let stdout = child.stdout.take().unwrap(); - let stderr = child.stderr.take().unwrap(); - - std::thread::spawn(move || { - let reader = BufReader::new(stdout); - for line in reader.lines() { - info!(target: "command:stdout", "{}", line.unwrap()); - } - }); - - std::thread::spawn(move || { - let reader = BufReader::new(stderr); - for line in reader.lines() { - error!(target: "command:stderr", "{}", line.unwrap()); - } - }); -}