use crate::store::Store;
#[cfg(feature = "host")]
use crate::sync;
use anyhow::{Context, Result};
pub(crate) fn ensure_store_gitignore(store: &Store) -> Result<()> {
let path = store.dir.join(".gitignore");
if !path.exists() {
std::fs::write(
&path,
"broker.sock\nnames\nremote\nconfig.toml\nstore/.versions/\nwraps/se-*.json\ngrants-*.age\nwindows-*.json\n",
)?;
}
Ok(())
}
pub(crate) fn git(store: &Store, args: &[String]) -> Result<()> {
ensure_store_gitignore(store)?;
let status = std::process::Command::new("git")
.arg("-C")
.arg(&store.dir)
.args(args)
.status()
.context("git is not on PATH")?;
std::process::exit(status.code().unwrap_or(1));
}
pub(crate) fn written(store: &Store, what: &str) {
commit(store, what);
mirror(store);
push(store);
}
fn in_git(store: &Store) -> bool {
store.dir.join(".git").exists()
}
pub(crate) fn git_quietly(store: &Store, args: &[&str]) {
let _ = std::process::Command::new("git")
.arg("-C")
.arg(&store.dir)
.args(args)
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status();
}
fn commit(store: &Store, what: &str) {
if !in_git(store) {
return;
}
let _ = ensure_store_gitignore(store);
git_quietly(store, &["add", "-A"]);
git_quietly(store, &["commit", "-m", what]);
}
#[cfg(feature = "host")]
fn mirror(store: &Store) {
if std::env::var_os("PASSBOX_NO_AUTOSYNC").is_some() {
return;
}
let remote = match sync::configured(store) {
Ok(Some(chosen)) if chosen.kind == sync::Kind::Directory => chosen.target,
Ok(_) => return,
Err(e) => {
eprintln!("not copied: {e:#}");
return;
}
};
match sync::sync(store, std::path::Path::new(&remote)) {
Ok(report) if report.pushed > 0 => eprintln!("{} copied to {remote}", report.pushed),
Ok(_) => {}
Err(e) => eprintln!("passbox: {e:#}"),
}
}
#[cfg(not(feature = "host"))]
fn mirror(_store: &Store) {}
#[cfg(feature = "host")]
pub(crate) fn git_push(store: &Store) {
if !in_git(store) {
return;
}
commit(store, "update");
push(store);
}
fn push(store: &Store) {
if !in_git(store) {
return;
}
let remotes = std::process::Command::new("git")
.arg("-C")
.arg(&store.dir)
.arg("remote")
.output();
let Some(remote) = remotes.ok().and_then(|o| {
String::from_utf8_lossy(&o.stdout)
.lines()
.next()
.map(str::to_string)
}) else {
return;
};
let out = std::process::Command::new("git")
.arg("-C")
.arg(&store.dir)
.args(["push", "-q", "-u", &remote, "HEAD"])
.output();
match out {
Ok(o) if o.status.success() => {}
Ok(o) => eprintln!(
"not pushed to {remote}: {}",
String::from_utf8_lossy(&o.stderr).trim()
),
Err(e) => eprintln!("not pushed to {remote}: {e}"),
}
}