summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTim Mulqueen <Multimo@users.noreply.github.com>2019-05-12 13:37:23 -0400
committerMatan Kushner <hello@matchai.me>2019-05-12 13:37:23 -0400
commit5fd715e7c30420ced129a41a1765919b31528cc6 (patch)
treef7284f4797f30757826d3487631444f0bf005a4d /src
parentd3ce00c5163b1c6a2b3bc510f8900d51f5320d54 (diff)
Implement directory scanner (#34)
Diffstat (limited to 'src')
-rw-r--r--src/context.rs135
-rw-r--r--src/modules/go.rs63
-rw-r--r--src/modules/nodejs.rs21
-rw-r--r--src/modules/python.rs32
-rw-r--r--src/modules/rust.rs19
5 files changed, 184 insertions, 86 deletions
diff --git a/src/context.rs b/src/context.rs
index 035eec90a..63ca28e76 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -1,6 +1,7 @@
use clap::ArgMatches;
use git2::Repository;
use std::env;
+use std::ffi::OsStr;
use std::fs;
use std::path::PathBuf;
@@ -56,4 +57,138 @@ impl<'a> Context<'a> {
}
dir
}
+
+ // returns a new ScanDir struct with reference to current dir_files of context
+ // see ScanDir for methods
+ pub fn new_scan_dir(&'a self) -> ScanDir<'a> {
+ ScanDir {
+ dir_files: self.dir_files.as_ref(),
+ files: &[],
+ folders: &[],
+ extensions: &[],
+ }
+ }
+}
+
+// A struct of Criteria which will be used to verify current PathBuf is
+// of X language, criteria can be set via the builder pattern
+pub struct ScanDir<'a> {
+ dir_files: &'a Vec<PathBuf>, // Replace with reference
+ files: &'a [&'a str],
+ folders: &'a [&'a str],
+ extensions: &'a [&'a str],
+}
+
+impl<'a> ScanDir<'a> {
+ pub fn set_files(mut self, files: &'a [&'a str]) -> Self {
+ self.files = files;
+ self
+ }
+
+ pub fn set_extensions(mut self, extensions: &'a [&'a str]) -> Self {
+ self.extensions = extensions;
+ self
+ }
+
+ pub fn set_folders(mut self, folders: &'a [&'a str]) -> Self {
+ self.folders = folders;
+ self
+ }
+
+ /// based on the current Pathbuf check to see
+ /// if any of this criteria match or exist and returning a boolean
+ pub fn scan(&mut self) -> bool {
+ self.dir_files.iter().any(|path| {
+ path_has_name(&path, &self.folders)
+ || path_has_name(&path, &self.files)
+ || has_extension(&path, &self.extensions)
+ })
+ }
+}
+
+/// checks to see if the pathbuf matches a file or folder name
+pub fn path_has_name<'a>(dir_entry: &PathBuf, names: &'a [&'a str]) -> bool {
+ let found_file_or_folder_name = names.into_iter().find(|file_or_folder_name| {
+ dir_entry
+ .file_name()
+ .and_then(OsStr::to_str)
+ .unwrap_or_default()
+ == **file_or_folder_name
+ });
+
+ match found_file_or_folder_name {
+ Some(name) => !name.is_empty(),
+ None => false,
+ }
+}
+
+/// checks if pathbuf matches the extension provided
+pub fn has_extension<'a>(dir_entry: &PathBuf, extensions: &'a [&'a str]) -> bool {
+ let found_ext = extensions.into_iter().find(|ext| {
+ dir_entry
+ .extension()
+ .and_then(OsStr::to_str)
+ .unwrap_or_default()
+ == **ext
+ });
+
+ match found_ext {
+ Some(extension) => !extension.is_empty(),
+ None => false,
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_path_has_name() {
+ let mut buf = PathBuf::from("/");
+ let files = vec!["package.json"];
+
+ assert_eq!(path_has_name(&buf, &files), false);
+
+ buf.set_file_name("some-file.js");
+ assert_eq!(path_has_name(&buf, &files), false);
+
+ buf.set_file_name("package.json");
+ assert_eq!(path_has_name(&buf, &files), true);
+ }
+
+ #[test]
+ fn test_has_extension() {
+ let mut buf = PathBuf::from("/");
+ let extensions = vec!["js"];
+
+ assert_eq!(has_extension(&buf, &extensions), false);
+
+ buf.set_file_name("some-file.rs");
+ assert_eq!(has_extension(&buf, &extensions), false);
+
+ buf.set_file_name("some-file.js");
+ assert_eq!(has_extension(&buf, &extensions), true)
+ }
+
+ #[test]
+ fn test_criteria_scan() {
+ let mut failing_criteria = ScanDir {
+ dir_files: &vec![PathBuf::new()],
+ files: &["package.json"],
+ extensions: &["js"],
+ folders: &["node_modules"],
+ };
+
+ // fails if buffer does not match any criteria
+ assert_eq!(failing_criteria.scan(), false);
+
+ let mut passing_criteria = ScanDir {
+ dir_files: &vec![PathBuf::from("package.json")],
+ files: &["package.json"],
+ extensions: &["js"],
+ folders: &["node_modules"],
+ };
+
+ assert_eq!(passing_criteria.scan(), true);
+ }
}
diff --git a/src/modules/go.rs b/src/modules/go.rs
index f6b2f2c9a..76728e38a 100644
--- a/src/modules/go.rs
+++ b/src/modules/go.rs
@@ -4,59 +4,44 @@ use std::process::Command;
use super::{Context, Module};
-/// Creates a segment with the current Python version
+/// Creates a segment with the current Go version
///
-/// Will display the Python version if any of the following criteria are met:
-/// - Current directory contains a `.go` file
+/// Will display the Go version if any of the following criteria are met:
/// - Current directory contains a `go.mod` file
/// - Current directory contains a `go.sum` file
-/// - Current directory contains a `Godeps` directory
/// - Current directory contains a `glide.yaml` file
/// - Current directory contains a `Gopkg.yml` file
/// - Current directory contains a `Gopkg.lock` file
+/// - Current directory contains a `.go` file
+/// - Current directory contains a `Godeps` directory
pub fn segment(context: &Context) -> Option<Module> {
- let is_go_project = context.dir_files.iter().any(has_go_files);
+ let is_go_project = context
+ .new_scan_dir()
+ .set_files(&["go.mod", "go.sum", "glide.yaml", "Gopkg.yml", "Gopkg.lock"])
+ .set_extensions(&["go"])
+ .set_folders(&["Godeps"])
+ .scan();
+
if !is_go_project {
return None;
}
- const GO_CHAR: &str = "🐹 ";
- let module_color = Color::Cyan.bold();
+ match get_go_version() {
+ Some(go_version) => {
+ const GO_CHAR: &str = "🐹 ";
+ let module_color = Color::Cyan.bold();
- let mut module = Module::new("go");
- module.set_style(module_color);
+ let mut module = Module::new("go");
+ module.set_style(module_color);
- let go_version = get_go_version()?;
- let formatted_version = format_go_version(go_version)?;
- module.new_segment("symbol", GO_CHAR);
- module.new_segment("version", formatted_version);
+ let formatted_version = format_go_version(go_version)?;
+ module.new_segment("symbol", GO_CHAR);
+ module.new_segment("version", formatted_version);
- Some(module)
-}
-
-fn has_go_files(dir_entry: &PathBuf) -> bool {
- let is_go_mod =
- |d: &PathBuf| -> bool { d.is_file() && d.file_name().unwrap_or_default() == "go.mod" };
- let is_go_sum =
- |d: &PathBuf| -> bool { d.is_file() && d.file_name().unwrap_or_default() == "go.sum" };
- let is_godeps =
- |d: &PathBuf| -> bool { d.is_dir() && d.file_name().unwrap_or_default() == "Godeps" };
- let is_glide_yaml =
- |d: &PathBuf| -> bool { d.is_file() && d.file_name().unwrap_or_default() == "glide.yaml" };
- let is_go_file =
- |d: &PathBuf| -> bool { d.is_file() && d.extension().unwrap_or_default() == "go" };
- let is_gopkg_yml =
- |d: &PathBuf| -> bool { d.is_file() && d.file_name().unwrap_or_default() == "Gopkg.yml" };
- let is_gopkg_lock =
- |d: &PathBuf| -> bool { d.is_file() && d.file_name().unwrap_or_default() == "Gopkg.lock" };
-
- is_go_mod(&dir_entry)
- || is_go_sum(&dir_entry)
- || is_godeps(&dir_entry)
- || is_glide_yaml(&dir_entry)
- || is_go_file(&dir_entry)
- || is_gopkg_yml(&dir_entry)
- || is_gopkg_lock(&dir_entry)
+ Some(module)
+ }
+ None => None,
+ }
}
fn get_go_version() -> Option<String> {
diff --git a/src/modules/nodejs.rs b/src/modules/nodejs.rs
index 6552c5556..b9736687e 100644
--- a/src/modules/nodejs.rs
+++ b/src/modules/nodejs.rs
@@ -1,5 +1,4 @@
use ansi_term::Color;
-use std::path::PathBuf;
use std::process::Command;
use super::{Context, Module};
@@ -11,7 +10,13 @@ use super::{Context, Module};
/// - Current directory contains a `package.json` file
/// - Current directory contains a `node_modules` directory
pub fn segment(context: &Context) -> Option<Module> {
- let is_js_project = context.dir_files.iter().any(has_js_files);
+ let is_js_project = context
+ .new_scan_dir()
+ .set_files(&["package.json"])
+ .set_extensions(&["js"])
+ .set_folders(&["node_modules"])
+ .scan();
+
if !is_js_project {
return None;
}
@@ -34,18 +39,6 @@ pub fn segment(context: &Context) -> Option<Module> {
}
}
-fn has_js_files(dir_entry: &PathBuf) -> bool {
- let is_js_file =
- |d: &PathBuf| -> bool { d.is_file() && d.extension().unwrap_or_default() == "js" };
- let is_node_modules =
- |d: &PathBuf| -> bool { d.is_dir() && d.file_name().unwrap_or_default() == "node_modules" };
- let is_package_json = |d: &PathBuf| -> bool {
- d.is_file() && d.file_name().unwrap_or_default() == "package.json"
- };
-
- is_js_file(&dir_entry) || is_node_modules(&dir_entry) || is_package_json(&dir_entry)
-}
-
fn get_node_version() -> Option<String> {
match Command::new("node").arg("--version").output() {
Ok(output) => Some(String::from_utf8(output.stdout).unwrap()),
diff --git a/src/modules/python.rs b/src/modules/python.rs
index 70625a47c..fdab440e3 100644
--- a/src/modules/python.rs
+++ b/src/modules/python.rs
@@ -1,5 +1,4 @@
use ansi_term::Color;
-use std::path::PathBuf;
use std::process::Command;
use super::{Context, Module};
@@ -12,7 +11,17 @@ use super::{Context, Module};
/// - Current directory contains a `requirements.txt` file
/// - Current directory contains a `pyproject.toml` file
pub fn segment(context: &Context) -> Option<Module> {
- let is_py_project = context.dir_files.iter().any(has_py_files);
+ let is_py_project = context
+ .new_scan_dir()
+ .set_files(&[
+ "requirements.txt",
+ ".python-version",
+ "pyproject.toml",
+ "pyproject.toml",
+ ])
+ .set_extensions(&["py"])
+ .scan();
+
if !is_py_project {
return None;
}
@@ -35,25 +44,6 @@ pub fn segment(context: &Context) -> Option<Module> {
}
}
-fn has_py_files(dir_entry: &PathBuf) -> bool {
- let is_py_file =
- |d: &PathBuf| -> bool { d.is_file() && d.extension().unwrap_or_default() == "py" };
- let is_python_version = |d: &PathBuf| -> bool {
- d.is_file() && d.file_name().unwrap_or_default() == ".python-version"
- };
- let is_requirements_txt = |d: &PathBuf| -> bool {
- d.is_file() && d.file_name().unwrap_or_default() == "requirements.txt"
- };
- let is_py_project = |d: &PathBuf| -> bool {
- d.is_file() && d.file_name().unwrap_or_default() == "pyproject.toml"
- };
-
- is_py_file(&dir_entry)
- || is_python_version(&dir_entry)
- || is_requirements_txt(&dir_entry)
- || is_py_project(&dir_entry)
-}
-
fn get_python_version() -> Option<String> {
match Command::new("python").arg("--version").output() {
Ok(output) => Some(String::from_utf8(output.stdout).unwrap()),
diff --git a/src/modules/rust.rs b/src/modules/rust.rs
index 1f0ae6036..ab3679e76 100644
--- a/src/modules/rust.rs
+++ b/src/modules/rust.rs
@@ -1,5 +1,4 @@
use ansi_term::Color;
-use std::path::PathBuf;
use std::process::Command;
use super::{Context, Module};
@@ -7,10 +6,15 @@ use super::{Context, Module};
/// Creates a segment with the current Rust version
///
/// Will display the Rust version if any of the following criteria are met:
-/// - Current directory contains a `.rs` file
+/// - Current directory contains a file with a `.rs` extension
/// - Current directory contains a `Cargo.toml` file
pub fn segment(context: &Context) -> Option<Module> {
- let is_rs_project = context.dir_files.iter().any(has_rs_files);
+ let is_rs_project = context
+ .new_scan_dir()
+ .set_files(&["Cargo.toml"])
+ .set_extensions(&["rs"])
+ .scan();
+
if !is_rs_project {
return None;
}
@@ -33,15 +37,6 @@ pub fn segment(context: &Context) -> Option<Module> {
}
}
-fn has_rs_files(dir_entry: &PathBuf) -> bool {
- let is_rs_file =
- |d: &PathBuf| -> bool { d.is_file() && d.extension().unwrap_or_default() == "rs" };
- let is_cargo_toml =
- |d: &PathBuf| -> bool { d.is_file() && d.file_name().unwrap_or_default() == "Cargo.toml" };
-
- is_rs_file(&dir_entry) || is_cargo_toml(&dir_entry)
-}
-
fn get_rust_version() -> Option<String> {
match Command::new("rustc").arg("-V").output() {
Ok(output) => Some(String::from_utf8(output.stdout).unwrap()),