use std::{
collections::HashSet,
path::{Path, PathBuf},
};
use anyhow::Context;
use glob::glob;
use serde::{Deserialize, Serialize};
use crate::{get_project_root, submodules::build::Step};
use super::Plugin;
#[derive(Default, Debug, Deserialize, Serialize)]
pub struct PluginToml {
pub name: String,
pub version: String,
pub stage: Stage,
#[serde(skip)]
pub path: PathBuf,
pub package_paths: Option<Vec<PathBuf>>,
}
#[derive(Default, Debug, Deserialize, Serialize)]
pub struct Stage {
pub pre: Option<PluginStage>,
pub aapt: Option<PluginStage>,
pub compile: Option<PluginStage>,
pub dex: Option<PluginStage>,
pub bundle: Option<PluginStage>,
pub post: Option<PluginStage>,
}
#[derive(Default, Debug, Deserialize, Serialize)]
pub struct PluginStage {
pub file: PathBuf,
pub priority: i32,
pub inputs: Option<Vec<String>>,
pub outputs: Option<Vec<String>>,
}
impl PluginToml {
pub fn get_steps(&self) -> anyhow::Result<Vec<Plugin>> {
let mut steps = vec![];
macro_rules! map_plugin {
[$($i:ident = $j:expr),*] => {
$(
// check if $i is set, if set then create a sub plugin
if let Some(s) = &self.stage.$i {
let mut path = self.path.clone();
path.push(s.file.clone());
let mut plugin = Plugin::new(self.name.clone(), self.version.clone(), path, $j);
plugin.priority = s.priority;
plugin.package_paths = if let Some(package_paths) = &self.package_paths{
load_package_paths(package_paths, &self.path)
}else{
load_package_paths(&[], &self.path)
};
if s.inputs.is_some() && s.outputs.is_some() {
plugin.dependents = Some((expand_globs(s.inputs.clone().unwrap()).context("Unable to expand global patterns specified by the inputs dependents")?,
expand_globs(s.outputs.clone().unwrap()).context("Unable to expand global patterns specified by the outputs dependents")?));
}
steps.push(plugin);
}
)*
};
}
map_plugin![
pre = Step::PRE,
aapt = Step::AAPT,
compile = Step::COMPILE,
dex = Step::DEX,
bundle = Step::BUNDLE,
post = Step::POST
];
Ok(steps)
}
}
fn expand_globs(patterns: Vec<String>) -> anyhow::Result<Vec<PathBuf>> {
let mut paths: HashSet<PathBuf> = HashSet::new();
for pattern in patterns {
let path = PathBuf::from(pattern);
let path = if path.is_relative() {
let mut root = get_project_root()
.context("Failed to get project root directory")?
.clone();
root.push(path);
root
} else {
path
};
glob(path.to_str().unwrap_or_default())
.context("Failed to match glob pattern")?
.filter_map(Result::ok)
.for_each(|p| {
paths.insert(p);
});
}
Ok(paths.iter().map(|p| p.to_owned()).collect())
}
fn load_package_paths(paths: &[PathBuf], plugin_root: &Path) -> Vec<PathBuf> {
let mut paths: Vec<PathBuf> = paths
.iter()
.map(|p| {
if p.is_relative() {
let mut new = PathBuf::from(plugin_root);
new.push(p);
new
} else {
p.to_owned()
}
})
.collect();
let mut lua_match = PathBuf::from(plugin_root);
lua_match.push("?.lua");
paths.push(lua_match);
let mut lua_init_match = PathBuf::from(plugin_root);
lua_init_match.push("?/init.lua");
paths.push(lua_init_match);
paths
}