package com.codechecker.cache.analyze;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
/**
* 扫描工作树中受包含/排除模块限制的 {@code src/main/java} 下的所有 Java 源文件。
*
返回路径 → 源码内容映射,供 {@link SchemaCheckAnalyzer} 构建新旧 {@code SourceIndex}。
*/
public class FileScanner {
private final Path repoRoot;
private final List includeModules;
private final List excludeModules;
public FileScanner(Path repoRoot, List includeModules, List excludeModules) {
this.repoRoot = repoRoot;
this.includeModules = includeModules;
this.excludeModules = excludeModules;
}
/**
* @return 相对仓库根(/ 分隔)-> 文件内容
*/
public Map scan() {
Map result = new LinkedHashMap<>();
try (Stream stream = Files.walk(repoRoot)) {
List javaFiles = stream
.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".java"))
.filter(p -> {
String rel = repoRoot.relativize(p).toString().replace('\\', '/');
return rel.contains("/src/main/java/") && moduleAllowed(rel);
})
.collect(java.util.stream.Collectors.toList());
javaFiles.parallelStream().forEach(p -> {
String rel = repoRoot.relativize(p).toString().replace('\\', '/');
try {
synchronized (result) {
result.put(rel, new String(Files.readAllBytes(p), StandardCharsets.UTF_8));
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return result;
}
boolean moduleAllowed(String relPath) {
String topModule = relPath.contains("/") ? relPath.substring(0, relPath.indexOf('/')) : relPath;
if (excludeModules != null && excludeModules.contains(topModule)) {
return false;
}
if (includeModules == null || includeModules.isEmpty()) {
return true;
}
return includeModules.contains(topModule);
}
}