Compare commits

...

8 Commits

@ -108,7 +108,11 @@
<version>2.6.10</version>
</dependency>
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>7.5.4</version>
</dependency>
</dependencies>
<build>

@ -65,6 +65,10 @@ public class DynamicDataSourceConfig {
masterDataSource.setInitialSize(initSize);
masterDataSource.setMaxActive(initSize);
masterDataSource.setMinIdle(initSize);
masterDataSource.setValidationQuery("select 1");
masterDataSource.setTestOnBorrow(true);
masterDataSource.setTestWhileIdle(true);
masterDataSource.setTimeBetweenEvictionRunsMillis(60000);
return masterDataSource;
}

@ -14,7 +14,7 @@ public class ThreadPoolConfig {
@Primary
public ExecutorService sonarScannerPool() {
ThreadFactory sonarScannerPool = new CustomizableThreadFactory("sonarScanner-pool-");
return new ThreadPoolExecutor(10, 10, 0,
return new ThreadPoolExecutor(4, 4, 0,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(10000), sonarScannerPool,
new ThreadPoolExecutor.AbortPolicy());
}

@ -7,7 +7,7 @@ public class Person {
public String getUid() {
return uid;
return uid.trim();
}
public void setUid(String uid) {

@ -28,6 +28,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -48,13 +50,25 @@ public class SonarService {
@Value("${extract.path}")
String extractProgramPath;
@Value("${sonar.scan.max-concurrent:2}")
int sonarScanMaxConcurrent;
@Value("${sonar.scan.retry-times:3}")
int sonarScanRetryTimes;
@Value("${sonar.scan.timeout-minutes:3}")
int sonarScanTimeoutMinutes;
@Autowired
private ExecutorService executorService;
private ConcurrentHashMap<String, Consumer<SonarScannerParam>> concurrentHashMap = new ConcurrentHashMap(8);
private Semaphore sonarScanSemaphore;
@PostConstruct
public void init() {
sonarScanSemaphore = new Semaphore(Math.max(1, sonarScanMaxConcurrent));
concurrentHashMap.put(Constant.JAVA, param -> {
String command = "sonar-scanner " +
"-Dsonar.host.url=" + sonarUrl + " " +
@ -184,7 +198,7 @@ public class SonarService {
}
public void sonar(String projectPath, String key) {
public boolean sonar(String projectPath, String key) {
String command = "sonar-scanner " +
"-Dsonar.host.url=" + sonarUrl + " " +
"-Dsonar.sourceEncoding=utf-8 " +
@ -192,7 +206,46 @@ public class SonarService {
"-Dsonar.java.binaries=./ " +
"-Dsonar.projectBaseDir=" + projectPath;
log.info("projectPath:{},key:{}, command: {}", projectPath, key, command);
SystemUtil.executeAndGetExitStatus(command);
boolean acquired = false;
try {
sonarScanSemaphore.acquire();
acquired = true;
for (int i = 1; i <= Math.max(1, sonarScanRetryTimes); i++) {
SystemUtil.ExecuteResp executeResp = SystemUtil.executeAndGetExitStatus(
command,
Math.max(1, sonarScanTimeoutMinutes),
TimeUnit.MINUTES,
line -> log.info("sonar-scanner key:{} | {}", key, line));
if (executeResp.getStatus() == 0) {
log.info("projectPath:{},key:{}, result: success", projectPath, key);
return true;
}
String output = executeResp.getOutput();
boolean retryable = isRetryableSonarError(output);
log.warn("projectPath:{},key:{}, sonar scanner failed, attempt:{}/{}, retryable:{}, result:{}",
projectPath, key, i, sonarScanRetryTimes, retryable, output);
if (!retryable || i >= sonarScanRetryTimes) {
return false;
}
TimeUnit.SECONDS.sleep(20L * i);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("projectPath:{},key:{}, sonar scanner interrupted", projectPath, key, e);
} finally {
if (acquired) {
sonarScanSemaphore.release();
}
}
return false;
}
private boolean isRetryableSonarError(String output) {
return StringUtils.contains(output, "Error 500")
|| StringUtils.contains(output, "/api/rules/search.protobuf")
|| StringUtils.contains(output, "Unable to load component class org.sonar.scanner.report.ActiveRulesPublisher")
|| StringUtils.contains(output, "Unable to load component interface org.sonar.api.batch.rule.ActiveRules");
}
/**
@ -249,6 +302,78 @@ public class SonarService {
}
public void downloadExcelArchives(String excelPath, int homeworkId) {
String basePath = String.format("/tmp/%d/", homeworkId);
try {
List<Person> personList = ExcelUtil.readExcel(excelPath);
Map<String, List<Person>> collect = personList.stream().collect(Collectors.groupingBy(Person::getUid));
collect.forEach((uid, persons) -> {
String studentPath = basePath + uid + "/";
File studentDir = new File(studentPath);
if (!studentDir.exists()) {
studentDir.mkdirs();
}
for (Person person : persons) {
try {
downloadToDirectory(person.getDownloadUrl(), studentPath);
} catch (Exception e) {
log.error("下载学生压缩包失败, homeworkId:{}, uid:{}, url:{}",
homeworkId, uid, person.getDownloadUrl(), e);
}
}
});
} catch (Exception e) {
log.error("读取Excel下载压缩包失败: {}", excelPath, e);
}
}
private void downloadToDirectory(String zipUrl, String directory) throws IOException {
log.info("下载文件到目录: {} ---> {}", zipUrl, directory);
String cookie = "_educoder_session=0bea28f7a6db39cefb2fc3cbe715d840;";
URL url = new URL(zipUrl);
URLConnection conn = url.openConnection();
conn.setRequestProperty("Cookie", cookie);
conn.setDoInput(true);
String fileName = getDownloadFileName(zipUrl, conn);
String savePath = directory + fileName;
File saveFile = new File(savePath);
if (saveFile.exists() && saveFile.length() > 0) {
log.info("文件已存在,跳过下载: {}", savePath);
return;
}
try (BufferedInputStream in = new BufferedInputStream(conn.getInputStream());
FileOutputStream fileOutputStream = new FileOutputStream(savePath)) {
byte dataBuffer[] = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
}
log.info("下载完成: {}", savePath);
}
private String getDownloadFileName(String zipUrl, URLConnection conn) throws UnsupportedEncodingException {
String fileName = conn.getHeaderField("Content-Disposition");
if(StringUtils.isNotEmpty(fileName)){
fileName = new String(fileName.getBytes("ISO-8859-1"), "UTF-8");
fileName = UrlUtil.getURLDecoderString(fileName);
fileName = UrlUtil.getURLDecoderString(fileName);
fileName = fileName.substring(fileName.indexOf("filename=")+10);
int semicolonIndex = fileName.indexOf(';');
if (semicolonIndex != -1) {
fileName = fileName.substring(0, semicolonIndex);
}
return fileName.replaceAll("\"", "");
}
String[] split = StringUtils.split(zipUrl, "/");
return UrlUtil.getURLDecoderString(split[split.length - 1]);
}
/**
* excel
@ -257,8 +382,11 @@ public class SonarService {
*/
public void scanExcel(String excelPath) {
int homeworkId = 20210101;
int homeworkId = 202605112;
scanExcel(excelPath, homeworkId);
}
public void scanExcel(String excelPath, int homeworkId) {
try {
List<Person> personList = ExcelUtil.readExcel(excelPath);

@ -1,17 +1,12 @@
package net.educoder.ecsonar.task;
import cn.hutool.core.io.FileUtil;
import net.educoder.ecsonar.model.api.SonarRequest;
import net.educoder.ecsonar.services.SonarService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.io.*;
/**
* @Author: youys
@ -33,54 +28,29 @@ public class ReadExcelRunnable implements Runnable{
@Override
public void run() {
String uid = sonarRequest.getPersonList().get(0).getUid();
int homeworkId = sonarRequest.getHomeworkId();
String path = String.format("/tmp/%d/%s/", homeworkId, uid);
File file = new File(path);
if(!file.exists()){
file.mkdir();
file.mkdirs();
}
// for (Person person : sonarRequest.getPersonList()) {
// String[] split = StringUtils.split(person.getDownloadUrl(), "/");
// String zipFilename = UrlUtil.getURLDecoderString(split[split.length - 1]);
// try {
// download(person.getDownloadUrl(),path+zipFilename);
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
String key = String.format("%d-%s", homeworkId, uid);
log.info("开始调用sonar:{}",key);
sonarService.sonar(path,key);
}
private void download(String zipUrl, String zipPath) throws IOException {
log.info("下载文件: {}-{}", zipUrl, zipPath);
String cookie = "_educoder_session=1f4bf34409fec2180b99aa1cbf0b7586";
URL url = new URL(zipUrl);
URLConnection conn = url.openConnection();
conn.setRequestProperty("Cookie", cookie);
conn.setDoInput(true);
String fileName = conn.getHeaderField("Content-Disposition");
if(StringUtils.isNotEmpty(fileName)){
fileName = new String(fileName.getBytes("ISO-8859-1"), "UTF-8");
fileName = fileName.substring(fileName.indexOf("filename=")+10,fileName.length()-1);
zipPath = zipPath.substring(0, zipPath.lastIndexOf("/")+1) + fileName;
String key = String.format("%d-%s", homeworkId, uid);
File scannerReport = new File(path + "/.scannerwork/report-task.txt");
if(scannerReport.exists()){
log.info("{} 已存在成功扫描标记,跳过: {}", key, scannerReport.getAbsolutePath());
return;
}
try (BufferedInputStream in = new BufferedInputStream(conn.getInputStream());
FileOutputStream fileOutputStream = new FileOutputStream(zipPath)) {
byte dataBuffer[] = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
} catch (IOException e) {
log.error("文件下载失败: {}-{}", zipUrl, zipPath);
throw e;
File scannerWork = new File(path + "/.scannerwork/");
if (scannerWork.exists()) {
log.info("{} 存在未完成的扫描工作目录,删除后重试: {}", key, scannerWork.getAbsolutePath());
FileUtil.del(scannerWork);
}
log.info("开始调用sonar:{}",key);
boolean success = sonarService.sonar(path,key);
if (!success) {
log.error("sonar扫描失败, uid:{}, key:{}, path:{}", uid, key, path);
}
}
}

@ -397,7 +397,15 @@ public class ExcelUtil {
Row row = sheet.getRow(i);
String name = row.getCell(0).getStringCellValue();
// String uid;
// try {
// uid = String.valueOf(row.getCell(1).getNumericCellValue());
// }catch (Exception e){
// uid = row.getCell(1).getStringCellValue();
// }
String uid = row.getCell(1).getStringCellValue();
String downloadUrl = row.getCell(2).getStringCellValue();
Person person = new Person();

@ -0,0 +1,445 @@
package net.educoder.ecsonar.utils;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RuntimeUtil;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* @Author: youys
* @Date: 2023/5/19
* @Description:
*/
public class RarUtil {
private static final Set<String> SOURCE_EXTENSIONS = new HashSet<>(Arrays.asList(
".java", ".py", ".c", ".cc", ".cpp", ".cxx", ".h", ".hpp",
".js", ".jsx", ".ts", ".tsx", ".vue", ".go", ".php", ".rb",
".cs", ".m", ".mm", ".swift", ".kt", ".kts", ".scala", ".ets"
));
private static final Set<String> TARGET_EXTENSIONS = new HashSet<>(Arrays.asList(".cs", ".m", ".ets"));
private static final double TARGET_EXTENSION_RATIO = 0.8;
private static final Set<String> BUILD_AND_DEPENDENCY_DIRS = new HashSet<>(Arrays.asList(
"node_modules", "target", "dist", "build", "out", "bin", "obj",
".gradle", ".mvn", ".idea", ".vscode", "__pycache__",
".venv", "venv", "env", "site-packages", ".pytest_cache", ".mypy_cache",
".next", ".nuxt", ".output", "coverage", ".cache", ".parcel-cache", ".turbo",
".pnpm-store", "vendor", "Pods", "DerivedData", ".cxx", ".externalNativeBuild"
));
public static void unrar(String sourceFilePath, String outputDirectory) {
String s = RuntimeUtil.execForStr("unar", sourceFilePath,"-o", outputDirectory);
System.out.println("result====" + s);
}
public static void un7Z(String sourceFilePath, String outputDirectory) {
String s = RuntimeUtil.execForStr("unar", sourceFilePath,"-o", outputDirectory);
System.out.println("result====" + s);
}
public static void main(String[] args) throws Exception{
// unrar("/tmp/20230301/201905962222/20230519153409_wuiol3vn.rar", "/Users/youyongsheng/Desktop/aa");
// un7Z("/tmp/20230301/201905962241/20230519153506_i39sv5p2.7z", "/Users/youyongsheng/Desktop/aa");
// unzip();
String path = "/tmp/202605112";
// valid(path);
// printSingleExtensionCodeDirs(path);
// removeFullCode(path);
removeDirectory(Paths.get(path));
}
public static void unzip(){
String sourceDir = "/tmp/2026051111";
String targetDir = "/tmp/202605112";
unzip(sourceDir, targetDir);
}
public static void unzip(String sourceDir, String targetDir){
File directory = new File(sourceDir);
File[] studentDirs = directory.listFiles();
if (studentDirs == null) {
System.out.println("No student directories found.");
return;
}
int i=0;
for (File studentDir : studentDirs) {
if (!studentDir.isDirectory()) {
System.out.println("111--------------------------------");
continue;
}
String studentId = studentDir.getName();
String studentTargetDir = targetDir + "/" + studentId;
File[] zipFiles = studentDir.listFiles();
if (zipFiles == null || zipFiles.length == 0) {
System.out.println("No archive files found for student: " + studentId);
continue;
}
for (File zipFile : zipFiles) {
if (!zipFile.isFile()) {
continue;
}
try {
String fileName = zipFile.getName().toLowerCase();
if(fileName.endsWith(".zip")){
unzipArchive(zipFile.getAbsolutePath(), studentTargetDir);
}else if(fileName.endsWith(".rar")){
unRar(zipFile.getAbsolutePath(), studentTargetDir);
}else{
RarUtil.un7Z(zipFile.getAbsolutePath(), studentTargetDir);
}
} catch (Exception e) {
System.out.println("Error occurred while unzipping file: "
+ zipFile.getName()
+ ", path:" + zipFile.getAbsolutePath()
+ ", reason:" + e.getMessage());
}
}
System.out.println("--------------------------------");
}
}
public static void prepareForScan(String path) throws IOException {
normalizeWindowsPathFiles(Paths.get(path));
valid(path);
printSingleExtensionCodeDirs(path);
removeFullCode(path);
removeDirectory(Paths.get(path));
}
public static void normalizeWindowsPathFiles(Path rootPath) throws IOException {
Path normalizedRootPath = rootPath.toAbsolutePath().normalize();
Files.walkFileTree(normalizedRootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fileName = file.getFileName().toString();
if (!fileName.contains("\\")) {
return FileVisitResult.CONTINUE;
}
Path parent = file.getParent();
if (parent == null) {
return FileVisitResult.CONTINUE;
}
Path targetPath = parent.resolve(fileName.replace("\\", "/")).normalize();
if (!targetPath.startsWith(normalizedRootPath)) {
System.out.println("Skip unsafe normalized path: " + file.toAbsolutePath());
return FileVisitResult.CONTINUE;
}
if (fileName.endsWith("\\")) {
Files.createDirectories(targetPath);
Files.deleteIfExists(file);
return FileVisitResult.CONTINUE;
}
Path targetParent = targetPath.getParent();
if (targetParent != null) {
Files.createDirectories(targetParent);
}
Files.move(file, targetPath, StandardCopyOption.REPLACE_EXISTING);
System.out.println("Normalize windows path file: " + file.toAbsolutePath() + " -> " + targetPath);
return FileVisitResult.CONTINUE;
}
});
}
private static void unzipArchive(String zipFilePath, String targetDir) throws IOException {
System.out.println(zipFilePath + " to " + targetDir);
unzipArchiveWithGbkAndWindowsPath(zipFilePath, targetDir);
}
private static void unzipArchiveWithGbkAndWindowsPath(String zipFilePath, String targetDir) throws IOException {
Path targetPath = Paths.get(targetDir).toAbsolutePath().normalize();
Files.createDirectories(targetPath);
try (ZipInputStream zipInputStream = new ZipInputStream(
new BufferedInputStream(new FileInputStream(zipFilePath)), Charset.forName("GBK"))) {
ZipEntry entry;
byte[] buffer = new byte[8192];
while ((entry = zipInputStream.getNextEntry()) != null) {
String entryName = entry.getName().replace("\\", "/");
Path outputPath = targetPath.resolve(entryName).normalize();
if (!outputPath.startsWith(targetPath)) {
System.out.println("Skip unsafe zip entry: " + entry.getName());
zipInputStream.closeEntry();
continue;
}
if (entry.isDirectory() || entryName.endsWith("/")) {
Files.createDirectories(outputPath);
} else {
Path parent = outputPath.getParent();
if (parent != null) {
Files.createDirectories(parent);
}
try (FileOutputStream outputStream = new FileOutputStream(outputPath.toFile())) {
int len;
while ((len = zipInputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, len);
}
}
}
zipInputStream.closeEntry();
}
}
}
private static void unRar(String zipFilePath, String targetDir) throws Exception {
System.out.println(zipFilePath + " to " + targetDir);
RarUtil.unrar(zipFilePath,targetDir);
}
public static void valid(String path){
File directory = new File(path);
File[] studentDirs = directory.listFiles();
if (studentDirs == null) {
System.out.println("No student directories found.");
return;
}
for (File studentDir : studentDirs) {
if (studentDir.isDirectory()) {
File[] files = studentDir.listFiles();
if(files == null || files.length == 0){
System.out.println(studentDir.getName()+" -> null");
}
for (File file : files) {
System.out.println(studentDir.getName()+" ->" + file.getName());
}
System.out.println("--------------------------------");
}
}
}
public static void printSingleExtensionCodeDirs(String path) {
File directory = new File(path);
File[] studentDirs = directory.listFiles();
if (studentDirs == null) {
System.out.println("No student directories found.");
return;
}
for (File studentDir : studentDirs) {
if (!studentDir.isDirectory()) {
continue;
}
try {
ExtensionScanResult result = scanSingleExtensionCodeDir(studentDir.toPath());
if (result.isMatched()) {
System.out.println(studentDir.getName()
+ " -> 主要是 " + result.getExtension()
+ " 文件, count:" + result.getTargetFileCount()
+ "/" + result.getSourceFileCount()
+ ", ratio:" + String.format("%.2f", result.getTargetRatio() * 100) + "%"
+ ", path:" + studentDir.getAbsolutePath());
}
} catch (IOException e) {
System.out.println(studentDir.getName() + " -> 检测失败: " + e.getMessage());
}
}
}
private static ExtensionScanResult scanSingleExtensionCodeDir(Path rootPath) throws IOException {
ExtensionScanResult result = new ExtensionScanResult();
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (!attrs.isRegularFile()) {
return FileVisitResult.CONTINUE;
}
String fileName = file.getFileName().toString();
if (shouldIgnoreWhenDetectingCodeExtension(fileName)) {
return FileVisitResult.CONTINUE;
}
String extension = getExtension(fileName);
if (!SOURCE_EXTENSIONS.contains(extension)) {
return FileVisitResult.CONTINUE;
}
result.addExtension(extension);
return FileVisitResult.CONTINUE;
}
});
result.finish(TARGET_EXTENSION_RATIO);
return result;
}
private static boolean isTargetCodeExtension(String extension) {
return ".cs".equals(extension) || ".m".equals(extension);
}
private static boolean shouldIgnoreWhenDetectingCodeExtension(String fileName) {
return fileName.startsWith(".") || fileName.toLowerCase().endsWith(".meta");
}
private static String getExtension(String fileName) {
int index = fileName.lastIndexOf(".");
if (index < 0 || index == fileName.length() - 1) {
return "";
}
return fileName.substring(index).toLowerCase();
}
public static void removeFullCode(String path){
// 删除完整代码
File directory = new File(path);
File[] studentDirs = directory.listFiles();
if (studentDirs == null) {
System.out.println("No student directories found.");
return;
}
for (File studentDir : studentDirs) {
if (studentDir.isDirectory()) {
String stuNo = studentDir.getName();
File[] files = studentDir.listFiles();
if(files.length == 2){
for (File file : files) {
if (file.getName().contains("完整")) {
System.out.println(stuNo + "==11===" + file.getAbsolutePath());
cn.hutool.core.io.FileUtil.del(file.getAbsolutePath());
}
}
}else if(files.length == 1){
File file = files[0];
File[] files1 = file.listFiles();
if(files1 != null && files1.length == 2){
for (File f : files1) {
if (f.getName().contains("完整")) {
System.out.println(stuNo + "==22===" + f.getAbsolutePath());
FileUtil.del(f.getAbsolutePath());
}
}
}
}
}
}
}
public static void removeDirectory(Path rootPath) throws IOException {
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
String folderName = dir.getFileName().toString();
if (BUILD_AND_DEPENDENCY_DIRS.contains(folderName)) {
System.out.println("Deleting directory: " + dir.toAbsolutePath());
deleteDirectoryRecursively(dir);
return FileVisitResult.SKIP_SUBTREE; // 不再进入已删除目录
}
return FileVisitResult.CONTINUE;
}
});
}
// 递归删除目录
private static void deleteDirectoryRecursively(Path path) throws IOException {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.deleteIfExists(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.deleteIfExists(dir);
return FileVisitResult.CONTINUE;
}
});
}
private static class ExtensionScanResult {
private boolean matched;
private String extension;
private int sourceFileCount;
private int targetFileCount;
private double targetRatio;
private final Map<String, Integer> extensionCountMap = new HashMap<>();
public void addExtension(String extension) {
sourceFileCount++;
extensionCountMap.put(extension, extensionCountMap.getOrDefault(extension, 0) + 1);
}
public void finish(double targetExtensionRatio) {
for (String targetExtension : TARGET_EXTENSIONS) {
int count = extensionCountMap.getOrDefault(targetExtension, 0);
double ratio = sourceFileCount == 0 ? 0 : count * 1.0 / sourceFileCount;
if (count > targetFileCount) {
extension = targetExtension;
targetFileCount = count;
targetRatio = ratio;
}
}
matched = sourceFileCount > 0 && targetFileCount > 0 && targetRatio >= targetExtensionRatio;
}
public boolean isMatched() {
return matched;
}
public void setMatched(boolean matched) {
this.matched = matched;
}
public String getExtension() {
return extension;
}
public int getSourceFileCount() {
return sourceFileCount;
}
public int getTargetFileCount() {
return targetFileCount;
}
public double getTargetRatio() {
return targetRatio;
}
}
}

@ -6,6 +6,8 @@ import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* Created by guange on 26/02/2017.
@ -41,6 +43,13 @@ public class SystemUtil {
* 退
*/
public static ExecuteResp executeAndGetExitStatus(String command) {
return executeAndGetExitStatus(command, 0, null, null);
}
public static ExecuteResp executeAndGetExitStatus(String command,
long timeout,
TimeUnit timeUnit,
Consumer<String> lineConsumer) {
ExecuteResp resp = new ExecuteResp();
logger.debug("execute: {}", command);
@ -52,13 +61,43 @@ public class SystemUtil {
pb.redirectErrorStream(true);
try {
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append(System.getProperty("line.separator"));
Thread outputThread = new Thread(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append(System.getProperty("line.separator"));
if (lineConsumer != null) {
lineConsumer.accept(line);
}
}
} catch (Exception e) {
logger.error("read process output failed: {}", command, e);
}
}, "command-output-reader");
outputThread.setDaemon(true);
outputThread.start();
boolean finished;
if (timeout > 0 && timeUnit != null) {
finished = process.waitFor(timeout, timeUnit);
} else {
exitStatus = process.waitFor();
finished = true;
}
if (!finished) {
process.destroyForcibly();
out.append("Command timeout after ")
.append(timeout)
.append(" ")
.append(timeUnit)
.append(System.getProperty("line.separator"));
logger.error("command timeout after {} {}: {}", timeout, timeUnit, command);
} else if (exitStatus == -1) {
exitStatus = process.exitValue();
}
exitStatus = process.waitFor();
outputThread.join(1000);
} catch (Exception e) {
e.printStackTrace();
@ -66,7 +105,7 @@ public class SystemUtil {
logger.error("executeAndGetExitStatus: ",e);
}
logger.debug("out: {}", out.toString());
logger.debug("out: {}", out);
resp.setOutput(out.toString().trim());
resp.setStatus(exitStatus);

@ -5,16 +5,16 @@
#spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.initSize=20
spring.datasource.master.url=jdbc:postgresql://127.0.0.1:5432/sonar7.7
#spring.datasource.url=jdbc:postgresql://117.50.14.123:5432/sonar
spring.datasource.master.username=root
spring.datasource.master.password=root
#spring.datasource.master.url=jdbc:postgresql://127.0.0.1:5432/sonar
spring.datasource.master.url=jdbc:postgresql://106.75.25.158:5432/sonar?connectTimeout=10&socketTimeout=60&tcpKeepAlive=true
spring.datasource.master.username=sonar
spring.datasource.master.password=sonar
spring.datasource.master.driverClassName=org.postgresql.Driver
#### test ######
spring.datasource.readonly.driverClassName=com.mysql.jdbc.Driver
spring.datasource.readonly.url=jdbc:mysql://rm-bp13v5020p7828r5rso.mysql.rds.aliyuncs.com:3306/preeducoderweb?userSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
spring.datasource.readonly.url=jdbc:mysql://testeducoder-public.rwlb.rds.aliyuncs.com:3306/testeducoderweb?userSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
spring.datasource.readonly.username=testeducoder
spring.datasource.readonly.password=TEST@123
@ -43,8 +43,11 @@ zip.save.path=/tmp/
#excel.template.path=/Users/guange/work/java/ecsonar/src/main/resources/template.xlsx
excel.template.path=template.xlsx
sonar.url=http://127.0.0.1:9000
#sonar.url=http://117.50.14.123:9000
#sonar.url=http://127.0.0.1:9000
sonar.url=http://106.75.25.158:9000
sonar.scan.max-concurrent=3
sonar.scan.retry-times=3
sonar.scan.timeout-minutes=10
# token令牌
sonar.token=0253a518e824a976ea2f11aec17938cb0f8c0495
@ -58,4 +61,4 @@ skip.checked=true
server.port=8081
sonar.host=http://localhost:9000
sonar.host=http://localhost:9000

Binary file not shown.

@ -7,6 +7,7 @@ import net.educoder.ecsonar.model.api.Person;
import net.educoder.ecsonar.services.ReportService;
import net.educoder.ecsonar.services.SonarService;
import net.educoder.ecsonar.utils.ExcelUtil;
import net.educoder.ecsonar.utils.RarUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -64,12 +65,19 @@ public class EcsonarApplicationTests {
}
@Test
public void scanExcel(){
public void scanExcel() throws Exception {
CountDownLatch countDownLatch = new CountDownLatch(1);
String excelPath = "/Users/youyongsheng/Desktop/res.xls";
// String excelPath = "/Users/youyongsheng/Desktop/res-test.xlsx";
sonarService.scanExcel(excelPath);
int downloadHomeworkId = 202605131;
int scanHomeworkId = 202605132;
String downloadDirectory = String.format("/tmp/%d", downloadHomeworkId);
String scanDirectory = String.format("/tmp/%d", scanHomeworkId);
String excelPath = "/Users/youyongsheng/Desktop/ZQ/质量分析/2026-05-11/2026届湘潭大学计算机科学与技术系.xlsx";
sonarService.downloadExcelArchives(excelPath, downloadHomeworkId);
RarUtil.unzip(downloadDirectory, scanDirectory);
RarUtil.prepareForScan(scanDirectory);
sonarService.scanExcel(excelPath, scanHomeworkId);
try {
countDownLatch.await();
@ -81,13 +89,13 @@ public class EcsonarApplicationTests {
@Test
public void writeExcel() throws Exception {
int homeworkId = 20210101;
String directory = "/tmp/20210101/";
int homeworkId = 202605132;
String directory = "/tmp/202605132/";
File file = new File(directory);
File[] files = file.listFiles();
System.out.println("学生数:" + files.length);
List<Person> personList = ExcelUtil.readExcel("/Users/youyongsheng/Desktop/res.xls");
List<Person> personList = ExcelUtil.readExcel("/Users/youyongsheng/Desktop/ZQ/质量分析/2026-05-11/2026届湘潭大学计算机科学与技术系.xlsx");
Map<String, List<Person>> collect = personList.stream().collect(Collectors.groupingBy(Person::getUid));
@ -100,7 +108,7 @@ public class EcsonarApplicationTests {
Metrics metrics = reportService.getMetrics(projectName);
String templatePath = this.getClass().getClassLoader().getResource("template1.xlsx").getPath();
String outPath = "/Users/youyongsheng/Desktop/202100000004.xlsx";
String outPath = "/Users/youyongsheng/Desktop/dddd3.xlsx";
System.out.println("第"+(i++)+"个学生," + uid);
if (CollectionUtils.isEmpty(collect.get(uid))) {
@ -110,6 +118,7 @@ public class EcsonarApplicationTests {
}
reportService.writeSpecifyTemplateToExcel(uid,
collect.get(uid).get(0).getName(),
metrics,
@ -122,4 +131,7 @@ public class EcsonarApplicationTests {
System.out.println("---------end------------");
}
}

Loading…
Cancel
Save