use std::{
collections::HashMap,
path::{Path, PathBuf},
};
use anyhow::Context;
use cargo_metadata::{Metadata, Package};
use serde_json::Value;
use super::{
AX_CONFIG_PATH_ENV, AXBUILD_METADATA, AXCONFIG_FILE, AXSTD_STD_CLIPPY_TARGET,
AXSTD_STD_DEFAULT_FEATURE, AXSTD_STD_PACKAGE, CLIPPY_FEATURE_AXCONFIG_OVERRIDES_METADATA,
check::ClippyAxconfigOverride,
};
pub(super) fn clippy_env(package: &Package) -> Vec<(String, String)> {
let Some(manifest_dir) = package.manifest_path.parent() else {
return Vec::new();
};
let axconfig = manifest_dir.join(AXCONFIG_FILE);
if !axconfig.exists() {
return Vec::new();
}
vec![(AX_CONFIG_PATH_ENV.to_string(), axconfig.to_string())]
}
fn package_axconfig_path(package: &Package) -> Option<PathBuf> {
let manifest_dir = package.manifest_path.parent()?;
let axconfig = manifest_dir.join(AXCONFIG_FILE);
axconfig.exists().then(|| axconfig.into_std_path_buf())
}
pub(super) fn feature_axconfig_overrides(package: &Package) -> HashMap<String, Vec<String>> {
let Some(overrides) = package
.metadata
.get(AXBUILD_METADATA)
.and_then(Value::as_object)
.and_then(|metadata| metadata.get(CLIPPY_FEATURE_AXCONFIG_OVERRIDES_METADATA))
.and_then(Value::as_object)
else {
return HashMap::new();
};
overrides
.iter()
.filter_map(|(feature, values)| {
let values = values
.as_array()?
.iter()
.map(Value::as_str)
.map(Option::unwrap_or_default)
.map(ToString::to_string)
.collect::<Vec<_>>();
Some((feature.clone(), values))
})
.collect()
}
pub(super) fn clippy_axconfig_override(
package: &Package,
target: Option<&str>,
feature: &str,
overrides: &[String],
workspace_root: &Path,
) -> Option<ClippyAxconfigOverride> {
if overrides.is_empty() {
return None;
}
let target = target?.to_string();
let platform_config = package_axconfig_path(package)?;
let out_config = crate::context::axbuild_tmp_dir(workspace_root)
.join("axconfig")
.join(package.name.as_str())
.join(target.as_str())
.join("clippy")
.join(feature)
.join(".axconfig.toml");
Some(ClippyAxconfigOverride {
target,
platform_config,
out_config,
overrides: overrides.to_vec(),
})
}
fn with_axconfig_env_override(
mut env: Vec<(String, String)>,
override_config: Option<&ClippyAxconfigOverride>,
) -> Vec<(String, String)> {
let Some(override_config) = override_config else {
return env;
};
env.retain(|(key, _)| key != AX_CONFIG_PATH_ENV);
env.push((
AX_CONFIG_PATH_ENV.to_string(),
override_config.out_config.display().to_string(),
));
env
}
fn axstd_std_clippy_env(metadata: &Metadata) -> anyhow::Result<Vec<(String, String)>> {
let mut envs = HashMap::new();
crate::build::prepare_std_build_env(&mut envs, AXSTD_STD_CLIPPY_TARGET, true, metadata)
.context("failed to prepare ax-std std clippy config")?;
Ok(envs.into_iter().collect())
}
pub(super) fn feature_clippy_env(
package: &Package,
feature: &str,
base_env: Vec<(String, String)>,
axconfig_override: Option<&ClippyAxconfigOverride>,
metadata: &Metadata,
) -> anyhow::Result<Vec<(String, String)>> {
if package.name == AXSTD_STD_PACKAGE && feature == AXSTD_STD_DEFAULT_FEATURE {
return axstd_std_clippy_env(metadata);
}
Ok(with_axconfig_env_override(base_env, axconfig_override))
}