112 lines
3.7 KiB
Rust
112 lines
3.7 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use crate::{
|
|
bare::GitBare,
|
|
errors::{GitError, GitResult},
|
|
};
|
|
|
|
pub struct ForkRepoParams {
|
|
pub namespace: String,
|
|
pub repo_name: String,
|
|
pub default_branch: String,
|
|
pub description: Option<String>,
|
|
pub enable_lfs: bool,
|
|
}
|
|
|
|
impl ForkRepoParams {
|
|
pub async fn fork_bare(
|
|
storage_root: String,
|
|
source_storage_path: String,
|
|
params: ForkRepoParams,
|
|
) -> GitResult<String> {
|
|
let target_dir = PathBuf::from(&storage_root)
|
|
.join("repo")
|
|
.join(¶ms.namespace)
|
|
.join(¶ms.repo_name);
|
|
|
|
if target_dir.exists() {
|
|
return Err(GitError::Internal(format!(
|
|
"repository directory already exists: {}",
|
|
target_dir.display()
|
|
)));
|
|
}
|
|
|
|
let source_dir = PathBuf::from(&source_storage_path);
|
|
if !source_dir.exists() {
|
|
return Err(GitError::Internal(format!(
|
|
"source repository does not exist: {}",
|
|
source_dir.display()
|
|
)));
|
|
}
|
|
let output = duct::cmd(
|
|
"git",
|
|
&[
|
|
"clone",
|
|
"--bare",
|
|
source_dir.to_string_lossy().as_ref(),
|
|
target_dir.to_string_lossy().as_ref(),
|
|
],
|
|
)
|
|
.stdout_capture()
|
|
.stderr_capture()
|
|
.env("GIT_CONFIG_NOSYSTEM", "1")
|
|
.env("GIT_TERMINAL_PROMPT", "0")
|
|
.unchecked()
|
|
.run()?;
|
|
|
|
if !output.status.success() {
|
|
std::fs::remove_dir_all(&target_dir).ok();
|
|
return Err(GitError::CommandFailed {
|
|
status_code: output.status.code(),
|
|
stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
|
|
});
|
|
}
|
|
|
|
let bare = GitBare {
|
|
bare_dir: target_dir.clone(),
|
|
};
|
|
let symref_output = bare.git_command_trusted(vec![
|
|
"symbolic-ref".to_string(),
|
|
"HEAD".to_string(),
|
|
format!("refs/heads/{}", params.default_branch),
|
|
])?;
|
|
if !symref_output.success {
|
|
return Err(GitError::CommandFailed {
|
|
status_code: symref_output.status_code,
|
|
stderr: symref_output.stderr_lossy(),
|
|
});
|
|
}
|
|
let remote_output = bare.git_command_trusted(vec![
|
|
"remote".to_string(),
|
|
"add".to_string(),
|
|
"upstream".to_string(),
|
|
source_dir.to_string_lossy().to_string(),
|
|
])?;
|
|
if !remote_output.success {
|
|
tracing::warn!(
|
|
"failed to add upstream remote: {}",
|
|
remote_output.stderr_lossy()
|
|
);
|
|
}
|
|
if let Some(desc) = ¶ms.description {
|
|
let desc_path = target_dir.join("description");
|
|
std::fs::write(&desc_path, desc)?;
|
|
}
|
|
if params.enable_lfs {
|
|
let gitattributes_path = target_dir.join("info").join("attributes");
|
|
if let Some(parent) = gitattributes_path.parent() {
|
|
std::fs::create_dir_all(parent)?;
|
|
}
|
|
let lfs_attributes = "*.psd filter=lfs diff=lfs merge=lfs -text\n\
|
|
*.zip filter=lfs diff=lfs merge=lfs -text\n\
|
|
*.tar filter=lfs diff=lfs merge=lfs -text\n\
|
|
*.gz filter=lfs diff=lfs merge=lfs -text\n\
|
|
*.mp4 filter=lfs diff=lfs merge=lfs -text\n\
|
|
*.mov filter=lfs diff=lfs merge=lfs -text\n";
|
|
std::fs::write(&gitattributes_path, lfs_attributes)?;
|
|
}
|
|
|
|
Ok(target_dir.to_string_lossy().to_string())
|
|
}
|
|
}
|