pji 0.1.7

A CLI for managing, finding, and opening Git repositories.
Documentation
use std::{fs::read_dir, io, path::PathBuf, process::Command};

use crate::repo::{GitProtocol, GitURI};
use regex::Regex;

pub fn parse_git_url(url: &str) -> Option<GitURI> {
    let ssh_re = Regex::new(r"^git@(?P<host>[^:]+):(?P<user>[^/]+)/(?P<repo>[^/]+)\.git$")
        .expect("Failed to compile SSH regex");
    let http_re = Regex::new(r"^https?://(?P<host>[^/]+)/(?P<user>[^/]+)/(?P<repo>[^/]+)\.git$")
        .expect("Failed to compile HTTP regex");

    if let Some(caps) = ssh_re.captures(url) {
        let hostname = caps.name("host").map(|m| m.as_str()).unwrap_or("");
        let user = caps.name("user").map(|m| m.as_str()).unwrap_or("");
        let repo = caps.name("repo").map(|m| m.as_str()).unwrap_or("");

        Some(GitURI {
            hostname: hostname.to_string(),
            user: user.to_string(),
            repo: repo.to_string(),
            protocol: GitProtocol::SSH,
            uri: url.to_string(),
        })
    } else if let Some(caps) = http_re.captures(url) {
        let hostname = caps.name("host").map(|m| m.as_str()).unwrap_or("");
        let user = caps.name("user").map(|m| m.as_str()).unwrap_or("");
        let repo = caps.name("repo").map(|m| m.as_str()).unwrap_or("");

        Some(GitURI {
            hostname: hostname.to_string(),
            user: user.to_string(),
            repo: repo.to_string(),
            protocol: GitProtocol::HTTP,
            uri: url.to_string(),
        })
    } else {
        None
    }
}

pub fn try_get_repo_from_dir(dir: &PathBuf) -> Option<String> {
    let output = Command::new("git")
        .arg("-C")
        .arg(dir)
        .arg("config")
        .arg("--get")
        .arg("remote.origin.url")
        .output();

    match output {
        Ok(output) => {
            if output.status.success() {
                let url = String::from_utf8_lossy(&output.stdout).trim().to_string();
                if url.is_empty() {
                    None
                } else {
                    Some(url)
                }
            } else {
                None
            }
        }
        Err(_) => None,
    }
}

pub fn list_dir(dir: &PathBuf) -> io::Result<Vec<PathBuf>> {
    let mut dirs = vec![];
    for entry in read_dir(dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_dir() {
            dirs.push(path);
        }
    }
    Ok(dirs)
}