package org.tmatesoft.svn.core.javahl17; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashSet; import java.util.Set; import org.apache.subversion.javahl.ClientException; import org.apache.subversion.javahl.ISVNRepos; import org.apache.subversion.javahl.SubversionException; import org.apache.subversion.javahl.callback.ReposNotifyCallback; import org.apache.subversion.javahl.types.Depth; import org.apache.subversion.javahl.types.Lock; import org.apache.subversion.javahl.types.Revision; import org.apache.subversion.javahl.types.Version; import org.tmatesoft.svn.core.SVNCancelException; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNLock; import org.tmatesoft.svn.core.SVNPropertyValue; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.io.fs.FSRepository; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.io.SVNRepositoryFactory; import org.tmatesoft.svn.core.wc.SVNWCUtil; import org.tmatesoft.svn.core.wc.admin.SVNAdminClient; import org.tmatesoft.svn.core.wc.admin.SVNAdminEvent; import org.tmatesoft.svn.core.wc.admin.SVNAdminEventAction; import org.tmatesoft.svn.core.wc.admin.SVNAdminEventAdapter; import org.tmatesoft.svn.core.wc.admin.SVNUUIDAction; import org.tmatesoft.svn.util.SVNLogType; public class SVNReposImpl { private SVNClientImpl client; private SVNAdminClient svnAdminClient; private boolean cancelOperation; /** * Filesystem in a Berkeley DB */ public static final String BDB = "bdb"; /** * Filesystem in the filesystem */ public static final String FSFS = "fsfs"; public SVNReposImpl() { client = SVNClientImpl.newInstance(); cancelOperation = false; } public void dispose() { client.dispose(); svnAdminClient = null; } public Version getVersion() { return client.getVersion(); } protected SVNAdminClient getAdminClient() { if (svnAdminClient == null) { svnAdminClient = new SVNAdminClient(SVNWCUtil.createDefaultAuthenticationManager(), SVNWCUtil.createDefaultOptions(true)); } return svnAdminClient; } public void create(File path, boolean disableFsyncCommit, boolean keepLog, File configPath, String fstype) throws ClientException { beforeOperation(); if (BDB.equalsIgnoreCase(fstype)) { notImplementedYet("Only " + FSFS + " type of repositories are supported by " + getVersion().toString()); } try { SVNRepositoryFactory.createLocalRepository(path, false, false); if (configPath != null) { } } catch (SVNException e) { throwException(e, client); } finally { afterOperation(); } } public void deltify(File path, Revision start, Revision end) throws ClientException { notImplementedYet(); } public void dump(File path, OutputStream dataOut, Revision start, Revision end, boolean incremental, boolean useDeltas, ReposNotifyCallback callback) throws ClientException { dump(path, dataOut, null, start, end, incremental, useDeltas, callback); } public void dump(File path, OutputStream dataOut, final OutputStream errorOut, Revision start, Revision end, boolean incremental, boolean useDeltas, ReposNotifyCallback callback) throws ClientException { beforeOperation(); OutputStream os = dataOut; try { getAdminClient().setEventHandler(new SVNAdminEventAdapter() { @Override public void checkCancelled() throws SVNCancelException { SVNReposImpl.this.checkCancelled(); } public void handleAdminEvent(SVNAdminEvent event, double progress) throws SVNException { if (errorOut != null && event.getAction() == SVNAdminEventAction.REVISION_DUMPED) { try { errorOut.write(event.getMessage().getBytes()); errorOut.write(client.getOptions().getNativeEOL()); } catch (IOException e) { } } } }); getAdminClient().doDump(path.getAbsoluteFile(), os, SVNClientImpl.getSVNRevision(start), SVNClientImpl.getSVNRevision(end), incremental, useDeltas); } catch (SVNException e) { try { if (errorOut != null) { errorOut.write(e.getErrorMessage().getFullMessage().getBytes("UTF-8")); errorOut.write(client.getOptions().getNativeEOL()); } } catch (IOException e1) { // } throwException(e, client); } finally { afterOperation(); } } public void hotcopy(File path, File targetPath, boolean cleanLogs) throws ClientException { beforeOperation(); try { getAdminClient().setEventHandler(new SVNAdminEventAdapter() { public void checkCancelled() throws SVNCancelException { SVNReposImpl.this.checkCancelled(); } }); getAdminClient().doHotCopy(path.getAbsoluteFile(), targetPath.getAbsoluteFile()); } catch (SVNException e) { throwException(e, client); } finally { afterOperation(); } } public void listDBLogs(File path, ISVNRepos.MessageReceiver receiver) throws ClientException { notImplementedYet("Only " + FSFS + " type of repositories are supported by " + getVersion().toString()); } public void listUnusedDBLogs(File path, ISVNRepos.MessageReceiver receiver) throws ClientException { notImplementedYet("Only " + FSFS + " type of repositories are supported by " + getVersion().toString()); } public void load(File path, InputStream dataInput, boolean ignoreUUID, boolean forceUUID, String relativePath, ReposNotifyCallback callback) throws ClientException { load(path, dataInput, ignoreUUID, forceUUID, false, false, relativePath, callback); } public void load(File path, InputStream dataInput, boolean ignoreUUID, boolean forceUUID, boolean usePreCommitHook, boolean usePostCommitHook, String relativePath, ReposNotifyCallback callback) throws ClientException { load(path, dataInput, null, ignoreUUID, forceUUID, usePreCommitHook, usePostCommitHook, relativePath, callback); } public void load(File path, InputStream dataInput, final OutputStream messageOutput, boolean ignoreUUID, boolean forceUUID, boolean usePreCommitHook, boolean usePostCommitHook, String relativePath, ReposNotifyCallback callback) throws ClientException { beforeOperation(); InputStream is = dataInput; try { SVNUUIDAction uuidAction = SVNUUIDAction.DEFAULT; if (ignoreUUID) { uuidAction = SVNUUIDAction.IGNORE_UUID; } else if (forceUUID) { uuidAction = SVNUUIDAction.FORCE_UUID; } getAdminClient().setEventHandler(new SVNAdminEventAdapter() { private boolean myIsNodeOpened; @Override public void checkCancelled() throws SVNCancelException { SVNReposImpl.this.checkCancelled(); } public void handleAdminEvent(SVNAdminEvent event, double progress) throws SVNException { if (messageOutput != null) { try { messageOutput.write(getLoadMessage(event).getBytes("UTF-8")); } catch (IOException e) { } } } protected String getLoadMessage(SVNAdminEvent event) { StringBuffer message = new StringBuffer(); if (event.getAction() != SVNAdminEventAction.REVISION_LOAD && myIsNodeOpened) { message.append(" done."); message.append(client.getOptions().getNativeEOL()); myIsNodeOpened = false; } if (event.getAction() == SVNAdminEventAction.REVISION_LOADED) { message.append(client.getOptions().getNativeEOL()); } message.append(event.getMessage()); message.append(client.getOptions().getNativeEOL()); if (event.getAction() == SVNAdminEventAction.REVISION_LOADED) { message.append(client.getOptions().getNativeEOL()); } myIsNodeOpened = event.getAction() != SVNAdminEventAction.REVISION_LOAD; return message.toString(); } }); getAdminClient().doLoad(path.getAbsoluteFile(), is, usePreCommitHook, usePostCommitHook, uuidAction, relativePath); } catch (SVNException e) { if (messageOutput != null) { try { messageOutput.write(e.getErrorMessage().getFullMessage().getBytes("UTF-8")); messageOutput.write(client.getOptions().getNativeEOL()); } catch (IOException e1) { } } throwException(e, client); } finally { afterOperation(); } } public void lstxns(File path, final ISVNRepos.MessageReceiver receiver) throws ClientException { beforeOperation(); getAdminClient().setEventHandler(new SVNAdminEventAdapter() { @Override public void checkCancelled() throws SVNCancelException { SVNReposImpl.this.checkCancelled(); } public void handleAdminEvent(SVNAdminEvent event, double progress) throws SVNException { if (receiver != null && event.getTxnName() != null) { receiver.receiveMessageLine(event.getTxnName()); } } }); try { getAdminClient().doListTransactions(path.getAbsoluteFile()); } catch (SVNException e) { throwException(e, client); } finally { afterOperation(); } } public long recover(File path, ReposNotifyCallback callback) throws ClientException { beforeOperation(); try { File repositoryRoot = path.getAbsoluteFile(); getAdminClient().doRecover(repositoryRoot); getAdminClient().setEventHandler(new SVNAdminEventAdapter(){ @Override public void checkCancelled() throws SVNCancelException { SVNReposImpl.this.checkCancelled(); } }); return getAdminClient().getYoungestRevision(repositoryRoot); } catch (SVNException e) { throwException(e, client); } finally { afterOperation(); } return -1; } public void rmtxns(File path, String[] transactions) throws ClientException { beforeOperation(); try { getAdminClient().setEventHandler(new SVNAdminEventAdapter() { @Override public void checkCancelled() throws SVNCancelException { SVNReposImpl.this.checkCancelled(); } }); getAdminClient().doRemoveTransactions(path.getAbsoluteFile(), transactions); } catch (SVNException e) { throwException(e, client); } finally { afterOperation(); } } public void setRevProp(File path, Revision rev, String propName, String propValue, boolean usePreRevPropChangeHook, boolean usePostRevPropChangeHook) throws SubversionException { beforeOperation(); try { setRevisionProperty(path, rev, propName, propValue, !usePreRevPropChangeHook, !usePostRevPropChangeHook); } catch (SVNException e) { throwException(e, client); } finally { afterOperation(); } } public void verify(File path, Revision start, Revision end, ReposNotifyCallback callback) throws ClientException { verify(path, null, start, end, callback); } public void verify(File path, final OutputStream messageOut, Revision start, Revision end, ReposNotifyCallback callback) throws ClientException { beforeOperation(); try { getAdminClient().setEventHandler(new SVNAdminEventAdapter() { public void handleAdminEvent(SVNAdminEvent event, double progress) throws SVNException { if (messageOut != null && event.getAction() == SVNAdminEventAction.REVISION_DUMPED) { try { messageOut.write(event.getMessage().getBytes()); messageOut.write(client.getOptions().getNativeEOL()); } catch (IOException e) { } } } }); getAdminClient().doVerify(path.getAbsoluteFile(), SVNClientImpl.getSVNRevision(start), SVNClientImpl.getSVNRevision(end)); } catch (SVNException e) { try { if (messageOut != null) { messageOut.write(e.getErrorMessage().getFullMessage().getBytes("UTF-8")); messageOut.write(client.getOptions().getNativeEOL()); } } catch (IOException e1) { // } throwException(e, client); } finally { afterOperation(); } } public Set<Lock> lslocks(File path, Depth depth) throws ClientException { beforeOperation(); final Set<Lock> locks = new HashSet<Lock>(); getAdminClient().setEventHandler(new SVNAdminEventAdapter() { public void handleAdminEvent(SVNAdminEvent event, double progress) throws SVNException { if (event.getAction() == SVNAdminEventAction.LOCK_LISTED) { SVNLock svnLock = event.getLock(); Lock lock = SVNClientImpl.getLock(svnLock); locks.add(lock); } } }); try { getAdminClient().doListLocks(path.getAbsoluteFile()); } catch (SVNException e) { throwException(e, client); } finally { afterOperation(); } return locks; } public void rmlocks(File path, String[] locks) throws ClientException { beforeOperation(); try { getAdminClient().doRemoveLocks(path.getAbsoluteFile(), locks); } catch (SVNException e) { throwException(e, client); } finally { afterOperation(); } } public void upgrade(File path, ReposNotifyCallback callback) throws ClientException { notImplementedYet(); } public void pack(File path, ReposNotifyCallback callback) throws ClientException { notImplementedYet(); } public void cancelOperation() throws ClientException { cancelOperation = true; } private void checkCancelled() throws SVNCancelException { if (cancelOperation) { cancelOperation = false; SVNErrorManager.cancel("operation cancelled", SVNLogType.DEFAULT); } } private static void setRevisionProperty(File path, Revision rev, String propName, String propValue, boolean bypassPreRevPropChangeHook, boolean bypassPostRevPropChangeHook) throws SVNException { SVNRepository repository = SVNRepositoryFactory.create(SVNURL.fromFile(path.getAbsoluteFile())); ((FSRepository) repository).setRevisionPropertyValue(SVNClientImpl.getSVNRevision(rev).getNumber(), propName, SVNPropertyValue.create(propValue), bypassPreRevPropChangeHook, bypassPostRevPropChangeHook); } private void notImplementedYet() throws ClientException { notImplementedYet(null); } private void notImplementedYet(String message) throws ClientException { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNSUPPORTED_FEATURE, message == null ? "Requested SVNAdmin functionality is not yet implemented" : message); throwException(new SVNException(err), client); } public static void throwException(SVNException e, SVNClientImpl svnClient) throws ClientException { ClientException ec = SVNClientImpl.getClientException(e); svnClient.getDebugLog().logFine(SVNLogType.DEFAULT, ec); svnClient.getDebugLog().logFine(SVNLogType.DEFAULT, e); throw ec; } private void beforeOperation() { cancelOperation = false; } private void afterOperation() { cancelOperation = false; getAdminClient().setEventHandler(null); } }