|
Intro
This section will introduce some articles on several parts of the JavaSVN API that give an extra description which can not be found in the Javadoc for the JavaSVN API classes. As needed this section will be enriched in future by including new articles covering frequently asked questions and misunderstandings that developers may have in using the API .
Table of Contents
1. How an update-related operation is performed using low-level API (org.tmatesoft.svn.core.io package)
1.1. How to use ISVNReporter
When SVNRepository.update(..)
is called ISVNReporterBaton.report(..)
is invoked to make reports (with the help of ISVNReporter) of the working files/directories
state. For example, if the scope is to update existing local copies to some
definite revision (that is passed to SVNRepository.update)
ISVNReporterBaton.report(..)
should describe to the server revisions of all the
copies if their revisions differ from the update target revision.
Suppose you have got the following tree you have somewhen checked out from a
repository:
/(4) /dirA(5)/ /dirB(6)/ /file1.txt(6) /dirC(4)/ /file2.txt(5) /file3.txt(7)
Numbers in brackets correspond to revisions. Well, you see that the root directory has the revision number=4, dirA - 5, dirB - 6 and so on. When you call SVNRepository.update to bring the root directory up to date say to revision 8 you should describe the revisions of all the entries top-down for each directory (starting with the root):
public void report(ISVNReporter
reporter) throwsSVNException
{ //for the root directory reporter.setPath("", null, 4, false); //for "/dirA" reporter.setPath("/dirA", null, 5, false); //for "/dirA/dirB" reporter.setPath("/dirA/dirB", null, 6, false); //for "/dirA/dirB/file1.txt" reporter.setPath("/dirA/dirB/file1.txt", null, 6, false); //for "/dirA/dirC" reporter.setPath("/dirA/dirC", null, 4, false); ....//and so on for all entries which revisions differ from 8 /* always called at the end of the report - when the state of the * entire tree is described. */ reporter.finishReport(); }
Several significant moments:
-
if some file was locked then you should provide the lock-token for
that entry as the 2nd parameter of
ISVNReporter.setPath(..)
. For example:/(4) /file.txt(7, locked)
file.txt is at the 7th revision and was locked.reporter.setPath("/file.txt", lockToken, 7, false);
Even though the revision of the locked file is the same as the target update revisionISVNReporter.setPath(..)
is called for such file anyway. -
The last parameter of
ISVNReporter.setPath(..)
- boolean flag startEmpty - must be true for a checkout. Also it's set to true for those directories that were not updated at a previous time due to errors (if such situation had a place). So, startEmpty = true means the directory is still empty. In other cases it must be false. -
If a user's local working copy is updated against a URL different from that
it was checked out from (being switched in other words), then instead of calling
reporter.setPath(..)
you should call:reporter.linkPath(newRepositoryLocation, path, lockToken, revision, false);
newRepositoryLocation is anSVNRepositoryLocation
which is the new parent root (meaning path is relative to this root since this moment). That's the only difference between just an update and a switch. -
If an entry was scheduled for deletion or if it's a missing directory (that was
accidentally deleted) then you should call:
//report that the path was deleted reporter.deletePath(path);
-
At the end of the report call
ISVNReporter.finishReport()
that denotes the end of the report. -
One more important moment: if during a report an exception occured - the report
failed - call
ISVNReporter.abortReport()
that properly finishes the report in a case of a fault.
1.2. How to use ISVNEditor
When ISVNReporterBaton
has finished his work and the server knows everything
of the user's working copy (dirs and files) state it sends to the client commands as
well as data (file/dir properties and file delta) to bring his copy up to date.
These commands are translated into calls to ISVNEditor
methods.
Suppose there's the following working copy tree which is being updated recursively (starting with the directory the update was initiated on and moving deep down) to 8th revision:
/(5) /dirA(5)/ /file1.txt(5) /file2.txt(5)Assume that only file1.txt is out of date and must be updated. The server sends commands to update the file which are translated into series of calls to
ISVNEditor
methods. Here is the scheme of this process (an implementor himself
doesn't make these calls, his aim is only to provide an ISVNEditor
implementation; the following is only an illustration describing how the JavaSVN
library invokes ISVNEditor
methods):
//sets the target revision the copy is being updated to. editor.targetRevision(revision); /* processing starts with the parent directory the update was * run for - "/"; now modifications can be applied to the opened * directory. */ editor.openRoot(revision); //changing root directory properties editor.changeDirProperty(propertyName1, propertyValue1); editor.changeDirProperty(propertyName2, propertyValue2); ..................................... //opens "/dirA". editor.openDir("/dirA", revision); /* now modifications can be applied to the opened directory. * For example, changing its properties. * Also all further calls like editor.openFile(..), * editor.addFile(..) or editor.openDir(..), editor.addDir(..) * are relative to the currently opened directory. */ editor.changeDirProperty(propertyName1, propertyValue1); editor.changeDirProperty(propertyName2, propertyValue2); ..................................... //opens file "file1.txt" to modify it editor.openFile("/dirA/file1.txt", revision); //changing properties of "file1.txt" editor.changeFileProperty(propertyName1, propertyValue1); editor.changeFileProperty(propertyName2, propertyValue2); ..................................... /* file contents are out of date - the server sends delta * (the difference between the local BASE-revision copy and * the file in the repository). * baseChecksum is provided by the server to make certain of * the delta will be applied correctly - the client should * compare it with his own one evaluated upon the contents of * the file at the BASE revision - that is the state of the file * it had just after the previous update (or checkout). If both * checksums match each other - it's ok, the delta can be applied * correctly, if don't - may be the local file is * corrupted, that's an error. */ editor.applyTextDelta(baseChecksum); /* well, if the previous step was ok, the next step is to receive * the delta itself. ISVNEditor.textDeltaChunk(..) receives * an SVNDiffWindow - this is an object which contains instructions * on how the delta (the entire delta or a part of it when the delta * is too big) must be applied. If the delta is too big * ISVNEditor.textDeltaChunk(..) is called several times to pass all * parts of the delta; in this case all passed diffWindows should be * accumulated and associated with their OutputStreams (each call to * ISVNEditor.textDeltaChunk(..) returns an OutputStream as a storage * where delta is written). */ OutputStream os = editor.textDeltaChunk(diffWindow); /* the following is called when all the delta is received. * that is where it's applied to a local file; in this illustration * "file1.txt" is modified. */ editor.textDeltaEnd(); /* the final point of the file modification: once again the server * sends a checksum to control if the resultant file ("file1.txt") * was modified correctly; the client repeats the operation of * comparing the got checksum with the own one evaluated upon the * resultant file contents. */ editor.closeFile(textChecksum); //closes the directory - "/dirA" editor.closeDir(); //closes the root directory - "/" editor.closeDir(); /* editing ends with a call to ISVNEditor.closeEdit() which returns * the commit information (SVNCommitInfo) - what revision the copy is * updated to, who is the author of the changes, when the changes were * committed. */ SVNCommitInfo commitInfo = editor.closeEdit();
That is how an update runs in common words. The described scheme is analogous for
the case when more than one file is out of date (what is more actual in reality),
the local copy tree is processed (by an ISVNEditor
) top-down for each directory
and file that must be updated.
Well, the case of a checkout is a little bit different. ISVNEditor.openDir(..)
and
ISVNEditor.openFile(..)
are not called, instead ISVNEditor.addDir(..)
, ISVNEditor.addFile(..)
are called for each directory and file to be checked out. This is a principal
model of how ISVNEditor
methods are invoked during a checkout (suppose we are
checking out some node tree from a repository what will lead us to the previous
illustrartion when the local copy already exists):
//sets the target revision of the copy being checked out. editor.targetRevision(revision); /* ISVNEditor.openRoot is not called; * setting root directory properties. */ editor.changeDirProperty(propertyName, propertyValue); /* adds "/dirA". copyDirFromPath & copyFromRevision - are irrelevant * in an update editor. * If you want to have a compatibility with the native Subversion * command line client in the case of a checkout (not simply an export) * an implementation of this method should create an administrative * area (.svn directory) for the directory being added ("/dirA"). */ editor.addDir("/dirA", copyDirFromPath, CopyFromRevision); /* setting the directory properties - they may be stored in the * previously created .svn directory (SVN command line client * compatibility). * Also all further calls like editor.addFile(..)/editor.addDir(..) * are relative to the added directory. */ editor.changeDirProperty(propertyName1, propertyValue1); editor.changeDirProperty(propertyName2, propertyValue2); ..................................... /* adds file "file1.txt". copyFileFromPath & copyFromRevision - are * irrelevant in an update editor. */ editor.addFile("/dirA/file1.txt", copyFileFromPath, CopyFromRevision); /* setting properties of "file1.txt". May be saved in .svn * directory (for compatibility with the native SVN command * line client). */ editor.changeFileProperty(propertyName1, propertyValue1); editor.changeFileProperty(propertyName2, propertyValue2); ..................................... /* if the file is empty - only ISVNEditor.applyTextDelta(..) * and ISVNEditor.textDeltaEnd(..) are called. Otherwise * ISVNEditor.textDeltaChunk(..) is also invoked. * baseChecksum is irrelevant for a checkout. */ editor.applyTextDelta(baseChecksum); //writing file contents (delta is contents in this case). OutputStream os1 = editor.textDeltaChunk(diffWindow1); //if "file1.txt" is too big... OutputStream os2 = editor.textDeltaChunk(diffWindow2); ..................................... //all contents are received, "file1.txt" can be created editor.textDeltaEnd(); /* the final point of the file modification: once again the * server sends a checksum to control if the resultant file * ("file1.txt") was transmitted and constructed correctly; * the client compares the got checksum with the own one * evaluated upon the resultant file contents. * It may be this method implementation where a copy of the * file ("file1.txt") - the BASE revision file copy - is * stored in .svn directory (for compatibility with the * native SVN command line client). */ editor.closeFile(textChecksum); /* again if you want to have a compatibility with the native * SVN command line client each entry (wheteher it's a file * or a directory) that is added should be reflected in its * parent's administrative directory - .svn */ //adds file "file2.txt". editor.addFile("/dirA/file2.txt", copyFileFromPath, CopyFromRevision); ............................................//so on //closes the directory - "/dirA" editor.closeDir(); //closes the root directory - "/" editor.closeDir(); SVNCommitInfo commitInfo = editor.closeEdit();