feat: 项目整体命名修改cache-schema-checker
All checks were successful
缓存序列化结构检查 / cache-schema-check (push) Has been skipped

This commit is contained in:
2026-07-14 11:03:34 +08:00
parent 114b053733
commit 110beb79c0
42 changed files with 197 additions and 199 deletions

View File

@@ -0,0 +1,210 @@
package com.codechecker.cache.config;
import org.yaml.snakeyaml.Yaml;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 双层配置加载器:先读取 jar 内 {@code default-config.yaml},再与业务仓库配置深度合并(业务配置优先)。
*/
public final class ConfigLoader {
private static final String DEFAULT_CONFIG_RESOURCE = "default-config.yaml";
private ConfigLoader() {
}
public static CheckerConfig load(Path businessConfigPath) {
Map<String, Object> merged = loadDefault();
if (businessConfigPath != null && Files.exists(businessConfigPath)) {
Map<String, Object> business = loadYaml(businessConfigPath);
merged = deepMerge(merged, business);
}
return bind(merged);
}
@SuppressWarnings("unchecked")
static Map<String, Object> loadDefault() {
try (InputStream in = ConfigLoader.class.getClassLoader().getResourceAsStream(DEFAULT_CONFIG_RESOURCE)) {
if (in == null) {
throw new IllegalStateException("jar 内缺少 default-config.yaml");
}
Object obj = new Yaml().load(in);
return obj == null ? new LinkedHashMap<>() : (Map<String, Object>) obj;
} catch (IOException e) {
throw new IllegalStateException("读取默认配置失败", e);
}
}
@SuppressWarnings("unchecked")
static Map<String, Object> loadYaml(Path path) {
try (InputStream in = Files.newInputStream(path)) {
Object obj = new Yaml().load(in);
return obj == null ? new LinkedHashMap<>() : (Map<String, Object>) obj;
} catch (IOException e) {
throw new IllegalStateException("读取业务配置失败: " + path, e);
}
}
@SuppressWarnings("unchecked")
static Map<String, Object> deepMerge(Map<String, Object> base, Map<String, Object> override) {
Map<String, Object> result = new LinkedHashMap<>(base);
for (Map.Entry<String, Object> entry : override.entrySet()) {
String key = entry.getKey();
Object overrideValue = entry.getValue();
Object baseValue = result.get(key);
if (baseValue instanceof Map && overrideValue instanceof Map) {
result.put(key, deepMerge((Map<String, Object>) baseValue, (Map<String, Object>) overrideValue));
} else {
// 标量、列表:业务配置直接覆盖
result.put(key, overrideValue);
}
}
return result;
}
@SuppressWarnings("unchecked")
private static CheckerConfig bind(Map<String, Object> map) {
CheckerConfig config = new CheckerConfig();
config.setEnabled(bool(map, "enabled", true));
config.setMode(str(map, "mode", "notify"));
config.setScanTestSources(bool(map, "scan_test_sources", false));
config.setSourceRoots(strList(map.get("source_roots")));
config.setIncludeModules(strList(map.get("include_modules")));
config.setExcludeModules(strList(map.get("exclude_modules")));
Map<String, Object> notify = asMap(map.get("notify"));
CheckerConfig.Notify n = config.getNotify();
n.setEnabled(bool(notify, "enabled", true));
n.setWebhookUrl(resolveWebhookUrl(notify));
n.setNotifyOnClean(bool(notify, "notify_on_clean", false));
n.setTitlePrefix(str(notify, "title_prefix", "[缓存结构变更]"));
Map<String, Object> ignore = asMap(map.get("ignore"));
CheckerConfig.Ignore ig = config.getIgnore();
ig.setKeyPatterns(strList(ignore.get("key_patterns")));
ig.setFilePatterns(strList(ignore.get("file_patterns")));
ig.setWriterMethods(strList(ignore.get("writer_methods")));
Map<String, Object> detection = asMap(map.get("detection"));
CheckerConfig.Detection d = config.getDetection();
d.setPatterns(strList(detection.get("patterns")));
d.setMinConfidence(dbl(detection, "min_confidence", 0.6));
d.setMaxFieldDepth((int) lng(detection, "max_field_depth", 8));
Map<String, Object> severityOverrides = asMap(map.get("severity_overrides"));
Map<String, String> so = new LinkedHashMap<>();
for (Map.Entry<String, Object> e : severityOverrides.entrySet()) {
so.put(e.getKey(), String.valueOf(e.getValue()));
}
config.setSeverityOverrides(so);
List<CheckerConfig.ManualMapping> mappings = new ArrayList<>();
for (Object item : asList(map.get("manual_mappings"))) {
Map<String, Object> m = asMap(item);
CheckerConfig.ManualMapping mm = new CheckerConfig.ManualMapping();
mm.setId(str(m, "id", null));
mm.setWriterMethod(str(m, "writer_method", null));
mm.setKeyPattern(str(m, "key_pattern", null));
mm.setValueType(str(m, "value_type", null));
mm.setDescription(str(m, "description", null));
mappings.add(mm);
}
config.setManualMappings(mappings);
List<CheckerConfig.Suppression> suppressions = new ArrayList<>();
for (Object item : asList(map.get("suppressions"))) {
Map<String, Object> m = asMap(item);
CheckerConfig.Suppression sp = new CheckerConfig.Suppression();
sp.setId(str(m, "id", null));
sp.setWriterMethod(str(m, "writer_method", null));
sp.setKeyPattern(str(m, "key_pattern", null));
sp.setChangeTypes(strList(m.get("change_types")));
sp.setReason(str(m, "reason", null));
suppressions.add(sp);
}
config.setSuppressions(suppressions);
return config;
}
/**
* 优先读取 webhook_url兼容旧字段 webhook_env值为 http 开头时视为 URL
*/
private static String resolveWebhookUrl(Map<String, Object> notify) {
String url = str(notify, "webhook_url", "");
if (url != null && !url.trim().isEmpty()) {
return url.trim();
}
String legacy = str(notify, "webhook_env", "");
if (legacy != null && legacy.trim().startsWith("http")) {
return legacy.trim();
}
return "";
}
@SuppressWarnings("unchecked")
private static Map<String, Object> asMap(Object obj) {
if (obj instanceof Map) {
return (Map<String, Object>) obj;
}
return new LinkedHashMap<>();
}
private static List<Object> asList(Object obj) {
if (obj instanceof List) {
return (List<Object>) obj;
}
return new ArrayList<>();
}
private static List<String> strList(Object obj) {
List<String> result = new ArrayList<>();
if (obj instanceof List) {
for (Object o : (List<?>) obj) {
if (o != null) {
result.add(String.valueOf(o));
}
}
}
return result;
}
private static String str(Map<String, Object> map, String key, String def) {
Object v = map.get(key);
return v == null ? def : String.valueOf(v);
}
private static boolean bool(Map<String, Object> map, String key, boolean def) {
Object v = map.get(key);
if (v instanceof Boolean) {
return (Boolean) v;
}
return v == null ? def : Boolean.parseBoolean(String.valueOf(v));
}
private static double dbl(Map<String, Object> map, String key, double def) {
Object v = map.get(key);
if (v instanceof Number) {
return ((Number) v).doubleValue();
}
return v == null ? def : Double.parseDouble(String.valueOf(v));
}
private static long lng(Map<String, Object> map, String key, long def) {
Object v = map.get(key);
if (v instanceof Number) {
return ((Number) v).longValue();
}
return v == null ? def : Long.parseLong(String.valueOf(v));
}
}