This commit is contained in:
parent
a689abbc5d
commit
c12b78b3c1
9 changed files with 157 additions and 38 deletions
|
@ -5,6 +5,8 @@ use clap::{Parser, Subcommand};
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
use manifest::Manifest;
|
use manifest::Manifest;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
use crate::CONFIG;
|
||||||
|
use crate::process::Process;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[clap(name = "pkgr", version)]
|
#[clap(name = "pkgr", version)]
|
||||||
|
@ -69,7 +71,7 @@ impl Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Starting install...");
|
trace!("Starting install...");
|
||||||
match pkg.install() {
|
match pkg.install(CONFIG.with(|c| if !*build { c.build_by_default } else { *build })) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Install failed: {}", e.to_string());
|
error!("Install failed: {}", e.to_string());
|
||||||
|
@ -110,6 +112,12 @@ impl Command {
|
||||||
info!("Info message.");
|
info!("Info message.");
|
||||||
warn!("Warning message.");
|
warn!("Warning message.");
|
||||||
error!("Error 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!("");
|
||||||
info!("PKGR VERSION: {}", env!("CARGO_PKG_VERSION"));
|
info!("PKGR VERSION: {}", env!("CARGO_PKG_VERSION"));
|
||||||
info!("PKGR AUTHORS: {}", env!("CARGO_PKG_AUTHORS"));
|
info!("PKGR AUTHORS: {}", env!("CARGO_PKG_AUTHORS"));
|
||||||
|
|
27
pkgr/src/config/mod.rs
Normal file
27
pkgr/src/config/mod.rs
Normal file
|
@ -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<Config, String> {
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,13 +10,18 @@ mod logging;
|
||||||
mod package;
|
mod package;
|
||||||
mod process;
|
mod process;
|
||||||
mod tmpfs;
|
mod tmpfs;
|
||||||
|
mod config;
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static CONFIG: config::Config = config::Config::from_path("/etc/pkgr.toml")
|
||||||
|
.unwrap_or(config::Config::default());
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
logging::setup_logger().expect("Unable to setup logger.");
|
logging::setup_logger().expect("Unable to setup logger.");
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
{
|
{
|
||||||
#[cfg(target_family = "unix")]
|
|
||||||
if unsafe { libc::getuid() } != 0 {
|
if unsafe { libc::getuid() } != 0 {
|
||||||
use log::error;
|
use log::error;
|
||||||
error!("pkgr must be run as root.");
|
error!("pkgr must be run as root.");
|
||||||
|
|
|
@ -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::<u32>().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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ impl Display for BuildError {
|
||||||
pub enum InstallError {
|
pub enum InstallError {
|
||||||
BuildError(BuildError),
|
BuildError(BuildError),
|
||||||
BinError(BinError),
|
BinError(BinError),
|
||||||
|
InvalidManifest,
|
||||||
Generic,
|
Generic,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ impl ToString for InstallError {
|
||||||
match self {
|
match self {
|
||||||
InstallError::BuildError(e) => format!("Build error: {}", e),
|
InstallError::BuildError(e) => format!("Build error: {}", e),
|
||||||
InstallError::BinError(e) => format!("Bin error: {}", e),
|
InstallError::BinError(e) => format!("Bin error: {}", e),
|
||||||
|
InstallError::InvalidManifest => "Invalid manifest".to_string(),
|
||||||
InstallError::Generic => "Install error".to_string(),
|
InstallError::Generic => "Install error".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
use crate::tmpfs::TempDir;
|
use crate::tmpfs::TempDir;
|
||||||
use errors::{BinError, BuildError, InstallError};
|
use errors::{BinError, BuildError, InstallError};
|
||||||
use log::{debug, trace};
|
use log::{debug, error, info, trace};
|
||||||
use manifest::Manifest;
|
use manifest::Manifest;
|
||||||
use pkgfile::PKGFile;
|
use pkgfile::PKGFile;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use std::process::exit;
|
||||||
|
use crate::CONFIG;
|
||||||
|
use crate::package::identifier::{PackageIdentifier, PackageLocator};
|
||||||
|
use crate::package::Package;
|
||||||
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
|
||||||
|
@ -59,14 +63,54 @@ impl PackageInstaller {
|
||||||
}
|
}
|
||||||
let build_manifest = self.manifest.build.clone().unwrap();
|
let build_manifest = self.manifest.build.clone().unwrap();
|
||||||
// TODO: Check dependencies
|
// 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install(&self) -> Result<(), InstallError> {
|
pub fn install(&mut self) -> Result<(), InstallError> {
|
||||||
match self.install_type {
|
match self.install_type {
|
||||||
InstallType::Bin => self.bin().map_err(|e| InstallError::BinError(e)),
|
InstallType::Bin => {
|
||||||
InstallType::Build => self.build().map_err(|e| InstallError::BuildError(e)),
|
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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use log::trace;
|
use log::{info, trace};
|
||||||
|
|
||||||
pub mod fetch;
|
pub mod fetch;
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
|
@ -51,12 +51,26 @@ impl Package {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Install the 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 manifest = self.manifest();
|
||||||
let installer = installer::PackageInstaller::new(
|
let mut installer = installer::PackageInstaller::new(
|
||||||
manifest.clone(),
|
manifest.clone(),
|
||||||
self.pkgfile.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() {
|
match installer.install() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use log::info;
|
||||||
|
|
||||||
pub mod output;
|
|
||||||
|
|
||||||
pub struct Process {
|
pub struct Process {
|
||||||
pub command: Vec<String>,
|
pub command: Vec<String>,
|
||||||
|
@ -31,7 +32,18 @@ impl Process {
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(std::process::Stdio::piped())
|
||||||
.stderr(std::process::Stdio::piped())
|
.stderr(std::process::Stdio::piped())
|
||||||
.spawn()?;
|
.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)
|
Ok(child)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
Loading…
Reference in a new issue