Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement in-house DB to avoid repetitive calls (Part-1) #6

Merged
merged 2 commits into from
Jun 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ btree-map = "0.1.0"
quicli = "0.4.0"
structopt = "0.3.26"
linecount = "0.1.0"
serde_json = "1.0.99"
serde = { version = "1.0.164", features = ["derive"] }
simple-home-dir = "0.1.2"
212 changes: 135 additions & 77 deletions src/algo_loc.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};
use std::path::Path;
use std::process::{Command, Stdio};

use crate::config::LAST_MANY_COMMIT_HASHES;
use crate::contextgpt_structs::AuthorDetails;
use crate::db::DB;

fn parse_str(input_str: &str, file_path: &str) -> Vec<AuthorDetails> {
let mut author_details_vec: Vec<AuthorDetails> = vec![];
Expand Down Expand Up @@ -56,22 +57,46 @@ fn get_data_for_line(
parsed_output: Vec<AuthorDetails>,
start_line_number: usize,
end_line_number: usize,
) -> Vec<AuthorDetails> {
) -> Option<Vec<AuthorDetails>> {
let mut output_list: Vec<AuthorDetails> = vec![];
for output in parsed_output {
if output.line_number >= start_line_number && output.line_number <= end_line_number {
output_list.push(output);
}
}
// TOOD: Address when line number is not valid or found
output_list
if output_list.is_empty() {
None
} else {
Some(output_list)
}
}

pub fn get_unique_files_changed(
file_path: String,
start_line_number: usize,
end_line_number: usize,
db_obj: &mut DB,
) -> String {
let configured_file_path: String =
format!("{file_path}**{start_line_number}**{end_line_number}");
// Check in the DB first
let mut res = String::new();
let mut visited: HashMap<String, usize> = HashMap::new();
if let Some(obj) = db_obj.exists(&configured_file_path) {
for author_detail in obj {
if visited.contains_key(&author_detail.file_path) {
continue;
}
visited.insert(author_detail.file_path.clone(), 1);
res.push_str(&author_detail.file_path);
res.push(',');
}
if res.ends_with(',') {
res.pop();
}
return res;
}
let mut binding = Command::new("git");
let command = binding.args([
"blame",
Expand All @@ -91,7 +116,7 @@ pub fn get_unique_files_changed(
get_data_for_line(parsed_output, start_line_number, end_line_number);

let mut all_files_changed: Vec<String> = Vec::new();
for author_detail_for_line in vec_author_detail_for_line {
for author_detail_for_line in vec_author_detail_for_line.unwrap() {
let val = author_detail_for_line;

let mut commit_id = val.commit_hash;
Expand Down Expand Up @@ -139,47 +164,59 @@ pub fn get_unique_files_changed(
.unwrap();
let out_buf = String::from_utf8(new_blame_command.stdout).unwrap();
let parsed_buf = parse_str(out_buf.as_str(), &file_path);
let author_detail_for_line =
get_data_for_line(parsed_buf, val.line_number, val.line_number);
if author_detail_for_line.is_empty() {
break;
}
let val = author_detail_for_line.get(0).unwrap();
commit_id = val.commit_hash.clone();
let out_files_for_commit_hash = get_files_for_commit_hash(&commit_id);
for each_file in out_files_for_commit_hash {
let each_file_path = Path::new(&each_file);
if !each_file_path.exists() {
// NOTE: If file doesn't exist, maybe it was moved/renamed/deleted - so skip it for now
continue;
// let author_detail_for_line =
// get_data_for_line(parsed_buf, val.line_number, val.line_number);
// let val = author_detail_for_line.unwrap().get(0).unwrap();
if let Some(valid_val) = get_data_for_line(parsed_buf, val.line_number, val.line_number)
{
commit_id = valid_val.get(0).unwrap().commit_hash.clone();
let out_files_for_commit_hash = get_files_for_commit_hash(&commit_id);
for each_file in out_files_for_commit_hash {
let each_file_path = Path::new(&each_file);
if !each_file_path.exists() {
// NOTE: If file doesn't exist, maybe it was moved/renamed/deleted - so skip it for now
continue;
}
all_files_changed.push(each_file);
// let mut sanitized_file_path = each_file.clone();
// // println!("Checking for {:?}", each_file);
// if !each_file_path.exists() {
// sanitized_file_path = get_correct_file_path(&each_file);
// // println!("Sanitized: {:?}", sanitized_file_path);
// // println!("Path before: {:?}", each_file);
// }
// all_files_changed.push(sanitized_file_path);
}
all_files_changed.push(each_file);
// let mut sanitized_file_path = each_file.clone();
// // println!("Checking for {:?}", each_file);
// if !each_file_path.exists() {
// sanitized_file_path = get_correct_file_path(&each_file);
// // println!("Sanitized: {:?}", sanitized_file_path);
// // println!("Path before: {:?}", each_file);
// }
// all_files_changed.push(sanitized_file_path);
}
}
}
let sorted_map = all_files_changed
.iter()
.fold(BTreeMap::new(), |mut acc, c| {
*acc.entry(c.to_string()).or_insert(0) += 1;
acc
});
let mut output_result = sorted_map.keys().fold(String::new(), |mut res, val| {
res.push_str(val);
res.push(',');
res
});
if output_result.ends_with(',') {
output_result.pop();
let mut res: HashMap<String, usize> = HashMap::new();
for file_val in all_files_changed {
let details = AuthorDetails {
file_path: file_val.clone(),
..Default::default()
};
db_obj.append(&configured_file_path, details.clone());
if res.contains_key(&file_val) {
let count = res.get(&file_val).unwrap() + 1;
res.insert(details.file_path, count);
continue;
}
res.insert(details.file_path, 0);
}
db_obj.store();
let mut res_string: String = String::new();
for key in res.keys() {
if key.contains("Commited Yet") {
continue;
}
res_string.push_str(key.as_str());
res_string.push(',');
}
output_result
if res_string.ends_with(',') {
res_string.pop();
}
res_string
}

pub fn parse_follow(input_str: &str, input_path: &str) -> Option<String> {
Expand Down Expand Up @@ -252,15 +289,10 @@ pub fn _correct_file_path(path_obj: &Path) -> Option<String> {
"--first-parent",
"--diff-filter=R",
"--name-status",
// "|",
// "grep",
// path_obj.to_str().unwrap(),
])
.stdout(Stdio::piped())
.output()
.unwrap();
// println!("output: {:?}", output);
// println!("path: {:?}", path_obj.to_str().unwrap());
let stdout_buf = String::from_utf8(output.stdout).unwrap();
let parsed_output = parse_moved(stdout_buf.as_str(), path_obj.to_str().unwrap());
if let Some(final_path) = parsed_output {
Expand All @@ -273,7 +305,30 @@ pub fn get_contextual_authors(
file_path: String,
start_line_number: usize,
end_line_number: usize,
db_obj: &mut DB,
) -> String {
let configured_file_path: String =
format!("{file_path}**{start_line_number}**{end_line_number}");
// Check in the DB first
let mut res = String::new();
let mut visited: HashMap<String, usize> = HashMap::new();
if let Some(obj) = db_obj.exists(&configured_file_path) {
for author_detail in obj {
if visited.contains_key(&author_detail.author_full_name) {
continue;
}
if author_detail.author_full_name.contains("Not Committed Yet") {
continue;
}
visited.insert(author_detail.author_full_name.clone(), 1);
res.push_str(&author_detail.author_full_name);
res.push(',');
}
if res.ends_with(',') {
res.pop();
}
return res;
}
let output = Command::new("git")
.args([
"blame",
Expand All @@ -292,21 +347,19 @@ pub fn get_contextual_authors(
let parsed_output = parse_str(stdout_buf.as_str(), &file_path);

let vec_author_detail_for_line =
get_data_for_line(parsed_output, start_line_number, end_line_number);
// TODO: Use this function when files don't exist and have been moved/renamed
// vec_author_detail_for_line = fix_details_in_case_of_move(vec_author_detail_for_line.clone());
get_data_for_line(parsed_output, start_line_number, end_line_number).unwrap_or(Vec::new());

let mut author_details: Vec<String> = Vec::new();
let mut author_details: Vec<AuthorDetails> = Vec::new();
for author_detail_for_line in vec_author_detail_for_line {
let val = author_detail_for_line;
author_details.push(val.author_full_name);
author_details.push(author_detail_for_line.clone());

let mut commit_id = val.commit_hash;
let mut commit_id = author_detail_for_line.clone().commit_hash;
let mut blame_count: i32 = 0;
while blame_count != LAST_MANY_COMMIT_HASHES {
blame_count += 1;
let line_string: String =
val.line_number.to_string() + &','.to_string() + &val.line_number.to_string();
let line_string: String = author_detail_for_line.line_number.to_string()
+ &','.to_string()
+ &author_detail_for_line.line_number.to_string();
let commit_url = commit_id.clone() + "^";
let cmd_args = vec![
"blame",
Expand All @@ -325,31 +378,36 @@ pub fn get_contextual_authors(
.unwrap();
let out_buf = String::from_utf8(new_blame_command.stdout).unwrap();
let parsed_buf = parse_str(out_buf.as_str(), &file_path);
let author_detail_for_line =
get_data_for_line(parsed_buf, val.line_number, val.line_number);
if author_detail_for_line.is_empty() {
break;

if let Some(valid_val) = get_data_for_line(
parsed_buf,
author_detail_for_line.line_number,
author_detail_for_line.line_number,
) {
commit_id = valid_val.get(0).unwrap().commit_hash.clone();
author_details.push(author_detail_for_line.clone());
}
let val = author_detail_for_line.get(0).unwrap();
commit_id = val.commit_hash.clone();
author_details.push(val.author_full_name.clone());
}
}
let sorted_map = author_details.iter().fold(BTreeMap::new(), |mut acc, c| {
*acc.entry(c.to_string()).or_insert(0) += 1;
acc
});
let reverse_sorted_map: BTreeMap<&i32, &String> =
sorted_map.iter().map(|(k, v)| (v, k)).collect();
let mut res = reverse_sorted_map
.values()
.fold(String::new(), |mut res, val| {
res.push_str(val);
res.push(',');
res
});
if res.ends_with(',') {
res.pop();

let mut res: HashMap<String, usize> = HashMap::new();
for author_detail_val in author_details {
db_obj.append(&configured_file_path, author_detail_val.clone());
if res.contains_key(&author_detail_val.author_full_name) {
let count = res.get(&author_detail_val.author_full_name).unwrap() + 1;
res.insert(author_detail_val.author_full_name, count);
continue;
}
res.insert(author_detail_val.author_full_name, 0);
}
db_obj.store();
let mut res_string: String = String::new();
for key in res.keys() {
if key.contains("Not Committed Yet") {
continue;
}
res_string.push_str(key.as_str());
res_string.push(',');
}
res
res_string
}
3 changes: 3 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
pub const LAST_MANY_COMMIT_HASHES: i32 = 5;
pub const AUTHOR_DB_PATH: &str = "db_author.json";
pub const FILE_DB_PATH: &str = "db_file.json";
pub const DB_FOLDER: &str = ".context_pilot_db";
3 changes: 2 additions & 1 deletion src/contextgpt_structs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use structopt::StructOpt;
use serde::{Deserialize, Serialize};

#[derive(Debug, StructOpt)]
pub struct Cli {
Expand All @@ -13,7 +14,7 @@ pub struct Cli {
pub request_type: String,
}

#[derive(Default, Debug, Clone)]
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct AuthorDetails {
pub commit_hash: String,
pub author_full_name: String,
Expand Down
Loading