tci/src/tci.rs

110 lines
2.6 KiB
Rust
Raw Normal View History

2024-02-14 20:06:49 +01:00
use std::io::Read;
use crate::{cfg::TciConfig, error::{TciErr, TciResult}, git::{RefUpdateVecHelper, TciRepo}};
2024-02-14 20:06:49 +01:00
2024-02-15 03:04:53 +01:00
pub struct Tci {
cfg: TciConfig,
repo: TciRepo,
2024-02-15 03:12:00 +01:00
// stdin: String,
2024-02-14 20:06:49 +01:00
}
2024-02-15 03:04:53 +01:00
impl Tci {
pub fn new() -> TciResult<Self> {
let cfg = TciConfig::load()
.unwrap_or_else(|e| {
eprintln!("[!] invalid config: {e}");
TciConfig::default()
});
2024-02-14 20:06:49 +01:00
2024-02-15 03:04:53 +01:00
// check which branches are being updated
let mut stdin = String::new();
std::io::stdin().read_to_string(&mut stdin)
.unwrap_or_else(|e| {
eprintln!("[!] could not read refs from stdin: {e}");
0
});
2024-02-14 20:06:49 +01:00
2024-02-15 03:12:00 +01:00
let repo = TciRepo::new(&stdin)?;
2024-02-14 20:06:49 +01:00
2024-02-15 03:12:00 +01:00
Ok(Tci{cfg, repo})
2024-02-14 20:06:49 +01:00
}
2024-02-15 03:04:53 +01:00
/// check if tci is allowed to run for this repository
pub fn allowed(&self) -> bool {
if !self.cfg.allow_all && !self.repo.cfg.get_bool("tci.allow").unwrap_or(false) {
return false; // we are in whitelist mode and this repo is not whitelisted
}
match self.cfg.branch.as_deref() {
None => self.repo.updates.contains_branch(".tci"),
Some("") => true,
Some(b) => self.repo.updates.contains_branch(b),
2024-02-15 03:04:53 +01:00
}
2024-02-14 20:06:49 +01:00
}
2024-02-15 03:04:53 +01:00
pub fn run(&self) -> TciResult<()> {
// run hooks
for hook in &self.cfg.hooks {
println!("[*] running hook ({hook})");
Tci::exec(&self.repo.path, hook)?;
}
if !self.allowed() { return Ok(()) }
2024-02-14 20:06:49 +01:00
2024-02-15 03:04:53 +01:00
let env = self.prepare_env()?;
2024-02-14 20:06:49 +01:00
let tci_script = self.repo.cfg.get_string("tci.script")
2024-02-15 03:12:00 +01:00
.unwrap_or_else(|_| ".tci".into());
let tci_path = env.path().join(tci_script);
2024-02-14 20:06:49 +01:00
if !tci_path.is_file() {
2024-02-15 03:12:00 +01:00
return Err(TciErr::Missing);
2024-02-15 03:04:53 +01:00
}
println!("[=] running tci script for {}", self.repo.name);
Tci::exec(env.path(), tci_path)?;
2024-02-15 03:04:53 +01:00
println!("[o] tci complete");
Ok(())
2024-02-14 20:06:49 +01:00
}
2024-02-15 03:04:53 +01:00
fn prepare_env(&self) -> TciResult<tempdir::TempDir> {
let tmp = tempdir::TempDir::new(
&format!("tci-{}", self.repo.name.replace('/', "_"))
)?;
// TODO allow customizing clone? just clone recursive? just let hook setup submodules?
git2::Repository::clone(
self.repo.path.to_str()
2024-02-15 03:12:00 +01:00
.ok_or(TciErr::FsError("repo path is not a valid string"))?,
2024-02-15 03:04:53 +01:00
tmp.path(),
)?;
Ok(tmp)
2024-02-14 20:06:49 +01:00
}
2024-02-15 03:04:53 +01:00
fn exec<S : AsRef<std::ffi::OsStr>>(cwd: &std::path::Path, s: S) -> TciResult<()> {
match std::process::Command::new(s)
.current_dir(cwd)
// .stdin(self.stdin.clone()) // TODO not this easy
.status()?
.code()
{
Some(0) => Ok(()),
2024-02-15 03:12:00 +01:00
Some(x) => Err(crate::error::TciErr::SubprocessError(x)),
None => Err(crate::error::TciErr::SubprocessTerminated),
2024-02-15 03:04:53 +01:00
}
2024-02-14 20:06:49 +01:00
}
#[allow(unused)]
fn spawn<S : AsRef<std::ffi::OsStr>>(cwd: &std::path::Path, s: S) -> TciResult<std::process::Child> {
Ok(
std::process::Command::new(s)
.current_dir(cwd)
// .stdin(self.stdin.clone()) // TODO not this easy
.spawn()?
)
}
2024-02-14 20:06:49 +01:00
}
2024-02-15 03:04:53 +01:00