use std::path::{Path, PathBuf};
pub fn sanitize_branch_name(branch: &str) -> String {
let mut result = branch.replace('/', "-");
result = result.trim_start_matches('.').to_string();
while result.contains("--") {
result = result.replace("--", "-");
}
result = result.trim_matches('-').to_string();
if result.is_empty() {
result = "branch".to_string();
}
result
}
pub fn worktree_dir(bare_repo: &Path, branch: &str) -> PathBuf {
bare_repo.join("trees").join(sanitize_branch_name(branch))
}
pub fn repo_name_from_url(url: &str) -> String {
let name = url
.trim_end_matches('/')
.rsplit('/')
.next()
.unwrap_or("repo");
name.strip_suffix(".git").unwrap_or(name).to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sanitize_simple_branch() {
assert_eq!(sanitize_branch_name("main"), "main");
}
#[test]
fn sanitize_slashes() {
assert_eq!(sanitize_branch_name("feature/my-thing"), "feature-my-thing");
}
#[test]
fn sanitize_leading_dot() {
assert_eq!(sanitize_branch_name(".hidden"), "hidden");
}
#[test]
fn sanitize_consecutive_dashes() {
assert_eq!(sanitize_branch_name("a//b"), "a-b");
}
#[test]
fn worktree_dir_path() {
let bare = Path::new("/repos/myproject.git");
assert_eq!(
worktree_dir(bare, "feature/login"),
PathBuf::from("/repos/myproject.git/trees/feature-login")
);
}
#[test]
fn repo_name_from_https_url() {
assert_eq!(
repo_name_from_url("https://github.com/user/repo.git"),
"repo"
);
}
#[test]
fn repo_name_from_ssh_url() {
assert_eq!(
repo_name_from_url("git@github.com:user/my-project.git"),
"my-project"
);
}
#[test]
fn repo_name_without_git_suffix() {
assert_eq!(repo_name_from_url("https://github.com/user/repo"), "repo");
}
#[test]
fn repo_name_trailing_slash() {
assert_eq!(
repo_name_from_url("https://github.com/user/repo.git/"),
"repo"
);
}
}