gitdataai/libs/git/ssh/git_service.rs

89 lines
2.3 KiB
Rust

use std::path::PathBuf;
use std::str::FromStr;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum GitService {
UploadPack,
ReceivePack,
UploadArchive,
}
impl FromStr for GitService {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"upload-pack" => Ok(Self::UploadPack),
"receive-pack" => Ok(Self::ReceivePack),
"upload-archive" => Ok(Self::UploadArchive),
_ => Err(()),
}
}
}
pub fn parse_git_command(cmd: &str) -> Option<(GitService, &str)> {
let (svc, path) = match cmd.split_once(' ') {
Some(("git-receive-pack", path)) => (GitService::ReceivePack, path),
Some(("git-upload-pack", path)) => (GitService::UploadPack, path),
Some(("git-upload-archive", path)) => (GitService::UploadArchive, path),
_ => return None,
};
Some((svc, strip_apostrophes(path)))
}
pub fn parse_repo_path(path: &str) -> Option<(&str, &str)> {
let path = path.trim_matches('/');
let mut parts = path.splitn(2, '/');
match (parts.next(), parts.next()) {
(Some(owner), Some(repo)) if !owner.is_empty() && !repo.is_empty() => Some((owner, repo)),
_ => None,
}
}
pub fn build_git_command(service: GitService, path: PathBuf) -> tokio::process::Command {
let mut cmd = tokio::process::Command::new("git");
let cwd = match path.canonicalize() {
Ok(p) => p,
Err(e) => {
tracing::debug!(error = %e, "path canonicalize failed, falling back to raw path");
path.clone()
}
};
cmd.current_dir(cwd);
match service {
GitService::UploadPack => {
cmd.arg("upload-pack");
}
GitService::ReceivePack => {
cmd.arg("receive-pack");
}
GitService::UploadArchive => {
cmd.arg("upload-archive");
}
}
cmd.arg(".")
.env("GIT_CONFIG_NOSYSTEM", "1")
.env("GIT_NO_REPLACE_OBJECTS", "1");
#[cfg(unix)]
{
cmd.env("GIT_CONFIG_GLOBAL", "/dev/null")
.env("GIT_CONFIG_SYSTEM", "/dev/null");
}
#[cfg(windows)]
{
let nul = "NUL";
cmd.env("GIT_CONFIG_GLOBAL", nul)
.env("GIT_CONFIG_SYSTEM", nul);
}
cmd
}
fn strip_apostrophes(s: &str) -> &str {
s.trim_matches('\'')
}