项目太老了,发版需要一个文件一个文件编译打包,再整合发版,太麻烦了,所以写了个自动编译
1.在项目中手动更新代码
2.加入依赖jar包
<!--svn包-->
<dependency>
<groupId>org.tmatesoft.svnkit</groupId>
<artifactId>svnkit</artifactId>
<version>1.9.2</version>
</dependency>
3.在项目中建一个test包,复制下面代码执行
package test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNWCUtil;
import edu.emory.mathcs.backport.java.util.Collections;
public class CopyFile {
//=================================================================================================//
//== ==//
//== 以下成员变量可作调整 ==//
//== ==//
//=================================================================================================//
//svn路径
private static String url = "svn://xxx"
//svn用户名
private static String username = "xxx"
//svn密码
private static String password = "xxx";
private static String startData = "2018-10-03 00:00:00"; //指定的日期戳之前或之间最接近的版本号
/**
* 是否校验文件最后修改时间,开启校验后,不满足的会警告,无论是否满足都会处理/编译
*/
private static boolean isCheckFileLastModifyDate = true;
/**
* 开启校验文件最后修改时间后,文件的最后修改时间小于此时间则会警告
*/
private static String fileLastModifyDateString = "2018-12-19 08:30:11";
/**
* 处理后的文件目录,以运行时的年与日时分秒为文件名,以防文件名重复
*/
private static String newPath = "D:/backups/"+new SimpleDateFormat("yyyy-MM-dd_HH_mm_ss").format(new Date())+"/";
/**
* 去除文件路径的前缀(svn路径修改之后则需要修改)
*/
private static String filePrefix = "/FTMSN/ftmsn";
/**
* 源文件目录
*/
private static String sourcePath = "D:/FTMSN/";
/**
* jdk安装目录
*/
private static String JDKPath = "D:/mocrisoft/java/JDK/jdk1.6.0_45";
//=================================================================================================//
//== ==//
//== 以下成员变量不需修改 ==//
//== ==//
//=================================================================================================//
/**
* 需要处理的文件列表路径 ,文件的编码要求是GBK
*/
private static String fileListPath = newPath +"fileList.txt";
/**
* 需要处理的文件列表
*/
private static List<String> fileList = new ArrayList<String>();
/**
* 删除的文件列表(删除的文件,svn上的操作是删除)
*/
private static List<String> deleteFileList = new ArrayList<String>();
/**
* 处理失败(编译失败或者文件复制失败)
*/
private static List<String> compileFailList = new ArrayList<String>();
/**
* 日志文件路径
*/
private static String logFilePath = newPath +"log.log";
private static String svnFileList = newPath +"svnFileList.txt";
/**
* 日志输出流
*/
private static MyPrintStream log = null;
/**
* 不处理的文件集合(ftmerge项目下的Java文件不处理)
*/
private static List<String> untreatedList = new ArrayList<String>();
/**
* 警告的文件集合(涉及到配置文件)
*/
private static List<String> warningList = new ArrayList<String>();
/**
* 文件最后修改日期不符合的文件集合
*/
private static List<String> fileLastModifyDateWarningList = new ArrayList<String>();
/**
* 此时间由 fileLastModifyDateString 转化而来
*/
private static Date fileLastModifyDate = null;
//初始化操作
static{
//创建文件列表
try {
File file = new File(newPath);
if (!file.exists()) {
file.mkdirs();
}
log = new MyPrintStream(new FileOutputStream(fileListPath, true),true);
} catch (IOException e) {
e.printStackTrace(log);
log.println("文件列表输出流创建失败,程序退出");
//日志输出流创建失败,退出程序
System.exit(0);
}
//转化时间
try {
fileLastModifyDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(fileLastModifyDateString);
} catch (ParseException e) {
e.printStackTrace(log);
fileLastModifyDate = new Date();
}
}
public static void main(String[] args) {
//从svn获取更改文件列表,并写进文本中
getSVNLogs()
//创建日志文件
try {
log = new MyPrintStream(new FileOutputStream(logFilePath, true), true);
} catch (IOException e) {
e.printStackTrace(log);
log.println("日志输出流创建失败,程序退出");
// 日志输出流创建失败,退出程序
System.exit(0);
}
//读取文件列表
log.println("=====================读取文件列表中=====================");
rederFileListPath();
log.println("=====================读取文件列表完成=====================");
log.println("=====================总文件数:"+fileList.size());
for (String filePath : fileList) {
//读取原文件
File sourceFile = new File(sourcePath+filePath);
if (!sourceFile.exists()) {
log.println("源文件或文件夹:"+sourcePath+filePath+" 不存在");
compileFailList.add("源文件或文件夹不存在:"+sourcePath+filePath);
continue;
}
//判断是否是文件
if (!sourceFile.isFile()) {
log.println("不是文件:"+sourcePath+filePath);
compileFailList.add("不是文件:"+sourcePath+filePath);
continue;
}
Date lastModified = new Date(sourceFile.lastModified());
log.println("原文件最后修改时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(lastModified));
if (isCheckFileLastModifyDate && lastModified.before(fileLastModifyDate)) {
fileLastModifyDateWarningList.add(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(lastModified)+":"+sourcePath+filePath);
}
//不是Java文件不需要编译
if (filePath.endsWith(".java")) {
compileFile(filePath);
}else {
copyFile(filePath);
}
} //for循环结束
log.println("=====================编译结束==========================================" );
log.println("\r\n" );
log.println("\r\n" );
log.println("=====================总文件数:"+fileList.size());
log.println("=====================处理失败数量:" + compileFailList.size());
if (compileFailList.size() >0) {
log.println("=====================文件如下:");
for (String string : compileFailList) {
log.println(string);
}
log.println("================处理失败文件结束===================");
}
log.println("\r\n" );
log.println("\r\n" );
log.println("=====================未处理的文件数量:" + untreatedList.size());
if (untreatedList.size() >0) {
log.println("=====================文件如下:");
for (String string : untreatedList) {
log.println(string);
}
log.println("================未处理的文件结束===================");
}
log.println("\r\n" );
log.println("\r\n" );
log.println("=====================注意,以下文件的操作是删除,删除的文件数量" + deleteFileList.size());
if (deleteFileList.size() >0) {
log.println("=====================文件如下:");
for (String string : deleteFileList) {
log.println(string);
}
log.println("================删除的文件结束===================");
}
log.println("\r\n" );
log.println("\r\n" );
if (warningList.size() >0) {
log.println("=====================警告,本次提交了以下配置文件或toftmerge项目文件,文件数量" + warningList.size());
log.println("=====================文件如下:");
for (String string : warningList) {
log.println(string);
}
log.println("================警告的文件结束===================");
}
if (isCheckFileLastModifyDate && fileLastModifyDateWarningList.size() >0) {
log.println("=====================警告,以下文件不符合时间要求,文件数量" + fileLastModifyDateWarningList.size());
log.println("=====================要求时间不得小于:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(fileLastModifyDate)+";文件如下:");
for (String string : fileLastModifyDateWarningList) {
log.println(string);
}
log.println("================警告的文件结束===================");
}
log.close();
}
/**
* 从svn获取更改文件的路径,并写入文本中
*/
public static void getSVNLogs() {
// 版本库初始化
DAVRepositoryFactory.setup();
// 资源库相关登录配置信息
long startRevision = 0;// 最初版本
long endRevision = SVNRepository.INVALID_REVISION;// 最新版本
SVNRepository repository = null;
List<SvnLogModel> svns = new ArrayList<SvnLogModel>();
try {
// 建立一个新的资源库
repository = DAVRepositoryFactory.create(SVNURL.parseURIEncoded(url)); // 登录确认信息
@SuppressWarnings("deprecation")
ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(username, password);
repository.setAuthenticationManager(authManager);
//获取日期最近的版本号
startRevision = repository.getDatedRevision(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startData));
log.print("起始版本号:"+startRevision +"\n");
// 存放结果
final List<SVNLogEntry> logEntries = new ArrayList<SVNLogEntry>();
//查询版本startRevision到版本endRevision的更新日志列表,列表结果logEntries
repository.log(new String[]{""}, logEntries, startRevision, endRevision, true, true);
log.println(" 总共"+logEntries.size()+"条记录" +"\r\n");
// 遍历
for (Iterator<SVNLogEntry> entries = logEntries.iterator(); entries.hasNext(); ) {
SVNLogEntry logEntry = (SVNLogEntry) entries.next();
SvnLogModel svn = new SvnLogModel();
svn.setMessage(logEntry.getMessage());
svn.setAuthor(logEntry.getAuthor());
svn.setDate(logEntry.getDate());
svn.setRevision(logEntry.getRevision());
List<String> changedPathsList = new ArrayList<String>();
//遍历变更的文件列表
if (logEntry.getChangedPaths().size() > 0) {
Set<String> changedPathsSet = logEntry.getChangedPaths().keySet();
for (Iterator<String> changedPaths = changedPathsSet.iterator(); changedPaths.hasNext(); ) {
SVNLogEntryPath entryPath = logEntry.getChangedPaths().get(changedPaths.next());
char entrytype = entryPath.getType();
String typeCN = "";
if ("M".equals(String.valueOf(entrytype))) {
typeCN = "已修改 : ";
} else if ("A".equals(String.valueOf(entrytype))) {
typeCN = "已增加 : ";
} else if ("D".equals(String.valueOf(entrytype))) {
typeCN = "已删除 : ";
}
changedPathsList.add(typeCN+entryPath.getPath());
}
}
svn.setLogEntry(changedPathsList);
svns.add(svn);
}
} catch (Exception ex) {
ex.printStackTrace(log);
}
Collections.reverse(svns);
for (SvnLogModel svnLogModel : svns) {
log.println(svnLogModel);
}
log.flush();
log.close();
log = null;
// 创建svn日志文件
try {
log = new MyPrintStream(new FileOutputStream(svnFileList, true), true);
} catch (IOException e) {
e.printStackTrace(log);
log.println("svn日志输出流创建失败,程序退出");
// 日志输出流创建失败,退出程序
System.exit(0);
}
long count = 0L;
for (SvnLogModel svnLogModel : svns) {
if (svnLogModel.getLogEntry() != null) {
for (String fileList : svnLogModel.getLogEntry()) {
fileList = fileList.replace("已修改 : ", "");
fileList = fileList.replace("已增加 : ", "");
fileList = fileList.replace("已删除 : ", "");
log.println("svn://xxx"+fileList);
count++;
}
}
}
log.println("总文件数:"+count+"个");
log.flush();
log.close();
log = null;
}
/**
* 编译Java文件
* @param filePath
*/
private static void compileFile(String filePath) {
//web web的编译环境包括了ejb编译环境
String webCP = sourcePath+"WEB/webapp/WEB-INF/classes;"+sourcePath+"EJB/classes";
String webLib =sourcePath+"WEB/webapp/WEB-INF/lib;"+sourcePath+"lib";
String webSourcepath = sourcePath+"WEB/src/";
//ejb ejb的编译环境
String ejbCP = sourcePath+"EJB/classes";
String ejbLib =sourcePath+"lib";
String ejbSourcepath = sourcePath+"EJB/src/";
//bankP bankP的编译环境
String bankPCP = sourcePath+"BankP/WebRoot/WEB-INF/classes;"+sourcePath+"EJB/classes";
String bankPLib =sourcePath+"lib;"+sourcePath+"BankP/lib/";
String bankPSourcepath = sourcePath+"BankP/src/";
//ftmerge ftmerge的编译环境
String ftmergeCP = sourcePath+"ftmerge/WebContent/WEB-INF/classes;"+sourcePath+"EJB/classes";
String ftmergeLib =sourcePath+"ftmerge/WebContent/WEB-INF/lib";
String ftmergeSourcepath = sourcePath+"ftmerge/src/";
String tmpCP = "";
String tmpLib = "";
String tmpSourcepath = "";
String targetPath = "";
//创建目标文件夹
if(filePath.startsWith("/WEB/src/")){
targetPath = "WEB/WEB-INF/classes/";
tmpCP = webCP;
tmpLib = webLib;
tmpSourcepath = webSourcepath;
}else if (filePath.toLowerCase().startsWith("/EJB/src/".toLowerCase())) {
targetPath = "EJB/";
tmpCP = ejbCP;
tmpLib = ejbLib;
tmpSourcepath = ejbSourcepath;
}
else if (filePath.toLowerCase().startsWith("/bankp/src/".toLowerCase())) {
targetPath = "BankP/WEB-INF/classes/";
tmpCP = bankPCP;
tmpLib = bankPLib;
tmpSourcepath = bankPSourcepath;
}else if (filePath.toLowerCase().startsWith("/ftmerge/src/".toLowerCase())) {
targetPath = "ftmerge/WEB-INF/classes/";
tmpCP = ftmergeCP;
tmpLib = ftmergeLib;
tmpSourcepath = ftmergeSourcepath;
warningList.add("有ftmerge项目的文件,请注意文件对应的位置"+sourcePath+filePath);
}else {
log.println("文件未处理:"+sourcePath+filePath);
untreatedList.add(sourcePath+filePath);
return;
}
File targetdir = new File(newPath + targetPath);
log.println("正在编译:"+sourcePath+filePath);
log.println("编译目标路径:"+targetdir.getAbsolutePath());
if (!targetdir.exists()) {
targetdir.mkdirs();
}
//编译
int result = -1;
log.println("编译环境:"+ tmpCP +"\n "+ tmpLib +"\n"+tmpSourcepath);
String[] args1 = {
"-g", //生成所有调试信息
"-implicit:none", //不生成依赖文件的class文件
"-nowarn", //不生成警告
"-classpath",tmpCP,
"-Djava.ext.dirs="+JDKPath+"/jre/lib/ext;"+tmpLib,
//加上这个,如果有包路径和类名都相同的情况下,优先使用sourcepath下的类
"-sourcepath",tmpSourcepath,
"-version", //输出编译版本 (默认与项目设置的版本一样)
// "-verbose", //输出解析详情
// "-encoding","GBK", //指定源文件使用的字符编码
// "-source","1.6.0", //提供与指定发行版的源兼容性
// "-target","1.6", //生成特定 VM 版本的类文件
"-d" , newPath+targetPath , //编译后的目标目录
sourcePath+filePath}; //原文件路径
// result = Main.compile(args1); //另一种编译方式,暂时不用
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
result = compiler.run(null, log, log, args1);
log.println("执行结果:"+result+(result==0?" 编译成功":" 编译失败"));
if (result != 0) {
compileFailList.add("编译失败:"+sourcePath+filePath);
}
}
/**
* 复制文件
* @param filePath
*/
private static void copyFile(String filePath) {
BufferedInputStream in = null;
BufferedOutputStream out = null;
try {
//检查是否为配置文件
if (filePath.toLowerCase().endsWith(".xml")||filePath.toLowerCase().endsWith(".properties")) {
warningList.add(sourcePath+filePath);
}
in = new BufferedInputStream(new FileInputStream(sourcePath+filePath));
filePath = filePath.replace("/WEB/src/", "/WEB/WEB-INF/classes/");
filePath = filePath.replace("/EJB/src/", "/EJB/");
filePath = filePath.replace("/BankP/src/", "/BankP/WEB-INF/classes/");
filePath = filePath.replace("/ftmerge/src/", "/ftmerge/WEB-INF/classes/");
filePath = filePath.replace("/BankP/WebRoot/", "/BankP/");
filePath = filePath.replace("/bankp/WebRoot/", "/BankP/");
filePath = filePath.replace("/WEB/webapp/", "/WEB/");
filePath = filePath.replace("/ftmerge/WebContent/", "/ftmerge/");
//目标文件夹
File file = new File(newPath+filePath.substring(0, filePath.lastIndexOf("/")));
//创建文件夹
if (!file.exists()) {
file.mkdirs();
}
log.println("正在复制文件:"+sourcePath+filePath);
log.println("目标路径:"+file.getAbsolutePath());
file = new File(file, filePath.substring(filePath.lastIndexOf("/")));
out = new BufferedOutputStream(new FileOutputStream(file));
int tmp = -1;
while((tmp = in.read())!= -1){
out.write(tmp);
out.flush();
}
} catch (FileNotFoundException e) {
log.println("文件:"+sourcePath+filePath+" 不存在! 或 目标文件"+newPath+filePath+"创建失败,请检查!");
compileFailList.add("文件不存在:"+sourcePath+filePath);
} catch (IOException e) {
e.printStackTrace(log);
log.println("复制文件出错:"+sourcePath+filePath);
compileFailList.add("复制文件出错:"+sourcePath+filePath);
}finally{
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace(log);
}
}
}
/**
* 读取文件列表
* @param fileList 接收文件列表的集合
* @param fileListPath 需读取的文件列表路径
* @param filePrefix 需去除的文件名前缀
*/
private static void rederFileListPath() {
try {
//读取文件列表
Reader in = new FileReader(fileListPath);
BufferedReader bufferedReader = new BufferedReader(in);
String tmp = null;
while ((tmp = bufferedReader.readLine())!= null) {
//只读取文件路径
String tmpFilePrefix = "";
if (tmp.startsWith("已修改 : ")) {
tmpFilePrefix = "已修改 : ";
}else if (tmp.startsWith("已增加 : ")) {
tmpFilePrefix = "已增加 : ";
}else if (tmp.startsWith("已删除 : ")) {
tmpFilePrefix = "已删除 : ";
tmp = tmp.replace(tmpFilePrefix +filePrefix, "");
log.println("已删除 : "+tmp);
deleteFileList.add(tmp);
continue;
}else if (tmp.toLowerCase().startsWith("/web") ||
tmp.toLowerCase().startsWith("/ejb")||
tmp.toLowerCase().startsWith("/bankp") ||
tmp.toLowerCase().startsWith("/lib")||
tmp.toLowerCase().startsWith("/ftmerge") ||
tmp.toLowerCase().startsWith("/webdoc")) {
//此类型没有前缀,不用做任何处理
//此IF判断处理的是:在项目中右键复制限定名,限定名的路径是以下形式
// /EJB/src/com/iss/closesystem/basebean/FunctionBaseBean.java
}else {
continue;
}
//去除前缀
tmp = tmp.replace(tmpFilePrefix +filePrefix, "");
fileList.add(tmp);
log.println(tmp);
}
} catch (FileNotFoundException e) {
e.printStackTrace(log);
log.println("文件:"+fileListPath+" 不存在!");
} catch (IOException e) {
e.printStackTrace(log);
}
}
}
/**
* 为了在控制台输出信息,重写write方法
* @author dong
*
*/
class MyPrintStream extends PrintStream{
public MyPrintStream(OutputStream out, boolean autoFlush) {
super(out, autoFlush);
}
@Override
public void write(byte[] buf, int off, int len) {
System.out.write(buf, off, len);
super.write(buf, off, len);
}
}
class SvnLogModel {
private String message; //提交svn时写的信息
private String author;//作者
private Date date; //日期
private long revision; //版本
private List<String> logEntry;//更改的文件列表
public SvnLogModel() {
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Date getDate() {
return date;
}
public String getDateToString() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
}
public void setDate(Date date) {
this.date = date;
}
public long getRevision() {
return revision;
}
public void setRevision(long revision) {
this.revision = revision;
}
public List<String> getLogEntry() {
return logEntry;
}
public void setLogEntry(List<String> logEntry) {
this.logEntry = logEntry;
}
public SvnLogModel(String message, String author, Date date, long revision, List<String> logEntry) {
this.message = message;
this.author = author;
this.date = date;
this.revision = revision;
this.logEntry = logEntry;
}
@Override
public String toString() {
String log = "版本:" + revision + "\r\n" +
"作者: " + author + "\r\n" +
"日期: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date) + "\r\n" +
"信息:" + message + "\r\n"+
"----"+ "\r\n";
for (String path : logEntry) {
log = log+path+"\r\n";
}
return log +"\r\n";
}
}