mirror of https://github.com/jdx/mise
362 lines
13 KiB
Rust
362 lines
13 KiB
Rust
use heck::ToUpperCamelCase;
|
|
use indexmap::IndexMap;
|
|
use std::path::{Path, PathBuf};
|
|
use std::{env, fs};
|
|
|
|
fn main() {
|
|
cfg_aliases::cfg_aliases! {
|
|
asdf: { any(feature = "asdf", not(target_os = "windows")) },
|
|
macos: { target_os = "macos" },
|
|
linux: { target_os = "linux" },
|
|
vfox: { any(feature = "vfox", target_os = "windows") },
|
|
}
|
|
built::write_built_file().expect("Failed to acquire build-time information");
|
|
|
|
codegen_settings();
|
|
codegen_registry();
|
|
codegen_aqua();
|
|
}
|
|
|
|
fn codegen_registry() {
|
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
let dest_path = Path::new(&out_dir).join("registry.rs");
|
|
let mut lines = vec!["[".to_string()];
|
|
|
|
let registry: toml::Table = fs::read_to_string("registry.toml")
|
|
.unwrap()
|
|
.parse()
|
|
.unwrap();
|
|
|
|
let tools = registry.get("tools").unwrap().as_table().unwrap();
|
|
for (short, info) in tools {
|
|
let info = info.as_table().unwrap();
|
|
let aliases = info
|
|
.get("aliases")
|
|
.cloned()
|
|
.unwrap_or(toml::Value::Array(vec![]))
|
|
.as_array()
|
|
.unwrap()
|
|
.iter()
|
|
.map(|v| v.as_str().unwrap().to_string())
|
|
.collect::<Vec<_>>();
|
|
let test = info.get("test").map(|t| {
|
|
let t = t.as_array().unwrap();
|
|
(
|
|
t[0].as_str().unwrap().to_string(),
|
|
t[1].as_str().unwrap().to_string(),
|
|
)
|
|
});
|
|
let mut backends = vec![];
|
|
for backend in info.get("backends").unwrap().as_array().unwrap() {
|
|
match backend {
|
|
toml::Value::String(backend) => {
|
|
backends.push(format!(
|
|
r##"RegistryBackend{{
|
|
full: r#"{backend}"#,
|
|
platforms: &[],
|
|
}}"##,
|
|
backend = backend
|
|
));
|
|
}
|
|
toml::Value::Table(backend) => {
|
|
let full = backend.get("full").unwrap().as_str().unwrap();
|
|
let platforms = backend
|
|
.get("platforms")
|
|
.map(|p| {
|
|
p.as_array()
|
|
.unwrap()
|
|
.iter()
|
|
.map(|p| p.as_str().unwrap().to_string())
|
|
.collect::<Vec<_>>()
|
|
})
|
|
.unwrap_or_default();
|
|
backends.push(format!(
|
|
r##"RegistryBackend{{
|
|
full: r#"{full}"#,
|
|
platforms: &[{platforms}],
|
|
}}"##,
|
|
platforms = platforms
|
|
.into_iter()
|
|
.map(|p| format!("\"{p}\""))
|
|
.collect::<Vec<_>>()
|
|
.join(", ")
|
|
));
|
|
}
|
|
_ => panic!("Unknown backend type"),
|
|
}
|
|
}
|
|
let os = info
|
|
.get("os")
|
|
.map(|os| {
|
|
let os = os.as_array().unwrap();
|
|
let mut os = os
|
|
.iter()
|
|
.map(|o| o.as_str().unwrap().to_string())
|
|
.collect::<Vec<_>>();
|
|
os.sort();
|
|
os
|
|
})
|
|
.unwrap_or_default();
|
|
let description = info
|
|
.get("description")
|
|
.map(|d| d.as_str().unwrap().to_string());
|
|
let depends = info
|
|
.get("depends")
|
|
.map(|depends| {
|
|
let depends = depends.as_array().unwrap();
|
|
let mut depends = depends
|
|
.iter()
|
|
.map(|d| d.as_str().unwrap().to_string())
|
|
.collect::<Vec<_>>();
|
|
depends.sort();
|
|
depends
|
|
})
|
|
.unwrap_or_default();
|
|
let idiomatic_files = info
|
|
.get("idiomatic_files")
|
|
.map(|idiomatic_files| {
|
|
idiomatic_files
|
|
.as_array()
|
|
.unwrap()
|
|
.iter()
|
|
.map(|f| f.as_str().unwrap().to_string())
|
|
.collect::<Vec<_>>()
|
|
})
|
|
.unwrap_or_default();
|
|
let rt = format!(
|
|
r#"RegistryTool{{short: "{short}", description: {description}, backends: &[{backends}], aliases: &[{aliases}], test: &{test}, os: &[{os}], depends: &[{depends}], idiomatic_files: &[{idiomatic_files}]}}"#,
|
|
description = description
|
|
.map(|d| format!("Some(r###\"{}\"###)", d))
|
|
.unwrap_or("None".to_string()),
|
|
backends = backends.into_iter().collect::<Vec<_>>().join(", "),
|
|
aliases = aliases
|
|
.iter()
|
|
.map(|a| format!("\"{a}\""))
|
|
.collect::<Vec<_>>()
|
|
.join(", "),
|
|
test = test
|
|
.map(|(t, v)| format!("Some((\"{t}\", \"{v}\"))", t = t, v = v))
|
|
.unwrap_or("None".to_string()),
|
|
os = os
|
|
.iter()
|
|
.map(|o| format!("\"{o}\""))
|
|
.collect::<Vec<_>>()
|
|
.join(", "),
|
|
depends = depends
|
|
.iter()
|
|
.map(|d| format!("\"{d}\""))
|
|
.collect::<Vec<_>>()
|
|
.join(", "),
|
|
idiomatic_files = idiomatic_files
|
|
.iter()
|
|
.map(|f| format!("\"{f}\""))
|
|
.collect::<Vec<_>>()
|
|
.join(", "),
|
|
);
|
|
lines.push(format!(r#" ("{short}", {rt}),"#));
|
|
for alias in aliases {
|
|
lines.push(format!(r#" ("{alias}", {rt}),"#));
|
|
}
|
|
}
|
|
lines.push(r#"].into()"#.to_string());
|
|
|
|
fs::write(&dest_path, lines.join("\n")).unwrap();
|
|
}
|
|
|
|
fn codegen_settings() {
|
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
let dest_path = Path::new(&out_dir).join("settings.rs");
|
|
let mut lines = vec![
|
|
r#"#[derive(Config, Default, Debug, Clone, Serialize)]
|
|
#[config(partial_attr(derive(Clone, Serialize, Default)))]
|
|
pub struct Settings {"#
|
|
.to_string(),
|
|
];
|
|
|
|
let settings: toml::Table = fs::read_to_string("settings.toml")
|
|
.unwrap()
|
|
.parse()
|
|
.unwrap();
|
|
let props_to_code = |key: &str, props: &toml::Value| {
|
|
let mut lines = vec![];
|
|
let props = props.as_table().unwrap();
|
|
if let Some(description) = props.get("description") {
|
|
lines.push(format!(" /// {}", description.as_str().unwrap()));
|
|
}
|
|
let type_ = props
|
|
.get("rust_type")
|
|
.map(|rt| rt.as_str().unwrap())
|
|
.or(props.get("type").map(|t| match t.as_str().unwrap() {
|
|
"Bool" => "bool",
|
|
"String" => "String",
|
|
"Integer" => "i64",
|
|
"Url" => "String",
|
|
"Path" => "PathBuf",
|
|
"Duration" => "String",
|
|
"ListString" => "Vec<String>",
|
|
"ListPath" => "Vec<PathBuf>",
|
|
t => panic!("Unknown type: {}", t),
|
|
}));
|
|
if let Some(type_) = type_ {
|
|
let type_ = if props.get("optional").is_some_and(|v| v.as_bool().unwrap()) {
|
|
format!("Option<{}>", type_)
|
|
} else {
|
|
type_.to_string()
|
|
};
|
|
let mut opts = IndexMap::new();
|
|
if let Some(env) = props.get("env") {
|
|
opts.insert("env".to_string(), env.to_string());
|
|
}
|
|
if let Some(default) = props.get("default") {
|
|
opts.insert("default".to_string(), default.to_string());
|
|
} else if type_ == "bool" {
|
|
opts.insert("default".to_string(), "false".to_string());
|
|
}
|
|
if let Some(parse_env) = props.get("parse_env") {
|
|
opts.insert(
|
|
"parse_env".to_string(),
|
|
parse_env.as_str().unwrap().to_string(),
|
|
);
|
|
}
|
|
lines.push(format!(
|
|
" #[config({})]",
|
|
opts.iter()
|
|
.map(|(k, v)| format!("{k} = {v}"))
|
|
.collect::<Vec<_>>()
|
|
.join(", ")
|
|
));
|
|
lines.push(format!(" pub {}: {},", key, type_));
|
|
} else {
|
|
lines.push(" #[config(nested)]".to_string());
|
|
lines.push(format!(
|
|
" pub {}: Settings{},",
|
|
key,
|
|
key.to_upper_camel_case()
|
|
));
|
|
}
|
|
lines.join("\n")
|
|
};
|
|
for (key, props) in &settings {
|
|
lines.push(props_to_code(key, props));
|
|
}
|
|
lines.push("}".to_string());
|
|
|
|
let nested_settings = settings
|
|
.iter()
|
|
.filter(|(_, v)| !v.as_table().unwrap().contains_key("type"))
|
|
.collect::<Vec<_>>();
|
|
for (child, props) in &nested_settings {
|
|
lines.push(format!(
|
|
r#"
|
|
#[derive(Config, Default, Debug, Clone, Serialize)]
|
|
#[config(partial_attr(derive(Clone, Serialize, Default)))]
|
|
#[config(partial_attr(serde(deny_unknown_fields)))]
|
|
pub struct Settings{name} {{"#,
|
|
name = child.to_upper_camel_case()
|
|
));
|
|
|
|
for (key, props) in props.as_table().unwrap() {
|
|
lines.push(props_to_code(key, props));
|
|
}
|
|
lines.push("}".to_string());
|
|
}
|
|
|
|
lines.push(
|
|
r#"
|
|
pub static SETTINGS_META: Lazy<IndexMap<&'static str, SettingsMeta>> = Lazy::new(|| {
|
|
indexmap!{"#
|
|
.to_string(),
|
|
);
|
|
for (name, props) in &settings {
|
|
let props = props.as_table().unwrap();
|
|
if let Some(type_) = props.get("type").map(|v| v.as_str().unwrap()) {
|
|
lines.push(format!(
|
|
r#" "{name}" => SettingsMeta {{
|
|
type_: SettingsType::{type_},"#,
|
|
));
|
|
if let Some(description) = props.get("description") {
|
|
let description = description.as_str().unwrap().to_string();
|
|
lines.push(format!(
|
|
r####" description: r###"{description}"###,"####
|
|
));
|
|
}
|
|
lines.push(" },".to_string());
|
|
}
|
|
}
|
|
for (name, props) in &nested_settings {
|
|
for (key, props) in props.as_table().unwrap() {
|
|
let props = props.as_table().unwrap();
|
|
if let Some(type_) = props.get("type").map(|v| v.as_str().unwrap()) {
|
|
lines.push(format!(
|
|
r#" "{name}.{key}" => SettingsMeta {{
|
|
type_: SettingsType::{type_},"#,
|
|
));
|
|
}
|
|
if let Some(description) = props.get("description") {
|
|
let description = description.as_str().unwrap().to_string();
|
|
lines.push(format!(
|
|
r####" description: r###"{description}"###,"####
|
|
));
|
|
}
|
|
lines.push(" },".to_string());
|
|
}
|
|
}
|
|
lines.push(
|
|
r#" }
|
|
});
|
|
"#
|
|
.to_string(),
|
|
);
|
|
|
|
fs::write(&dest_path, lines.join("\n")).unwrap();
|
|
}
|
|
|
|
// pub static AQUA_STANDARD_REGISTRY_FILES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
|
// include!(concat!(env!("OUT_DIR"), "/aqua_standard_registry.rs"));
|
|
// });
|
|
|
|
fn codegen_aqua() {
|
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
let dest_path = Path::new(&out_dir).join("aqua_standard_registry.rs");
|
|
let mut lines = vec!["[".to_string()];
|
|
for (k, v) in aqua_registries(®istry_dir()).unwrap_or_default() {
|
|
lines.push(format!(r####" ("{k}", r###"{v}"###),"####));
|
|
}
|
|
lines.push("].into()".to_string());
|
|
fs::write(&dest_path, lines.join("\n")).unwrap();
|
|
}
|
|
|
|
fn ls(path: &Path) -> Result<Vec<PathBuf>, std::io::Error> {
|
|
fs::read_dir(path)?
|
|
.map(|entry| entry.map(|e| e.path()))
|
|
.collect()
|
|
}
|
|
|
|
fn aqua_registries(d: &Path) -> Result<Vec<(String, String)>, std::io::Error> {
|
|
let mut registries = vec![];
|
|
for f in ls(d)? {
|
|
if f.is_dir() {
|
|
registries.extend(aqua_registries(&f)?);
|
|
} else if f.file_name() == Some("registry.yaml".as_ref()) {
|
|
registries.push((
|
|
f.parent()
|
|
.unwrap()
|
|
.strip_prefix(registry_dir())
|
|
.unwrap()
|
|
.to_string_lossy()
|
|
.split(std::path::MAIN_SEPARATOR_STR)
|
|
.collect::<Vec<_>>()
|
|
.join("/"),
|
|
fs::read_to_string(&f).unwrap(),
|
|
));
|
|
}
|
|
}
|
|
Ok(registries)
|
|
}
|
|
|
|
fn registry_dir() -> PathBuf {
|
|
PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap())
|
|
.join("aqua-registry")
|
|
.join("pkgs")
|
|
}
|