feat(fix) 在线升级执行脚本、脚本模版等兼容 debian

This commit is contained in:
bwcx_jzy 2022-02-23 10:31:31 +08:00
parent 37731c12c1
commit b2cba06872
No known key found for this signature in database
GPG Key ID: 5E48E9372088B9E5
10 changed files with 925 additions and 927 deletions

View File

@ -14,6 +14,7 @@
3. 【server】在线构建 ssh 发布选择授权目录切换不生效问题(感谢@天天) 3. 【server】在线构建 ssh 发布选择授权目录切换不生效问题(感谢@天天)
4. 【server】在线构建本地构建命令不能换行问题感谢@华仔) 4. 【server】在线构建本地构建命令不能换行问题感谢@华仔)
5. 【server】日志弹窗新增行号 5. 【server】日志弹窗新增行号
6. 【server】在线升级执行脚本、脚本模版等兼容 `debian` (感谢@wxyShine [Gitee issues I4UQBD](https://gitee.com/dromara/Jpom/issues/I4UQBD)
------ ------

View File

@ -29,7 +29,6 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.LineHandler; import cn.hutool.core.io.LineHandler;
import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;
import cn.jiangzeyin.common.DefaultSystemLog; import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.spring.SpringUtil; import cn.jiangzeyin.common.spring.SpringUtil;
import io.jpom.model.data.DslYmlDto; import io.jpom.model.data.DslYmlDto;
@ -75,9 +74,7 @@ public class DslScriptBuilder extends BaseRunScript implements Runnable {
ProcessBuilder processBuilder = new ProcessBuilder(); ProcessBuilder processBuilder = new ProcessBuilder();
List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE); List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE);
command.add(0, script); command.add(0, script);
if (SystemUtil.getOsInfo().isLinux() || SystemUtil.getOsInfo().isMac()) { command.add(0, CommandUtil.EXECUTE_PREFIX);
command.add(0, CommandUtil.SUFFIX);
}
DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE)); DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE));
if (environment != null) { if (environment != null) {
processBuilder.environment().putAll(environment); processBuilder.environment().putAll(environment);

View File

@ -30,7 +30,6 @@ import cn.hutool.core.io.LineHandler;
import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;
import cn.jiangzeyin.common.DefaultSystemLog; import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage; import cn.jiangzeyin.common.JsonMessage;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
@ -53,171 +52,169 @@ import java.util.concurrent.ConcurrentHashMap;
* @date 2019/4/25 * @date 2019/4/25
*/ */
public class ScriptProcessBuilder extends BaseRunScript implements Runnable { public class ScriptProcessBuilder extends BaseRunScript implements Runnable {
/** /**
* 执行中的缓存 * 执行中的缓存
*/ */
private static final ConcurrentHashMap<String, ScriptProcessBuilder> FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<String, ScriptProcessBuilder> FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
private final ProcessBuilder processBuilder; private final ProcessBuilder processBuilder;
private final Set<Session> sessions = new HashSet<>(); private final Set<Session> sessions = new HashSet<>();
private final String executeId; private final String executeId;
private ScriptProcessBuilder(NodeScriptModel nodeScriptModel, String executeId, String args) { private ScriptProcessBuilder(NodeScriptModel nodeScriptModel, String executeId, String args) {
super(nodeScriptModel.logFile(executeId)); super(nodeScriptModel.logFile(executeId));
this.executeId = executeId; this.executeId = executeId;
File scriptFile = nodeScriptModel.getFile(true); File scriptFile = nodeScriptModel.getFile(true);
// //
String script = FileUtil.getAbsolutePath(scriptFile); String script = FileUtil.getAbsolutePath(scriptFile);
processBuilder = new ProcessBuilder(); processBuilder = new ProcessBuilder();
List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE); List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE);
command.add(0, script); command.add(0, script);
if (SystemUtil.getOsInfo().isLinux() || SystemUtil.getOsInfo().isMac()) { command.add(0, CommandUtil.EXECUTE_PREFIX);
command.add(0, CommandUtil.SUFFIX); DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE));
} processBuilder.redirectErrorStream(true);
DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE)); processBuilder.command(command);
processBuilder.redirectErrorStream(true); processBuilder.directory(scriptFile.getParentFile());
processBuilder.command(command); }
processBuilder.directory(scriptFile.getParentFile());
}
/** /**
* 创建执行 并监听 * 创建执行 并监听
* *
* @param nodeScriptModel 脚本模版 * @param nodeScriptModel 脚本模版
* @param executeId 执行ID * @param executeId 执行ID
* @param args 参数 * @param args 参数
*/ */
public static ScriptProcessBuilder create(NodeScriptModel nodeScriptModel, String executeId, String args) { public static ScriptProcessBuilder create(NodeScriptModel nodeScriptModel, String executeId, String args) {
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.computeIfAbsent(executeId, file1 -> { return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.computeIfAbsent(executeId, file1 -> {
ScriptProcessBuilder scriptProcessBuilder1 = new ScriptProcessBuilder(nodeScriptModel, executeId, args); ScriptProcessBuilder scriptProcessBuilder1 = new ScriptProcessBuilder(nodeScriptModel, executeId, args);
ThreadUtil.execute(scriptProcessBuilder1); ThreadUtil.execute(scriptProcessBuilder1);
return scriptProcessBuilder1; return scriptProcessBuilder1;
}); });
} }
/** /**
* 创建执行 并监听 * 创建执行 并监听
* *
* @param nodeScriptModel 脚本模版 * @param nodeScriptModel 脚本模版
* @param executeId 执行ID * @param executeId 执行ID
* @param args 参数 * @param args 参数
* @param session 会话 * @param session 会话
*/ */
public static void addWatcher(NodeScriptModel nodeScriptModel, String executeId, String args, Session session) { public static void addWatcher(NodeScriptModel nodeScriptModel, String executeId, String args, Session session) {
ScriptProcessBuilder scriptProcessBuilder = create(nodeScriptModel, executeId, args); ScriptProcessBuilder scriptProcessBuilder = create(nodeScriptModel, executeId, args);
// //
if (scriptProcessBuilder.sessions.add(session)) { if (scriptProcessBuilder.sessions.add(session)) {
if (FileUtil.exist(scriptProcessBuilder.logFile)) { if (FileUtil.exist(scriptProcessBuilder.logFile)) {
// 读取之前的信息并发送 // 读取之前的信息并发送
FileUtil.readLines(scriptProcessBuilder.logFile, CharsetUtil.CHARSET_UTF_8, (LineHandler) line -> { FileUtil.readLines(scriptProcessBuilder.logFile, CharsetUtil.CHARSET_UTF_8, (LineHandler) line -> {
try { try {
SocketSessionUtil.send(session, line); SocketSessionUtil.send(session, line);
} catch (IOException e) { } catch (IOException e) {
DefaultSystemLog.getLog().error("发送消息失败", e); DefaultSystemLog.getLog().error("发送消息失败", e);
} }
}); });
} }
} }
} }
/** /**
* 判断是否还在执行中 * 判断是否还在执行中
* *
* @param executeId 执行id * @param executeId 执行id
* @return true 还在执行 * @return true 还在执行
*/ */
public static boolean isRun(String executeId) { public static boolean isRun(String executeId) {
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.containsKey(executeId); return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.containsKey(executeId);
} }
/** /**
* 关闭会话 * 关闭会话
* *
* @param session 会话 * @param session 会话
*/ */
public static void stopWatcher(Session session) { public static void stopWatcher(Session session) {
Collection<ScriptProcessBuilder> scriptProcessBuilders = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.values(); Collection<ScriptProcessBuilder> scriptProcessBuilders = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.values();
for (ScriptProcessBuilder scriptProcessBuilder : scriptProcessBuilders) { for (ScriptProcessBuilder scriptProcessBuilder : scriptProcessBuilders) {
Set<Session> sessions = scriptProcessBuilder.sessions; Set<Session> sessions = scriptProcessBuilder.sessions;
sessions.removeIf(session1 -> session1.getId().equals(session.getId())); sessions.removeIf(session1 -> session1.getId().equals(session.getId()));
} }
} }
/** /**
* 停止脚本命令 * 停止脚本命令
* *
* @param executeId 执行ID * @param executeId 执行ID
*/ */
public static void stopRun(String executeId) { public static void stopRun(String executeId) {
ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.get(executeId); ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.get(executeId);
if (scriptProcessBuilder != null) { if (scriptProcessBuilder != null) {
scriptProcessBuilder.end("停止运行"); scriptProcessBuilder.end("停止运行");
} }
} }
@Override @Override
public void run() { public void run() {
//初始化ProcessBuilder对象 //初始化ProcessBuilder对象
try { try {
this.handle("start execute:" + DateUtil.now()); this.handle("start execute:" + DateUtil.now());
process = processBuilder.start(); process = processBuilder.start();
{ {
inputStream = process.getInputStream(); inputStream = process.getInputStream();
IoUtil.readLines(inputStream, ExtConfigBean.getInstance().getConsoleLogCharset(), (LineHandler) ScriptProcessBuilder.this::handle); IoUtil.readLines(inputStream, ExtConfigBean.getInstance().getConsoleLogCharset(), (LineHandler) ScriptProcessBuilder.this::handle);
} }
int waitFor = process.waitFor(); int waitFor = process.waitFor();
JsonMessage<String> jsonMessage = new JsonMessage<>(200, "执行完毕:" + waitFor); JsonMessage<String> jsonMessage = new JsonMessage<>(200, "执行完毕:" + waitFor);
JSONObject jsonObject = jsonMessage.toJson(); JSONObject jsonObject = jsonMessage.toJson();
jsonObject.put("op", ConsoleCommandOp.stop.name()); jsonObject.put("op", ConsoleCommandOp.stop.name());
this.end(jsonObject.toString()); this.end(jsonObject.toString());
this.handle("execute done:" + waitFor + " time:" + DateUtil.now()); this.handle("execute done:" + waitFor + " time:" + DateUtil.now());
} catch (Exception e) { } catch (Exception e) {
DefaultSystemLog.getLog().error("执行异常", e); DefaultSystemLog.getLog().error("执行异常", e);
this.end("执行异常:" + e.getMessage()); this.end("执行异常:" + e.getMessage());
} finally { } finally {
this.close(); this.close();
} }
} }
/** /**
* 结束执行 * 结束执行
* *
* @param msg 响应的消息 * @param msg 响应的消息
*/ */
@Override @Override
protected void end(String msg) { protected void end(String msg) {
Iterator<Session> iterator = sessions.iterator(); Iterator<Session> iterator = sessions.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Session session = iterator.next(); Session session = iterator.next();
try { try {
SocketSessionUtil.send(session, msg); SocketSessionUtil.send(session, msg);
} catch (IOException e) { } catch (IOException e) {
DefaultSystemLog.getLog().error("发送消息失败", e); DefaultSystemLog.getLog().error("发送消息失败", e);
} }
iterator.remove(); iterator.remove();
} }
FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.remove(this.executeId); FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.remove(this.executeId);
} }
/** /**
* 响应 * 响应
* *
* @param line 信息 * @param line 信息
*/ */
@Override @Override
protected void handle(String line) { protected void handle(String line) {
super.handle(line); super.handle(line);
// //
Iterator<Session> iterator = sessions.iterator(); Iterator<Session> iterator = sessions.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Session session = iterator.next(); Session session = iterator.next();
try { try {
SocketSessionUtil.send(session, line); SocketSessionUtil.send(session, line);
} catch (IOException e) { } catch (IOException e) {
DefaultSystemLog.getLog().error("发送消息失败", e); DefaultSystemLog.getLog().error("发送消息失败", e);
iterator.remove(); iterator.remove();
} }
} }
} }
} }

View File

@ -196,9 +196,7 @@ public class JpomApplication extends ApplicationBuilder {
// Waiting for method caller,For example, the interface response // Waiting for method caller,For example, the interface response
ThreadUtil.sleep(2, TimeUnit.SECONDS); ThreadUtil.sleep(2, TimeUnit.SECONDS);
try { try {
String command = SystemUtil.getOsInfo().isWindows() ? StrUtil.EMPTY : CommandUtil.SUFFIX; String command = CommandUtil.EXECUTE_PREFIX + StrUtil.SPACE + FileUtil.getAbsolutePath(scriptFile) + " restart upgrade";
command += " " + FileUtil.getAbsolutePath(scriptFile) + " restart upgrade";
if (SystemUtil.getOsInfo().isWindows()) { if (SystemUtil.getOsInfo().isWindows()) {
CommandUtil.execSystemCommand(command, scriptFile.getParentFile()); CommandUtil.execSystemCommand(command, scriptFile.getParentFile());
} else { } else {

View File

@ -23,7 +23,10 @@
package io.jpom.util; package io.jpom.util;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.*; import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil; import cn.hutool.system.SystemUtil;
import cn.jiangzeyin.common.DefaultSystemLog; import cn.jiangzeyin.common.DefaultSystemLog;
import io.jpom.system.ExtConfigBean; import io.jpom.system.ExtConfigBean;
@ -42,189 +45,193 @@ import java.util.List;
* @date 2019/4/15 * @date 2019/4/15
*/ */
public class CommandUtil { public class CommandUtil {
/** /**
* 系统命令 * 系统命令
*/ */
private static final List<String> COMMAND = new ArrayList<>(); private static final List<String> COMMAND = new ArrayList<>();
/** /**
* 文件后缀 * 文件后缀
*/ */
public static final String SUFFIX; public static final String SUFFIX;
/**
* 执行前缀
*/
public static final String EXECUTE_PREFIX;
static { static {
if (SystemUtil.getOsInfo().isLinux()) { if (SystemUtil.getOsInfo().isLinux()) {
//执行linux系统命令 //执行linux系统命令
COMMAND.add("/bin/bash"); COMMAND.add("/bin/bash");
COMMAND.add("-c"); COMMAND.add("-c");
} else if (SystemUtil.getOsInfo().isMac()) { } else if (SystemUtil.getOsInfo().isMac()) {
COMMAND.add("/bin/bash"); COMMAND.add("/bin/bash");
COMMAND.add("-c"); COMMAND.add("-c");
} else { } else {
COMMAND.add("cmd"); COMMAND.add("cmd");
COMMAND.add("/c"); COMMAND.add("/c");
} }
/** //
* 文件后缀 if (SystemUtil.getOsInfo().isWindows()) {
*/ SUFFIX = "bat";
if (SystemUtil.getOsInfo().isWindows()) { EXECUTE_PREFIX = StrUtil.EMPTY;
SUFFIX = "bat"; } else {
} else { SUFFIX = "sh";
SUFFIX = "sh"; EXECUTE_PREFIX = "bash";
} }
} }
/** /**
* 获取执行命令的 前缀 * 获取执行命令的 前缀
* *
* @return list * @return list
*/ */
public static List<String> getCommand() { public static List<String> getCommand() {
return ObjectUtil.clone(COMMAND); return ObjectUtil.clone(COMMAND);
} }
public static String execSystemCommand(String command) { public static String execSystemCommand(String command) {
return execSystemCommand(command, null); return execSystemCommand(command, null);
} }
/** /**
* 在指定文件夹下执行命令 * 在指定文件夹下执行命令
* *
* @param command 命令 * @param command 命令
* @param file 文件夹 * @param file 文件夹
* @return msg * @return msg
*/ */
public static String execSystemCommand(String command, File file) { public static String execSystemCommand(String command, File file) {
String newCommand = StrUtil.replace(command, StrUtil.CRLF, StrUtil.SPACE); String newCommand = StrUtil.replace(command, StrUtil.CRLF, StrUtil.SPACE);
newCommand = StrUtil.replace(newCommand, StrUtil.LF, StrUtil.SPACE); newCommand = StrUtil.replace(newCommand, StrUtil.LF, StrUtil.SPACE);
String result = "error"; String result = "error";
try { try {
List<String> commands = getCommand(); List<String> commands = getCommand();
commands.add(newCommand); commands.add(newCommand);
String[] cmd = commands.toArray(new String[]{}); String[] cmd = commands.toArray(new String[]{});
result = exec(cmd, file); result = exec(cmd, file);
} catch (Exception e) { } catch (Exception e) {
DefaultSystemLog.getLog().error("执行命令异常", e); DefaultSystemLog.getLog().error("执行命令异常", e);
result += e.getMessage(); result += e.getMessage();
} }
return result; return result;
} }
/** /**
* 执行命令 * 执行命令
* *
* @param cmd 命令行 * @param cmd 命令行
* @return 结果 * @return 结果
* @throws IOException IO * @throws IOException IO
*/ */
private static String exec(String[] cmd, File file) throws IOException { private static String exec(String[] cmd, File file) throws IOException {
Process process = new ProcessBuilder(cmd).directory(file).redirectErrorStream(true).start(); Process process = new ProcessBuilder(cmd).directory(file).redirectErrorStream(true).start();
Charset charset; Charset charset;
boolean log; boolean log;
try { try {
charset = ExtConfigBean.getInstance().getConsoleLogCharset(); charset = ExtConfigBean.getInstance().getConsoleLogCharset();
log = true; log = true;
} catch (Exception e) { } catch (Exception e) {
// 直接执行使用默认编码格式 // 直接执行使用默认编码格式
charset = CharsetUtil.systemCharset(); charset = CharsetUtil.systemCharset();
// 不记录日志 // 不记录日志
log = false; log = false;
} }
charset = ObjectUtil.defaultIfNull(charset, CharsetUtil.defaultCharset()); charset = ObjectUtil.defaultIfNull(charset, CharsetUtil.defaultCharset());
String result = RuntimeUtil.getResult(process, charset); String result = RuntimeUtil.getResult(process, charset);
if (log) { if (log) {
DefaultSystemLog.getLog().debug("exec {} {} {}", charset.name(), Arrays.toString(cmd), result); DefaultSystemLog.getLog().debug("exec {} {} {}", charset.name(), Arrays.toString(cmd), result);
} }
return result; return result;
} }
/** /**
* 异步执行命令 * 异步执行命令
* *
* @param file 文件夹 * @param file 文件夹
* @param command 命令 * @param command 命令
* @throws IOException 异常 * @throws IOException 异常
*/ */
public static void asyncExeLocalCommand(File file, String command) throws Exception { public static void asyncExeLocalCommand(File file, String command) throws Exception {
String newCommand = StrUtil.replace(command, StrUtil.CRLF, StrUtil.SPACE); String newCommand = StrUtil.replace(command, StrUtil.CRLF, StrUtil.SPACE);
newCommand = StrUtil.replace(newCommand, StrUtil.LF, StrUtil.SPACE); newCommand = StrUtil.replace(newCommand, StrUtil.LF, StrUtil.SPACE);
// //
DefaultSystemLog.getLog().debug(newCommand); DefaultSystemLog.getLog().debug(newCommand);
List<String> commands = getCommand(); List<String> commands = getCommand();
commands.add(newCommand); commands.add(newCommand);
ProcessBuilder pb = new ProcessBuilder(commands); ProcessBuilder pb = new ProcessBuilder(commands);
if (file != null) { if (file != null) {
pb.directory(file); pb.directory(file);
} }
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT); pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT); pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectInput(ProcessBuilder.Redirect.INHERIT); pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
pb.start(); pb.start();
} }
/** /**
* 判断是否包含删除命令 * 判断是否包含删除命令
* *
* @param script 命令行 * @param script 命令行
* @return true 包含 * @return true 包含
*/ */
public static boolean checkContainsDel(String script) { public static boolean checkContainsDel(String script) {
// 判断删除 // 判断删除
String[] commands = StrUtil.splitToArray(script, StrUtil.LF); String[] commands = StrUtil.splitToArray(script, StrUtil.LF);
for (String commandItem : commands) { for (String commandItem : commands) {
if (checkContainsDelItem(commandItem)) { if (checkContainsDelItem(commandItem)) {
return true; return true;
} }
} }
return false; return false;
} }
/** /**
* 执行系统命令 快速删除. * 执行系统命令 快速删除.
* 执行删除后再检查文件是否存在 * 执行删除后再检查文件是否存在
* *
* @param file 文件或者文件夹 * @param file 文件或者文件夹
* @return true 文件还存在 * @return true 文件还存在
*/ */
public static boolean systemFastDel(File file) { public static boolean systemFastDel(File file) {
String path = FileUtil.getAbsolutePath(file); String path = FileUtil.getAbsolutePath(file);
String command; String command;
if (SystemUtil.getOsInfo().isWindows()) { if (SystemUtil.getOsInfo().isWindows()) {
// Windows // Windows
command = StrUtil.format("rd /s/q \"{}\"", path); command = StrUtil.format("rd /s/q \"{}\"", path);
} else { } else {
// Linux MacOS // Linux MacOS
command = StrUtil.format("rm -rf '{}'", path); command = StrUtil.format("rm -rf '{}'", path);
} }
CommandUtil.execSystemCommand(command); CommandUtil.execSystemCommand(command);
// 再次尝试 // 再次尝试
boolean del = FileUtil.del(file); boolean del = FileUtil.del(file);
if (!del) { if (!del) {
FileUtil.del(file.toPath()); FileUtil.del(file.toPath());
} }
return FileUtil.exist(file); return FileUtil.exist(file);
} }
private static boolean checkContainsDelItem(String script) { private static boolean checkContainsDelItem(String script) {
String[] split = StrUtil.splitToArray(script, StrUtil.SPACE); String[] split = StrUtil.splitToArray(script, StrUtil.SPACE);
if (SystemUtil.getOsInfo().isWindows()) { if (SystemUtil.getOsInfo().isWindows()) {
for (String s : split) { for (String s : split) {
if (StrUtil.startWithAny(s, "rd", "del")) { if (StrUtil.startWithAny(s, "rd", "del")) {
return true; return true;
} }
if (StrUtil.containsAnyIgnoreCase(s, " rd", " del")) { if (StrUtil.containsAnyIgnoreCase(s, " rd", " del")) {
return true; return true;
} }
} }
} else { } else {
for (String s : split) { for (String s : split) {
if (StrUtil.startWithAny(s, "rm", "\\rm")) { if (StrUtil.startWithAny(s, "rm", "\\rm")) {
return true; return true;
} }
if (StrUtil.containsAnyIgnoreCase(s, " rm", " \\rm", "&rm", "&\\rm")) { if (StrUtil.containsAnyIgnoreCase(s, " rm", " \\rm", "&rm", "&\\rm")) {
return true; return true;
} }
} }
} }
return false; return false;
} }
} }

View File

@ -37,7 +37,6 @@ import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.ssh.JschUtil; import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.extra.ssh.Sftp; import cn.hutool.extra.ssh.Sftp;
import cn.hutool.http.HttpStatus; import cn.hutool.http.HttpStatus;
import cn.hutool.system.SystemUtil;
import cn.jiangzeyin.common.JsonMessage; import cn.jiangzeyin.common.JsonMessage;
import cn.jiangzeyin.common.spring.SpringUtil; import cn.jiangzeyin.common.spring.SpringUtil;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
@ -86,22 +85,22 @@ import java.util.stream.Collectors;
@Builder @Builder
public class ReleaseManage implements Runnable { public class ReleaseManage implements Runnable {
private final UserModel userModel; private final UserModel userModel;
private final int buildId; private final int buildId;
private final BuildExtraModule buildExtraModule; private final BuildExtraModule buildExtraModule;
private final String logId; private final String logId;
private final BuildExecuteService buildExecuteService; private final BuildExecuteService buildExecuteService;
private LogRecorder logRecorder; private LogRecorder logRecorder;
private File resultFile; private File resultFile;
private void init() { private void init() {
if (this.logRecorder == null) { if (this.logRecorder == null) {
File logFile = BuildUtil.getLogFile(buildExtraModule.getId(), buildId); File logFile = BuildUtil.getLogFile(buildExtraModule.getId(), buildId);
this.logRecorder = LogRecorder.builder().file(logFile).build(); this.logRecorder = LogRecorder.builder().file(logFile).build();
} }
this.resultFile = BuildUtil.getHistoryPackageFile(buildExtraModule.getId(), this.buildId, buildExtraModule.getResultDirFile()); this.resultFile = BuildUtil.getHistoryPackageFile(buildExtraModule.getId(), this.buildId, buildExtraModule.getResultDirFile());
} }
// /** // /**
// * new ReleaseManage constructor // * new ReleaseManage constructor
@ -138,417 +137,417 @@ public class ReleaseManage implements Runnable {
// } // }
public void updateStatus(BuildStatus status) { public void updateStatus(BuildStatus status) {
buildExecuteService.updateStatus(this.buildExtraModule.getId(), this.logId, status); buildExecuteService.updateStatus(this.buildExtraModule.getId(), this.logId, status);
} }
/** /**
* 不修改为发布中状态 * 不修改为发布中状态
*/ */
public void start() { public void start() {
init(); init();
updateStatus(BuildStatus.PubIng); updateStatus(BuildStatus.PubIng);
logRecorder.info("start release" + FileUtil.readableFileSize(FileUtil.size(this.resultFile))); logRecorder.info("start release" + FileUtil.readableFileSize(FileUtil.size(this.resultFile)));
if (!this.resultFile.exists()) { if (!this.resultFile.exists()) {
logRecorder.info("不存在构建产物"); logRecorder.info("不存在构建产物");
updateStatus(BuildStatus.PubError); updateStatus(BuildStatus.PubError);
return; return;
} }
long time = SystemClock.now(); long time = SystemClock.now();
int releaseMethod = this.buildExtraModule.getReleaseMethod(); int releaseMethod = this.buildExtraModule.getReleaseMethod();
logRecorder.info("release method:" + BaseEnum.getDescByCode(BuildReleaseMethod.class, releaseMethod)); logRecorder.info("release method:" + BaseEnum.getDescByCode(BuildReleaseMethod.class, releaseMethod));
try { try {
if (releaseMethod == BuildReleaseMethod.Outgiving.getCode()) { if (releaseMethod == BuildReleaseMethod.Outgiving.getCode()) {
// //
this.doOutGiving(); this.doOutGiving();
} else if (releaseMethod == BuildReleaseMethod.Project.getCode()) { } else if (releaseMethod == BuildReleaseMethod.Project.getCode()) {
this.doProject(); this.doProject();
} else if (releaseMethod == BuildReleaseMethod.Ssh.getCode()) { } else if (releaseMethod == BuildReleaseMethod.Ssh.getCode()) {
this.doSsh(); this.doSsh();
} else if (releaseMethod == BuildReleaseMethod.LocalCommand.getCode()) { } else if (releaseMethod == BuildReleaseMethod.LocalCommand.getCode()) {
this.localCommand(); this.localCommand();
} else if (releaseMethod == BuildReleaseMethod.DockerImage.getCode()) { } else if (releaseMethod == BuildReleaseMethod.DockerImage.getCode()) {
this.doDockerImage(); this.doDockerImage();
} else { } else {
logRecorder.info(" 没有实现的发布分发:" + releaseMethod); logRecorder.info(" 没有实现的发布分发:" + releaseMethod);
} }
} catch (Exception e) { } catch (Exception e) {
this.pubLog("发布异常", e); this.pubLog("发布异常", e);
return; return;
} }
logRecorder.info("release complete : " + DateUtil.formatBetween(SystemClock.now() - time, BetweenFormatter.Level.MILLISECOND)); logRecorder.info("release complete : " + DateUtil.formatBetween(SystemClock.now() - time, BetweenFormatter.Level.MILLISECOND));
updateStatus(BuildStatus.PubSuccess); updateStatus(BuildStatus.PubSuccess);
} }
/** /**
* 格式化命令模版 * 格式化命令模版
* *
* @param commands 命令 * @param commands 命令
*/ */
private void formatCommand(String[] commands) { private void formatCommand(String[] commands) {
for (int i = 0; i < commands.length; i++) { for (int i = 0; i < commands.length; i++) {
commands[i] = this.formatCommandItem(commands[i]); commands[i] = this.formatCommandItem(commands[i]);
} }
// //
WorkspaceEnvVarService workspaceEnvVarService = SpringUtil.getBean(WorkspaceEnvVarService.class); WorkspaceEnvVarService workspaceEnvVarService = SpringUtil.getBean(WorkspaceEnvVarService.class);
workspaceEnvVarService.formatCommand(this.buildExtraModule.getWorkspaceId(), commands); workspaceEnvVarService.formatCommand(this.buildExtraModule.getWorkspaceId(), commands);
} }
/** /**
* 格式化命令模版 * 格式化命令模版
* *
* @param command 命令 * @param command 命令
* @return 格式化后 * @return 格式化后
*/ */
private String formatCommandItem(String command) { private String formatCommandItem(String command) {
String replace = StrUtil.replace(command, "#{BUILD_ID}", this.buildExtraModule.getId()); String replace = StrUtil.replace(command, "#{BUILD_ID}", this.buildExtraModule.getId());
replace = StrUtil.replace(replace, "#{BUILD_NAME}", this.buildExtraModule.getName()); replace = StrUtil.replace(replace, "#{BUILD_NAME}", this.buildExtraModule.getName());
replace = StrUtil.replace(replace, "#{BUILD_RESULT_FILE}", FileUtil.getAbsolutePath(this.resultFile)); replace = StrUtil.replace(replace, "#{BUILD_RESULT_FILE}", FileUtil.getAbsolutePath(this.resultFile));
replace = StrUtil.replace(replace, "#{BUILD_NUMBER_ID}", this.buildId + StrUtil.EMPTY); replace = StrUtil.replace(replace, "#{BUILD_NUMBER_ID}", this.buildId + StrUtil.EMPTY);
return replace; return replace;
} }
private String parseDockerTag(File envFile, String tag) { private String parseDockerTag(File envFile, String tag) {
if (!FileUtil.isFile(envFile)) { if (!FileUtil.isFile(envFile)) {
return tag; return tag;
} }
final String[] newTag = {tag}; final String[] newTag = {tag};
FileUtil.readLines(envFile, StandardCharsets.UTF_8, (LineHandler) line -> { FileUtil.readLines(envFile, StandardCharsets.UTF_8, (LineHandler) line -> {
line = StrUtil.trim(line); line = StrUtil.trim(line);
if (StrUtil.startWith(line, "#")) { if (StrUtil.startWith(line, "#")) {
return; return;
} }
List<String> list = StrUtil.splitTrim(line, "="); List<String> list = StrUtil.splitTrim(line, "=");
if (CollUtil.size(list) != 2) { if (CollUtil.size(list) != 2) {
return; return;
} }
newTag[0] = StrUtil.replace(newTag[0], "${" + list.get(0) + "}", list.get(1)); newTag[0] = StrUtil.replace(newTag[0], "${" + list.get(0) + "}", list.get(1));
}); });
return newTag[0]; return newTag[0];
} }
private void doDockerImage() { private void doDockerImage() {
// 生成临时目录 // 生成临时目录
File tempPath = FileUtil.file(ConfigBean.getInstance().getTempPath(), "build_temp", "docker_image", this.buildExtraModule.getId() + StrUtil.DASHED + this.buildId); File tempPath = FileUtil.file(ConfigBean.getInstance().getTempPath(), "build_temp", "docker_image", this.buildExtraModule.getId() + StrUtil.DASHED + this.buildId);
try { try {
File sourceFile = BuildUtil.getSourceById(this.buildExtraModule.getId()); File sourceFile = BuildUtil.getSourceById(this.buildExtraModule.getId());
FileUtil.copyContent(sourceFile, tempPath, true); FileUtil.copyContent(sourceFile, tempPath, true);
File historyPackageFile = BuildUtil.getHistoryPackageFile(buildExtraModule.getId(), this.buildId, StrUtil.SLASH); File historyPackageFile = BuildUtil.getHistoryPackageFile(buildExtraModule.getId(), this.buildId, StrUtil.SLASH);
FileUtil.copyContent(historyPackageFile, tempPath, true); FileUtil.copyContent(historyPackageFile, tempPath, true);
// env file // env file
File envFile = FileUtil.file(tempPath, ".env"); File envFile = FileUtil.file(tempPath, ".env");
String dockerTag = this.buildExtraModule.getDockerTag(); String dockerTag = this.buildExtraModule.getDockerTag();
dockerTag = this.parseDockerTag(envFile, dockerTag); dockerTag = this.parseDockerTag(envFile, dockerTag);
// docker file // docker file
String moduleDockerfile = this.buildExtraModule.getDockerfile(); String moduleDockerfile = this.buildExtraModule.getDockerfile();
List<String> list = StrUtil.splitTrim(moduleDockerfile, StrUtil.COLON); List<String> list = StrUtil.splitTrim(moduleDockerfile, StrUtil.COLON);
String dockerFile = CollUtil.getLast(list); String dockerFile = CollUtil.getLast(list);
File dockerfile = FileUtil.file(tempPath, dockerFile); File dockerfile = FileUtil.file(tempPath, dockerFile);
if (!FileUtil.isFile(dockerfile)) { if (!FileUtil.isFile(dockerfile)) {
logRecorder.info("仓库目录下没有找到 Dockerfile 文件:", dockerFile); logRecorder.info("仓库目录下没有找到 Dockerfile 文件:", dockerFile);
return; return;
} }
File baseDir = FileUtil.file(tempPath, list.size() == 1 ? StrUtil.SLASH : CollUtil.get(list, 0)); File baseDir = FileUtil.file(tempPath, list.size() == 1 ? StrUtil.SLASH : CollUtil.get(list, 0));
// //
String fromTag = this.buildExtraModule.getFromTag(); String fromTag = this.buildExtraModule.getFromTag();
// 根据 tag 查询 // 根据 tag 查询
List<DockerInfoModel> dockerInfoModels = buildExecuteService List<DockerInfoModel> dockerInfoModels = buildExecuteService
.dockerInfoService .dockerInfoService
.queryByTag(this.buildExtraModule.getWorkspaceId(), 1, fromTag); .queryByTag(this.buildExtraModule.getWorkspaceId(), 1, fromTag);
DockerInfoModel dockerInfoModel = CollUtil.getFirst(dockerInfoModels); DockerInfoModel dockerInfoModel = CollUtil.getFirst(dockerInfoModels);
if (dockerInfoModel == null) { if (dockerInfoModel == null) {
logRecorder.info("没有可用的 docker server"); logRecorder.info("没有可用的 docker server");
return; return;
} }
for (DockerInfoModel infoModel : dockerInfoModels) { for (DockerInfoModel infoModel : dockerInfoModels) {
this.doDockerImage(infoModel, dockerfile, baseDir, dockerTag); this.doDockerImage(infoModel, dockerfile, baseDir, dockerTag);
} }
// 发布 docker 服务 // 发布 docker 服务
this.updateSwarmService(dockerTag, this.buildExtraModule.getDockerSwarmId(), this.buildExtraModule.getDockerSwarmServiceName()); this.updateSwarmService(dockerTag, this.buildExtraModule.getDockerSwarmId(), this.buildExtraModule.getDockerSwarmServiceName());
} finally { } finally {
CommandUtil.systemFastDel(tempPath); CommandUtil.systemFastDel(tempPath);
} }
} }
private void updateSwarmService(String dockerTag, String swarmId, String serviceName) { private void updateSwarmService(String dockerTag, String swarmId, String serviceName) {
if (StrUtil.isEmpty(swarmId)) { if (StrUtil.isEmpty(swarmId)) {
return; return;
} }
List<String> splitTrim = StrUtil.splitTrim(dockerTag, StrUtil.COMMA); List<String> splitTrim = StrUtil.splitTrim(dockerTag, StrUtil.COMMA);
String first = CollUtil.getFirst(splitTrim); String first = CollUtil.getFirst(splitTrim);
logRecorder.info("start update swarm service: {} use image {}", serviceName, first); logRecorder.info("start update swarm service: {} use image {}", serviceName, first);
Map<String, Object> pluginMap = buildExecuteService.dockerInfoService.getBySwarmPluginMap(swarmId); Map<String, Object> pluginMap = buildExecuteService.dockerInfoService.getBySwarmPluginMap(swarmId);
pluginMap.put("serviceId", serviceName); pluginMap.put("serviceId", serviceName);
pluginMap.put("image", first); pluginMap.put("image", first);
try { try {
IPlugin plugin = PluginFactory.getPlugin(DockerSwarmInfoService.DOCKER_PLUGIN_NAME); IPlugin plugin = PluginFactory.getPlugin(DockerSwarmInfoService.DOCKER_PLUGIN_NAME);
plugin.execute("updateServiceImage", pluginMap); plugin.execute("updateServiceImage", pluginMap);
} catch (Exception e) { } catch (Exception e) {
logRecorder.error("调用容器异常", e); logRecorder.error("调用容器异常", e);
} }
} }
private void doDockerImage(DockerInfoModel dockerInfoModel, File dockerfile, File baseDir, String dockerTag) { private void doDockerImage(DockerInfoModel dockerInfoModel, File dockerfile, File baseDir, String dockerTag) {
logRecorder.info("{} start build image {}", dockerInfoModel.getName(), dockerTag); logRecorder.info("{} start build image {}", dockerInfoModel.getName(), dockerTag);
Map<String, Object> map = dockerInfoModel.toParameter(); Map<String, Object> map = dockerInfoModel.toParameter();
map.put("Dockerfile", dockerfile); map.put("Dockerfile", dockerfile);
map.put("baseDirectory", baseDir); map.put("baseDirectory", baseDir);
// //
map.put("tags", dockerTag); map.put("tags", dockerTag);
Consumer<String> logConsumer = s -> logRecorder.append(s); Consumer<String> logConsumer = s -> logRecorder.append(s);
map.put("logConsumer", logConsumer); map.put("logConsumer", logConsumer);
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME); IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
try { try {
plugin.execute("buildImage", map); plugin.execute("buildImage", map);
} catch (Exception e) { } catch (Exception e) {
logRecorder.error("调用容器异常", e); logRecorder.error("调用容器异常", e);
} }
} }
/** /**
* 本地命令执行 * 本地命令执行
*/ */
private void localCommand() { private void localCommand() {
// 执行命令 // 执行命令
String[] commands = StrUtil.splitToArray(this.buildExtraModule.getReleaseCommand(), StrUtil.LF); String[] commands = StrUtil.splitToArray(this.buildExtraModule.getReleaseCommand(), StrUtil.LF);
if (ArrayUtil.isEmpty(commands)) { if (ArrayUtil.isEmpty(commands)) {
logRecorder.info("没有需要执行的ssh命令"); logRecorder.info("没有需要执行的ssh命令");
return; return;
} }
String command = StrUtil.EMPTY; String command = StrUtil.EMPTY;
logRecorder.info(DateUtil.now() + " start exec"); logRecorder.info(DateUtil.now() + " start exec");
InputStream templateInputStream = null; InputStream templateInputStream = null;
try { try {
templateInputStream = ResourceUtil.getStream("classpath:/bin/execTemplate." + CommandUtil.SUFFIX); templateInputStream = ResourceUtil.getStream("classpath:/bin/execTemplate." + CommandUtil.SUFFIX);
if (templateInputStream == null) { if (templateInputStream == null) {
logRecorder.info("系统中没有命令模版"); logRecorder.info("系统中没有命令模版");
return; return;
} }
String sshExecTemplate = IoUtil.readUtf8(templateInputStream); String sshExecTemplate = IoUtil.readUtf8(templateInputStream);
StringBuilder stringBuilder = new StringBuilder(sshExecTemplate); StringBuilder stringBuilder = new StringBuilder(sshExecTemplate);
// 替换变量 // 替换变量
this.formatCommand(commands); this.formatCommand(commands);
// //
stringBuilder.append(ArrayUtil.join(commands, StrUtil.LF)); stringBuilder.append(ArrayUtil.join(commands, StrUtil.LF));
File tempPath = ConfigBean.getInstance().getTempPath(); File tempPath = ConfigBean.getInstance().getTempPath();
File commandFile = FileUtil.file(tempPath, "build", this.buildExtraModule.getId() + StrUtil.DOT + CommandUtil.SUFFIX); File commandFile = FileUtil.file(tempPath, "build", this.buildExtraModule.getId() + StrUtil.DOT + CommandUtil.SUFFIX);
FileUtil.writeUtf8String(stringBuilder.toString(), commandFile); FileUtil.writeUtf8String(stringBuilder.toString(), commandFile);
// //
command = SystemUtil.getOsInfo().isWindows() ? StrUtil.EMPTY : CommandUtil.SUFFIX; // command = SystemUtil.getOsInfo().isWindows() ? StrUtil.EMPTY : CommandUtil.SUFFIX;
command += " " + FileUtil.getAbsolutePath(commandFile); command = CommandUtil.EXECUTE_PREFIX + StrUtil.SPACE + FileUtil.getAbsolutePath(commandFile);
String result = CommandUtil.execSystemCommand(command); String result = CommandUtil.execSystemCommand(command);
logRecorder.info(result); logRecorder.info(result);
} catch (Exception e) { } catch (Exception e) {
this.pubLog("执行本地命令异常:" + command, e); this.pubLog("执行本地命令异常:" + command, e);
} finally { } finally {
IoUtil.close(templateInputStream); IoUtil.close(templateInputStream);
} }
} }
/** /**
* ssh 发布 * ssh 发布
*/ */
private void doSsh() { private void doSsh() {
String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId(); String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId();
SshService sshService = SpringUtil.getBean(SshService.class); SshService sshService = SpringUtil.getBean(SshService.class);
List<String> strings = StrUtil.splitTrim(releaseMethodDataId, StrUtil.COMMA); List<String> strings = StrUtil.splitTrim(releaseMethodDataId, StrUtil.COMMA);
for (String releaseMethodDataIdItem : strings) { for (String releaseMethodDataIdItem : strings) {
SshModel item = sshService.getByKey(releaseMethodDataIdItem, false); SshModel item = sshService.getByKey(releaseMethodDataIdItem, false);
if (item == null) { if (item == null) {
logRecorder.info("没有找到对应的ssh项" + releaseMethodDataIdItem); logRecorder.info("没有找到对应的ssh项" + releaseMethodDataIdItem);
continue; continue;
} }
this.doSsh(item, sshService); this.doSsh(item, sshService);
} }
} }
private void doSsh(SshModel item, SshService sshService) { private void doSsh(SshModel item, SshService sshService) {
Session session = SshService.getSessionByModel(item); Session session = SshService.getSessionByModel(item);
try { try {
String releasePath = this.buildExtraModule.getReleasePath(); String releasePath = this.buildExtraModule.getReleasePath();
if (StrUtil.isEmpty(releasePath)) { if (StrUtil.isEmpty(releasePath)) {
logRecorder.info("发布目录为空"); logRecorder.info("发布目录为空");
} else { } else {
logRecorder.info("{} {} start ftp upload", DateUtil.now(), item.getName()); logRecorder.info("{} {} start ftp upload", DateUtil.now(), item.getName());
try (Sftp sftp = new Sftp(session, item.getCharsetT())) { try (Sftp sftp = new Sftp(session, item.getCharsetT())) {
String prefix = ""; String prefix = "";
if (!StrUtil.startWith(releasePath, StrUtil.SLASH)) { if (!StrUtil.startWith(releasePath, StrUtil.SLASH)) {
prefix = sftp.pwd(); prefix = sftp.pwd();
} }
String normalizePath = FileUtil.normalize(prefix + StrUtil.SLASH + releasePath); String normalizePath = FileUtil.normalize(prefix + StrUtil.SLASH + releasePath);
if (this.buildExtraModule.isClearOld()) { if (this.buildExtraModule.isClearOld()) {
try { try {
sftp.delDir(normalizePath); sftp.delDir(normalizePath);
} catch (Exception e) { } catch (Exception e) {
if (!StrUtil.startWithIgnoreCase(e.getMessage(), "No such file")) { if (!StrUtil.startWithIgnoreCase(e.getMessage(), "No such file")) {
this.pubLog("清除构建产物失败", e); this.pubLog("清除构建产物失败", e);
} }
} }
} }
sftp.syncUpload(this.resultFile, normalizePath); sftp.syncUpload(this.resultFile, normalizePath);
logRecorder.info("{} ftp upload done", item.getName()); logRecorder.info("{} ftp upload done", item.getName());
} catch (Exception e) { } catch (Exception e) {
this.pubLog("执行ssh发布异常", e); this.pubLog("执行ssh发布异常", e);
} }
} }
} finally { } finally {
JschUtil.close(session); JschUtil.close(session);
} }
logRecorder.info(""); logRecorder.info("");
// 执行命令 // 执行命令
String[] commands = StrUtil.splitToArray(this.buildExtraModule.getReleaseCommand(), StrUtil.LF); String[] commands = StrUtil.splitToArray(this.buildExtraModule.getReleaseCommand(), StrUtil.LF);
if (commands == null || commands.length <= 0) { if (commands == null || commands.length <= 0) {
logRecorder.info("没有需要执行的ssh命令"); logRecorder.info("没有需要执行的ssh命令");
return; return;
} }
// 替换变量 // 替换变量
this.formatCommand(commands); this.formatCommand(commands);
// //
logRecorder.info("{} {} start exec", DateUtil.now(), item.getName()); logRecorder.info("{} {} start exec", DateUtil.now(), item.getName());
try { try {
String s = sshService.exec(item, commands); String s = sshService.exec(item, commands);
logRecorder.info(s); logRecorder.info(s);
} catch (Exception e) { } catch (Exception e) {
this.pubLog(item.getName() + " 执行异常", e); this.pubLog(item.getName() + " 执行异常", e);
} }
} }
/** /**
* 差异上传发布 * 差异上传发布
* *
* @param nodeModel 节点 * @param nodeModel 节点
* @param projectId 项目ID * @param projectId 项目ID
* @param afterOpt 发布后的操作 * @param afterOpt 发布后的操作
*/ */
private void diffSyncProject(NodeModel nodeModel, String projectId, AfterOpt afterOpt, boolean clearOld) { private void diffSyncProject(NodeModel nodeModel, String projectId, AfterOpt afterOpt, boolean clearOld) {
File resultFile = this.resultFile; File resultFile = this.resultFile;
String resultFileParent = resultFile.isFile() ? String resultFileParent = resultFile.isFile() ?
FileUtil.getAbsolutePath(resultFile.getParent()) : FileUtil.getAbsolutePath(this.resultFile); FileUtil.getAbsolutePath(resultFile.getParent()) : FileUtil.getAbsolutePath(this.resultFile);
// //
List<File> files = FileUtil.loopFiles(resultFile); List<File> files = FileUtil.loopFiles(resultFile);
List<JSONObject> collect = files.stream().map(file -> { List<JSONObject> collect = files.stream().map(file -> {
// //
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("name", StringUtil.delStartPath(file, resultFileParent, true)); jsonObject.put("name", StringUtil.delStartPath(file, resultFileParent, true));
jsonObject.put("sha1", SecureUtil.sha1(file)); jsonObject.put("sha1", SecureUtil.sha1(file));
return jsonObject; return jsonObject;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
// //
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("id", projectId); jsonObject.put("id", projectId);
jsonObject.put("data", collect); jsonObject.put("data", collect);
JsonMessage<JSONObject> requestBody = NodeForward.requestBody(nodeModel, NodeUrl.MANAGE_FILE_DIFF_FILE, this.userModel, jsonObject); JsonMessage<JSONObject> requestBody = NodeForward.requestBody(nodeModel, NodeUrl.MANAGE_FILE_DIFF_FILE, this.userModel, jsonObject);
if (requestBody.getCode() != HttpStatus.HTTP_OK) { if (requestBody.getCode() != HttpStatus.HTTP_OK) {
throw new JpomRuntimeException("对比项目文件失败:" + requestBody); throw new JpomRuntimeException("对比项目文件失败:" + requestBody);
} }
JSONObject data = requestBody.getData(); JSONObject data = requestBody.getData();
JSONArray diff = data.getJSONArray("diff"); JSONArray diff = data.getJSONArray("diff");
JSONArray del = data.getJSONArray("del"); JSONArray del = data.getJSONArray("del");
int delSize = CollUtil.size(del); int delSize = CollUtil.size(del);
int diffSize = CollUtil.size(diff); int diffSize = CollUtil.size(diff);
if (clearOld) { if (clearOld) {
logRecorder.info(StrUtil.format("对比文件结果,产物文件 {} 个、需要上传 {} 个、需要删除 {} 个", CollUtil.size(collect), CollUtil.size(diff), delSize)); logRecorder.info(StrUtil.format("对比文件结果,产物文件 {} 个、需要上传 {} 个、需要删除 {} 个", CollUtil.size(collect), CollUtil.size(diff), delSize));
} else { } else {
logRecorder.info(StrUtil.format("对比文件结果,产物文件 {} 个、需要上传 {} 个", CollUtil.size(collect), CollUtil.size(diff))); logRecorder.info(StrUtil.format("对比文件结果,产物文件 {} 个、需要上传 {} 个", CollUtil.size(collect), CollUtil.size(diff)));
} }
// 清空发布才先执行删除 // 清空发布才先执行删除
if (delSize > 0 && clearOld) { if (delSize > 0 && clearOld) {
jsonObject.put("data", del); jsonObject.put("data", del);
requestBody = NodeForward.requestBody(nodeModel, NodeUrl.MANAGE_FILE_BATCH_DELETE, this.userModel, jsonObject); requestBody = NodeForward.requestBody(nodeModel, NodeUrl.MANAGE_FILE_BATCH_DELETE, this.userModel, jsonObject);
if (requestBody.getCode() != HttpStatus.HTTP_OK) { if (requestBody.getCode() != HttpStatus.HTTP_OK) {
throw new JpomRuntimeException("删除项目文件失败:" + requestBody); throw new JpomRuntimeException("删除项目文件失败:" + requestBody);
} }
} }
for (int i = 0; i < diffSize; i++) { for (int i = 0; i < diffSize; i++) {
boolean last = (i == diffSize - 1); boolean last = (i == diffSize - 1);
JSONObject diffData = (JSONObject) diff.get(i); JSONObject diffData = (JSONObject) diff.get(i);
String name = diffData.getString("name"); String name = diffData.getString("name");
File file = FileUtil.file(resultFileParent, name); File file = FileUtil.file(resultFileParent, name);
// //
String startPath = StringUtil.delStartPath(file, resultFileParent, false); String startPath = StringUtil.delStartPath(file, resultFileParent, false);
// //
JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(file, startPath, JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(file, startPath,
projectId, false, last ? afterOpt : AfterOpt.No, nodeModel, this.userModel, false); projectId, false, last ? afterOpt : AfterOpt.No, nodeModel, this.userModel, false);
if (jsonMessage.getCode() != HttpStatus.HTTP_OK) { if (jsonMessage.getCode() != HttpStatus.HTTP_OK) {
throw new JpomRuntimeException("同步项目文件失败:" + jsonMessage); throw new JpomRuntimeException("同步项目文件失败:" + jsonMessage);
} }
if (last) { if (last) {
// 最后一个 // 最后一个
logRecorder.info("发布项目包成功:" + jsonMessage); logRecorder.info("发布项目包成功:" + jsonMessage);
} }
} }
} }
/** /**
* 发布项目 * 发布项目
*/ */
private void doProject() { private void doProject() {
// AfterOpt afterOpt, boolean clearOld, boolean diffSync // AfterOpt afterOpt, boolean clearOld, boolean diffSync
AfterOpt afterOpt = BaseEnum.getEnum(AfterOpt.class, this.buildExtraModule.getAfterOpt(), AfterOpt.No); AfterOpt afterOpt = BaseEnum.getEnum(AfterOpt.class, this.buildExtraModule.getAfterOpt(), AfterOpt.No);
boolean clearOld = this.buildExtraModule.isClearOld(); boolean clearOld = this.buildExtraModule.isClearOld();
boolean diffSync = this.buildExtraModule.isDiffSync(); boolean diffSync = this.buildExtraModule.isDiffSync();
String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId(); String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId();
String[] strings = StrUtil.splitToArray(releaseMethodDataId, CharPool.COLON); String[] strings = StrUtil.splitToArray(releaseMethodDataId, CharPool.COLON);
if (ArrayUtil.length(strings) != 2) { if (ArrayUtil.length(strings) != 2) {
throw new IllegalArgumentException(releaseMethodDataId + " error"); throw new IllegalArgumentException(releaseMethodDataId + " error");
} }
NodeService nodeService = SpringUtil.getBean(NodeService.class); NodeService nodeService = SpringUtil.getBean(NodeService.class);
NodeModel nodeModel = nodeService.getByKey(strings[0]); NodeModel nodeModel = nodeService.getByKey(strings[0]);
Objects.requireNonNull(nodeModel, "节点不存在"); Objects.requireNonNull(nodeModel, "节点不存在");
String projectId = strings[1]; String projectId = strings[1];
if (diffSync) { if (diffSync) {
this.diffSyncProject(nodeModel, projectId, afterOpt, clearOld); this.diffSyncProject(nodeModel, projectId, afterOpt, clearOld);
return; return;
} }
File zipFile = BuildUtil.isDirPackage(this.resultFile); File zipFile = BuildUtil.isDirPackage(this.resultFile);
boolean unZip = true; boolean unZip = true;
if (zipFile == null) { if (zipFile == null) {
zipFile = this.resultFile; zipFile = this.resultFile;
unZip = false; unZip = false;
} }
JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(zipFile, null, JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(zipFile, null,
projectId, projectId,
unZip, unZip,
afterOpt, afterOpt,
nodeModel, this.userModel, clearOld); nodeModel, this.userModel, clearOld);
if (jsonMessage.getCode() == HttpStatus.HTTP_OK) { if (jsonMessage.getCode() == HttpStatus.HTTP_OK) {
logRecorder.info("发布项目包成功:" + jsonMessage); logRecorder.info("发布项目包成功:" + jsonMessage);
} else { } else {
throw new JpomRuntimeException("发布项目包失败:" + jsonMessage); throw new JpomRuntimeException("发布项目包失败:" + jsonMessage);
} }
} }
/** /**
* 分发包 * 分发包
*/ */
private void doOutGiving() { private void doOutGiving() {
String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId(); String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId();
File zipFile = BuildUtil.isDirPackage(this.resultFile); File zipFile = BuildUtil.isDirPackage(this.resultFile);
boolean unZip = true; boolean unZip = true;
if (zipFile == null) { if (zipFile == null) {
zipFile = this.resultFile; zipFile = this.resultFile;
unZip = false; unZip = false;
} }
OutGivingRun.startRun(releaseMethodDataId, zipFile, userModel, unZip); OutGivingRun.startRun(releaseMethodDataId, zipFile, userModel, unZip);
logRecorder.info("开始执行分发包啦,请到分发中查看当前状态"); logRecorder.info("开始执行分发包啦,请到分发中查看当前状态");
} }
/** /**
* 发布异常日志 * 发布异常日志
* *
* @param title 描述 * @param title 描述
* @param throwable 异常 * @param throwable 异常
*/ */
private void pubLog(String title, Throwable throwable) { private void pubLog(String title, Throwable throwable) {
logRecorder.error(title, throwable); logRecorder.error(title, throwable);
this.updateStatus(BuildStatus.PubError); this.updateStatus(BuildStatus.PubError);
} }
@Override @Override
public void run() { public void run() {
this.start(); this.start();
} }
} }

View File

@ -30,7 +30,6 @@ import cn.hutool.core.io.LineHandler;
import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;
import cn.jiangzeyin.common.DefaultSystemLog; import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage; import cn.jiangzeyin.common.JsonMessage;
import cn.jiangzeyin.common.spring.SpringUtil; import cn.jiangzeyin.common.spring.SpringUtil;
@ -55,177 +54,175 @@ import java.util.concurrent.ConcurrentHashMap;
* @date 2022/1/19 * @date 2022/1/19
*/ */
public class ScriptProcessBuilder extends BaseRunScript implements Runnable { public class ScriptProcessBuilder extends BaseRunScript implements Runnable {
/** /**
* 执行中的缓存 * 执行中的缓存
*/ */
private static final ConcurrentHashMap<String, ScriptProcessBuilder> FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<String, ScriptProcessBuilder> FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
private final ProcessBuilder processBuilder; private final ProcessBuilder processBuilder;
private final Set<WebSocketSession> sessions = new HashSet<>(); private final Set<WebSocketSession> sessions = new HashSet<>();
private final String executeId; private final String executeId;
private ScriptProcessBuilder(ScriptModel nodeScriptModel, String executeId, String args) { private ScriptProcessBuilder(ScriptModel nodeScriptModel, String executeId, String args) {
super(nodeScriptModel.logFile(executeId)); super(nodeScriptModel.logFile(executeId));
this.executeId = executeId; this.executeId = executeId;
// //
WorkspaceEnvVarService workspaceEnvVarService = SpringUtil.getBean(WorkspaceEnvVarService.class); WorkspaceEnvVarService workspaceEnvVarService = SpringUtil.getBean(WorkspaceEnvVarService.class);
Map<String, String> env = workspaceEnvVarService.getEnv(nodeScriptModel.getWorkspaceId()); Map<String, String> env = workspaceEnvVarService.getEnv(nodeScriptModel.getWorkspaceId());
File scriptFile = nodeScriptModel.scriptFile(); File scriptFile = nodeScriptModel.scriptFile();
// //
String script = FileUtil.getAbsolutePath(scriptFile); String script = FileUtil.getAbsolutePath(scriptFile);
processBuilder = new ProcessBuilder(); processBuilder = new ProcessBuilder();
List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE); List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE);
command.add(0, script); command.add(0, script);
if (SystemUtil.getOsInfo().isLinux() || SystemUtil.getOsInfo().isMac()) { command.add(0, CommandUtil.EXECUTE_PREFIX);
command.add(0, CommandUtil.SUFFIX); DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE));
} processBuilder.redirectErrorStream(true);
DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE)); processBuilder.command(command);
processBuilder.redirectErrorStream(true); Map<String, String> environment = processBuilder.environment();
processBuilder.command(command); environment.putAll(env);
Map<String, String> environment = processBuilder.environment(); processBuilder.directory(scriptFile.getParentFile());
environment.putAll(env); }
processBuilder.directory(scriptFile.getParentFile());
}
/** /**
* 创建执行 并监听 * 创建执行 并监听
* *
* @param nodeScriptModel 脚本模版 * @param nodeScriptModel 脚本模版
* @param executeId 执行ID * @param executeId 执行ID
* @param args 参数 * @param args 参数
*/ */
public static ScriptProcessBuilder create(ScriptModel nodeScriptModel, String executeId, String args) { public static ScriptProcessBuilder create(ScriptModel nodeScriptModel, String executeId, String args) {
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.computeIfAbsent(executeId, file1 -> { return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.computeIfAbsent(executeId, file1 -> {
ScriptProcessBuilder scriptProcessBuilder1 = new ScriptProcessBuilder(nodeScriptModel, executeId, args); ScriptProcessBuilder scriptProcessBuilder1 = new ScriptProcessBuilder(nodeScriptModel, executeId, args);
ThreadUtil.execute(scriptProcessBuilder1); ThreadUtil.execute(scriptProcessBuilder1);
return scriptProcessBuilder1; return scriptProcessBuilder1;
}); });
} }
/** /**
* 创建执行 并监听 * 创建执行 并监听
* *
* @param nodeScriptModel 脚本模版 * @param nodeScriptModel 脚本模版
* @param executeId 执行ID * @param executeId 执行ID
* @param args 参数 * @param args 参数
* @param session 会话 * @param session 会话
*/ */
public static void addWatcher(ScriptModel nodeScriptModel, String executeId, String args, WebSocketSession session) { public static void addWatcher(ScriptModel nodeScriptModel, String executeId, String args, WebSocketSession session) {
ScriptProcessBuilder scriptProcessBuilder = create(nodeScriptModel, executeId, args); ScriptProcessBuilder scriptProcessBuilder = create(nodeScriptModel, executeId, args);
// //
if (scriptProcessBuilder.sessions.add(session)) { if (scriptProcessBuilder.sessions.add(session)) {
if (FileUtil.exist(scriptProcessBuilder.logFile)) { if (FileUtil.exist(scriptProcessBuilder.logFile)) {
// 读取之前的信息并发送 // 读取之前的信息并发送
FileUtil.readLines(scriptProcessBuilder.logFile, CharsetUtil.CHARSET_UTF_8, (LineHandler) line -> { FileUtil.readLines(scriptProcessBuilder.logFile, CharsetUtil.CHARSET_UTF_8, (LineHandler) line -> {
try { try {
SocketSessionUtil.send(session, line); SocketSessionUtil.send(session, line);
} catch (IOException e) { } catch (IOException e) {
DefaultSystemLog.getLog().error("发送消息失败", e); DefaultSystemLog.getLog().error("发送消息失败", e);
} }
}); });
} }
} }
} }
/** /**
* 判断是否还在执行中 * 判断是否还在执行中
* *
* @param executeId 执行id * @param executeId 执行id
* @return true 还在执行 * @return true 还在执行
*/ */
public static boolean isRun(String executeId) { public static boolean isRun(String executeId) {
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.containsKey(executeId); return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.containsKey(executeId);
} }
/** /**
* 关闭会话 * 关闭会话
* *
* @param session 会话 * @param session 会话
*/ */
public static void stopWatcher(WebSocketSession session) { public static void stopWatcher(WebSocketSession session) {
Collection<ScriptProcessBuilder> scriptProcessBuilders = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.values(); Collection<ScriptProcessBuilder> scriptProcessBuilders = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.values();
for (ScriptProcessBuilder scriptProcessBuilder : scriptProcessBuilders) { for (ScriptProcessBuilder scriptProcessBuilder : scriptProcessBuilders) {
Set<WebSocketSession> sessions = scriptProcessBuilder.sessions; Set<WebSocketSession> sessions = scriptProcessBuilder.sessions;
sessions.removeIf(session1 -> session1.getId().equals(session.getId())); sessions.removeIf(session1 -> session1.getId().equals(session.getId()));
} }
} }
/** /**
* 停止脚本命令 * 停止脚本命令
* *
* @param executeId 执行ID * @param executeId 执行ID
*/ */
public static void stopRun(String executeId) { public static void stopRun(String executeId) {
ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.get(executeId); ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.get(executeId);
if (scriptProcessBuilder != null) { if (scriptProcessBuilder != null) {
scriptProcessBuilder.end("停止运行"); scriptProcessBuilder.end("停止运行");
} }
} }
@Override @Override
public void run() { public void run() {
//初始化ProcessBuilder对象 //初始化ProcessBuilder对象
try { try {
this.handle("start execute:" + DateUtil.now()); this.handle("start execute:" + DateUtil.now());
process = processBuilder.start(); process = processBuilder.start();
{ {
inputStream = process.getInputStream(); inputStream = process.getInputStream();
IoUtil.readLines(inputStream, ExtConfigBean.getInstance().getConsoleLogCharset(), (LineHandler) ScriptProcessBuilder.this::handle); IoUtil.readLines(inputStream, ExtConfigBean.getInstance().getConsoleLogCharset(), (LineHandler) ScriptProcessBuilder.this::handle);
} }
int waitFor = process.waitFor(); int waitFor = process.waitFor();
JsonMessage<String> jsonMessage = new JsonMessage<>(200, "执行完毕:" + waitFor); JsonMessage<String> jsonMessage = new JsonMessage<>(200, "执行完毕:" + waitFor);
JSONObject jsonObject = jsonMessage.toJson(); JSONObject jsonObject = jsonMessage.toJson();
jsonObject.put("op", ConsoleCommandOp.stop.name()); jsonObject.put("op", ConsoleCommandOp.stop.name());
this.end(jsonObject.toString()); this.end(jsonObject.toString());
this.handle("execute done:" + waitFor + " time:" + DateUtil.now()); this.handle("execute done:" + waitFor + " time:" + DateUtil.now());
} catch (Exception e) { } catch (Exception e) {
DefaultSystemLog.getLog().error("执行异常", e); DefaultSystemLog.getLog().error("执行异常", e);
this.end("执行异常:" + e.getMessage()); this.end("执行异常:" + e.getMessage());
} finally { } finally {
this.close(); this.close();
} }
} }
/** /**
* 结束执行 * 结束执行
* *
* @param msg 响应的消息 * @param msg 响应的消息
*/ */
@Override @Override
protected void end(String msg) { protected void end(String msg) {
Iterator<WebSocketSession> iterator = sessions.iterator(); Iterator<WebSocketSession> iterator = sessions.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
WebSocketSession session = iterator.next(); WebSocketSession session = iterator.next();
try { try {
SocketSessionUtil.send(session, msg); SocketSessionUtil.send(session, msg);
} catch (IOException e) { } catch (IOException e) {
DefaultSystemLog.getLog().error("发送消息失败", e); DefaultSystemLog.getLog().error("发送消息失败", e);
} }
iterator.remove(); iterator.remove();
} }
FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.remove(this.executeId); FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.remove(this.executeId);
} }
/** /**
* 响应 * 响应
* *
* @param line 信息 * @param line 信息
*/ */
@Override @Override
protected void handle(String line) { protected void handle(String line) {
super.handle(line); super.handle(line);
// //
Iterator<WebSocketSession> iterator = sessions.iterator(); Iterator<WebSocketSession> iterator = sessions.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
WebSocketSession session = iterator.next(); WebSocketSession session = iterator.next();
try { try {
SocketSessionUtil.send(session, line); SocketSessionUtil.send(session, line);
} catch (IOException e) { } catch (IOException e) {
DefaultSystemLog.getLog().error("发送消息失败", e); DefaultSystemLog.getLog().error("发送消息失败", e);
iterator.remove(); iterator.remove();
} }
} }
} }
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="full-content"> <div class="full-content">
<!-- 数据表格 --> <!-- 数据表格 -->
<a-table :data-source="list" :columns="columns" @change="changePage" :pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false" bordered rowKey="id"> <a-table :data-source="list" size="middle" :columns="columns" @change="changePage" :pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false" bordered rowKey="id">
<template slot="title"> <template slot="title">
<a-space> <a-space>
<a-input v-model="listQuery['%name%']" placeholder="名称" @pressEnter="loadData" allowClear class="search-input-item" /> <a-input v-model="listQuery['%name%']" placeholder="名称" @pressEnter="loadData" allowClear class="search-input-item" />
@ -46,9 +46,9 @@
</a-tooltip> </a-tooltip>
<template slot="operation" slot-scope="text, record"> <template slot="operation" slot-scope="text, record">
<a-space> <a-space>
<a-button type="primary" @click="handleExec(record)">执行</a-button> <a-button size="small" type="primary" @click="handleExec(record)">执行</a-button>
<a-button type="primary" @click="handleEdit(record)">编辑</a-button> <a-button size="small" type="primary" @click="handleEdit(record)">编辑</a-button>
<a-button type="danger" @click="handleDelete(record)">删除</a-button> <a-button size="small" type="danger" @click="handleDelete(record)">删除</a-button>
</a-space> </a-space>
</template> </template>
</a-table> </a-table>
@ -137,7 +137,7 @@ export default {
{ title: "修改时间", dataIndex: "modifyTimeMillis", sorter: true, width: 170, ellipsis: true, scopedSlots: { customRender: "modifyTimeMillis" } }, { title: "修改时间", dataIndex: "modifyTimeMillis", sorter: true, width: 170, ellipsis: true, scopedSlots: { customRender: "modifyTimeMillis" } },
{ title: "修改人", dataIndex: "modifyUser", ellipsis: true, scopedSlots: { customRender: "modifyUser" }, width: 120 }, { title: "修改人", dataIndex: "modifyUser", ellipsis: true, scopedSlots: { customRender: "modifyUser" }, width: 120 },
{ title: "最后操作人", dataIndex: "lastRunUser", ellipsis: true, scopedSlots: { customRender: "lastRunUser" } }, { title: "最后操作人", dataIndex: "lastRunUser", ellipsis: true, scopedSlots: { customRender: "lastRunUser" } },
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 260 }, { title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 180 },
], ],
rules: { rules: {
name: [{ required: true, message: "Please input Script name", trigger: "blur" }], name: [{ required: true, message: "Please input Script name", trigger: "blur" }],

View File

@ -3,6 +3,7 @@
<a-table <a-table
:data-source="commandList" :data-source="commandList"
:columns="columns" :columns="columns"
size="middle"
bordered bordered
:pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false" :pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false"
@change="changePage" @change="changePage"
@ -43,9 +44,9 @@
<template slot="operation" slot-scope="text, record"> <template slot="operation" slot-scope="text, record">
<a-space> <a-space>
<a-button type="primary" @click="handleEdit(record)">编辑</a-button> <a-button size="small" type="primary" @click="handleEdit(record)">编辑</a-button>
<a-button type="primary" @click="handleExecute(record)">执行</a-button> <a-button size="small" type="primary" @click="handleExecute(record)">执行</a-button>
<a-button type="danger" @click="handleDelete(record)">删除</a-button> <a-button size="small" type="danger" @click="handleDelete(record)">删除</a-button>
</a-space> </a-space>
</template> </template>
</a-table> </a-table>
@ -204,7 +205,7 @@ export default {
ellipsis: true, ellipsis: true,
scopedSlots: { customRender: "modifyUser" }, scopedSlots: { customRender: "modifyUser" },
}, },
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 250 }, { title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 180 },
], ],
}; };
}, },

View File

@ -7,6 +7,7 @@
<a-table <a-table
:data-source="list" :data-source="list"
:columns="columns" :columns="columns"
size="middle"
:pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false" :pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false"
@change="changePage" @change="changePage"
bordered bordered
@ -42,7 +43,7 @@
<div v-if="sshAgentInfo[record.id]"> <div v-if="sshAgentInfo[record.id]">
<div v-if="sshAgentInfo[record.id].javaVersion"> <div v-if="sshAgentInfo[record.id].javaVersion">
<a-tooltip v-if="sshAgentInfo[record.id].nodeId" placement="topLeft" :title="`节点名称:${sshAgentInfo[record.id].nodeName}`"> <a-tooltip v-if="sshAgentInfo[record.id].nodeId" placement="topLeft" :title="`节点名称:${sshAgentInfo[record.id].nodeName}`">
<a-button style="width: 90px; padding: 0 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis" type="" @click="toNode(sshAgentInfo[record.id].nodeId)"> <a-button size="small" style="width: 90px; padding: 0 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis" type="" @click="toNode(sshAgentInfo[record.id].nodeId)">
{{ sshAgentInfo[record.id].nodeName }} {{ sshAgentInfo[record.id].nodeName }}
</a-button> </a-button>
</a-tooltip> </a-tooltip>
@ -54,7 +55,7 @@
placement="topLeft" placement="topLeft"
:title="`${sshAgentInfo[record.id].pid > 0 ? 'ssh 中已经运行了插件端进程ID' + sshAgentInfo[record.id].pid : '点击快速安装插件端,java :' + sshAgentInfo[record.id].javaVersion}`" :title="`${sshAgentInfo[record.id].pid > 0 ? 'ssh 中已经运行了插件端进程ID' + sshAgentInfo[record.id].pid : '点击快速安装插件端,java :' + sshAgentInfo[record.id].javaVersion}`"
> >
<a-button type="primary" @click="install(record)" :disabled="sshAgentInfo[record.id].pid > 0">安装节点</a-button> <a-button size="small" type="primary" @click="install(record)" :disabled="sshAgentInfo[record.id].pid > 0">安装节点</a-button>
</a-tooltip> </a-tooltip>
</div> </div>
<div v-else><a-tag>没有Java环境</a-tag></div> <div v-else><a-tag>没有Java环境</a-tag></div>
@ -63,9 +64,9 @@
</template> </template>
<template slot="operation" slot-scope="text, record"> <template slot="operation" slot-scope="text, record">
<a-space> <a-space>
<a-button type="primary" @click="handleTerminal(record)">终端</a-button> <a-button size="small" type="primary" @click="handleTerminal(record)">终端</a-button>
<a-tooltip placement="topLeft" title="如果按钮不可用,请去 ssh 编辑中添加允许管理的授权文件夹"> <a-tooltip placement="topLeft" title="如果按钮不可用,请去 ssh 编辑中添加允许管理的授权文件夹">
<a-button type="primary" :disabled="!record.fileDirs" @click="handleFile(record)">文件</a-button> <a-button size="small" type="primary" :disabled="!record.fileDirs" @click="handleFile(record)">文件</a-button>
</a-tooltip> </a-tooltip>
<a-dropdown> <a-dropdown>
<a class="ant-dropdown-link" @click="(e) => e.preventDefault()"> <a class="ant-dropdown-link" @click="(e) => e.preventDefault()">
@ -412,8 +413,8 @@ export default {
title: "操作", title: "操作",
dataIndex: "operation", dataIndex: "operation",
scopedSlots: { customRender: "operation" }, scopedSlots: { customRender: "operation" },
width: 230, width: 180,
fixed: "right", align: "center",
// ellipsis: true, // ellipsis: true,
}, },
], ],