use git_policy_cli::service_journal::{DONE_RETAINED, prune_done};
use git_policy_cli::service_land::{LandContext, recover_instance};
use git_policy_cli::service_protocol::PROTOCOL_VERSION;
use git_policy_cli::service_timing::{log, started_line};
use git_policy_cli::service_server::{Bind, IDLE_EXIT, ServeSettings, bind, serve};
use git_policy_cli::transaction_git::GitContext;
use std::path::PathBuf;
use std::time::Duration;
fn option(arguments: &[String], name: &str) -> Option<String> {
return arguments.iter().position(|argument| { return argument == name; }).and_then(|at| { return arguments.get(at + 1).cloned(); });
}
fn main() {
git_policy_cli::hooks_off::activate();
git_policy_cli::service_signal::install();
git_policy_cli::push_deadline_advice::mark_service_process();
let arguments: Vec<String> = std::env::args().collect();
let Some(journal) = option(&arguments, "--journal").map(PathBuf::from) else {
git_policy_cli::service_error!("--journal <directory> is required");
std::process::exit(2);
};
let git: PathBuf = option(&arguments, "--git").map_or_else(|| { return PathBuf::from("/usr/bin/git"); }, PathBuf::from);
let address: Bind = match (option(&arguments, "--abstract"), option(&arguments, "--path")) {
(Some(name), _) => Bind::Abstract(name),
(None, Some(path)) => Bind::Path(PathBuf::from(path)),
(None, None) => Bind::Inherited,
};
if let Err(error) = std::fs::create_dir_all(&journal) {
git_policy_cli::service_error!("cannot create the journal directory {}: {error}", journal.display());
std::process::exit(2);
}
let listener = match bind(&address) {
Ok(listener) => listener,
Err(error) => {
git_policy_cli::service_error!("cannot listen: {error}");
std::process::exit(3);
}
};
let context: LandContext = LandContext {
git: GitContext { real_git: git, overlay: git_policy_cli::child_environment::lockfile_pid_overlay(std::env::vars_os().collect::<Vec<_>>().as_slice()), global_prefix: Vec::new(), common_dir: None },
journal,
on_objects_written: None,
index_wait: git_policy_cli::wait_limit::live_wait_limit(),
};
let idle: Duration = option(&arguments, "--idle-seconds")
.and_then(|text| { return text.parse::<u64>().ok(); })
.map_or(IDLE_EXIT, Duration::from_secs);
let mut settings: ServeSettings = ServeSettings::new(idle);
if let Some(release) = option(&arguments, "--release") {
settings.release = release;
}
settings.instance = option(&arguments, "--instance");
git_policy_cli::service_timing::set_context(settings.release.as_str(), settings.instance.as_deref());
log(started_line(settings.release.as_str(), PROTOCOL_VERSION, settings.instance.as_deref()).as_str());
if let (Some(instance), Some(shared)) = (settings.instance.as_deref(), context.journal.parent()) {
let earlier: LandContext = LandContext { git: context.git.clone(), journal: shared.to_path_buf(), on_objects_written: None, index_wait: context.index_wait };
let _reports = recover_instance(&earlier, instance);
let _pruned = prune_done(shared, DONE_RETAINED);
}
git_policy_cli::service_log!("ready");
serve(listener, &context, &settings);
}