需求
项目为svn+maven的配置,需要生成增量补丁,经百度操作后并未得到想要的结果,故自定义实现一个打包的工具类(基于svn工程路径),直接上代码,其中使用的IO工具类为hutool,时间字段均为“yyyy-MM-dd"
,为方便使用版本号也暂定义为String
/**
* svn maven 增量补丁zip包生成
*/
public class IncrementalPatchUtil {
/**
* 项目根路径
*
*/
private static String projectPath = "项目所在目录";
/**
* 补丁所在目录
*
*/
private static String targetPath = "补丁所在目录";
/**
* 获取指定版本号文件改动命令
*/
private static String specifyVersion(String versionNumber) {
return String.format("svn log -r %s:%s -v", versionNumber, versionNumber);
}
/**
* 获取指定版本到当前的所有文件改动列表
*/
private static String currentVersion(String version) {
return String.format(" svn diff -r %s --summarize ", version);
}
/**
* 时间区间
* 获取指定时间到当前的所有文件改动列表
*/
private static String interval(String date) {
return String.format(" svn diff -r {%s} --summarize ", date);
}
/**
* 获取指定时间段当前的所有文件改动列表
*/
private static String currentDate(String startDate, String endDate) {
return String.format("svn diff -r {%s}:{%s} --summarize", startDate, endDate);
}
/**
* 获取所有改动的Java类
*/
public static Map<String, List<String>> getClasses(String cmd, String projectPath) {
Map<String, List<String>> result = new ConcurrentHashMap<>();
List<String> strings = execForLines(projectPath, cmd);
// 筛选所有的java文件
List<String> classes = strings.stream()
.filter(str -> str.contains(".java"))
// 过滤掉删除的文件
.filter(str -> !str.contains("D "))
.filter(str -> str.contains("java"))
// 去除 新增和修改的标识
.map(str -> str.substring(str.indexOf("java"))
.replaceFirst("java", "")
.replace(".java", ".class")
.trim()
).collect(Collectors.toList());
result.put("java", classes);
List<String> configList = strings.stream()
.filter(str -> str.endsWith(".xml") || str.endsWith(".properties"))
.map(str -> str.substring(str.indexOf("config")))
.collect(Collectors.toList());
result.put("config", configList);
return result;
}
private static List<String> execForLines(String projectPath, String cmd) {
return RuntimeUtil.execForLines((SystemUtil.getOsInfo().isWindows() ? "cmd /c C: && cd " : " cd ") + projectPath + " && " + " svn up &&" + cmd);
}
/**
* 执行编译并打包
*
* @param cmd 执行的命令
* @param projectPath 项目路径
* @param targetPath 目标路径
* @param project 工程名(打包后的包名)
*/
private static void exeCmd(String cmd, String projectPath, String targetPath, String project) {
System.out.println("svn 编译开始");
List<String> strings1 = execForLines(projectPath, " mvn clean compile");
System.out.println("编译信息如下");
strings1.forEach(System.out::println);
boolean buildFlag = strings1.stream().filter(s -> s.contains("BUILD SUCCESS")).count() > 0;
if (!buildFlag) {
System.out.println("编译失败,补丁包生成失败");
}
System.out.println("获取更新的Java类");
// 获取更新后的
Map<String, List<String>> map = getClasses(cmd, projectPath);
// 补丁版本为当前日期
String projectVersion = project + "_" + DateUtil.today();
String targetClassDir = targetPath + File.separator + projectVersion + File.separator + "WEB-INF" + File.separator + "classes";
Path target = Paths.get(targetClassDir);
FileUtil.del(target);
FileUtil.mkdir(target);
System.out.println("迁移class文件");
moveClass(map.get("java"), projectPath, targetClassDir);
// 迁移config 文件
File zip = zip(targetPath, projectVersion);
if (zip.exists()) {
System.out.println("补丁生成成功,补丁文件位置为" + zip.getAbsolutePath());
// 压缩完成后删除class 文件
FileUtil.del(Paths.get(targetPath, projectVersion));
} else {
System.out.println("补丁文件生成失败");
}
}
/**
* 迁移 class 文件
*/
private static void moveClass(List<String> classes, String projectPath, String targetClassDir) {
for (String str : classes) {
Path src = Paths.get(projectPath, "target", "classes", str);
File parent = FileUtil.getParent(src.toFile(), 1);
// 获取所有非public 类
for (File file : Objects.requireNonNull(parent.listFiles())) {
String fileName = src.getFileName().toString();
String fi = fileName.replace(".class", "");
if (file.getName().contains(fi + "$")) {
FileUtil.move(file.toPath(), Paths.get(targetClassDir, str.replace(fileName, file.getName())), true);
}
}
FileUtil.move(src, Paths.get(targetClassDir, str), true);
}
}
/**
* 压缩文件
*/
private static File zip(String targetPath, String project) {
return ZipUtil.zip(Paths.get(targetPath, project).toFile(), StandardCharsets.UTF_8);
}