Skip to content

Commit

Permalink
Allow the user to specify multiple paths to codebase
Browse files Browse the repository at this point in the history
  • Loading branch information
ketkarameya committed Aug 21, 2023
1 parent b16fa19 commit befb375
Show file tree
Hide file tree
Showing 15 changed files with 133 additions and 76 deletions.
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.1.0
rev: v4.4.0
hooks:
- id: check-byte-order-marker
- id: check-case-conflict
Expand Down Expand Up @@ -51,13 +51,13 @@ repos:
- --comment-style
- "#"
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: "v2.0.1"
rev: "v2.0.2"
hooks:
- id: autopep8
files: demo/
exclude: only_lists.py
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "" # Use the sha or tag you want to point at
rev: "v3.0.2" # Use the sha or tag you want to point at
hooks:
- id: prettier
files: ^experimental/piranha_playground/
7 changes: 4 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,12 @@ impl Piranha {

let mut parser = piranha_args.language().parser();

let mut path_to_codebase = self.piranha_arguments.path_to_codebase().to_string();
let mut paths_to_codebase = self.piranha_arguments.paths_to_codebase().clone();

let temp_dir = if !self.piranha_arguments.code_snippet().is_empty() {
let td = self.write_code_snippet_to_temp();
path_to_codebase = td.path().to_str().unwrap_or_default().to_string();
// let td_path = td.path().to_str().unwrap().to_string();
paths_to_codebase = vec![td.path().to_str().unwrap_or_default().to_string()];
Some(td)
} else {
None
Expand All @@ -137,7 +138,7 @@ impl Piranha {
// Iterate over each file containing the usage of the feature flag API

for (path, content) in self.rule_store.get_relevant_files(
&path_to_codebase,
&paths_to_codebase,
piranha_args.include(),
piranha_args.exclude(),
) {
Expand Down
4 changes: 2 additions & 2 deletions src/models/default_configs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ pub fn default_dry_run() -> bool {
false
}

pub fn default_path_to_codebase() -> String {
String::new()
pub fn default_paths_to_codebase() -> Vec<String> {
Vec::new()
}

pub fn default_code_snippet() -> String {
Expand Down
6 changes: 3 additions & 3 deletions src/models/language.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
limitations under the License.
*/

use std::str::FromStr;
use std::{path::PathBuf, str::FromStr};

use getset::Getters;
use serde_derive::Deserialize;
Expand Down Expand Up @@ -91,8 +91,8 @@ impl PiranhaLanguage {
parser
}

pub(crate) fn can_parse(&self, de: &jwalk::DirEntry<((), ())>) -> bool {
de.path()
pub(crate) fn can_parse(&self, path: &PathBuf) -> bool {
path
.extension()
.and_then(|e| e.to_str().filter(|x| x.eq(&self.extension())))
.is_some()
Expand Down
18 changes: 9 additions & 9 deletions src/models/piranha_arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use super::{
default_allow_dirty_ast, default_cleanup_comments, default_cleanup_comments_buffer,
default_code_snippet, default_delete_consecutive_new_lines, default_delete_file_if_empty,
default_dry_run, default_exclude, default_global_tag_prefix, default_graph_validation,
default_include, default_number_of_ancestors_in_parent_scope, default_path_to_codebase,
default_path_to_configurations, default_path_to_output_summaries, default_piranha_language,
default_include, default_number_of_ancestors_in_parent_scope, default_path_to_configurations,
default_path_to_output_summaries, default_paths_to_codebase, default_piranha_language,
default_rule_graph, default_substitutions, GO, JAVA, KOTLIN, PYTHON, SWIFT, TSX, TYPESCRIPT,
},
language::PiranhaLanguage,
Expand Down Expand Up @@ -50,9 +50,9 @@ use std::collections::HashMap;
pub struct PiranhaArguments {
/// Path to source code folder or file
#[get = "pub"]
#[builder(default = "default_path_to_codebase()")]
#[builder(default = "default_paths_to_codebase()")]
#[clap(short = 'c', long, required = true)]
path_to_codebase: String,
paths_to_codebase: Vec<String>,

/// Paths to include (as glob patterns)
#[get = "pub"]
Expand Down Expand Up @@ -191,7 +191,7 @@ impl PiranhaArguments {
/// Returns PiranhaArgument.
#[new]
fn py_new(
language: String, path_to_codebase: Option<String>, include: Option<Vec<String>>,
language: String, paths_to_codebase: Vec<String>, include: Option<Vec<String>>,
exclude: Option<Vec<String>>, substitutions: Option<&PyDict>,
path_to_configurations: Option<String>, rule_graph: Option<RuleGraph>,
code_snippet: Option<String>, dry_run: Option<bool>, cleanup_comments: Option<bool>,
Expand All @@ -208,7 +208,7 @@ impl PiranhaArguments {

let rg = rule_graph.unwrap_or_else(|| RuleGraphBuilder::default().build());
PiranhaArgumentsBuilder::default()
.path_to_codebase(path_to_codebase.unwrap_or_else(default_path_to_codebase))
.paths_to_codebase(paths_to_codebase)
.include(
include
.unwrap_or_default()
Expand Down Expand Up @@ -258,7 +258,7 @@ impl PiranhaArguments {
pub fn from_cli() -> Self {
let p = PiranhaArguments::parse();
PiranhaArgumentsBuilder::default()
.path_to_codebase(p.path_to_codebase().to_string())
.paths_to_codebase(p.paths_to_codebase().clone())
.substitutions(p.substitutions.clone())
.language(p.language().clone())
.path_to_configurations(p.path_to_configurations().to_string())
Expand Down Expand Up @@ -344,14 +344,14 @@ fn get_rule_graph(_arg: &PiranhaArguments) -> RuleGraph {
impl Validator for PiranhaArguments {
fn validate(&self) -> Result<(), String> {
let _arg: PiranhaArguments = self.clone();
if _arg.code_snippet().is_empty() && _arg.path_to_codebase().is_empty() {
if _arg.code_snippet().is_empty() && _arg.paths_to_codebase().is_empty() {
return Err(
"Invalid Piranha Argument. Missing `path_to_codebase` or `code_snippet`.
Please specify the `path_to_codebase` or `code_snippet` when creating PiranhaArgument !!!"
.to_string(),
);
}
if !_arg.code_snippet().is_empty() && !_arg.path_to_codebase().is_empty() {
if !_arg.code_snippet().is_empty() && !_arg.paths_to_codebase().is_empty() {
return Err(
"Invalid Piranha arguments. Please either specify the `path_to_codebase` or the `code_snippet`. Not Both."
.to_string(),
Expand Down
77 changes: 51 additions & 26 deletions src/models/rule_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,19 +143,58 @@ impl RuleStore {
/// Note that `WalkDir` traverses the directory with parallelism.
/// If all the global rules have no holes (i.e. we will have no grep patterns), we will try to find a match for each global rule in every file in the target.
pub(crate) fn get_relevant_files(
&self, path_to_codebase: &str, include: &Vec<Pattern>, exclude: &Vec<Pattern>,
&self, paths_to_codebase: &Vec<String>, include: &Vec<Pattern>, exclude: &Vec<Pattern>,
) -> HashMap<PathBuf, String> {
let _path_to_codebase = Path::new(path_to_codebase).to_path_buf();

//If the path_to_codebase is a file, then execute piranha on it
if _path_to_codebase.is_file() {
return HashMap::from_iter([(
_path_to_codebase.clone(),
read_file(&_path_to_codebase).unwrap(),
)]);
let mut candidate_files: HashMap<PathBuf, String> = HashMap::new();

for p2codebase in paths_to_codebase {
if !Path::new(p2codebase).exists() {
panic!("Path to codebase does not exist: {}", p2codebase);
}
let _paths_to_codebase = Path::new(p2codebase).to_path_buf();
// If the path to codebase is a file, and the language can parse it, then add it to the files
if _paths_to_codebase.is_file() && self.language().can_parse(&_paths_to_codebase) {
candidate_files.insert(
_paths_to_codebase.clone(),
read_file(&_paths_to_codebase).unwrap(),
);
continue;
}
candidate_files.extend(self.get_candidate_files_from_dir(p2codebase, include, exclude));
}

let mut files: HashMap<PathBuf, String> = WalkDir::new(path_to_codebase)
// Filter the files based on the global rules with holes
let final_file_set = self.filter_files_based_on_global_rule_holes(candidate_files);

debug!(
"{}",
format!("{} files will be analyzed.", final_file_set.len()).green()
);
final_file_set
}

// If there are global rules with holes (grep patterns containing placeholders), filter files to find matches for those patterns in the target.
// Otherwise, report all the files in the target.
fn filter_files_based_on_global_rule_holes(
&self, candidate_files: HashMap<PathBuf, String>,
) -> HashMap<PathBuf, String> {
if self.any_global_rules_has_holes() {
let pattern = self.get_grep_heuristics();
return candidate_files
.iter()
// Filter the files containing the desired regex pattern
.filter(|x| pattern.is_match(x.1.as_str()))
.map(|(x, y)| (x.clone(), y.clone()))
.collect();
}
candidate_files
}

/// Gets all the files from the code base that (i) have the language appropriate file extension, and (ii) satisfy include/exclude glob pattern
fn get_candidate_files_from_dir(
&self, p2codebase: &String, include: &Vec<Pattern>, exclude: &Vec<Pattern>,
) -> HashMap<PathBuf, String> {
let mut _files: HashMap<PathBuf, String> = WalkDir::new(p2codebase)
// walk over the entire code base
.into_iter()
// ignore errors
Expand All @@ -165,24 +204,10 @@ impl RuleStore {
// filter out all excluded paths (if any)
.filter(|f| exclude.is_empty() || exclude.iter().all(|p| !p.matches_path(&f.path())))
// filter files with the desired extension
.filter(|de| self.language().can_parse(de))
.filter(|de| self.language().can_parse(&de.path()))
// read the file
.map(|f| (f.path(), read_file(&f.path()).unwrap()))
.collect();

if self.any_global_rules_has_holes() {
let pattern = self.get_grep_heuristics();
files = files
.iter()
// Filter the files containing the desired regex pattern
.filter(|x| pattern.is_match(x.1.as_str()))
.map(|(x, y)| (x.clone(), y.clone()))
.collect();
}
debug!(
"{}",
format!("{} files will be analyzed.", files.len()).green()
);
files
_files
}
}
2 changes: 1 addition & 1 deletion src/models/unit_tests/piranha_arguments_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn piranha_argument_invalid_no_codebase_and_snippet() {
fn piranha_argument_invalid_both_codebase_and_snippet() {
let _ = PiranhaArgumentsBuilder::default()
.path_to_configurations("some/path".to_string())
.path_to_codebase("dev/null".to_string())
.paths_to_codebase(vec!["dev/null".to_string()])
.code_snippet("class A { }".to_string())
.language(PiranhaLanguage::from(JAVA))
.substitutions(substitutions! {"super_interface_name" => "SomeInterface"})
Expand Down
10 changes: 5 additions & 5 deletions src/models/unit_tests/rule_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ fn test_get_edit_positive_recursive() {
let mut rule_store = RuleStore::default();

let args = PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.build();
let mut parser = args.language().parser();

Expand Down Expand Up @@ -173,7 +173,7 @@ fn test_get_edit_negative_recursive() {
let mut rule_store = RuleStore::default();

let args = PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.build();
let mut parser = args.language().parser();

Expand Down Expand Up @@ -214,7 +214,7 @@ fn test_get_edit_for_context_positive() {

let mut rule_store = RuleStore::default();
let args = PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.build();
let mut parser = args.language().parser();

Expand Down Expand Up @@ -255,7 +255,7 @@ fn test_get_edit_for_context_negative() {
let mut rule_store = RuleStore::default();

let args = PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.build();
let mut parser = args.language().parser();

Expand Down Expand Up @@ -302,7 +302,7 @@ fn run_test_satisfies_filters_not_enclosing_node(
let java = PiranhaLanguage::from(JAVA);
let mut parser = java.parser();
let piranha_args = PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.language(java)
.build();
let source_code_unit = SourceCodeUnit::new(
Expand Down
16 changes: 8 additions & 8 deletions src/models/unit_tests/source_code_unit_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl SourceCodeUnit {
&HashMap::new(),
PathBuf::new().as_path(),
&PiranhaArgumentsBuilder::default()
.path_to_codebase("some/test/path/".to_string())
.paths_to_codebase(vec!["some/test/path/".to_string()])
.language(PiranhaLanguage::from(language_name.as_str()))
.build(),
)
Expand Down Expand Up @@ -156,7 +156,7 @@ fn run_test_satisfies_filters(
let java = get_java_tree_sitter_language();
let mut parser = java.parser();
let piranha_args = PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.language(java)
.build();
let source_code_unit = SourceCodeUnit::new(
Expand Down Expand Up @@ -316,7 +316,7 @@ fn test_satisfies_filters_not_contains_positive() {
let java = get_java_tree_sitter_language();
let mut parser = java.parser();
let piranha_args = PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.language(java)
.build();
let source_code_unit = SourceCodeUnit::new(
Expand Down Expand Up @@ -381,7 +381,7 @@ fn test_satisfies_filters_not_contains_negative() {
let java = get_java_tree_sitter_language();
let mut parser = java.parser();
let piranha_arguments = &PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.language(java)
.build();
let source_code_unit = SourceCodeUnit::new(
Expand Down Expand Up @@ -456,7 +456,7 @@ fn test_satisfies_filters_child_count() {
let java = get_java_tree_sitter_language();
let mut parser = java.parser();
let piranha_arguments = &PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.language(java)
.build();
let source_code_unit = SourceCodeUnit::new(
Expand Down Expand Up @@ -527,7 +527,7 @@ fn test_satisfies_filters_sibling_count() {
let java = get_java_tree_sitter_language();
let mut parser = java.parser();
let piranha_arguments = &PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.language(java)
.build();
let source_code_unit = SourceCodeUnit::new(
Expand Down Expand Up @@ -578,7 +578,7 @@ fn run_test_satisfies_filters_without_enclosing(
let java = get_java_tree_sitter_language();
let mut parser = java.parser();
let piranha_args = PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.language(java)
.build();
let source_code_unit = SourceCodeUnit::new(
Expand Down Expand Up @@ -679,7 +679,7 @@ fn test_satisfies_outermost_enclosing_node() {
let java = get_java_tree_sitter_language();
let mut parser = java.parser();
let piranha_arguments = &PiranhaArgumentsBuilder::default()
.path_to_codebase(UNUSED_CODE_PATH.to_string())
.paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()])
.language(java)
.build();
let source_code_unit = SourceCodeUnit::new(
Expand Down
Loading

0 comments on commit befb375

Please sign in to comment.