use cargo_metadata::camino::Utf8PathBuf;
use clap::{Parser, Subcommand};
use serde::{Deserialize, Serialize};
#[derive(Parser, Deserialize, Serialize)]
#[command(
version,
about,
long_about,
disable_help_flag = true,
bin_name = "cargo bevy-api-gen",
arg_required_else_help = true
)]
pub struct Args {
#[command(subcommand)]
pub cmd: Command,
#[command(flatten)]
pub verbose: Verbosity,
#[arg(
global = true,
short,
long,
default_value = "",
use_value_delimiter = true,
value_delimiter = ','
)]
pub features: Vec<String>,
#[arg(global = true, long, default_value = "false")]
pub no_default_features: bool,
#[arg(global = true, long, default_value = "bevy")]
pub workspace_root: Option<String>,
#[arg(global = true, long)]
pub template_args: Option<String>,
}
#[derive(clap::Args, Debug, Clone, Default, Serialize, Deserialize)]
#[command(about = None, long_about = None)]
pub struct Verbosity {
#[arg(
long,
short = 'v',
help = "Increase verbosity, can be used multiple times to increase verbosity further",
action = clap::ArgAction::Count,
global = true,
)]
pub verbose: u8,
#[arg(
long,
short = 'q',
help = "Decrease verbosity, can be used multiple times to decrease verbosity further",
action = clap::ArgAction::Count,
global = true,
conflicts_with = "verbose",
)]
pub quiet: u8,
}
impl Verbosity {
pub fn get_log_level_int(&self) -> i8 {
(self.verbose as i8) - (self.quiet as i8)
}
pub fn get_log_level(&self) -> log::Level {
match self.get_log_level_int() {
0 => log::Level::Info,
1 => log::Level::Debug,
x if x >= 2 => log::Level::Trace,
_ => log::Level::Error,
}
}
pub fn get_rustlog_value(&self) -> &str {
match self.get_log_level_int() {
0 => "info",
1 => "debug",
x if x >= 2 => "trace",
_ => "error",
}
}
}
fn default_ignored_types() -> String {
[
"bevy_reflect::DynamicArray",
"bevy_reflect::DynamicList",
"bevy_reflect::DynamicMap",
"bevy_reflect::DynamicStruct",
"bevy_reflect::DynamicTuple",
"bevy_reflect::DynamicTupleStruct",
"bevy_reflect::DynamicEnum",
"bevy_reflect::OsString", ]
.join(",")
}
#[derive(Subcommand, Deserialize, Serialize, strum::EnumIs)]
pub enum Command {
Print {
#[arg(value_enum, value_name = "TEMPLATE")]
template: crate::TemplateKind,
},
ListTypes,
ListTemplates,
Generate {
#[arg(short, long, default_value = compute_default_dir(), value_name = "DIR")]
output: Utf8PathBuf,
#[arg(short, long, value_name = "DIR")]
templates: Option<Utf8PathBuf>,
#[arg(long, default_value = "false")]
include_private: bool,
#[arg(short, long, value_name = "DIR")]
meta: Option<Vec<Utf8PathBuf>>,
#[arg(short, long, value_name = "DIR")]
meta_output: Option<Utf8PathBuf>,
#[arg(long, action)]
template_data_only: bool,
#[arg(
long,
default_value = default_ignored_types(),
use_value_delimiter = true,
value_delimiter = ','
)]
ignored_types: Vec<String>,
},
Collect {
#[arg(short, long, default_value = compute_default_dir(), value_name = "DIR")]
output: Utf8PathBuf,
#[arg(short, long, value_name = "DIR")]
templates: Option<Utf8PathBuf>,
#[arg(short, long, value_name = "NAME", default_value = "LuaBevyAPIProvider")]
api_name: String,
},
}
pub(crate) fn compute_default_dir() -> String {
WorkspaceMeta::from_env().plugin_target_dir.to_string()
}
#[derive(Default, Clone)]
pub struct WorkspaceMeta {
pub crates: Vec<String>,
pub plugin_target_dir: Utf8PathBuf,
pub include_crates: Option<Vec<String>>,
}
impl WorkspaceMeta {
const CRATES_ENV_NAME: &'static str = "WORKSPACE_CRATES_META";
const PLUGIN_DIR_NAME: &'static str = "WORKSPACE_PLUGIN_DIR_META";
const INCLUDE_CRATES_ENV_NAME: &'static str = "WORKSPACE_OPT_INCLUDE_CRATES_META";
pub fn is_workspace_and_included_crate(&self, crate_name: &str) -> bool {
self.include_crates
.as_ref()
.map(|include_crates| include_crates.contains(&crate_name.to_owned()))
.unwrap_or(true)
&& self.crates.contains(&crate_name.to_owned())
}
pub fn from_env() -> Self {
Self {
crates: std::env::var(Self::CRATES_ENV_NAME)
.unwrap_or_default()
.split(',')
.map(|s| s.to_owned())
.collect(),
plugin_target_dir: std::env::var(Self::PLUGIN_DIR_NAME)
.unwrap_or_default()
.into(),
include_crates: std::env::var(Self::INCLUDE_CRATES_ENV_NAME)
.ok()
.map(|s| s.split(',').map(|s| s.to_owned()).collect()),
}
}
pub fn set_env(&self) {
std::env::set_var(Self::CRATES_ENV_NAME, self.crates.join(","));
std::env::set_var(Self::PLUGIN_DIR_NAME, &self.plugin_target_dir);
if let Some(include_crates) = &self.include_crates {
std::env::set_var(Self::INCLUDE_CRATES_ENV_NAME, include_crates.join(","));
}
}
}