🐞 fix: Even more git fixes
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::Utc;
|
||||
@@ -196,6 +197,72 @@ fn remote_callbacks() -> git2::RemoteCallbacks<'static> {
|
||||
callbacks
|
||||
}
|
||||
|
||||
fn use_git_cli_fallback() -> bool {
|
||||
std::env::var("IRONPAD_GIT_USE_CLI_FALLBACK")
|
||||
.map(|v| !matches!(v.to_ascii_lowercase().as_str(), "0" | "false" | "no" | "off"))
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn known_hosts_path() -> Option<PathBuf> {
|
||||
if let Ok(path) = std::env::var("IRONPAD_GIT_SSH_KNOWN_HOSTS") {
|
||||
let p = PathBuf::from(path);
|
||||
if p.exists() {
|
||||
return Some(p);
|
||||
}
|
||||
}
|
||||
|
||||
let default = PathBuf::from("/root/.ssh/known_hosts");
|
||||
if default.exists() {
|
||||
Some(default)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn git_ssh_command(auth: &GitAuthConfig) -> Option<String> {
|
||||
let private_key = auth.private_key.as_ref()?;
|
||||
|
||||
let mut cmd = format!(
|
||||
"ssh -i {} -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes",
|
||||
private_key.display()
|
||||
);
|
||||
if let Some(known_hosts) = known_hosts_path() {
|
||||
cmd.push_str(&format!(" -o UserKnownHostsFile={}", known_hosts.display()));
|
||||
}
|
||||
Some(cmd)
|
||||
}
|
||||
|
||||
fn run_git_cli(args: &[&str]) -> Result<(), String> {
|
||||
let auth = git_auth_config();
|
||||
let data_path = config::data_dir();
|
||||
let mut cmd = Command::new("git");
|
||||
cmd.args(args)
|
||||
.current_dir(data_path)
|
||||
.env("GIT_TERMINAL_PROMPT", "0");
|
||||
|
||||
if let Some(ssh_cmd) = git_ssh_command(&auth) {
|
||||
cmd.env("GIT_SSH_COMMAND", ssh_cmd);
|
||||
}
|
||||
|
||||
let output = cmd
|
||||
.output()
|
||||
.map_err(|e| format!("Failed to run git CLI: {}", e))?;
|
||||
|
||||
if output.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
|
||||
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
let msg = if !stderr.is_empty() { stderr } else { stdout };
|
||||
Err(format!(
|
||||
"git {} failed (exit {}): {}",
|
||||
args.join(" "),
|
||||
output.status.code().unwrap_or(-1),
|
||||
msg
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get repository status
|
||||
pub fn get_status() -> Result<RepoStatus, String> {
|
||||
let data_path = config::data_dir();
|
||||
@@ -423,12 +490,27 @@ pub fn push_to_remote() -> Result<(), String> {
|
||||
|
||||
// Push the current branch
|
||||
let refspec = format!("refs/heads/{}:refs/heads/{}", branch_name, branch_name);
|
||||
remote
|
||||
.push(&[&refspec], Some(&mut push_options))
|
||||
.map_err(|e| format!("Push failed: {}. Make sure SSH keys are configured.", e))?;
|
||||
|
||||
tracing::info!("Successfully pushed to origin/{}", branch_name);
|
||||
Ok(())
|
||||
match remote.push(&[&refspec], Some(&mut push_options)) {
|
||||
Ok(_) => {
|
||||
tracing::info!("Successfully pushed to origin/{}", branch_name);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
let err_text = e.to_string();
|
||||
if !use_git_cli_fallback() {
|
||||
return Err(format!(
|
||||
"Push failed: {}. Make sure SSH keys are configured.",
|
||||
err_text
|
||||
));
|
||||
}
|
||||
tracing::warn!("libgit2 push failed, trying git CLI fallback: {}", err_text);
|
||||
run_git_cli(&["push", "origin", branch_name]).map_err(|cli_err| {
|
||||
format!("Push failed: {} (libgit2) / {} (git CLI)", err_text, cli_err)
|
||||
})?;
|
||||
tracing::info!("Successfully pushed to origin/{} (git CLI fallback)", branch_name);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if remote is configured
|
||||
@@ -850,18 +932,20 @@ pub fn fetch_from_remote() -> Result<(), String> {
|
||||
.find_remote("origin")
|
||||
.map_err(|e| format!("Remote 'origin' not found: {}", e))?;
|
||||
|
||||
// Create callbacks for authentication
|
||||
let mut callbacks = git2::RemoteCallbacks::new();
|
||||
callbacks.credentials(|_url, username_from_url, _allowed_types| {
|
||||
git2::Cred::ssh_key_from_agent(username_from_url.unwrap_or("git"))
|
||||
});
|
||||
|
||||
let mut fetch_options = git2::FetchOptions::new();
|
||||
fetch_options.remote_callbacks(callbacks);
|
||||
fetch_options.remote_callbacks(remote_callbacks());
|
||||
|
||||
remote
|
||||
.fetch(&[] as &[&str], Some(&mut fetch_options), None)
|
||||
.map_err(|e| format!("Fetch failed: {}", e))?;
|
||||
|
||||
Ok(())
|
||||
match remote.fetch(&[] as &[&str], Some(&mut fetch_options), None) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => {
|
||||
let err_text = e.to_string();
|
||||
if !use_git_cli_fallback() {
|
||||
return Err(format!("Fetch failed: {}", err_text));
|
||||
}
|
||||
tracing::warn!("libgit2 fetch failed, trying git CLI fallback: {}", err_text);
|
||||
run_git_cli(&["fetch", "origin", "--prune"]).map_err(|cli_err| {
|
||||
format!("Fetch failed: {} (libgit2) / {} (git CLI)", err_text, cli_err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user