前面的对比数据源已经弄好了,接下来就是具体操作流程。
实现逻辑:简单的新增和列表显示功能
public Response insertSelective(Project record) {
ProjectMapper.insertSelective(record);
return Response.success();
}
public Response selectProjectGroup(int page, int limit, String search) {
PageHelper.startPage(page, limit);
List<Project> list = projectMapper.selectProjectGroup(search);
return Response.success(list);
}
实现逻辑:根据远程仓库路径,新增分支、解析分支名称、同步分支代码 (svn 命令)
新增分支
分支列表
public Response insertSelective(ProjectSubversion record) {
String svnStore = record.getSvnStore();
int projectId = record.getProjectId();
int len = svnStore.split("/").length;
String svnName = svnStore.split("/")[len - 1];//解析分支名称
record.setSvnName(svnName);
ProjectSubversionExample ps = new ProjectSubversionExample();
ps.createCriteria().andProjectIdEqualTo(projectId).andSvnNameEqualTo(svnName);
if (projectSubversionMapper.selectOneByExample(ps) != null) {
return Response.error("svn版本已存在");
}
String projectname = projectMapper.selectByPrimaryKey(projectId).getName();
String res = commandService.executeCmd("cd " + testSvnPath + "&&mkdir " + projectname); //创建目录
String res2 = commandService.executeCmd("cd " + testSvnPath + projectname + "&&svn co " + svnStore); //同步分支代码
if (res2.contains("exec cmd error")) {
return Response.error(res2);
}
record.setCreateTime(LocalDateTime.now());
record.setSvnLocalPath(testSvnPath + projectname + File.separator + svnName);
projectSubversionMapper.insertSelective(record);
return Response.success();
}
public Response selectSvnByProjectId(int projectId) {
List<ProjectSubversion> list = projectSubversionMapper.selectSvnByProjectId(projectId);
return Response.success(list);
}
实现逻辑:更新分支 svn 代码 (svn 命令),获取最近 20 条记录并解析 (svn 命令),前端展示
public Response selectSvnLog(int projectId, String svnName) throws IOException {
String projectname = projectMapper.selectByPrimaryKey(projectId).getName();
String command = "cd " + testSvnPath + projectname + File.separator + svnName + "&&svn update";
log.info(command);
String res1 = commandService.executeCmd("cd " + testSvnPath + projectname + File.separator + svnName + "&&svn update");
if (res1.contains("error")) {
return null;
}
String res = commandService.executeCmd("cd " + testSvnPath + projectname + File.separator + svnName + "&&svn log -v -l 20");//获取最近20条记录
log.info(res);
if (res.contains("exec cmd error")) {
return Response.error(res);
}
BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(res.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));
String line;
List<LogBean> listLog = new ArrayList<>();
int index = -1;
while ((line = br.readLine()) != null) {
if (line.trim().contains(" 行") || line.trim().contains(" line")) {
index++;
LogBean log = new LogBean();
String logNum = line.split("\\|")[0].split("r")[1].trim();//每行可以做加工
String logTime = line.split("\\+")[0].split("\\|", 3)[2].trim();
log.setLogNum(Integer.parseInt(logNum));
log.setLogTime(logTime);
listLog.add(log);
}
if (line.trim().length() != 0) {
if (line.trim().substring(0, 1).equals("A")) {
LogFile logfile = new LogFile();
logfile.setFile(line.trim());
logfile.setType(1);
LogBean nlogBean = listLog.get(index);
List<LogFile> logFiles = nlogBean.getLogfiles();
if (logFiles == null) {
logFiles = new ArrayList<>();
}
logFiles.add(logfile);
nlogBean.setLogfiles(logFiles);
listLog.set(index, nlogBean);
continue;
}
if (line.trim().substring(0, 1).equals("M")) {
LogFile logfile = new LogFile();
logfile.setFile(line.trim());
logfile.setType(2);
LogBean nlogBean = listLog.get(index);
List<LogFile> logFiles = nlogBean.getLogfiles();
if (logFiles == null) {
logFiles = new ArrayList<>();
}
logFiles.add(logfile);
nlogBean.setLogfiles(logFiles);
listLog.set(index, nlogBean);
continue;
}
if (line.trim().substring(0, 1).equals("D")) {
LogFile logfile = new LogFile();
logfile.setFile(line.trim());
logfile.setType(3);
LogBean nlogBean = listLog.get(index);
List<LogFile> logFiles = nlogBean.getLogfiles();
if (logFiles == null) {
logFiles = new ArrayList<>();
}
logFiles.add(logfile);
nlogBean.setLogfiles(logFiles);
listLog.set(index, nlogBean);
}
}
}
return Response.success(listLog);
}
package com.jp.core.tools.shell;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* @author wl
*/
@Slf4j
@Service
public class CommandServiceImpl implements CommandService, InitializingBean {
@Value("${cmd.threadname:cmd-executor}")
private String threadName;
@Value("${cmd.taskQueueMaxStorage:20}")
private Integer taskQueueMaxStorage;
@Value("${cmd.corePoolSize:4}")
private Integer corePoolSize;
@Value("${cmd.maximumPoolSize:8}")
private Integer maximumPoolSize;
@Value("${cmd.keepAliveSeconds:15}")
private Integer keepAliveSeconds;
private ThreadPoolExecutor executor;
private static final String BASH = "sh";
private static final String BASH_PARAM = "-c";
private static final String BASH_win = "cmd.exe";
private static final String BASH_PARAM_win = "/c";
// use thread pool to read streams
@Override
public void afterPropertiesSet() {
executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveSeconds, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(taskQueueMaxStorage),
new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(r, threadName + r.hashCode());
}
},
new ThreadPoolExecutor.AbortPolicy());
}
@Override
public String executeCmd(String cmd) {
boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
Process p = null;
String res;
log.debug("CommandService cmd info : {}", cmd);
try {
// need to pass command as bash's param,
// so that we can compatible with commands: "echo a >> b.txt" or "bash a && bash b"
List<String> cmds = new ArrayList<>();
if(isWindows){
cmds.add(BASH_win);
cmds.add(BASH_PARAM_win);
}
else{
cmds.add(BASH);
cmds.add(BASH_PARAM);
}
cmds.add(cmd);
ProcessBuilder pb = new ProcessBuilder(cmds);
p = pb.start();
Future<String> errorFuture = executor.submit(new ReadTask(p.getErrorStream()));
Future<String> resFuture = executor.submit(new ReadTask(p.getInputStream()));
int exitValue = p.waitFor();
if (exitValue > 0) {
log.info("exec cmd error: {} ", errorFuture.get());
res = "exec cmd error:"+errorFuture.get();
//throw new RuntimeException(errorFuture.get());
} else {
res = resFuture.get();
}
} catch (Exception e) {
log.info("exec cmd error: {} ", e.getMessage());
res = "exec cmd error:"+e.getMessage();
//throw new RuntimeException(e);
} finally {
if (p != null) {
p.destroy();
}
}
// remove System.lineSeparator() (actually it's '\n') in the end of res if exists
if (StringUtils.isNotBlank(res) && res.endsWith(System.lineSeparator())) {
res = res.substring(0, res.lastIndexOf(System.lineSeparator()));
}
return res;
}
class ReadTask implements Callable<String> {
InputStream is;
ReadTask(InputStream is) {
this.is = is;
}
@Override
public String call() throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n"); //这里加\n,就是正常的按行输出
}
return sb.toString();
}
}
}