use std::path::PathBuf;
use crate::error::{Result, ThesaError};
#[derive(Debug, Clone)]
pub(crate) enum Target {
Owner(String),
Repo { owner: String, repo: String },
}
impl Target {
pub(crate) fn archive_target_id(&self) -> String {
match self {
Target::Owner(owner) => owner.clone(),
Target::Repo { owner, repo } => format!("{owner}/{repo}"),
}
}
}
pub(crate) fn parse_target(input: &str) -> Result<Target> {
let cleaned = input.trim().trim_end_matches(".git");
if cleaned.is_empty() {
return Err(ThesaError::InvalidTarget(input.to_string()));
}
if let Some(path) = cleaned.strip_prefix("https://github.com/") {
return parse_owner_or_repo_path(path);
}
if let Some(path) = cleaned.strip_prefix("http://github.com/") {
return parse_owner_or_repo_path(path);
}
if let Some(path) = cleaned.strip_prefix("git@github.com:") {
return parse_owner_or_repo_path(path);
}
parse_owner_or_repo_path(cleaned)
}
fn parse_owner_or_repo_path(input: &str) -> Result<Target> {
let parts: Vec<&str> = input
.trim_matches('/')
.split('/')
.filter(|part| !part.is_empty())
.collect();
if parts.is_empty() {
return Err(ThesaError::InvalidTarget(input.to_string()));
}
if parts.len() == 1 {
return Ok(Target::Owner(parts[0].to_string()));
}
Ok(Target::Repo {
owner: parts[0].to_string(),
repo: parts[1].to_string(),
})
}
pub(crate) fn default_output_path(target: &Target) -> PathBuf {
let slug = match target {
Target::Owner(owner) => owner.clone(),
Target::Repo { repo, .. } => repo.clone(),
};
PathBuf::from("./archives").join(slug)
}