|
1 |
| -use crate::onefetch::{commit_info::CommitInfo, error::*}; |
2 |
| -use git2::{Repository, RepositoryOpenFlags}; |
3 |
| -use regex::Regex; |
4 |
| -use std::path::Path; |
5 |
| - |
6 |
| -pub fn get_repo_work_dir(repo: &Repository) -> Result<String> { |
7 |
| - if let Some(workdir) = work_dir(&repo)?.to_str() { |
8 |
| - Ok(workdir.to_string()) |
9 |
| - } else { |
10 |
| - Err("invalid workdir".into()) |
| 1 | +use crate::onefetch::error::*; |
| 2 | +use std::process::Command; |
| 3 | + |
| 4 | +pub fn get_git_history(dir: &str, no_merges: bool) -> Result<Vec<String>> { |
| 5 | + let mut args = vec!["-C", dir, "log"]; |
| 6 | + if no_merges { |
| 7 | + args.push("--no-merges"); |
11 | 8 | }
|
12 |
| -} |
13 | 9 |
|
14 |
| -fn work_dir(repo: &Repository) -> Result<&Path> { |
15 |
| - repo.workdir().ok_or_else(|| "unable to query workdir".into()) |
| 10 | + args.push("--pretty=%cr\t%ae\t%an"); |
| 11 | + |
| 12 | + let output = Command::new("git").args(args).output()?; |
| 13 | + |
| 14 | + let output = String::from_utf8_lossy(&output.stdout); |
| 15 | + Ok(output.lines().map(|x| x.to_string()).collect::<Vec<_>>()) |
16 | 16 | }
|
17 | 17 |
|
18 |
| -pub fn get_repo_name_and_url(repo: &Repository) -> Result<(String, String)> { |
19 |
| - let config = repo.config()?; |
20 |
| - let mut remote_origin_url: Option<String> = None; |
21 |
| - let mut remote_url_fallback = String::new(); |
22 |
| - let mut repository_name = String::new(); |
23 |
| - let remote_regex = Regex::new(r"remote\.[a-zA-Z0-9]+\.url").unwrap(); |
24 |
| - |
25 |
| - for entry in &config.entries(None).unwrap() { |
26 |
| - let entry = entry?; |
27 |
| - let entry_name = entry.name().unwrap(); |
28 |
| - if entry_name == "remote.origin.url" { |
29 |
| - remote_origin_url = Some(entry.value().unwrap().to_string()); |
30 |
| - } else if remote_regex.is_match(entry_name) { |
31 |
| - remote_url_fallback = entry.value().unwrap().to_string() |
32 |
| - } |
| 18 | +pub fn get_authors(git_history: &[String], n: usize) -> Vec<(String, usize, usize)> { |
| 19 | + let mut authors = std::collections::HashMap::new(); |
| 20 | + let mut author_name_by_email = std::collections::HashMap::new(); |
| 21 | + let mut total_commits = 0; |
| 22 | + for line in git_history { |
| 23 | + let author_email = line.split('\t').collect::<Vec<_>>()[1].to_string(); |
| 24 | + let author_name = line.split('\t').collect::<Vec<_>>()[2].to_string(); |
| 25 | + let commit_count = authors.entry(author_email.to_string()).or_insert(0); |
| 26 | + author_name_by_email.entry(author_email.to_string()).or_insert(author_name); |
| 27 | + *commit_count += 1; |
| 28 | + total_commits += 1; |
33 | 29 | }
|
34 | 30 |
|
35 |
| - let remote_url = if let Some(url) = remote_origin_url { url } else { remote_url_fallback }; |
| 31 | + let mut authors: Vec<(String, usize)> = authors.into_iter().collect(); |
| 32 | + authors.sort_by(|(_, a_count), (_, b_count)| b_count.cmp(a_count)); |
36 | 33 |
|
37 |
| - let name_parts: Vec<&str> = remote_url.split('/').collect(); |
| 34 | + authors.truncate(n); |
38 | 35 |
|
39 |
| - if !name_parts.is_empty() { |
40 |
| - let mut i = 1; |
41 |
| - while repository_name.is_empty() && i <= name_parts.len() { |
42 |
| - repository_name = name_parts[name_parts.len() - i].to_string(); |
43 |
| - i += 1; |
44 |
| - } |
45 |
| - } |
| 36 | + let authors: Vec<(String, usize, usize)> = authors |
| 37 | + .into_iter() |
| 38 | + .map(|(author, count)| { |
| 39 | + ( |
| 40 | + author_name_by_email.get(&author).unwrap().trim_matches('\'').to_string(), |
| 41 | + count, |
| 42 | + count * 100 / total_commits, |
| 43 | + ) |
| 44 | + }) |
| 45 | + .collect(); |
46 | 46 |
|
47 |
| - if repository_name.contains(".git") { |
48 |
| - let repo_name = repository_name.clone(); |
49 |
| - let parts: Vec<&str> = repo_name.split(".git").collect(); |
50 |
| - repository_name = parts[0].to_string(); |
51 |
| - } |
| 47 | + authors |
| 48 | +} |
| 49 | + |
| 50 | +pub fn get_date_of_last_commit(git_history: &[String]) -> Result<String> { |
| 51 | + let last_commit = git_history.first(); |
| 52 | + |
| 53 | + let output = match last_commit { |
| 54 | + Some(date) => date.split('\t').collect::<Vec<_>>()[0].to_string(), |
| 55 | + None => "??".into(), |
| 56 | + }; |
52 | 57 |
|
53 |
| - Ok((repository_name, remote_url)) |
| 58 | + Ok(output) |
54 | 59 | }
|
55 | 60 |
|
56 |
| -pub fn get_current_commit_info(repo: &Repository) -> Result<CommitInfo> { |
57 |
| - let head = repo.head()?; |
58 |
| - let head_oid = head.target().ok_or("")?; |
59 |
| - let refs = repo.references()?; |
60 |
| - let refs_info = refs |
61 |
| - .filter_map(|reference| match reference { |
62 |
| - Ok(reference) => match (reference.target(), reference.shorthand()) { |
63 |
| - (Some(oid), Some(shorthand)) if oid == head_oid => Some(if reference.is_tag() { |
64 |
| - String::from("tags/") + shorthand |
65 |
| - } else { |
66 |
| - String::from(shorthand) |
67 |
| - }), |
68 |
| - _ => None, |
69 |
| - }, |
70 |
| - Err(_) => None, |
71 |
| - }) |
72 |
| - .collect::<Vec<String>>(); |
73 |
| - Ok(CommitInfo::new(head_oid, refs_info)) |
| 61 | +pub fn get_creation_date(git_history: &[String]) -> Result<String> { |
| 62 | + let first_commit = git_history.last(); |
| 63 | + |
| 64 | + let output = match first_commit { |
| 65 | + Some(creation_time) => creation_time.split('\t').collect::<Vec<_>>()[0].to_string(), |
| 66 | + None => "??".into(), |
| 67 | + }; |
| 68 | + |
| 69 | + Ok(output) |
74 | 70 | }
|
75 | 71 |
|
76 |
| -pub fn is_valid_repo(repo_path: &str) -> Result<bool> { |
77 |
| - let repo = Repository::open_ext(repo_path, RepositoryOpenFlags::empty(), Vec::<&Path>::new()); |
| 72 | +pub fn get_number_of_commits(git_history: &[String]) -> String { |
| 73 | + let number_of_commits = git_history.len(); |
| 74 | + number_of_commits.to_string() |
| 75 | +} |
| 76 | + |
| 77 | +pub fn get_packed_size(dir: &str) -> Result<String> { |
| 78 | + let output = Command::new("git") |
| 79 | + .arg("-C") |
| 80 | + .arg(dir) |
| 81 | + .arg("count-objects") |
| 82 | + .arg("-vH") |
| 83 | + .output() |
| 84 | + .expect("Failed to execute git."); |
| 85 | + |
| 86 | + let output = String::from_utf8_lossy(&output.stdout); |
| 87 | + let lines = output.to_string(); |
| 88 | + let size_line = lines.split('\n').find(|line| line.starts_with("size-pack:")); |
78 | 89 |
|
79 |
| - Ok(repo.is_ok() && !repo?.is_bare()) |
| 90 | + let repo_size = match size_line { |
| 91 | + None => "??", |
| 92 | + Some(size_str) => &(size_str[11..]), |
| 93 | + }; |
| 94 | + |
| 95 | + let output = Command::new("git") |
| 96 | + .arg("-C") |
| 97 | + .arg(dir) |
| 98 | + .arg("ls-files") |
| 99 | + .output() |
| 100 | + .expect("Failed to execute git."); |
| 101 | + // To check if command executed successfully or not |
| 102 | + let error = &output.stderr; |
| 103 | + |
| 104 | + if error.is_empty() { |
| 105 | + let output = String::from_utf8_lossy(&output.stdout); |
| 106 | + |
| 107 | + let lines = output.to_string(); |
| 108 | + let files_list = lines.split('\n'); |
| 109 | + let mut files_count: u128 = 0; |
| 110 | + for _file in files_list { |
| 111 | + files_count += 1; |
| 112 | + } |
| 113 | + files_count -= 1; // As splitting giving one line extra(blank). |
| 114 | + let res = repo_size.to_owned() + (" (") + &(files_count.to_string()) + (" files)"); |
| 115 | + Ok(res) |
| 116 | + } else { |
| 117 | + let res = repo_size; |
| 118 | + Ok(res.into()) |
| 119 | + } |
80 | 120 | }
|
0 commit comments