项目开发过程中代码变化很频繁,需要更新文件时,每次都需要手动制作补丁包,打包成Zip包后更新到生产环境,相当麻烦。
考虑是否可以根据SVN日志,自动生成补丁包。同时生成的输出可以当作更新日志使用。
原理就是自动去复制tomcat下的文件,包括根据src下的java文件去tomcat下查找编译类文件,包括内部类。
支持新增和修改的文件,不支持删除哦~~
于是产生了下面这个工具类。。用到了第三方库Svnkit 请自行导入。
package svnpatch;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.ISvnObjectReceiver;
import org.tmatesoft.svn.core.wc2.SvnLog;
import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
import org.tmatesoft.svn.core.wc2.SvnRevisionRange;
import org.tmatesoft.svn.core.wc2.SvnTarget;
public class PatchMaker_hello {
/**
* 设置一下
*/
public static String destPath = "E:\\update1120\\hello\\"; //输出路径 ,可以自动建立
public static String tomcatPath = "E:\\tomcat\\webapps\\hello\\"; //tomcat的路径,需要包含最新的二进制文件哦
public static String start_date = "20141118000000";//上次更新时间 yyyyMMddHHmmss
public static String end_date = "20141120234500";//截至时间 yyyyMMddHHmmss
private static Map<String,String> typeDic = new HashMap<String,String>();
static {
typeDic.put("M", "修改");
typeDic.put("A", "新增");
}
public static void main(String[] args) {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
final SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
final SvnOperationFactory svnOperationFactory = new SvnOperationFactory();
try {
//svn的 url
final SVNURL url = SVNURL.parseURIEncoded("https://xxx/svn/xxx/hello");
svnOperationFactory.setAuthenticationManager(new BasicAuthenticationManager(
"username", "password"));//svn用户名密码
final SvnLog log = svnOperationFactory.createLog();
Date date1 = sdf.parse(start_date);
Date date2 = sdf.parse(end_date);
log.addRange(SvnRevisionRange.create(SVNRevision.create(date1),SVNRevision.create(date2)));
log.setDiscoverChangedPaths(true);
log.setSingleTarget(SvnTarget.fromURL(url));
log.setReceiver(new ISvnObjectReceiver<SVNLogEntry>() {
public void receive(SvnTarget arg0, SVNLogEntry arg1)
throws SVNException {
//每个版本执行一次
System.out.println("版本:"+arg1.getRevision()+"===========作者:"+arg1.getAuthor()+"======时间:"+sdf2.format(arg1.getDate()));
System.out.println("===修改内容:"+arg1.getMessage());
Map<String,SVNLogEntryPath> map = arg1.getChangedPaths();
if(map.size()>0){
Set set = map.keySet();
for (Iterator iterator = set.iterator(); iterator
.hasNext();) {
String key = (String) iterator.next();
SVNLogEntryPath path = map.get(key);
System.out.println(typeDic.get(path.getType()+"")+":"+key);
handleFile(key);
}
}
System.out.println("\n");
}
});
log.run();
}catch(Exception ex){
ex.printStackTrace();
} finally {
svnOperationFactory.dispose();
}
}
/**
* 缓存 处理重复文件
*/
private static Map<String,String> cache = new HashMap<String,String>();
/**
* 处理文件
* 方法描述
* @param path
*/
public static void handleFile(String path){
if(cache.get("path")==null){
if(path.indexOf("/WebRoot/")>-1){
String purePath = path.substring(path.indexOf("/WebRoot/")+9);
String srcPath = tomcatPath+purePath.replace("/", "\\");
String desPath = destPath+purePath.replace("/", "\\");
copyFile(srcPath,desPath);
}else if(path.indexOf("/src/")>-1){
if(path.toLowerCase().endsWith("java")){
String purePath = path.substring(path.indexOf("/src/")+5);
String className = purePath.substring(purePath.lastIndexOf("/")+1).replace(".java", "");
String classPath = purePath.substring(0,purePath.lastIndexOf("/")+1).replace("/", "\\");
String srcPath = tomcatPath+"WEB-INF\\classes\\"+classPath;
String desPath = destPath+"WEB-INF\\classes\\"+classPath;
copyJava(srcPath,desPath,className);
}else{
String purePath = path.substring(path.indexOf("/src/")+5);
String srcPath = tomcatPath+"WEB-INF\\classes\\"+purePath.replace("/", "\\");
String desPath = destPath+"WEB-INF\\classes\\"+purePath.replace("/", "\\");
copyFile(srcPath,desPath);
}
}
cache.put(path, "1");//放到缓存
}else{
//处理过了 跳过
}
}
/**
* 复制普通文件
* 方法描述
* @param src
* @param dest
*/
public static void copyFile(String src,String dest){
File destF = new File(dest);
if(!destF.getParentFile().exists()){
destF.getParentFile().mkdirs();
}
try {
File fsrc = new File(src);
File fdest = new File(dest);
if(fsrc.isDirectory()){
if(!fdest.exists()){
fdest.mkdirs();
}
}else{
copyFile(fsrc,fdest);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 主要是考虑 含有内部类的 java文件
* 方法描述
* @param src
* @param dest
*/
public static void copyJava(String src,String dest,String cname){
File destF = new File(dest);
if(!destF.exists()){
destF.mkdirs();
}
File srcF = new File(src);
File [] files = srcF.listFiles();
for (int i = 0; i < files.length; i++) {
if(files[i].getName().startsWith(cname)){
//包含了内部类了吧
String destPath1 = dest+files[i].getName();
try {
copyFile(files[i],new File(destPath1));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 复制文件
* 方法描述
* @param sourceFile
* @param targetFile
* @throws IOException
*/
public static void copyFile(File sourceFile, File targetFile) throws IOException {
BufferedInputStream inBuff = null;
BufferedOutputStream outBuff = null;
try {
// 新建文件输入流并对它进行缓冲
inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
// 新建文件输出流并对它进行缓冲
outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));
// 缓冲数组
byte[] b = new byte[1024 * 5];
int len;
while ((len = inBuff.read(b)) != -1) {
outBuff.write(b, 0, len);
}
// 刷新此缓冲的输出流
outBuff.flush();
} finally {
// 关闭流
if (inBuff != null)
inBuff.close();
if (outBuff != null)
outBuff.close();
}
}
}