WIP
This commit is contained in:
parent
16e9c422a8
commit
9fcd0269a8
@ -1,4 +1,4 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use crate::projects::framework_macro::FrameworkHeuristics;
|
||||||
|
|
||||||
pub enum Framework {
|
pub enum Framework {
|
||||||
Laravel,
|
Laravel,
|
||||||
@ -8,63 +8,29 @@ pub enum Framework {
|
|||||||
Ansible,
|
Ansible,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_file<P: AsRef<Path>>(project_path: P, file: P) -> bool {
|
crate::frameworks! {
|
||||||
PathBuf::from(project_path.as_ref()).join(file).exists()
|
Laravel {
|
||||||
}
|
files: ["composer.json"],
|
||||||
|
json_checks: [("composer.json", "require.laravel/framework")],
|
||||||
fn read_json_config<P: AsRef<Path>>(project_path: P, file: P) -> Option<serde_json::Value> {
|
},
|
||||||
let pb = PathBuf::from(project_path.as_ref());
|
Ansible {
|
||||||
if let Ok(text) = std::fs::read_to_string(pb.join(file)) {
|
directories: ["playbooks"],
|
||||||
if let Ok(v) = serde_json::from_str::<serde_json::Value>(&text) {
|
custom: |project_path: &str| {
|
||||||
return Some(v);
|
use crate::projects::framework_macro::has_file;
|
||||||
}
|
has_file(project_path, "ansible.cfg") ||
|
||||||
} else {
|
has_file(project_path, "playbook.yml") ||
|
||||||
return None;
|
has_file(project_path, "site.yml") ||
|
||||||
}
|
has_file(project_path, "inventory") ||
|
||||||
|
has_file(project_path, "hosts") ||
|
||||||
None
|
has_file(project_path, "hosts.yml")
|
||||||
}
|
},
|
||||||
|
},
|
||||||
trait FrameworkHeuristics: Sync {
|
|
||||||
fn name(&self) -> &'static str;
|
|
||||||
fn matches(&self, project_path: &str) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Laravel;
|
|
||||||
impl FrameworkHeuristics for Laravel {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"Laravel"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn matches(&self, project_path: &str) -> bool {
|
|
||||||
// Check for composer.json
|
|
||||||
if !has_file(project_path, "composer.json") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If composer.json has "laravel/framework"
|
|
||||||
// we can say yes immediately
|
|
||||||
if let Some(cfg) = read_json_config(project_path, "composer.json") {
|
|
||||||
let requires_laravel = cfg
|
|
||||||
.get("require")
|
|
||||||
.and_then(|r| r.get("laravel/framework"))
|
|
||||||
.is_some();
|
|
||||||
if requires_laravel {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FrameworkDetector {
|
pub struct FrameworkDetector {
|
||||||
heuristics: &'static [&'static dyn FrameworkHeuristics],
|
heuristics: &'static [&'static dyn FrameworkHeuristics],
|
||||||
}
|
}
|
||||||
|
|
||||||
static LARAVEL: Laravel = Laravel;
|
|
||||||
static HEURISTICS: &[&dyn FrameworkHeuristics] = &[&LARAVEL];
|
|
||||||
|
|
||||||
impl FrameworkDetector {
|
impl FrameworkDetector {
|
||||||
pub fn new() -> FrameworkDetector {
|
pub fn new() -> FrameworkDetector {
|
||||||
FrameworkDetector {
|
FrameworkDetector {
|
||||||
|
118
waycast-plugins/src/projects/framework_macro.rs
Normal file
118
waycast-plugins/src/projects/framework_macro.rs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub fn has_file<P: AsRef<Path>>(project_path: P, file: P) -> bool {
|
||||||
|
PathBuf::from(project_path.as_ref()).join(file).exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_directory<P: AsRef<Path>>(project_path: P, dir: P) -> bool {
|
||||||
|
let path = PathBuf::from(project_path.as_ref()).join(dir);
|
||||||
|
path.exists() && path.is_dir()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_json_config<P: AsRef<Path>>(project_path: P, file: P) -> Option<serde_json::Value> {
|
||||||
|
let pb = PathBuf::from(project_path.as_ref());
|
||||||
|
if let Ok(text) = std::fs::read_to_string(pb.join(file)) {
|
||||||
|
if let Ok(v) = serde_json::from_str::<serde_json::Value>(&text) {
|
||||||
|
return Some(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_json_path(json: &serde_json::Value, path: &str) -> bool {
|
||||||
|
let parts: Vec<&str> = path.split('.').collect();
|
||||||
|
let mut current = json;
|
||||||
|
|
||||||
|
for part in parts {
|
||||||
|
if let Some(next) = current.get(part) {
|
||||||
|
current = next;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FrameworkHeuristics: Sync {
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
fn matches(&self, project_path: &str) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! frameworks {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
$name:ident {
|
||||||
|
$(files: [$($file:literal),* $(,)?],)?
|
||||||
|
$(directories: [$($dir:literal),* $(,)?],)?
|
||||||
|
$(json_checks: [$(($json_file:literal, $json_path:literal)),* $(,)?],)?
|
||||||
|
$(custom: $custom_fn:expr,)?
|
||||||
|
}
|
||||||
|
),* $(,)?
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
struct $name;
|
||||||
|
impl $crate::projects::framework_macro::FrameworkHeuristics for $name {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
stringify!($name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches(&self, project_path: &str) -> bool {
|
||||||
|
// Check required files first
|
||||||
|
$(
|
||||||
|
$(
|
||||||
|
if !$crate::projects::framework_macro::has_file(project_path, $file) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
)?
|
||||||
|
|
||||||
|
// Check directories - any match returns true
|
||||||
|
$(
|
||||||
|
$(
|
||||||
|
if $crate::projects::framework_macro::has_directory(project_path, $dir) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
)?
|
||||||
|
|
||||||
|
// Check JSON paths - any match returns true
|
||||||
|
$(
|
||||||
|
$(
|
||||||
|
if let Some(json) = $crate::projects::framework_macro::read_json_config(project_path, $json_file) {
|
||||||
|
if $crate::projects::framework_macro::check_json_path(&json, $json_path) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
)?
|
||||||
|
|
||||||
|
// Custom validation
|
||||||
|
$(
|
||||||
|
if ($custom_fn)(project_path) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
)?
|
||||||
|
|
||||||
|
// If we have files specified but no other checks, files existing means match
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
$(
|
||||||
|
$(
|
||||||
|
let _ = $file; // Use the file variable to indicate files were specified
|
||||||
|
return true;
|
||||||
|
)*
|
||||||
|
)?
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
)*
|
||||||
|
|
||||||
|
static HEURISTICS: &[&dyn $crate::projects::framework_macro::FrameworkHeuristics] = &[
|
||||||
|
$(&$name {},)*
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
pub mod framework_detector;
|
pub mod framework_detector;
|
||||||
|
pub mod framework_macro;
|
||||||
pub mod type_scanner;
|
pub mod type_scanner;
|
||||||
// TODO: Project type detection and icon
|
// TODO: Project type detection and icon
|
||||||
use std::{
|
use std::{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user