pullcode 1.0.0

Pull code from remote repositories through a YAML file.
use std::{fs::File, io, process::Command};

use anyhow::Result;
use clap::Parser;
use serde::Deserialize;

#[derive(Debug, Parser)]
#[command(
    version,
    name = "pullcode",
    about = "Pull code from remote repositories through a YAML file."
)]
struct Args {
    /// file path of yaml
    path: String,
}

#[derive(Debug, Deserialize)]
struct Projects {
    git_name: String,
    git_email: String,
    repos: Vec<Repository>,
}

#[derive(Debug, Deserialize)]
struct Repository {
    name: String,
    url: String,
}

fn main() -> Result<()> {
    let args = Args::parse();

    let file = File::open(args.path)?;

    let projects: Projects = serde_yaml_bw::from_reader(file)?;

    println!(
        "start to git clone projects, count: {}",
        projects.repos.len()
    );

    for repo in projects.repos {
        if let Err(e) = git_clone(
            &projects.git_name,
            &projects.git_email,
            &repo.name,
            &repo.url,
        ) {
            println!("git clone {} fail: {}", repo.url, e);
        }
    }

    println!("pull code finished");
    Ok(())
}

fn git_clone(git_name: &str, git_email: &str, name: &str, url: &str) -> Result<()> {
    let mut git = Command::new("git");
    git.arg("clone");

    if !git_name.is_empty() {
        git.args(["-c", &format!("user.name={}", git_name)]);
    }
    if !git_email.is_empty() {
        git.args(["-c", &format!("user.email={}", git_email)]);
    }

    git.arg(url);

    if name.ends_with('/') {
        let repo_name = get_repo_name(url).ok_or(anyhow::anyhow!("Get repo name fail"))?;
        git.arg(format!("{}{}", name, repo_name));
    } else if !name.is_empty() {
        git.arg(name);
    }
    git.stdout(io::stdout()).status()?;

    println!("git clone {} finished", url);
    Ok(())
}

fn get_repo_name(url: &str) -> Option<&str> {
    let end = url.rfind('.')?;
    let start = url.rfind('/')?;
    url.get(start + 1..end)
}

#[test]
fn test_get_repo_name() {
    println!(
        "{:?}",
        get_repo_name("https://github.com/something/some_project.git")
    );
}