|
|
@@ -0,0 +1,220 @@
|
|
|
+package cn.seecoder.web.core.gradlellm.impl;
|
|
|
+
|
|
|
+import cn.seecoder.web.core.gradlellm.CodeFileService;
|
|
|
+import cn.seecoder.web.core.gradlellm.ConfigService;
|
|
|
+import cn.seecoder.web.core.gradlellm.DifyService;
|
|
|
+import cn.seecoder.web.core.gradlellm.FileChangeService;
|
|
|
+import cn.seecoder.web.core.gradlellm.utils.FIleUtil;
|
|
|
+import cn.seecoder.web.core.gradlellm.utils.ModuleGradleVisitor;
|
|
|
+import cn.seecoder.web.core.gradlellm.utils.PrintGradleVisitor;
|
|
|
+import cn.seecoder.web.core.gradlellm.utils.RootGradleVisitor;
|
|
|
+import cn.seecoder.web.dao.gradlellm.FileChangeMapper;
|
|
|
+import cn.seecoder.web.model.enums.DifyApiKeyEnum;
|
|
|
+import cn.seecoder.web.model.po.gradlellm.CodeFilePO;
|
|
|
+import cn.seecoder.web.model.po.gradlellm.FileChangePO;
|
|
|
+import cn.seecoder.web.model.vo.gradlellm.ChatMessageRequest;
|
|
|
+import cn.seecoder.web.model.vo.gradlellm.ChatMessageResponse;
|
|
|
+import cn.seecoder.web.service.user.UserService;
|
|
|
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
|
|
|
+import org.codehaus.groovy.ast.builder.AstBuilder;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.StringWriter;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class ConfigServiceImpl implements ConfigService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private FileChangeService fileChangeService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private CodeFileService codeFileService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DifyService difyService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private FileChangeMapper fileChangeMapper;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean modifyConfigByAST(String FilePath, String content) {
|
|
|
+ if (FilePath == null || FilePath.isEmpty()){
|
|
|
+ throw new IllegalArgumentException("Project directory path cannot be null or empty");
|
|
|
+ }
|
|
|
+
|
|
|
+ File projectDir = new File(FilePath);
|
|
|
+ if (!projectDir.exists()) {
|
|
|
+ throw new IllegalArgumentException("Project directory does not exist: " + FilePath);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ Files.walk(projectDir.toPath())
|
|
|
+ .filter(path -> path.getFileName().toString().trim().equals("build.gradle"))
|
|
|
+ .forEach(path -> {
|
|
|
+ try {
|
|
|
+ patchGradleFile(path.toFile(), path.getParent().equals(projectDir.toPath()));
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new RuntimeException("Failed to patch gradle files", e);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void patchGradleFile(File file, boolean isRoot) throws IOException {
|
|
|
+ String modifyString;
|
|
|
+ String codeString;
|
|
|
+ try {
|
|
|
+ AstBuilder astBuilder = new AstBuilder();
|
|
|
+ codeString = FIleUtil.readFileAsString(file.toPath());
|
|
|
+ java.util.List<?> ast = astBuilder.buildFromString(codeString);
|
|
|
+ ClassCodeVisitorSupport visitor = isRoot ?
|
|
|
+ new RootGradleVisitor() :
|
|
|
+ new ModuleGradleVisitor();
|
|
|
+
|
|
|
+ for (Object node : ast) {
|
|
|
+ ((org.codehaus.groovy.ast.ASTNode) node).visit(visitor);
|
|
|
+ }
|
|
|
+
|
|
|
+ StringWriter writer = new StringWriter();
|
|
|
+ PrintGradleVisitor visitorOutput = new PrintGradleVisitor(writer);
|
|
|
+
|
|
|
+ for (Object node : ast) {
|
|
|
+ ((org.codehaus.groovy.ast.ASTNode) node).visit(visitorOutput);
|
|
|
+ }
|
|
|
+
|
|
|
+ modifyString = writer.toString();
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new RuntimeException("Failed to patch gradle file: " + file.getPath(), e);
|
|
|
+ }
|
|
|
+ System.out.println(modifyString);
|
|
|
+ CodeFilePO oldFile = new CodeFilePO();
|
|
|
+ oldFile.setFilePath(file.getAbsolutePath());
|
|
|
+ oldFile.setContent(codeString);
|
|
|
+ oldFile.setCreatedTime(new Date());
|
|
|
+ codeFileService.createCodeFile(oldFile);
|
|
|
+ FileChangePO fileChange = new FileChangePO();
|
|
|
+ fileChange.setOldFileId(oldFile.getId());
|
|
|
+ fileChange.setUserId(2999L);
|
|
|
+ CodeFilePO newFile = new CodeFilePO();
|
|
|
+ newFile.setFilePath(file.getAbsolutePath());
|
|
|
+ newFile.setContent(modifyString);
|
|
|
+ newFile.setCreatedTime(new Date());
|
|
|
+ codeFileService.createCodeFile(newFile);
|
|
|
+ fileChange.setNewFileId(newFile.getId());
|
|
|
+ fileChange.setCreatedTime(new Date());
|
|
|
+ fileChangeService.insert(fileChange);
|
|
|
+ FIleUtil.writeString(file.toPath(), modifyString);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean modifyConfigByLLM(String FilePath, String content) {
|
|
|
+ if (FilePath == null || FilePath.isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("Project directory path cannot be null or empty");
|
|
|
+ }
|
|
|
+
|
|
|
+ File projectDir = new File(FilePath);
|
|
|
+ if (!projectDir.exists()) {
|
|
|
+ throw new IllegalArgumentException("Project directory does not exist: " + FilePath);
|
|
|
+ }
|
|
|
+
|
|
|
+ try{
|
|
|
+ Files.walk(projectDir.toPath())
|
|
|
+ .filter(path -> path.getFileName().toString().trim().equals("build.gradle"))
|
|
|
+ .forEach(path -> {
|
|
|
+ System.out.println(path.toAbsolutePath());
|
|
|
+ modifyWithDify(path.toFile(), path.getParent().equals(projectDir.toPath()));
|
|
|
+ });
|
|
|
+ }catch (Exception e) {
|
|
|
+ throw new RuntimeException("Failed to patch gradle files", e);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void modifyWithDify(File file, boolean isRoot) {
|
|
|
+ try {
|
|
|
+ String codeString = FIleUtil.readFileAsString(file.toPath());
|
|
|
+ ChatMessageRequest request = new ChatMessageRequest();
|
|
|
+ CodeFilePO oldFile = new CodeFilePO();
|
|
|
+ oldFile.setFilePath(file.getAbsolutePath());
|
|
|
+ oldFile.setContent(codeString);
|
|
|
+ oldFile.setCreatedTime(new Date());
|
|
|
+ codeFileService.createCodeFile(oldFile);
|
|
|
+ request.setQuery( isRoot ? "\"file_type\":\"project\" \n " + codeString : "\"file_type\":\"module\" \n " + codeString);
|
|
|
+ request.setUser("abc-123");
|
|
|
+ request.setResponse_mode("blocking");
|
|
|
+ difyService.setApiKey(DifyApiKeyEnum.GRADLE.getApiKey());
|
|
|
+ ChatMessageResponse modifiedCode = difyService.sendMessage(request);
|
|
|
+ String modifiedCodeString = modifiedCode.getAnswer();
|
|
|
+ if (modifiedCodeString == null || modifiedCodeString.isEmpty()) {
|
|
|
+ throw new RuntimeException("Received empty response from Dify");
|
|
|
+ }
|
|
|
+ modifiedCodeString = modifiedCodeString.replace("gradle\n", "");
|
|
|
+ modifiedCodeString = modifiedCodeString.replace("```", "");
|
|
|
+ FileChangePO fileChange = new FileChangePO();
|
|
|
+ CodeFilePO newFile = new CodeFilePO();
|
|
|
+ newFile.setFilePath(file.getAbsolutePath());
|
|
|
+ newFile.setContent(modifiedCodeString);
|
|
|
+ newFile.setCreatedTime(new Date());
|
|
|
+ codeFileService.createCodeFile(newFile);
|
|
|
+ fileChange.setOldFileId(oldFile.getId());
|
|
|
+ fileChange.setUserId(2999L);
|
|
|
+ fileChange.setNewFileId(newFile.getId());
|
|
|
+ fileChange.setCreatedTime(new Date());
|
|
|
+ fileChangeService.insert(fileChange);
|
|
|
+ FIleUtil.writeString(file.toPath(), modifiedCodeString);
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException("Failed to modify gradle file", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<FileChangePO> listConfigChanges() {
|
|
|
+ int userId = UserService.loginUser().getId();
|
|
|
+ return fileChangeMapper.selectByUserId((long) userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<CodeFilePO> getChangeDetail(Long fileChangeId) {
|
|
|
+ FileChangePO fileChange = fileChangeMapper.selectById(fileChangeId);
|
|
|
+ long oldFileId = fileChange.getOldFileId();
|
|
|
+ long newFileId = fileChange.getNewFileId();
|
|
|
+ CodeFilePO oldFile = codeFileService.getCodeFileById(oldFileId);
|
|
|
+ CodeFilePO newFile = codeFileService.getCodeFileById(newFileId);
|
|
|
+ List<CodeFilePO> res = new ArrayList<>();
|
|
|
+ res.add(oldFile);
|
|
|
+ res.add(newFile);
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean rollbackChange(Long fileChangeId) {
|
|
|
+ FileChangePO fileChange = fileChangeMapper.selectById(fileChangeId);
|
|
|
+ long oldFileId = fileChange.getOldFileId();
|
|
|
+ CodeFilePO oldFile = codeFileService.getCodeFileById(oldFileId);
|
|
|
+ String filePath = oldFile.getFilePath();
|
|
|
+ String content = oldFile.getContent();
|
|
|
+ File file = new File(filePath);
|
|
|
+ if (!file.exists()) {
|
|
|
+ throw new IllegalArgumentException("File does not exist: " + filePath);
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ FIleUtil.writeString(file.toPath(), content);
|
|
|
+ fileChangeMapper.delete(fileChangeId);
|
|
|
+ codeFileService.deleteCodeFile(oldFileId);
|
|
|
+ return true;
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException("Failed to rollback change", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|