引入包:svnkit
https://mvnrepository.com/artifact/org.tmatesoft.svnkit/svnkit
代码demo
package com.yy.svn;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.tmatesoft.svn.core.ISVNLogEntryHandler;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNDiffClient;
import org.tmatesoft.svn.core.wc.SVNLogClient;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNWCUtil;
public class SvnkitDemo {
private String userName = "user";
private String password = "password";
private String urlString = "svn url";
boolean readonly = true;
private String tempDir = System.getProperty("java.io.tmpdir");
private DefaultSVNOptions options = SVNWCUtil.createDefaultOptions( readonly );
private Random random = new Random();
private SVNRepository repos;
private ISVNAuthenticationManager authManager;
public SvnkitDemo() {
try {
init();
} catch (SVNException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void init() throws SVNException{
ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(new File(tempDir+"/auth"), userName, password.toCharArray());
options.setDiffCommand("-x -w");
repos = SVNRepositoryFactory.create(SVNURL
.parseURIEncoded(urlString));
repos.setAuthenticationManager(authManager);
System.out.println("init completed");
}
/**获取一段时间内,所有的commit记录
* @param st 开始时间
* @param et 结束时间
* @return
* @throws SVNException
*/
public SVNLogEntry[] getLogByTime(Date st, Date et) throws SVNException{
long startRevision = repos.getDatedRevision(st);
long endRevision = repos.getDatedRevision(et);
@SuppressWarnings("unchecked")
Collection logEntries = repos.log(new String[]{""}, null,
startRevision, endRevision, true, true);
SVNLogEntry[] svnLogEntries = logEntries.toArray(new SVNLogEntry[0]);
return svnLogEntries;
}
/**获取版本比较日志,并存入临时文件
* @param startVersion
* @param endVersion
* @return
* @throws SVNException
* @throws IOException
*/
public File getChangeLog(long startVersion, long endVersion) throws SVNException, IOException{
SVNDiffClient diffClient = new SVNDiffClient(authManager, options);
diffClient.setGitDiffFormat(true);
File tempLogFile = null;
OutputStream outputStream = null;
String svnDiffFile = null;
do {
svnDiffFile = tempDir + "/svn_diff_file_"+startVersion+"_"+endVersion+"_"+random.nextInt(10000)+".txt";
tempLogFile = new File(svnDiffFile);
} while (tempLogFile != null && tempLogFile.exists());
try {
tempLogFile.createNewFile();
outputStream = new FileOutputStream(svnDiffFile);
diffClient.doDiff(SVNURL.parseURIEncoded(urlString),
SVNRevision.create(startVersion),
SVNURL.parseURIEncoded(urlString),
SVNRevision.create(endVersion),
org.tmatesoft.svn.core.SVNDepth.UNKNOWN, true, outputStream);
} catch (Exception e) {
e.printStackTrace();
}finally {
if(outputStream!=null)
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return tempLogFile;
}
/**分析变更的代码,统计代码增量
* @param file
* @return
* @throws Exception
*/
public int staticticsCodeAdd(File file) throws Exception{
System.out.println("开始统计修改代码行数");
FileReader fileReader = new FileReader(file);
BufferedReader in = new BufferedReader(fileReader);
int sum = 0;
String line = null;
StringBuffer buffer = new StringBuffer(1024);
boolean start = false;
while((line=in.readLine()) != null){
if(line.startsWith("Index:")){
if(start){
ChangeFile changeFile = parseChangeFile(buffer);
int oneSize = staticOneFileChange(changeFile);
System.out.println("filePath="+changeFile.getFilePath()+" changeType="+changeFile.getChangeType()+" addLines="+oneSize);
sum += oneSize;
buffer.setLength(0);
}
start = true;
}
buffer.append(line).append('\n');
}
if(buffer.length() > 0){
ChangeFile changeFile = parseChangeFile(buffer);
int oneSize = staticOneFileChange(changeFile);
System.out.println("filePath="+changeFile.getFilePath()+" changeType="+changeFile.getChangeType()+" addLines="+oneSize);
sum += oneSize;
}
in.close();
fileReader.close();
boolean deleteFile = file.delete();
System.out.println("-----delete file-----"+deleteFile);
return sum;
}
/**统计单个文件的增加行数,(先通过过滤器,如文件后缀、文件路径等等),也可根据修改类型来统计等,这里只统计增加或者修改的文件
* @param changeFile
* @return
*/
public int staticOneFileChange(ChangeFile changeFile){
char changeType = changeFile.getChangeType();
if(changeType == 'A'){
return countAddLine(changeFile.getFileContent());
}else if(changeType == 'M'){
return countAddLine(changeFile.getFileContent());
}
return 0;
}
/**解析单个文件变更日志
* @param str
* @return
*/
public ChangeFile parseChangeFile(StringBuffer str){
int index = str.indexOf("\n@@");
if(index > 0){
String header = str.substring(0, index);
String[] headers = header.split("\n");
String filePath = headers[0].substring(7);
char changeType = 'U';
boolean oldExist = !headers[2].endsWith("(nonexistent)");
boolean newExist = !headers[3].endsWith("(nonexistent)");
if(oldExist && !newExist){
changeType = 'D';
}else if(!oldExist && newExist){
changeType = 'A';
}else if(oldExist && newExist){
changeType = 'M';
}
int bodyIndex = str.indexOf("@@\n")+3;
String body = str.substring(bodyIndex);
ChangeFile changeFile = new ChangeFile(filePath, changeType, body);
return changeFile;
}else{
String[] headers = str.toString().split("\n");
String filePath = headers[0].substring(7);
ChangeFile changeFile = new ChangeFile(filePath, 'U', null);
return changeFile;
}
}
/**通过比较日志,统计以+号开头的非空行
* @param content
* @return
*/
public int countAddLine(String content){
int sum = 0;
if(content !=null){
content = '\n' + content +'\n';
char[] chars = content.toCharArray();
int len = chars.length;
//判断当前行是否以+号开头
boolean startPlus = false;
//判断当前行,是否为空行(忽略第一个字符为加号)
boolean notSpace = false;
for(int i=0;i ' '){//如果当前行以+开头才进行非空行判断
notSpace = true;
}
}
}
return sum;
}
/**统计一段时间内代码增加量
* @param st
* @param et
* @return
* @throws Exception
*/
public int staticticsCodeAddByTime(Date st, Date et) throws Exception{
int sum = 0;
SVNLogEntry[] logs = getLogByTime(st, et);
if(logs.length > 0){
long lastVersion = logs[0].getRevision()-1;
for(SVNLogEntry log:logs){
File logFile = getChangeLog(lastVersion, log.getRevision());
int addSize = staticticsCodeAdd(logFile);
sum+=addSize;
lastVersion = log.getRevision();
}
}
return sum;
}
/**获取某一版本有变动的文件路径
* @param version
* @return
* @throws SVNException
*/
public List getChangeFileList(long version) throws SVNException{
List result = new ArrayList<>();
SVNLogClient logClient = new SVNLogClient( authManager, options );
SVNURL url = SVNURL.parseURIEncoded(urlString);
String[] paths = { "." };
SVNRevision pegRevision = SVNRevision.create( version );
SVNRevision startRevision = SVNRevision.create( version );
SVNRevision endRevision = SVNRevision.create( version );
boolean stopOnCopy = false;
boolean discoverChangedPaths = true;
long limit = 9999l;
ISVNLogEntryHandler handler = new ISVNLogEntryHandler() {
/**
* This method will process when doLog() is done
*/
@Override
public void handleLogEntry( SVNLogEntry logEntry ) throws SVNException {
System.out.println( "Author: " + logEntry.getAuthor() );
System.out.println( "Date: " + logEntry.getDate() );
System.out.println( "Message: " + logEntry.getMessage() );
System.out.println( "Revision: " + logEntry.getRevision() );
System.out.println("-------------------------");
Map maps = logEntry.getChangedPaths();
Set> entries = maps.entrySet();
for(Map.Entry entry : entries){
//System.out.println(entry.getKey());
SVNLogEntryPath entryPath = entry.getValue();
result.add(entryPath);
System.out.println(entryPath.getType()+" "+entryPath.getPath());
}
}
};
// Do log
try {
logClient.doLog( url, paths, pegRevision, startRevision, endRevision, stopOnCopy, discoverChangedPaths, limit, handler );
}
catch ( SVNException e ) {
System.out.println( "Error in doLog() " );
e.printStackTrace();
}
return result;
}
/**获取指定文件内容
* @param url svn地址
* @return
*/
public String checkoutFileToString(String url){//"", -1, null
try {
SVNDirEntry entry = repos.getDir("", -1, false, null);
int size = (int)entry.getSize();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(size);
SVNProperties properties = new SVNProperties();
repos.getFile("", -1, properties, outputStream);
String doc = new String(outputStream.toByteArray(),Charset.forName("utf-8"));
return doc;
} catch (SVNException e) {
e.printStackTrace();
}
return null;
}
/**列出指定SVN 地址目录下的子目录
* @param url
* @return
* @throws SVNException
*/
public List listFolder(String url){
if(checkPath(url)==1){
try {
Collection list = repos.getDir("", -1, null, (List)null);
List dirs = new ArrayList(list.size());
dirs.addAll(list);
return dirs;
} catch (SVNException e) {
e.printStackTrace();
}
}
return null;
}
/**检查路径是否存在
* @param url
* @return 1:存在 0:不存在 -1:出错
*/
public int checkPath(String url){
SVNNodeKind nodeKind;
try {
nodeKind = repos.checkPath("", -1);
boolean result = nodeKind == SVNNodeKind.NONE ? false : true;
if(result) return 1;
} catch (SVNException e) {
e.printStackTrace();
return -1;
}
return 0;
}
public static void main(String[] args) {
SvnkitDemo demo = new SvnkitDemo();
Date now = new Date();
Date twoDayAgo = new Date(now.getTime()-2*24*3600000);
try {
// int sum = demo.staticticsCodeAddByTime(now, twoDayAgo);
// System.out.println("sum="+sum);
demo.getChangeFileList(487837L);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ChangeFile {
private String filePath;
private String fileType;
/**A表示增加文件,M表示修改文件,D表示删除文件,U表示末知
*
*/
private Character changeType;
private String fileContent;
public ChangeFile() {
}
public ChangeFile(String filePath) {
this.filePath = filePath;
this.fileType = getFileTypeFromPath(filePath);
}
public ChangeFile(String filePath, Character changeType, String fileContent) {
this.filePath = filePath;
this.changeType = changeType;
this.fileContent = fileContent;
this.fileType = getFileTypeFromPath(filePath);
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public Character getChangeType() {
return changeType;
}
public void setChangeType(Character changeType) {
this.changeType = changeType;
}
public String getFileContent() {
return fileContent;
}
public void setFileContent(String fileContent) {
this.fileContent = fileContent;
}
private static String getFileTypeFromPath(String path) {
String FileType = "";
int idx = path.lastIndexOf(".");
if (idx > -1) {
FileType = path.substring(idx + 1).trim().toLowerCase();
}
return FileType;
}
}