SVNKit Low Level API 使用(1)
编辑操作:提交到存储库
Low Level API提供一个抽象的编辑器(editor),给开发人员以构建和改变存储库(repository)中树的层次的能力。有了这样的编辑器,你可以手动(即在你的代码中明确)编辑存储库:在这些节点下添加新节点(目录)和条目(文件),根据路径更改或删除仓库。接下来我们详细介绍这些操作。
?
使用ISVNEditor接口
ISVNEditor是用于编辑操作的接口,尤其是提交更改到存储库。ISVNEditor也用来接收和应用存储库的更新,但这属于下一个例子的范畴。
试想一下,我们已经在我们的资料库中得到了以下的树结构:
?
?
我们要将它改变成以下这个结构:
?
?
换句话说,我们要:
...FSRepositoryFactory.setup();String url = "file:///C:/path/to/repos/nodeB/";SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIDecoded( url ));...
...String logMessage = "log message";ISVNEditor editor = repository.getCommitEditor( logMessage , null /*locks*/ , true /*keepLocks*/ , null /*mediator*/ );...
... //provide your local revision of nodeB1 long r = ...; editor.openRoot( r ); //provide your local revision of itemB12 r = ...; editor.deleteEntry( "itemB1" , r ); //provide your local revision of nodeC3 r = ...; editor.openDir( "nodeC" , r ); //provide your local revision of itemC14 r = ...; editor.openFile( "nodeC/itemC1" , r );
String baseChecksum = ...;editor.applyTextDelta( "nodeC/itemC1" , baseChecksum );
?
?
InputStream baseData = ...;InputStream workingData = ...;//100Kb-window generatorSVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator( );String checksum = deltaGenerator.sendDelta( "nodeC/itemC1" , baseData , 0 , workingData , editor , true );
?
editor.textDeltaChunk( "nodeC/itemC1" , window );?当成器通完成后,它调用编辑器的textDeltaEnd()方法:
editor.textDeltaEnd( "nodeC/itemC1" );?sendDelta()方法返回工作版本条目的checksum。此checksum可用于验证更改被正确应用到了资源库侧。如果本地的工作条目和内资源库中的不匹配,checksum可能是不同的:
editor.closeFile( "nodeC/itemC1" , checksum ); 5 //the second and the third parameters are the path and revision respectively //of the item's ancestor if the item is being added with history editor.addFile( "nodeC/itemC2" , null , -1 ); baseChecksum = ...; editor.applyTextDelta( "nodeC/itemC2" , baseChecksum ); baseData = ...; workingData = ...; checksum = deltaGenerator.sendDelta( "nodeC/itemC2" , baseData , 0 , workingData , editor , true ); editor.closeFile( "nodeC/itemC2" , checksum ); 6 editor.changeFileProperty( "nodeC/itemC2" , "propName1" , "propValue1" ); editor.changeFileProperty( "nodeC/itemC2" , "propName2" , "propValue2" ); ... //we are finished with changes under nodeC, so closing nodeC editor.closeDir( );7 //now we are under nodeB again editor.addDir( "nodeD" , null , -1 ); //close nodeD editor.closeDir( ); //close root - nodeB editor.closeDir( );?在步骤5中,我们添加了一个新的条目,而不是不复制现有的条目。但是,如果我们需要做一个现有条目的副本,我们应该提供复制源的绝对路径和版本分别作为editor.addFile()方法的第二个和第三个参数。如果您只想复制(文件)不做更改,你不需要为了增加一个目录,ddFile()中其他的参数犹如以上所列,我们不是复制一个目录,只是增加一个没有历史的新目录。正如你看到的每一个打开/添加目录(包括根),以及每一个打开/添加文件操作,都必须关闭编辑器。最后一点,关闭编辑器会引发资源库提交事务:
SVNCommitInfo info = editor.closeEdit();?如果事务成功,这个调用使得我们改变存储库中的内容。编辑器返回SVNCommitInfo对象,其中包含了新的版本信息。然而,该操作可能抛出一个异常,这意味着什么地方出错了。当我们捕获了这样一个异常,我们按照以下的方式来终止事务:
try { ... editor.addFile( "nodeC/itemC2" , null , -1 );} catch( SVNException svne ) { editor.abortEdit( );}?当我们关闭了编辑器后,我们可能会继续使用我们的SVNRepository驱动。下图说明了我们一步一步的改变,图中的数字对应了我们在代码中的步骤:?附注:?? 通过ISVNEditor进行编辑时,可能会以分层的方式遍历一个必要的子树。如果你的驱动绑定到/a,而你要改变/a?? 所有目前在本地机器上的版本数据,你必须?? 您不必在打开了一个文件时,立即?? 在操作存储库版本的提交编辑器时,你永远不需要调用以方法(他们与提交无关,但与更新有关):
private static SVNCommitInfo addDir( ISVNEditor editor , String dirPath , String filePath , byte[] data ) throws SVNException { editor.openRoot( -1 ); editor.addDir( dirPath , null , -1 ); editor.addFile( filePath , null , -1 ); editor.applyTextDelta( filePath , null ); SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator( ); String checksum = deltaGenerator.sendDelta( filePath , new ByteArrayInputStream( data ) , editor , true ); editor.closeFile(filePath, checksum); //Closes dirPath. editor.closeDir(); //Closes the root directory. editor.closeDir(); return editor.closeEdit(); }
?
?
2、文件修改:
private static SVNCommitInfo modifyFile( ISVNEditor editor , String dirPath , String filePath , byte[] oldData , byte[] newData ) throws SVNException { editor.openRoot( -1 ); editor.openDir( dirPath , -1 ); editor.openFile( filePath , -1 ); editor.applyTextDelta( filePath , null ); SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator( ); String checksum = deltaGenerator.sendDelta( filePath , new ByteArrayInputStream( oldData ) , 0 , new ByteArrayInputStream( newData ) , editor , true ); //Closes filePath. editor.closeFile( filePath , checksum ); // Closes dirPath. editor.closeDir( ); //Closes the root directory. editor.closeDir( ); return editor.closeEdit( ); }
?
?
在这里,我们使用无效的版本号(-1),以简化的例子,这样也是可行的。而这也是我们现在需要的。当然,在实际系统中,他们最好是真实的(有效)版本号。对于checksum也是如此。
?
3、目录复制:
?
private static SVNCommitInfo copyDir( ISVNEditor editor , String srcDirPath , String dstDirPath , long revision ) throws SVNException { editor.openRoot( -1 ); editor.addDir( dstDirPath , srcDirPath , revision ); //Closes dstDirPath. editor.closeDir( ); //Closes the root directory. editor.closeDir( ); return editor.closeEdit( ); }
?
private static SVNCommitInfo deleteDir( ISVNEditor editor , String dirPath ) throws SVNException { editor.openRoot( -1 ); editor.deleteEntry( dirPath , -1 ); //Closes the root directory. editor.closeDir( ); return editor.closeEdit( ); }
public class Commit { public static void main( String[] args ) { FSRepositoryFactory.setup( ); SVNURL url = SVNURL.parseURIDecoded( "file:///localhost/testRepos" ); String userName = "foo"; String userPassword = "bar"; byte[] contents = "This is a new file".getBytes( ); byte[] modifiedContents = "This is the same file but modified a little.".getBytes( ); SVNRepository repository = SVNRepositoryFactory.create( url ); ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager( userName, userPassword ); repository.setAuthenticationManager( authManager ); SVNNodeKind nodeKind = repository.checkPath( "" , -1 ); if ( nodeKind == SVNNodeKind.NONE ) { System.out.println( "No entry at URL " + url ); System.exit( 1 ); } else if ( nodeKind == SVNNodeKind.FILE ) { System.out.println( "Entry at URL " + url + " is a file while directory was expected" ); System.exit( 1 ); } //Get exact value of the latest (HEAD) revision. long latestRevision = repository.getLatestRevision( ); System.out.println( "Repository latest revision (before committing): " + latestRevision ); ISVNEditor editor = repository.getCommitEditor( "directory and file added" , null ); try { SVNCommitInfo commitInfo = addDir( editor , "test" , "test/file.txt" , contents ); System.out.println( "The directory was added: " + commitInfo ); } catch ( SVNException svne ) { editor.abortEdit( ); throw svne; } editor = repository.getCommitEditor( "file contents changed" , null ); try { commitInfo = modifyFile( editor , "test" , "test/file.txt" , contents , modifiedContents ); System.out.println( "The file was changed: " + commitInfo ); } catch ( SVNException svne ) { editor.abortEdit( ); throw svne; } //converts a relative path to an absolute one String absoluteSrcPath = repository.getRepositoryPath( "test" ); long srcRevision = repository.getLatestRevision( ); editor = repository.getCommitEditor( "directory copied" , null ); try { commitInfo = copyDir( editor , absoluteSrcPath , "test2" , srcRevision ); System.out.println( "The directory was copied: " + commitInfo ); } catch ( SVNException svne ) { editor.abortEdit( ); throw svne; } //Delete directory "test". editor = repository.getCommitEditor( "directory deleted" , null ); try { commitInfo = deleteDir( editor , "test" ); System.out.println( "The directory was deleted: " + commitInfo ); } catch ( SVNException svne ) { editor.abortEdit( ); throw svne; } //Delete directory "test2". editor = repository.getCommitEditor( "copied directory deleted" , null ); try { commitInfo = deleteDir( editor , "test2" ); System.out.println( "The copied directory was deleted: " + commitInfo ); } catch ( SVNException svne ) { editor.abortEdit( ); throw svne; } latestRevision = repository.getLatestRevision( ); System.out.println( "Repository latest revision (after committing): " + latestRevision ); ... } ...}
Repository latest revision (before committing): 0The directory was added: r1 by 'foo' at Tue Jun 27 15:46:59 NOVST 2006The file was changed: r2 by 'foo' at Tue Jun 27 15:46:59 NOVST 2006The directory was copied: r3 by 'foo' at Tue Jun 27 15:46:59 NOVST 2006The directory was deleted: r4 by 'foo' at Tue Jun 27 15:46:59 NOVST 2006The copied directory was deleted: r5 by 'foo' at Tue Jun 27 15:47:00 NOVST 2006Repository latest revision (after committing): 5
?
下载示例源码:?example program source code
?
?