最近在做一个仓库管理系统,架构在svn之上。要求每一项操作要记录在log文件中,弄了很久起初感觉无法向库中的文本文件添加东西,就是修改库中的文本文件。于是采用了一个很笨的办法: 现将库中的log文件export下来到本地,修改完之后将库中的原来的log文件删除,然后上传(import)本地这个新的日志文件,然后删除掉本地的这个日志文件。
先看看代码:
package com.repositoryclient.svnoptions; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl; import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions; import org.tmatesoft.svn.core.wc.ISVNOptions; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.SVNCommitClient; import org.tmatesoft.svn.core.wc.SVNCopyClient; import org.tmatesoft.svn.core.wc.SVNCopySource; import org.tmatesoft.svn.core.wc.SVNMoveClient; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.SVNUpdateClient; import org.tmatesoft.svn.core.wc.SVNWCUtil; import com.repositoryclient.models.User; import com.repositoryclient.treeview.FileNode; public class UserLogOption { public boolean doLog(String userName,String passwd,String LogMessage){ SVNClientManager ourClientManager; SVNRepositoryFactoryImpl.setup(); SVNURL repositoryUrl = null; String SVNServerUrl=User.getLogUrl(); File outFile=new File("./"); try { repositoryUrl = SVNURL.parseURIEncoded(SVNServerUrl); ISVNOptions options = SVNWCUtil.createDefaultOptions(true); ourClientManager = SVNClientManager.newInstance( (DefaultSVNOptions) options, userName, passwd); //将log文件下载到本地 SVNUpdateClient updateClient=ourClientManager.getUpdateClient(); updateClient.doExport(repositoryUrl, outFile, SVNRevision.HEAD, SVNRevision.HEAD, LogMessage,false,true); //添加此次操作的内容到log文件 try { BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("./Log.txt",true))); bw.append("\r\n"+LogMessage); bw.flush(); bw.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } //上传新的log文件,替换掉老的log文件 outFile=new File("./log.txt"); SVNURL repositoryTrgtUrl = SVNURL.parseURIEncoded(SVNServerUrl); SVNCopySource[] copySources = new SVNCopySource[1]; copySources[0] = new SVNCopySource(null, null, outFile); SVNCopyClient copyClient=ourClientManager.getCopyClient(); SVNMoveClient moveClient=ourClientManager.getMoveClient(); SVNCommitClient commitClient=ourClientManager.getCommitClient(); SVNURL[] svnurl = new SVNURL[1]; svnurl[0] = SVNURL.parseURIEncoded(SVNServerUrl); commitClient.doDelete(svnurl, "delete log file."); commitClient.doImport(outFile, repositoryTrgtUrl, "dologlog", true); //updateClient.doSwitch(outFile,repositoryTrgtUrl,SVNRevision.HEAD , true); //copyClient.doCopy(copySources, repositoryTrgtUrl, true, true, true, "move", null); //SVNCommitClient commitClient=ourClientManager.getCommitClient(); //commitClient.doCommit(new File[]{outFile}, false, LogMessage, true, true); //删除本地的log文件 outFile.delete(); return true; } catch (SVNException e) { // TODO: handle exception e.printStackTrace(); return false; } } }
测试代码:
package com.repositoryclient.svnoptions; import com.repositoryclient.models.User; public class testlog { public static void main(String args[]){ UserLogOption logOption=new UserLogOption(); logOption.doLog(User.getUserName(), User.getPasswd(), "do log is good."); } }
发现虽然是可行的,但是真的很不好。
于是给svnkit的作者写了封邮件问了问能否直接修改库中的文本文件,他们很快给我回了邮件
You need to commit a file modification. There is an example at http://wiki.svnkit.com/Committing_To_A_Repository Alexander Kitaev, TMate Software Support, TMate Software, http://subgit.com/ - Safe Svn To Git Migration! http://svnkit.com/ - Java [Sub]Versioning Library! http://hg4j.com/ - Java Mercurial Library! http://sqljet.com/ - Java SQLite Library!
于是我就试了试svnkit的low api,结果成功了,但是有点问题:直接覆盖了log中的内容而不是添加到log中原内容的后边。这个之后再解决。
先看看代码:
public void logRepository(){ FSRepositoryFactory.setup(); try { byte[] oldData={}; byte[] newData; String logMessage="you are the god."; newData=logMessage.getBytes(); SVNRepository repository=SVNRepositoryFactory.create(SVNURL.parseURIDecoded("http://10.13.30.22/svn/SVNRepository/Log/")); ISVNAuthenticationManager authenticationManager = SVNWCUtil .createDefaultAuthenticationManager(userName, passwd); repository.setAuthenticationManager(authenticationManager); ISVNEditor editor=repository.getCommitEditor("logMessage", null,true,null); editor.openRoot(-1); editor.openFile("log.txt", -1); editor.applyTextDelta("log.txt", null); SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator( ); String checksum =deltaGenerator.sendDelta( "log.txt" ,new ByteArrayInputStream(newData),editor , true ); // String checksum = deltaGenerator.sendDelta( "log.txt" , new ByteArrayInputStream(oldData) , -1 , new ByteArrayInputStream(newData) , editor , true ); //Closes filePath. editor.closeFile( "log.txt" , checksum ); //Closes the root directory. editor.closeDir( ); editor.closeEdit(); } catch (SVNException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
这个执行完之后,就将库中Log文件夹下的log.txt文件的内容修改为: you are the god.了。
注意这个很重要的类:SVNDeltaGenerator:http:
http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/diff/SVNDeltaGenerator.html#sendDelta(java.lang.String, java.io.InputStream, long, java.io.InputStream, org.tmatesoft.svn.core.io.ISVNDeltaConsumer, boolean)
public String sendDelta(String path, InputStream target, ISVNDeltaConsumer consumer, boolean computeChecksum) throws SVNException Generates a series of diff windows of fixed size comparing target bytes (from target stream) against an empty file and sends produced windows to the provided consumer. consumer's textDeltaChunk() method is called to receive and process generated windows. Now new data comes within a window, so the output stream is either ignored (if it's null) or immediately closed (if it's not null). If computeChecksum is true, the return value will be a strig containing a hex representation of the MD5 digest computed for the target contents. Parameters: path - a file repository path target - an input stream to read target bytes from consumer - a diff windows consumer computeChecksum - true to compute a checksum Returns: if computeChecksum is true, a string representing a hex form of the MD5 checksum computed for the target contents; otherwise null Throws: SVNException
---------------------------------------------------------------------------------------------------------------------------------------------------------------
刚才上面提到的问题有一个笨办法,就是获得log.txt的原内容,将新的log信息组织到原内容的后面,然后通过sendDelta就行了。
上代码:
public void logRepository(String logMessage){ FSRepositoryFactory.setup(); try { String readmeContent=getFileInfo("http://10.13.30.22/svn/SVNRepository/Log/log.txt"); SVNRepository repository=SVNRepositoryFactory.create(SVNURL.parseURIDecoded("http://10.13.30.22/svn/SVNRepository/Log/")); ISVNAuthenticationManager authenticationManager = SVNWCUtil .createDefaultAuthenticationManager(userName, passwd); repository.setAuthenticationManager(authenticationManager); ISVNEditor editor=repository.getCommitEditor("logMessage", null,true,null); editor.openRoot(-1); editor.openFile("log.txt", -1); editor.applyTextDelta("log.txt", null); SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator( ); String checksum =deltaGenerator.sendDelta( "log.txt" ,new StringBufferInputStream(readmeContent+"\r\n"+logMessage),editor , true ); // String checksum = deltaGenerator.sendDelta( "log.txt" , new ByteArrayInputStream(oldData) , -1 , new ByteArrayInputStream(newData) , editor , true ); //Closes filePath. editor.closeFile( "log.txt" , checksum ); //Closes the root directory. editor.closeDir( ); editor.closeEdit(); } catch (SVNException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
public String getFileInfo(String SVNServerUrl){ SVNClientManager ourClientManager; // 初始化支持svn://协议的库 SVNRepositoryFactoryImpl.setup(); // 相关变量赋值 SVNURL repositoryUrl = null; try { repositoryUrl = SVNURL.parseURIEncoded(SVNServerUrl); ISVNOptions options = SVNWCUtil.createDefaultOptions(true); // 实例化客户端管理类 ourClientManager = SVNClientManager.newInstance( (DefaultSVNOptions) options, userName, passwd); OutputStream outputStream; outputStream = new ByteArrayOutputStream(); SVNWCClient svnWCClient = ourClientManager.getWCClient(); svnWCClient.doGetFileContents(repositoryUrl, SVNRevision.HEAD, SVNRevision.HEAD, false, outputStream); return outputStream.toString(); } catch (SVNException e) { // TODO: handle exception e.printStackTrace(); return null; } }
测试代码:
package com.repositoryclient.svnoptions; import com.repositoryclient.models.User; public class testEditor { public static void main(String args[]){ StoreManagerFileNodeOption fileNodeOption=new StoreManagerFileNodeOption(User.getUserName(), User.getPasswd()); fileNodeOption.logRepository("新的log信息"); } }