Skip to content

Commit

Permalink
Merge pull request #6 from krshrimali/development/db/part-1
Browse files Browse the repository at this point in the history
Implement in-house DB to avoid repetitive calls (Part-1)
  • Loading branch information
krshrimali authored Jun 25, 2023
2 parents f8816a1 + 494e2ad commit 137a4d0
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 80 deletions.
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

0 comments on commit 137a4d0

Please sign in to comment.