fad06fd
use crate::GitBaby;
use crate::error::BabyError;
use crate::remote::helper;
use crate::remote::types::{
FetchRemoteCommitResult, RemoteOption, UpdateRemoteMirrorRequest, UpdateRemoteMirrorResult,
};
async fn build_env(
gitbaby: &GitBaby,
) -> Result<(std::path::PathBuf, crate::command::env::Env), BabyError> {
let dir = gitbaby
.facade
.git_repo_dir()
.await
.map_err(crate::share::facade_error)?;
let alternates = gitbaby
.facade
.git_alternate_object_directories()
.await
.map_err(crate::share::facade_error)?;
Ok((dir, crate::share::build_env_safe(&alternates)))
}
impl GitBaby {
pub async fn get_remote_address(&self, name: &str) -> Result<Option<String>, BabyError> {
if name.is_empty() {
return Err(BabyError::Custom(
"remote name must not be empty".to_string(),
));
}
let (dir, env) = build_env(self).await?;
let mut cmd = helper::build_get_url_cmd("gitbaby::remote", &dir, env, name)?;
match cmd.run().await {
Ok(output) => {
if output.status.success() {
let url = String::from_utf8_lossy(&output.stdout).trim().to_string();
return Ok(Some(url));
}
let stderr = String::from_utf8_lossy(&output.stderr);
if stderr.contains("No such remote") || stderr.contains("no such remote") {
return Ok(None);
}
Err(BabyError::Custom(format!(
"git remote get-url failed: {}",
stderr.trim()
)))
}
Err(crate::command::error::CmdError::NonZeroExit { stderr, .. }) => {
if stderr.contains("No such remote") || stderr.contains("no such remote") {
Ok(None)
} else {
Err(BabyError::Custom(format!(
"git remote get-url failed: {}",
stderr.trim()
)))
}
}
Err(e) => Err(BabyError::from(e)),
}
}
pub async fn add_remote(
&self,
name: &str,
url: &str,
opts: RemoteOption,
) -> Result<(), BabyError> {
if name.is_empty() {
return Err(BabyError::Custom(
"remote name must not be empty".to_string(),
));
}
if url.is_empty() {
return Err(BabyError::InvalidRemoteUrl(url.to_string()));
}
let (dir, env) = build_env(self).await?;
let mut cmd = helper::build_add_cmd("gitbaby::remote", &dir, env, name, url, opts)?;
let output = cmd.run_soft().await.map_err(BabyError::from)?;
if output.status.success() {
return Ok(());
}
Err(helper::classify_stderr_add(
&String::from_utf8_lossy(&output.stderr),
name,
))
}
pub async fn remove_remote(&self, name: &str) -> Result<(), BabyError> {
if name.is_empty() {
return Err(BabyError::Custom(
"remote name must not be empty".to_string(),
));
}
let (dir, env) = build_env(self).await?;
let mut cmd = helper::build_remove_cmd("gitbaby::remote", &dir, env, name)?;
let output = cmd.run_soft().await.map_err(BabyError::from)?;
if output.status.success() {
return Ok(());
}
Err(helper::classify_stderr_rm(
&String::from_utf8_lossy(&output.stderr),
name,
))
}
pub async fn fetch_remote_commit(
&self,
remote_repo_path: &str,
commit_id: &str,
) -> Result<FetchRemoteCommitResult, BabyError> {
if remote_repo_path.is_empty() {
return Err(BabyError::Custom(
"remote repository path must not be empty".to_string(),
));
}
if commit_id.is_empty() {
return Err(BabyError::Custom("commit id must not be empty".to_string()));
}
let (dir, env) = build_env(self).await?;
let mut cmd =
helper::build_fetch_cmd("gitbaby::remote", &dir, env, remote_repo_path, commit_id)?;
let output = cmd.run_soft().await.map_err(BabyError::from)?;
if output.status.success() {
let _ = crate::cache::invalidation::flush_cache().await;
return Ok(FetchRemoteCommitResult { fetched: true });
}
let stderr = String::from_utf8_lossy(&output.stderr);
if stderr.contains("not a git repository") {
return Err(BabyError::NotARepository(remote_repo_path.to_string()));
}
Err(helper::classify_stderr_fetch(&stderr))
}
pub async fn find_remote_repository(&self, url: &str) -> Result<bool, BabyError> {
if url.is_empty() {
return Err(BabyError::InvalidRemoteUrl(url.to_string()));
}
let dir = self
.facade
.git_repo_dir()
.await
.map_err(crate::share::facade_error)?;
let alternates = self
.facade
.git_alternate_object_directories()
.await
.map_err(crate::share::facade_error)?;
let env = crate::share::build_env_safe(&alternates);
let mut cmd = helper::build_ls_remote_head_cmd("gitbaby::remote", &dir, env, url)?;
match cmd.run().await {
Ok(output) => {
if !output.status.success() {
return Ok(false);
}
Ok(helper::parse_oid_tab_head(&output.stdout).is_some())
}
Err(crate::command::error::CmdError::Spawn { .. }) => Ok(false),
Err(crate::command::error::CmdError::NonZeroExit { .. }) => Ok(false),
Err(crate::command::error::CmdError::Io { .. }) => Ok(false),
Err(e) => Err(helper::classify_stderr_ls_remote(&format!("{:?}", e))),
}
}
pub async fn find_remote_root_ref(&self, url: &str) -> Result<Option<String>, BabyError> {
if url.is_empty() {
return Err(BabyError::InvalidRemoteUrl(url.to_string()));
}
let dir = self
.facade
.git_repo_dir()
.await
.map_err(crate::share::facade_error)?;
let alternates = self
.facade
.git_alternate_object_directories()
.await
.map_err(crate::share::facade_error)?;
let env = crate::share::build_env_safe(&alternates);
let mut cmd = helper::build_show_remote_cmd("gitbaby::remote", &dir, env, url)?;
let output = match cmd.run().await {
Ok(o) => o,
Err(crate::command::error::CmdError::NonZeroExit { stderr, .. }) => {
if helper::classify_stderr_show_remote(&stderr).is_none() {
return Ok(None);
}
return Err(BabyError::Custom(format!(
"git remote show failed: {}",
stderr.trim()
)));
}
Err(e) => return Err(BabyError::from(e)),
};
if !output.status.success() {
return Ok(None);
}
match helper::parse_head_branch_line(&output.stdout) {
Some(ref_name) if ref_name == "(unknown)" => Ok(None),
Some(ref_name) => Ok(Some(ref_name)),
None => Ok(None),
}
}
pub async fn update_remote_mirror(
&self,
req: UpdateRemoteMirrorRequest,
) -> Result<UpdateRemoteMirrorResult, BabyError> {
if req.url.is_empty() {
return Err(BabyError::InvalidRemoteUrl(req.url.clone()));
}
if req.refs.is_empty() {
return Err(BabyError::Custom(
"update_remote_mirror requires at least one ref".to_string(),
));
}
let (dir, env) = build_env(self).await?;
let mut cmd =
helper::build_push_mirror_cmd("gitbaby::remote", &dir, env, &req, req.refs.clone())?;
let output = cmd.run_soft().await.map_err(BabyError::from)?;
if output.status.success() {
return Ok(UpdateRemoteMirrorResult::default());
}
Err(helper::classify_stderr_push(&String::from_utf8_lossy(
&output.stderr,
)))
}
}