From 27851221c066106849f3c12549b609948583d1e5 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Jul 2013 11:32:28 +0400 Subject: [PATCH 01/30] IDEA-94942 initial svn 1.8 support with already existing command line functionality Replace SVNWCClient.doInfo calls with command line implementation Updated authentication support Updated several commands to command line implementation (not in all possible places) - add, cat, info --- plugins/svn4idea/bindSvn/bindSvn.iml | 11 + .../idea/svn/AuthenticationCallback.java | 4 + .../jetbrains/idea/svn/SvnCommitRunner.java | 2 +- .../idea/svn/commandLine/SvnCommand.java | 4 + .../idea/svn/commandLine/SvnCommandName.java | 4 +- .../idea/svn/commandLine/SvnLineCommand.java | 108 ++++++++- .../svn/commandLine/SvnSimpleCommand.java | 6 +- .../idea/svn/ForNestedRootChecker.java | 4 +- .../idea/svn/RootsToWorkingCopies.java | 51 ++-- .../idea/svn/SvnAuthenticationNotifier.java | 2 +- .../jetbrains/idea/svn/SvnBundle.properties | 1 + .../jetbrains/idea/svn/SvnChangeProvider.java | 4 +- .../idea/svn/SvnChangeProviderContext.java | 24 +- .../jetbrains/idea/svn/SvnConfigurable.form | 27 +-- .../idea/svn/SvnFileSystemListener.java | 25 +- .../idea/svn/SvnFileUrlMappingImpl.java | 11 +- .../jetbrains/idea/svn/SvnFormatSelector.java | 16 ++ .../idea/svn/SvnRecursiveStatusWalker.java | 44 ++-- .../src/org/jetbrains/idea/svn/SvnUtil.java | 228 +++++++++++------- .../src/org/jetbrains/idea/svn/SvnVcs.java | 92 ++++++- .../jetbrains/idea/svn/WorkingCopyFormat.java | 14 +- .../svn/annotate/SvnAnnotationProvider.java | 6 +- .../svn/branchConfig/DefaultConfigLoader.java | 2 +- .../SvnBranchConfigurationNew.java | 5 +- ...IdeaSvnkitBasedAuthenticationCallback.java | 6 + .../svn/checkin/SvnCheckinEnvironment.java | 40 ++- .../idea/svn/commandLine/SvnAddClient.java | 37 +++ .../idea/svn/commandLine/SvnCatClient.java | 25 ++ .../commandLine/SvnCommandLineInfoClient.java | 68 ++++-- .../SvnCommandLineStatusClient.java | 6 +- .../idea/svn/commandLine/SvnInfoHandler.java | 54 ++++- .../svn/commandLine/SvnInfoStructure.java | 1 + .../svn/dialogs/CreateBranchOrTagDialog.java | 27 +-- .../history/SvnCommittedChangesProvider.java | 5 +- .../history/SvnEditCommitMessageAction.java | 2 +- .../idea/svn/history/SvnHistorySession.java | 32 +-- .../IntegratedSelectedOptionsDialog.java | 15 +- .../idea/svn/mergeinfo/BranchInfo.java | 7 +- .../svn/update/AbstractSvnUpdatePanel.java | 13 +- .../idea/svn/update/MergeRootInfo.java | 15 +- .../idea/svn/update/SvnUpdateEnvironment.java | 26 +- .../idea/svn/update/UpdateRootInfo.java | 15 +- 42 files changed, 717 insertions(+), 372 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnAddClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java diff --git a/plugins/svn4idea/bindSvn/bindSvn.iml b/plugins/svn4idea/bindSvn/bindSvn.iml index 846587cef36f..fa6b992f74e3 100644 --- a/plugins/svn4idea/bindSvn/bindSvn.iml +++ b/plugins/svn4idea/bindSvn/bindSvn.iml @@ -20,6 +20,17 @@ + + + + + + + + + + + diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java index bdc9c2deb03c..26c0759c4b4b 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java @@ -16,6 +16,8 @@ package org.jetbrains.idea.svn; import org.jetbrains.annotations.Nullable; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.auth.SVNAuthentication; import java.io.File; import java.io.IOException; @@ -50,6 +52,8 @@ public interface AuthenticationCallback { */ boolean authenticateFor(@Nullable String realm, File base, boolean previousFailed, boolean passwordRequest); + SVNAuthentication requestCredentials(@Nullable SVNURL url); + /** * @return config directory if TMP was created */ diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java index 525d675303fc..23645129e600 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java @@ -96,7 +96,7 @@ public class SvnCommitRunner { return myCommandListener.getCommittedRevision(); } - private static class CommandListener extends LineCommandListener { + public static class CommandListener extends LineCommandListener { @Nullable private final CommitEventHandler myHandler; private SvnBindException myException; private long myCommittedRevision = Revision.SVN_INVALID_REVNUM; diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java index d6df6bae947e..4e89ef1fca91 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java @@ -186,6 +186,10 @@ public abstract class SvnCommand { } } + public String getCommandText() { + return myCommandLine.getCommandLineString(); + } + /** * check that process is not started yet * diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index 58c2ff2ab308..1b0f7a9b3b53 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -27,7 +27,9 @@ public enum SvnCommandName { st("st", false), up("up", true), ci("commit", true), - cleanup("cleanup", true); + cleanup("cleanup", true), + cat("cat", false), + add("add", true); private final String myName; private final boolean myWriteable; diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java index 5821d7a5fb18..ef87d953a632 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java @@ -23,6 +23,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.LineHandlerHelper; import com.intellij.openapi.vcs.LineProcessEventListener; import com.intellij.openapi.vcs.VcsException; +import com.intellij.util.ArrayUtil; import com.intellij.util.EventDispatcher; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -30,13 +31,22 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.AuthenticationCallback; import org.jetbrains.idea.svn.SvnBindUtil; import org.jetbrains.idea.svn.config.SvnBindException; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.auth.SVNAuthentication; +import org.tmatesoft.svn.core.auth.SVNPasswordAuthentication; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Created with IntelliJ IDEA. @@ -52,6 +62,7 @@ public class SvnLineCommand extends SvnCommand { public static final String PASSPHRASE_FOR = "Passphrase for"; public static final String UNABLE_TO_CONNECT = "svn: E170001:"; public static final String CANNOT_AUTHENTICATE_TO_PROXY = "Could not authenticate to proxy server"; + public static final String AUTHENTICATION_FAILED_MESSAGE = "Authentication failed"; // kept for exact text //public static final String CLIENT_CERTIFICATE_FILENAME = "Client certificate filename:"; @@ -66,6 +77,7 @@ public class SvnLineCommand extends SvnCommand { private final EventDispatcher myLineListeners; private final AtomicReference myExitCode; private final StringBuffer myErr; + private final StringBuffer myOut; public SvnLineCommand(File workingDirectory, @NotNull SvnCommandName commandName, @NotNull @NonNls String exePath) { this(workingDirectory, commandName, exePath, null); @@ -76,6 +88,7 @@ public class SvnLineCommand extends SvnCommand { myLineListeners = EventDispatcher.create(LineProcessEventListener.class); myExitCode = new AtomicReference(); myErr = new StringBuffer(); + myOut = new StringBuffer(); } @Override @@ -94,8 +107,20 @@ public class SvnLineCommand extends SvnCommand { SvnCommandName commandName, final LineCommandListener listener, @Nullable AuthenticationCallback authenticationCallback, - final String... parameters) throws SvnBindException { - File base = firstFile.isDirectory() ? firstFile : firstFile.getParentFile(); + String... parameters) throws SvnBindException { + runWithAuthenticationAttempt(exePath, firstFile, null, commandName, listener, authenticationCallback, false, parameters); + } + + + public static void runWithAuthenticationAttempt(final String exePath, + final File firstFile, + final SVNURL url, + SvnCommandName commandName, + final LineCommandListener listener, + @Nullable AuthenticationCallback authenticationCallback, + boolean needCleanup, + String... parameters) throws SvnBindException { + File base = firstFile != null ? (firstFile.isDirectory() ? firstFile : firstFile.getParentFile()) : null; base = SvnBindUtil.correctUpToExistingParent(base); listener.baseDirectory(base); @@ -114,13 +139,16 @@ public class SvnLineCommand extends SvnCommand { if (command.myErr.length() > 0) { final String errText = command.myErr.toString().trim(); if (authenticationCallback != null) { - final AuthCallbackCase callback = createCallback(errText, authenticationCallback, base); + final AuthCallbackCase callback = createCallback(errText, authenticationCallback, base, url); if (callback != null) { - cleanup(exePath, commandName, base); + if (needCleanup) { + cleanup(exePath, commandName, base); + } if (callback.getCredentials(errText)) { if (authenticationCallback.getSpecialConfigDir() != null) { configDir = authenticationCallback.getSpecialConfigDir(); } + parameters = updateParameters(callback, parameters); continue; } } @@ -140,6 +168,27 @@ public class SvnLineCommand extends SvnCommand { } } + private static String[] updateParameters(AuthCallbackCase callback, String[] parameters) { + String[] result = parameters; + + if (callback instanceof UsernamePasswordCallback && + ((UsernamePasswordCallback)callback).getAuthentication() instanceof SVNPasswordAuthentication) { + SVNPasswordAuthentication auth = (SVNPasswordAuthentication)((UsernamePasswordCallback)callback).getAuthentication(); + List p = new ArrayList(Arrays.asList(parameters)); + + p.add("--username"); + p.add(auth.getUserName()); + p.add("--password"); + p.add(auth.getPassword()); + if (!auth.isStorageAllowed()) { + p.add("--no-auth-cache"); + } + result = ArrayUtil.toStringArray(p); + } + + return result; + } + private static void writeIdeaConfig2SubversionConfig(@NotNull AuthenticationCallback authenticationCallback, @NotNull File base) throws SvnBindException { if (authenticationCallback.haveDataForTmpConfig()) { try { @@ -158,7 +207,7 @@ public class SvnLineCommand extends SvnCommand { } } - private static AuthCallbackCase createCallback(final String errText, final AuthenticationCallback callback, final File base) { + private static AuthCallbackCase createCallback(final String errText, final AuthenticationCallback callback, final File base, final SVNURL url) { if (errText.startsWith(CERTIFICATE_ERROR)) { return new CertificateCallbackCase(callback, base); } @@ -171,9 +220,54 @@ public class SvnLineCommand extends SvnCommand { if (errText.startsWith(UNABLE_TO_CONNECT) && errText.contains(CANNOT_AUTHENTICATE_TO_PROXY)) { return new ProxyCallback(callback, base); } + if (errText.contains(AUTHENTICATION_FAILED_MESSAGE)) { + return new UsernamePasswordCallback(callback, base, url); + } return null; } + private static class UsernamePasswordCallback extends AuthCallbackCase { + private SVNAuthentication myAuthentication; + private SVNURL myUrl; + + protected UsernamePasswordCallback(AuthenticationCallback callback, File base, SVNURL url) { + super(callback, base); + myUrl = url; + } + + @Override + boolean getCredentials(String errText) throws SvnBindException { + myAuthentication = myAuthenticationCallback.requestCredentials(myUrl != null ? myUrl : parseUrlFromError(errText)); + + return true; + } + + private SVNURL parseUrlFromError(String errorText) { + Pattern pattern = Pattern.compile("Unable to connect to a repository at URL '(.*)'"); + Matcher matcher = pattern.matcher(errorText); + String urlValue = null; + + if (matcher.find()) { + urlValue = matcher.group(1); + } + + return urlValue != null ? parseUrl(urlValue) : null; + } + + private SVNURL parseUrl(String urlValue) { + try { + return SVNURL.parseURIDecoded(urlValue); + } + catch (SVNException e) { + return null; + } + } + + public SVNAuthentication getAuthentication() { + return myAuthentication; + } + } + private static class ProxyCallback extends AuthCallbackCase { protected ProxyCallback(AuthenticationCallback callback, File base) { super(callback, base); @@ -192,7 +286,7 @@ public class SvnLineCommand extends SvnCommand { @Override boolean getCredentials(String errText) throws SvnBindException { - final String realm = cutFirstLine(errText).substring(AUTHENTICATION_REALM.length()).trim(); + final String realm = errText.startsWith(AUTHENTICATION_REALM) ? cutFirstLine(errText).substring(AUTHENTICATION_REALM.length()).trim() : null; final boolean isPassword = StringUtil.containsIgnoreCase(errText, "password"); if (myTried) { myAuthenticationCallback.clearPassiveCredentials(realm, myBase, isPassword); @@ -320,6 +414,8 @@ public class SvnLineCommand extends SvnCommand { command.addLineListener(new LineProcessEventListener() { @Override public void onLineAvailable(String line, Key outputType) { + command.myOut.append(line); + if (SvnCommand.LOG.isDebugEnabled()) { SvnCommand.LOG.debug("==> " + line); } diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java index 75c43befb6cb..a088da0334a3 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java @@ -94,7 +94,11 @@ public class SvnSimpleCommand extends SvnCommand { if (myException != null) throw myException; final int code = getExitCode(); if (code == 0) { - return myStdout.toString(); + String result = myStdout.toString(); + + LOG.debug(result); + + return result; } else { final String msg = new StringBuilder("Svn process exited with error code: ").append(code).append("\n") .append("stderr: ").append(myStderr.toString()).append("\nstdout: ").append(getStdout().toString()) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/ForNestedRootChecker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/ForNestedRootChecker.java index 4559a3e603e2..660edef07f08 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/ForNestedRootChecker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/ForNestedRootChecker.java @@ -49,16 +49,14 @@ public class ForNestedRootChecker { private static class UrlConstructor { final SvnVcs myVcs; - final SVNWCClient myClient; private UrlConstructor(final SvnVcs vcs) { myVcs = vcs; - myClient = myVcs.createWCClient(); } @Nullable public Real createReal(final VirtualFile file, final VirtualFile vcsRoot) { - final SVNInfo info = myVcs.getInfo(file); + final SVNInfo info = myVcs.runInfoCommand(file); if (info == null || info.getRepositoryRootURL() == null || info.getURL() == null) { return null; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/RootsToWorkingCopies.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/RootsToWorkingCopies.java index 6cd0df2744d1..5ca7f9eaa39b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/RootsToWorkingCopies.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/RootsToWorkingCopies.java @@ -123,52 +123,31 @@ public class RootsToWorkingCopies implements VcsListener { @Nullable private WorkingCopy calculateRoot(final VirtualFile root) { + File workingCopyRoot = SvnUtil.getWorkingCopyRootNew(new File(root.getPath())); WorkingCopy workingCopy = null; - final File ioFile = new File(root.getPath()); - File workingCopyRoot = null; - try { - workingCopyRoot = SVNWCUtil.getWorkingCopyRoot(ioFile, true); - if (workingCopyRoot != null) { - // ok to use low-level 1.6 API, 1.7 is checked below - SVNWCAccess wcAccess = SVNWCAccess.newInstance(null); - try { - wcAccess.probeOpen(workingCopyRoot, false, 0); - SVNEntry entry = wcAccess.getVersionedEntry(workingCopyRoot, false); - final SVNURL url = entry.getSVNURL(); - if (url != null) { - workingCopy = new WorkingCopy(workingCopyRoot, url, false); - } - } finally { - wcAccess.close(); - } - } - } - catch (SVNException e) { - // - } - if (workingCopy == null) { - workingCopyRoot = SvnUtil.getWcCopyRootIf17(ioFile, null); - if (workingCopyRoot != null) { - final SVNInfo svnInfo; - try { - svnInfo = SvnVcs.getInstance(myProject).createWCClient().doInfo(workingCopyRoot, SVNRevision.UNDEFINED); - workingCopy = new WorkingCopy(workingCopyRoot, svnInfo.getURL(), true); - } - catch (SVNException e) { - // - } + + if (workingCopyRoot != null) { + final SVNInfo svnInfo = myVcs.getInfo(workingCopyRoot); + + if (svnInfo != null && svnInfo.getURL() != null) { + workingCopy = new WorkingCopy(workingCopyRoot, svnInfo.getURL(), true); } } + + return registerWorkingCopy(root, workingCopy); + } + + private WorkingCopy registerWorkingCopy(@NotNull VirtualFile root, @Nullable WorkingCopy resolvedWorkingCopy) { synchronized (myLock) { - if (workingCopy == null) { + if (resolvedWorkingCopy == null) { myRootMapping.remove(root); myUnversioned.add(root); } else { myUnversioned.remove(root); - myRootMapping.put(root, workingCopy); + myRootMapping.put(root, resolvedWorkingCopy); } } - return workingCopy; + return resolvedWorkingCopy; } public void clear() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java index 8a94f0076acf..56e55bb86bdd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java @@ -350,7 +350,7 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl - + @@ -29,7 +29,7 @@ - + @@ -87,7 +87,7 @@ - + @@ -96,7 +96,7 @@ - + @@ -123,36 +123,29 @@ - + - + - - - - - - - - - + - + - + + diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java index 062c412f2336..d61f3575afd8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java @@ -44,10 +44,8 @@ import com.intellij.util.containers.MultiMap; import com.intellij.vcsUtil.ActionWithTempFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.tmatesoft.svn.core.SVNErrorCode; -import org.tmatesoft.svn.core.SVNErrorMessage; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNNodeKind; +import org.jetbrains.idea.svn.commandLine.SvnAddClient; +import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.wc.*; @@ -160,10 +158,10 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } private class UUIDHelper { - private final SVNWCClient myWcClient; + private final SvnVcs myVcs; private UUIDHelper(final SvnVcs vcs) { - myWcClient = vcs.createWCClient(); + myVcs = vcs; } /** @@ -175,7 +173,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp final SVNInfo info1 = new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws SVNException { - myT = myWcClient.doInfo(new File(dir.getPath()), SVNRevision.UNDEFINED); + myT = myVcs.getInfo(new File(dir.getPath())); } }.compute(); if (info1 == null || info1.getRepositoryUUID() == null) { @@ -793,7 +791,18 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws SVNException { - wcClient.doAdd(ioFile, true, false, false, true); + WorkingCopyFormat format = vcs.getWorkingCopyFormat(ioFile); + + if (WorkingCopyFormat.ONE_DOT_EIGHT.equals(format)) { + SvnAddClient client = new SvnAddClient(project); + try { + client.add(ioFile, null, false, false, true); + } catch(VcsException e) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); + } + } else { + wcClient.doAdd(ioFile, true, false, false, true); + } } }.execute(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java index 46545c43a4cc..711bb8045f91 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java @@ -312,8 +312,8 @@ public class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentState LOG.info("Error: cannot find repository URL for versioned folder: " + foundRoot.getFile().getPath()); } else { myRepositoryRoots.register(repoRoot); - myTopRoots.add(new RootUrlInfo(repoRoot, foundRoot.getInfo().getURL(), - SvnFormatSelector.getWorkingCopyFormat(new File(foundRoot.getFile().getPath())), foundRoot.getFile(), vcsRoot)); + myTopRoots.add(new RootUrlInfo(repoRoot, foundRoot.getInfo().getURL(), SvnFormatSelector.findRootAndGetFormat( + new File(foundRoot.getFile().getPath())), foundRoot.getFile(), vcsRoot)); } } } @@ -538,11 +538,12 @@ public class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentState if (copyRoot == null || vcsRoot == null) continue; final SvnVcs vcs = SvnVcs.getInstance(myProject); - final SVNInfo svnInfo = vcs.getInfo(copyRoot); + final SVNInfo svnInfo = vcs.runInfoCommand(copyRoot); if ((svnInfo == null) || (svnInfo.getRepositoryRootURL() == null)) continue; - final RootUrlInfo info = new RootUrlInfo(svnInfo.getRepositoryRootURL(), svnInfo.getURL(), - SvnFormatSelector.getWorkingCopyFormat(svnInfo.getFile()), copyRoot, vcsRoot); + final RootUrlInfo info = + new RootUrlInfo(svnInfo.getRepositoryRootURL(), svnInfo.getURL(), SvnFormatSelector.findRootAndGetFormat(svnInfo.getFile()), + copyRoot, vcsRoot); mapping.add(info); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFormatSelector.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFormatSelector.java index 94d21dbbbd9d..77783badc2f8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFormatSelector.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFormatSelector.java @@ -16,6 +16,7 @@ package org.jetbrains.idea.svn; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.util.WaitForProgressToShow; @@ -37,6 +38,9 @@ import java.util.Collections; import java.util.Iterator; public class SvnFormatSelector implements ISVNAdminAreaFactorySelector { + + private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnFormatSelector"); + public Collection getEnabledFactories(File path, Collection factories, boolean writeAccess) throws SVNException { if (ApplicationManager.getApplication().isUnitTestMode()) { return factories; @@ -145,7 +149,19 @@ public class SvnFormatSelector implements ISVNAdminAreaFactorySelector { return newMode[0]; } + public static WorkingCopyFormat findRootAndGetFormat(final File path) { + File root = SvnUtil.getWorkingCopyRootNew(path); + + return root != null ? getWorkingCopyFormat(root) : WorkingCopyFormat.UNKNOWN; + } + public static WorkingCopyFormat getWorkingCopyFormat(final File path) { + WorkingCopyFormat format = SvnUtil.getFormat(path); + + return WorkingCopyFormat.UNKNOWN.equals(format) ? detectWithSvnKit(path) : format; + } + + private static WorkingCopyFormat detectWithSvnKit(File path) { try { final SvnWcGeneration svnWcGeneration = SvnOperationFactory.detectWcGeneration(path, true); if (SvnWcGeneration.V17.equals(svnWcGeneration)) return WorkingCopyFormat.ONE_DOT_SEVEN; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java index 4a49dc16a153..dd926b464736 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java @@ -47,13 +47,15 @@ import java.util.LinkedList; public class SvnRecursiveStatusWalker { private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnRecursiveStatusWalker"); private final StatusWalkerPartner myPartner; + private final SvnVcs myVcs; private final Project myProject; private final StatusReceiver myReceiver; private final LinkedList myQueue; private final MyHandler myHandler; - public SvnRecursiveStatusWalker(final Project project, final StatusReceiver receiver, final StatusWalkerPartner partner) { - myProject = project; + public SvnRecursiveStatusWalker(final SvnVcs vcs, final StatusReceiver receiver, final StatusWalkerPartner partner) { + myVcs = vcs; + myProject = vcs.getProject(); myReceiver = receiver; myPartner = partner; myQueue = new LinkedList(); @@ -61,7 +63,7 @@ public class SvnRecursiveStatusWalker { } public void go(final FilePath rootPath, final SVNDepth depth) throws SVNException { - final MyItem root = new MyItem(myProject, rootPath, depth, myPartner.createStatusClient(), false); + final MyItem root = new MyItem(myVcs, rootPath, depth, myPartner.createStatusClient(), false); myQueue.add(root); while (! myQueue.isEmpty()) { @@ -83,7 +85,7 @@ public class SvnRecursiveStatusWalker { } } else { try { - final SVNStatus status = item.getClient().doStatus(ioFile, false, false); + final SVNStatus status = item.getClient(ioFile).doStatus(ioFile, false, false); myReceiver.process(path, status); } catch (SVNException e) { handleStatusException(item, path, e); @@ -115,18 +117,20 @@ public class SvnRecursiveStatusWalker { private final Project myProject; private final FilePath myPath; private final SVNDepth myDepth; - private final SVNStatusClient myClient; private final SvnStatusClientI mySvnClient; + private final SvnStatusClientI myCommandLineClient; private final boolean myIsInnerCopyRoot; private final SvnConfiguration myConfiguration17; + private final SvnVcs myVcs; - private MyItem(Project project, FilePath path, SVNDepth depth, SVNStatusClient client, boolean isInnerCopyRoot) { - myProject = project; + private MyItem(SvnVcs vcs, FilePath path, SVNDepth depth, SVNStatusClient client, boolean isInnerCopyRoot) { + myVcs = vcs; + myProject = vcs.getProject(); myConfiguration17 = SvnConfiguration.getInstance(myProject); myPath = path; myDepth = depth; - myClient = client; mySvnClient = new SvnkitSvnStatusClient(client); + myCommandLineClient = new SvnCommandLineStatusClient(myProject); myIsInnerCopyRoot = isInnerCopyRoot; } @@ -138,11 +142,13 @@ public class SvnRecursiveStatusWalker { return myDepth; } - public SvnStatusClientI getClient() { - return mySvnClient; - } - public SvnStatusClientI getClient(final File file) { + WorkingCopyFormat format = myVcs.getWorkingCopyFormat(file); + + if (format == WorkingCopyFormat.ONE_DOT_EIGHT) { + return myCommandLineClient; + } + if (! SVNDepth.INFINITY.equals(myDepth)) { return mySvnClient; } @@ -150,8 +156,9 @@ public class SvnRecursiveStatusWalker { if (CheckJavaHL.isPresent() && SvnConfiguration.UseAcceleration.javaHL.equals(myConfiguration17.myUseAcceleration) && Svn17Detector.is17(myProject, file)) { return new JavaHLSvnStatusClient(myProject); - } else if (SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration17.myUseAcceleration) && Svn17Detector.is17(myProject, file)) { - return new SvnCommandLineStatusClient(myProject); + } else if (SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration17.myUseAcceleration)) { + // apply command line disregarding working copy format + return myCommandLineClient; } return mySvnClient; } @@ -186,7 +193,7 @@ public class SvnRecursiveStatusWalker { return true; } if (file.isDirectory() && new File(file, SVNFileUtil.getAdminDirectoryName()).exists()) { - final MyItem childItem = new MyItem(myProject, path, newDepth, myPartner.createStatusClient(), true); + final MyItem childItem = new MyItem(myVcs, path, newDepth, myPartner.createStatusClient(), true); myQueue.add(childItem); } else if (vf != null) { myReceiver.processUnversioned(vf); @@ -228,12 +235,13 @@ public class SvnRecursiveStatusWalker { } public void checkIfCopyRootWasReported(@Nullable final SVNStatus ioFileStatus, final File ioFile) { - if (! myMetCurrentItem && FileUtil.filesEqual(ioFile, myCurrentItem.getPath().getIOFile())) { + File itemFile = myCurrentItem.getPath().getIOFile(); + if (! myMetCurrentItem && FileUtil.filesEqual(ioFile, itemFile)) { myMetCurrentItem = true; SVNStatus statusInner; try { statusInner = ioFileStatus != null ? ioFileStatus : - myCurrentItem.getClient().doStatus(myCurrentItem.getPath().getIOFile(), false); + myCurrentItem.getClient(itemFile).doStatus(itemFile, false); } catch (SVNException e) { LOG.info(e); @@ -294,7 +302,7 @@ public class SvnRecursiveStatusWalker { //myReceiver.processUnversioned(vFile); //processRecursively(vFile, myCurrentItem.getDepth()); } else { - final MyItem childItem = new MyItem(myProject, new FilePathImpl(vFile), SVNDepth.INFINITY, + final MyItem childItem = new MyItem(myVcs, new FilePathImpl(vFile), SVNDepth.INFINITY, myPartner.createStatusClient(), true); myQueue.add(childItem); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index 0c049ac4671d..b5d5b3152147 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -31,10 +31,7 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangesUtil; import com.intellij.openapi.vcs.impl.ContentRevisionCache; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VfsUtilCore; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.vfs.*; import com.intellij.openapi.wm.impl.status.StatusBarUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.Convertor; @@ -44,7 +41,10 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; +import org.jetbrains.idea.svn.commandLine.SvnCatClient; import org.jetbrains.idea.svn.dialogs.LockDialog; +import org.tmatesoft.sqljet.core.SqlJetException; +import org.tmatesoft.sqljet.core.table.SqlJetDb; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; @@ -71,13 +71,9 @@ public class SvnUtil { private SvnUtil() { } public static boolean isSvnVersioned(final Project project, File parent) { - try { - final SVNInfo info = SvnVcs.getInstance(project).createWCClient().doInfo(parent, SVNRevision.UNDEFINED); - return info != null; - } - catch (SVNException e) { - return false; - } + final SVNInfo info = SvnVcs.getInstance(project).getInfo(parent); + + return info != null; } public static Collection crawlWCRoots(final Project project, File path, SvnWCRootCrawler callback, ProgressIndicator progress) { @@ -123,15 +119,8 @@ public class SvnUtil { @Nullable public static String getExactLocation(final SvnVcs vcs, File path) { - try { - SVNWCClient wcClient = vcs.createWCClient(); - SVNInfo info = wcClient.doInfo(path, SVNRevision.UNDEFINED); - if (info != null && info.getURL() != null) { - return info.getURL().toString(); - } - } - catch (SVNException ignored) { } - return null; + SVNInfo info = vcs.getInfo(path); + return info != null && info.getURL() != null ? info.getURL().toString() : null; } public static Map getLocationInfoForModule(final SvnVcs vcs, File path, ProgressIndicator progress) { @@ -288,7 +277,9 @@ public class SvnUtil { } public static String formatRepresentation(final WorkingCopyFormat format) { - if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)) { + if (WorkingCopyFormat.ONE_DOT_EIGHT.equals(format)) { + return SvnBundle.message("dialog.show.svn.map.table.version18.text"); + } else if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)) { return SvnBundle.message("dialog.show.svn.map.table.version17.text"); } else if (WorkingCopyFormat.ONE_DOT_SIX.equals(format)) { return SvnBundle.message("dialog.show.svn.map.table.version16.text"); @@ -352,6 +343,54 @@ public class SvnUtil { return result; } + /** + * Gets working copy internal format. Works for 1.7 and 1.8. + * + * @param path + * @return + */ + public static WorkingCopyFormat getFormat(final File path) { + int format = 0; + File dbFile = resolveDatabase(path); + + if (dbFile != null) { + SqlJetDb db = null; + try { + db = SqlJetDb.open(dbFile, false); + format = db.getOptions().getUserVersion(); + } + catch (SqlJetException e) { + LOG.error(e); + } finally { + if (db != null) { + try { + db.close(); + } + catch (SqlJetException e) { + LOG.error(e); + } + } + } + } + + return WorkingCopyFormat.getInstance(format); + } + + private static File resolveDatabase(final File path) { + File dbFile = getWcDb(path); + File result = null; + + try { + if (dbFile.exists() && dbFile.isFile()) { + result = dbFile; + } + } catch (SecurityException e) { + LOG.error("Failed to access working copy database", e); + } + + return result; + } + private static class LocationsCrawler implements SvnWCRootCrawler { private final SvnVcs myVcs; private final Map myLocations; @@ -371,15 +410,9 @@ public class SvnUtil { oldText = progress.getText(); progress.setText(SvnBundle.message("progress.text.discovering.location", root.getAbsolutePath())); } - try { - SVNWCClient wcClient = myVcs.createWCClient(); - SVNInfo info = wcClient.doInfo(root, SVNRevision.UNDEFINED); - if (info != null && info.getURL() != null) { - myLocations.put(info.getURL().toString(), info.getFile()); - } - } - catch (SVNException e) { - // + SVNInfo info = myVcs.getInfo(root); + if (info != null && info.getURL() != null) { + myLocations.put(info.getURL().toString(), info.getFile()); } if (progress != null) { progress.setText(oldText); @@ -389,20 +422,15 @@ public class SvnUtil { @Nullable public static String getRepositoryUUID(final SvnVcs vcs, final File file) { - final SVNWCClient client = vcs.createWCClient(); - try { - final SVNInfo info = client.doInfo(file, SVNRevision.UNDEFINED); - return (info == null) ? null : info.getRepositoryUUID(); - } catch (SVNException e) { - return null; - } + final SVNInfo info = vcs.getInfo(file); + return info != null ? info.getRepositoryUUID() : null; } @Nullable public static String getRepositoryUUID(final SvnVcs vcs, final SVNURL url) { - final SVNWCClient client = vcs.createWCClient(); try { - final SVNInfo info = client.doInfo(url, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED); + final SVNInfo info = vcs.getInfo(url, SVNRevision.UNDEFINED); + return (info == null) ? null : info.getRepositoryUUID(); } catch (SVNException e) { return null; @@ -411,19 +439,14 @@ public class SvnUtil { @Nullable public static SVNURL getRepositoryRoot(final SvnVcs vcs, final File file) { - final SVNWCClient client = vcs.createWCClient(); - try { - final SVNInfo info = client.doInfo(file, SVNRevision.UNDEFINED); - return (info == null) ? null : info.getRepositoryRootURL(); - } catch (SVNException e) { - return null; - } + final SVNInfo info = vcs.getInfo(file); + return info != null ? info.getRepositoryRootURL() : null; } @Nullable public static SVNURL getRepositoryRoot(final SvnVcs vcs, final String url) { try { - return getRepositoryRoot(vcs, SVNURL.parseURIEncoded(url), true); + return getRepositoryRoot(vcs, SVNURL.parseURIEncoded(url)); } catch (SVNException e) { return null; @@ -431,18 +454,14 @@ public class SvnUtil { } @Nullable - public static SVNURL getRepositoryRoot(final SvnVcs vcs, final SVNURL url, boolean allowRemote) throws SVNException { - final SVNWCClient client = vcs.createWCClient(); - SVNInfo info = client.doInfo(url, SVNRevision.UNDEFINED, SVNRevision.HEAD); + public static SVNURL getRepositoryRoot(final SvnVcs vcs, final SVNURL url) throws SVNException { + SVNInfo info = vcs.getInfo(url, SVNRevision.HEAD); + return (info == null) ? null : info.getRepositoryRootURL(); } public static boolean isWorkingCopyRoot(final File file) { - try { - return SVNWCUtil.isWorkingCopyRoot(file); - } catch (SVNException e) { - return false; - } + return FileUtil.filesEqual(file, getWorkingCopyRootNew(file)); } @Nullable @@ -548,17 +567,9 @@ public class SvnUtil { } public static SVNDepth getDepth(final SvnVcs vcs, final File file) { - final SVNWCClient client = vcs.createWCClient(); - try { - final SVNInfo svnInfo = client.doInfo(file, SVNRevision.UNDEFINED); - if (svnInfo != null) { - return svnInfo.getDepth(); - } - } - catch (SVNException e) { - // - } - return SVNDepth.UNKNOWN; + SVNInfo info = vcs.getInfo(file); + + return info != null && info.getDepth() != null ? info.getDepth() : SVNDepth.UNKNOWN; } public static boolean seemsLikeVersionedDir(final VirtualFile file) { @@ -590,21 +601,17 @@ public class SvnUtil { } public static SVNURL getCommittedURL(final SvnVcs vcs, final File file) { - final File root = getWorkingCopyRoot(file); - if (root == null) return null; - return getUrl(vcs, root); + final File root = getWorkingCopyRootNew(file); + + return root == null ? null : getUrl(vcs, root); } @Nullable public static SVNURL getUrl(final SvnVcs vcs, final File file) { - try { - final SVNInfo info = vcs.createWCClient().doInfo(file, SVNRevision.UNDEFINED); - return info == null ? null : info.getURL(); // todo for moved items? - } - catch (SVNException e) { - LOG.debug(e); - return null; - } + // todo for moved items? + final SVNInfo info = vcs.getInfo(file); + + return info == null ? null : info.getURL(); } public static boolean doesRepositorySupportMergeInfo(final SvnVcs vcs, final SVNURL url) { @@ -648,17 +655,9 @@ public class SvnUtil { @Nullable public static File getWcCopyRootIf17(final File file, @Nullable final File upperBound) { - File current = file; - boolean wcDbFound = false; - while (current != null) { - File wcDb; - if ((wcDb = getWcDb(current)).exists() && ! wcDb.isDirectory()) { - wcDbFound = true; - break; - } - current = current.getParentFile(); - } - if (! wcDbFound) return null; + File current = getParentWithDb(file); + if (current == null) return null; + while (current != null) { try { final SvnWcGeneration svnWcGeneration = SvnOperationFactory.detectWcGeneration(current, false); @@ -674,6 +673,40 @@ public class SvnUtil { return null; } + /** + * Utility method that deals also with 1.8 working copies. + * TODO: Should be renamed when all parts updated for 1.8. + * + * @param file + * @return + */ + @Nullable + public static File getWorkingCopyRootNew(final File file) { + File current = getParentWithDb(file); + if (current == null) return getWorkingCopyRoot(file); + + WorkingCopyFormat format = getFormat(current); + + return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) || WorkingCopyFormat.ONE_DOT_SEVEN.equals(format) + ? current + : getWorkingCopyRoot(file); + } + + private static File getParentWithDb(File file) { + File current = file; + boolean wcDbFound = false; + while (current != null) { + File wcDb; + if ((wcDb = getWcDb(current)).exists() && ! wcDb.isDirectory()) { + wcDbFound = true; + break; + } + current = current.getParentFile(); + } + if (! wcDbFound) return null; + return current; + } + public static boolean is17CopyPart(final File file) { try { return SvnWcGeneration.V17.equals(SvnOperationFactory.detectWcGeneration(file, true)); @@ -706,6 +739,25 @@ public class SvnUtil { public static byte[] getFileContents(final SvnVcs vcs, final String path, final boolean isUrl, final SVNRevision revision, final SVNRevision pegRevision) throws VcsException { + + File file = new File(path); + WorkingCopyFormat format = vcs.getWorkingCopyFormat(file); + + return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) + ? getFileContentsCommandLine(vcs, file) + : getFileContentWithSvnKit(vcs, path, isUrl, revision, pegRevision); + } + + private static byte[] getFileContentsCommandLine(SvnVcs vcs, File file) throws VcsException { + // TODO: Enhance command to use all parameters - isUrl, revision, pegRevision + SvnCatClient client = new SvnCatClient(vcs.getProject()); + String content = client.getFileContents(file); + + return CharsetToolkit.getUtf8Bytes(content); + } + + private static byte[] getFileContentWithSvnKit(SvnVcs vcs, String path, boolean isUrl, SVNRevision revision, SVNRevision pegRevision) + throws VcsException { final int maxSize = VcsUtil.getMaxVcsLoadedFileSize(); ByteArrayOutputStream buffer = new ByteArrayOutputStream() { @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index 748fc86c694c..1b0ed4cb9867 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -70,6 +70,7 @@ import org.jetbrains.idea.svn.actions.SvnMergeProvider; import org.jetbrains.idea.svn.annotate.SvnAnnotationProvider; import org.jetbrains.idea.svn.checkin.SvnCheckinEnvironment; import org.jetbrains.idea.svn.checkout.SvnCheckoutProvider; +import org.jetbrains.idea.svn.commandLine.SvnCommandLineInfoClient; import org.jetbrains.idea.svn.commandLine.SvnExecutableChecker; import org.jetbrains.idea.svn.dialogs.SvnBranchPointsCalculator; import org.jetbrains.idea.svn.dialogs.WCInfo; @@ -79,6 +80,7 @@ import org.jetbrains.idea.svn.history.SvnCommittedChangesProvider; import org.jetbrains.idea.svn.history.SvnHistoryProvider; import org.jetbrains.idea.svn.lowLevel.PrimitivePool; import org.jetbrains.idea.svn.networking.SSLProtocolExceptionParser; +import org.jetbrains.idea.svn.portable.SvnWcClientI; import org.jetbrains.idea.svn.rollback.SvnRollbackEnvironment; import org.jetbrains.idea.svn.update.SvnIntegrateEnvironment; import org.jetbrains.idea.svn.update.SvnUpdateEnvironment; @@ -911,24 +913,96 @@ public class SvnVcs extends AbstractVcs { return new File(file, pathToDirProps); } + public SVNInfo runInfoCommand(final File file) { + SVNInfo result = null; + + try { + result = SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration.myUseAcceleration) + ? getInfoCommandLine(file) + : getInfoSvnKit(file); + } + catch (SVNException e) { + handleInfoException(e); + } + + return result; + } + + public SVNInfo runInfoCommand(final VirtualFile file) { + return runInfoCommand(new File(file.getPath())); + } + + public SVNInfo getInfo(@NotNull SVNURL url, SVNRevision revision, ISVNAuthenticationManager manager) throws SVNException { + if (SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration.myUseAcceleration)) { + return createInfoClient().doInfo(url, SVNRevision.UNDEFINED, revision); + } else { + return (manager != null ? createWCClient(manager) : createWCClient()).doInfo(url, SVNRevision.UNDEFINED, SVNRevision.HEAD); + } + } + + public SVNInfo getInfo(@NotNull SVNURL url, SVNRevision revision) throws SVNException { + return getInfo(url, revision, null); + } + @Nullable - public SVNInfo getInfo(final VirtualFile file) { + public SVNInfo getInfo(@NotNull final VirtualFile file) { final File ioFile = new File(file.getPath()); return getInfo(ioFile); } - public SVNInfo getInfo(File ioFile) { + @Nullable + public SVNInfo getInfo(@NotNull String path) { + return getInfo(new File(path)); + } + + @Nullable + public SVNInfo getInfo(@NotNull File ioFile) { + WorkingCopyFormat format = getWorkingCopyFormat(ioFile); + SVNInfo result = null; + try { - SVNWCClient wcClient = createWCClient(); - SVNInfo info = wcClient.doInfo(ioFile, SVNRevision.UNDEFINED); - if (info == null || info.getRepositoryRootURL() == null) { - info = wcClient.doInfo(ioFile, SVNRevision.HEAD); - } - return info; + result = format == WorkingCopyFormat.ONE_DOT_EIGHT ? getInfoCommandLine(ioFile) : runInfoCommand(ioFile); } catch (SVNException e) { - return null; + handleInfoException(e); } + + return result; + } + + private void handleInfoException(SVNException e) { + final SVNErrorCode errorCode = e.getErrorMessage().getErrorCode(); + + if (SVNErrorCode.WC_PATH_NOT_FOUND.equals(errorCode) || + SVNErrorCode.UNVERSIONED_RESOURCE.equals(errorCode) || SVNErrorCode.WC_NOT_WORKING_COPY.equals(errorCode)) { + LOG.debug(e); + } else { + LOG.error(e); + } + } + + private SVNInfo getInfoSvnKit(@NotNull File ioFile) throws SVNException { + SVNWCClient wcClient = createWCClient(); + SVNInfo info = wcClient.doInfo(ioFile, SVNRevision.UNDEFINED); + if (info == null || info.getRepositoryRootURL() == null) { + info = wcClient.doInfo(ioFile, SVNRevision.HEAD); + } + return info; + } + + private SVNInfo getInfoCommandLine(@NotNull File ioFile) throws SVNException { + SvnCommandLineInfoClient client = new SvnCommandLineInfoClient(myProject); + return client.doInfo(ioFile, SVNRevision.UNDEFINED); + } + + private SvnWcClientI createInfoClient() { + return new SvnCommandLineInfoClient(myProject); + } + + public WorkingCopyFormat getWorkingCopyFormat(@NotNull File ioFile) { + RootUrlInfo rootInfo = getSvnFileUrlMapping().getWcRootForFilePath(ioFile); + + return rootInfo != null ? rootInfo.getFormat() : WorkingCopyFormat.UNKNOWN; } public void refreshSSLProperty() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopyFormat.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopyFormat.java index d40f947a71ee..c007541816c5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopyFormat.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopyFormat.java @@ -15,19 +15,22 @@ */ package org.jetbrains.idea.svn; -import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb; - /** * since not all constants are available from svnkit & constants are fixed */ public enum WorkingCopyFormat { + ONE_DOT_THREE(4, false, false, false, SvnBundle.message("dialog.show.svn.map.table.version13.text")), ONE_DOT_FOUR(8, false, false, false, SvnBundle.message("dialog.show.svn.map.table.version14.text")), ONE_DOT_FIVE(9, true, true, false, SvnBundle.message("dialog.show.svn.map.table.version15.text")), ONE_DOT_SIX(10, true, true, true, SvnBundle.message("dialog.show.svn.map.table.version16.text")), ONE_DOT_SEVEN(12, true, true, true, SvnBundle.message("dialog.show.svn.map.table.version17.text")), + ONE_DOT_EIGHT(12, true, true, true, SvnBundle.message("dialog.show.svn.map.table.version18.text")), UNKNOWN(0, false, false, false, "unknown"); + public static final int INTERNAL_FORMAT_17 = 29; + public static final int INTERNAL_FORMAT_18 = 31; + private final int myFormat; private final boolean myChangelistSupport; private final boolean myMergeInfoSupport; @@ -60,10 +63,11 @@ public enum WorkingCopyFormat { public static WorkingCopyFormat getInstance(final int value) { // somewhy 1.7 wc format can also be 29 - if (ISVNWCDb.WC_FORMAT_17 == value) { + if (INTERNAL_FORMAT_17 == value) { return ONE_DOT_SEVEN; - } - if (ONE_DOT_FIVE.getFormat() == value) { + } else if (INTERNAL_FORMAT_18 == value) { + return ONE_DOT_EIGHT; + } else if (ONE_DOT_FIVE.getFormat() == value) { return ONE_DOT_FIVE; } else if (ONE_DOT_FOUR.getFormat() == value) { return ONE_DOT_FOUR; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java index d0885c8a293e..93c55a1331da 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java @@ -99,8 +99,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn final SvnFileAnnotation result = new SvnFileAnnotation(myVcs, file, contents, lastChangedRevision); - SVNWCClient wcClient = myVcs.createWCClient(); - info = wcClient.doInfo(ioFile, SVNRevision.UNDEFINED); + info = myVcs.getInfo(ioFile); if (info == null) { exception[0] = new VcsException(new SVNException(SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "File ''{0}'' is not under version control", ioFile))); return; @@ -214,8 +213,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn final String relativePath = FileUtil.getRelativePath(root.getPath(), wasFile.getPath(), File.separatorChar); if (relativePath == null) throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString()); - SVNWCClient wcClient = myVcs.createWCClient(); - SVNInfo wcRootInfo = wcClient.doInfo(root, SVNRevision.UNDEFINED); + SVNInfo wcRootInfo = myVcs.getInfo(root); if (wcRootInfo == null || wcRootInfo.getURL() == null) { throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString()); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultConfigLoader.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultConfigLoader.java index 021568aac806..2b779fd0de70 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultConfigLoader.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultConfigLoader.java @@ -49,7 +49,7 @@ public class DefaultConfigLoader { final SvnVcs vcs = SvnVcs.getInstance(project); File rootFile = new File(vcsRoot.getPath()); - final SVNInfo info = vcs.createWCClient().doInfo(rootFile, SVNRevision.UNDEFINED); + final SVNInfo info = vcs.getInfo(rootFile); if (info == null || info.getURL() == null) { LOG.info("Directory is not a working copy: " + vcsRoot.getPresentableUrl()); return null; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java index 28e74e7c395e..483bfda7cfd3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java @@ -223,9 +223,8 @@ public class SvnBranchConfigurationNew { private BranchRootSearcher(final SvnVcs vcs, final VirtualFile root) throws SVNException { myRoot = root; myBranchesUnder = new HashMap(); - final SVNWCClient client = vcs.createWCClient(); - final SVNInfo info = client.doInfo(new File(myRoot.getPath()), SVNRevision.UNDEFINED); - myRootUrl = info.getURL(); + final SVNInfo info = vcs.getInfo(myRoot.getPath()); + myRootUrl = info != null ? info.getURL() : null; } public boolean accept(final String url) throws SVNException { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java index 995646f50d45..fba10664bd5d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java @@ -77,6 +77,12 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall return new CredentialsAuthenticator(myVcs).tryAuthenticate(realm, url, file, previousFailed, passwordRequest); } + @Override + public SVNAuthentication requestCredentials(@Nullable SVNURL url) { + return url != null ? myVcs.getSvnConfiguration().getInteractiveManager(myVcs).getProvider().requestClientAuthentication( + ISVNAuthenticationManager.PASSWORD, url, url.toDecodedString(), null, null, true) : null; + } + @Override public boolean acceptSSLServerCertificate(final File file, final String realm) { final File base = getExistingParent(file); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java index 433e4063e02c..16efee33ada9 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java @@ -177,7 +177,7 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { if (committables.isEmpty()) { return; } - if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(format) && + if (WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) || WorkingCopyFormat.ONE_DOT_SEVEN.equals(format) && SvnConfiguration.UseAcceleration.commandLine.equals(SvnConfiguration.getInstance(mySvnVcs.getProject()).myUseAcceleration) && (SvnAuthenticationManager.HTTP.equals(url.getProtocol()) || SvnAuthenticationManager.HTTPS.equals(url.getProtocol()))) { doWithCommandLine(committables, comment, exception, feedback); @@ -348,25 +348,19 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { private List getCommitables(List paths) { final Adder adder = new Adder(); - SVNStatusClient statusClient = mySvnVcs.createStatusClient(); for (File path : paths) { File file = path.getAbsoluteFile(); adder.add(file); if (file.getParentFile() != null) { - addParents(statusClient, file.getParentFile(), adder); + addParents(file.getParentFile(), adder); } } return adder.getResult(); } - private static void addParents(SVNStatusClient statusClient, File file, final Adder adder) { - SVNStatus status; - try { - status = statusClient.doStatus(file, false); - } - catch (SVNException e) { - return; - } + private void addParents(File file, final Adder adder) { + SVNStatus status = getStatus(file); + if (status != null && (SvnVcs.svnStatusIs(status, SVNStatusType.STATUS_ADDED) || SvnVcs.svnStatusIs(status, SVNStatusType.STATUS_REPLACED))) { @@ -374,11 +368,33 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { adder.add(file); file = file.getParentFile(); if (file != null) { - addParents(statusClient, file, adder); + addParents(file, adder); } } } + private SVNStatus getStatus(File file) { + SVNStatus result = null; + WorkingCopyFormat format = mySvnVcs.getWorkingCopyFormat(file); + + try { + result = WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) ? getStatusCommandLine(file) : getStatusSvnKit(file); + } + catch (SVNException e) { + // do nothing + } + + return result; + } + + private SVNStatus getStatusSvnKit(File file) throws SVNException { + return mySvnVcs.createStatusClient().doStatus(file, false); + } + + private SVNStatus getStatusCommandLine(File file) throws SVNException { + return new SvnCommandLineStatusClient(mySvnVcs.getProject()).doStatus(file, false); + } + private static List collectPaths(final List changes) { // case sensitive.. ArrayList result = new ArrayList(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnAddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnAddClient.java new file mode 100644 index 000000000000..b8606d5914e2 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnAddClient.java @@ -0,0 +1,37 @@ +package org.jetbrains.idea.svn.commandLine; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.tmatesoft.svn.core.SVNDepth; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnAddClient { + private Project myProject; + + public SvnAddClient(@NotNull Project project) { + myProject = project; + } + + public void add(@NotNull File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) throws VcsException { + SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, null, SvnCommandName.add); + command.addParameters(file.getAbsolutePath()); + if (depth != null) { + command.addParameters("--depth", depth.getName()); + } + if (makeParents) { + command.addParameters("--parents"); + } + if (includeIgnored) { + command.addParameters("--no-ignore"); + } + if (force) { + command.addParameters("--force"); + } + command.run(); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java new file mode 100644 index 000000000000..63cd7e2e6dc7 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java @@ -0,0 +1,25 @@ +package org.jetbrains.idea.svn.commandLine; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnCatClient { + + private Project myProject; + + public SvnCatClient(@NotNull Project project) { + myProject = project; + } + + public String getFileContents(@NotNull File file) throws VcsException { + SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, null, SvnCommandName.cat); + command.addParameters(file.getAbsolutePath()); + return command.run(); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java index 0d2f4d00bd39..9c44ba0d0432 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java @@ -15,13 +15,19 @@ */ package org.jetbrains.idea.svn.commandLine; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; +import org.jetbrains.idea.svn.SvnApplicationSettings; import org.jetbrains.idea.svn.SvnBindUtil; +import org.jetbrains.idea.svn.SvnCommitRunner; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; +import org.jetbrains.idea.svn.config.SvnBindException; import org.jetbrains.idea.svn.portable.SvnExceptionWrapper; import org.jetbrains.idea.svn.portable.SvnkitSvnWcClient; import org.tmatesoft.svn.core.*; @@ -36,7 +42,9 @@ import javax.xml.parsers.SAXParserFactory; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** * Created with IntelliJ IDEA. @@ -45,9 +53,12 @@ import java.util.Collection; * Time: 12:59 PM */ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { + + private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.commandLine.SvnCommandLineInfoClient"); private final Project myProject; public SvnCommandLineInfoClient(final Project project) { + // TODO: Remove svn kit client instantiation super(SvnVcs.getInstance(project).createWCClient()); myProject = project; } @@ -76,21 +87,20 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { // very unrealistic throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), new RuntimeException("Can not find existing parent file")); } - final SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, base, SvnCommandName.info); + issueCommand(path.getPath(), pegRevision, revision, depth, changeLists, handler, base); + } - if (depth != null) { - command.addParameters("--depth", depth.getName()); - } - if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) { - command.addParameters("-r", revision.toString()); - } - command.addParameters("--xml"); + private void issueCommand(String path, SVNRevision pegRevision, + SVNRevision revision, + SVNDepth depth, + Collection changeLists, + final ISVNInfoHandler handler, File base) throws SVNException { + final SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, base, SvnCommandName.info); + List parameters = new ArrayList(); + + fillParameters(path, pegRevision, revision, depth, parameters); + command.addParameters(parameters); SvnCommandLineStatusClient.changelistsToCommand(changeLists, command); - if (pegRevision != null && ! SVNRevision.UNDEFINED.equals(pegRevision) && ! SVNRevision.WORKING.equals(pegRevision)) { - command.addParameters(path.getPath() + "@" + pegRevision.toString()); - } else { - command.addParameters(path.getPath()); - } final SvnInfoHandler[] infoHandler = new SvnInfoHandler[1]; infoHandler[0] = new SvnInfoHandler(base, new Consumer() { @@ -138,6 +148,23 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { } } + private void fillParameters(String path, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, Collection parameters) { + if (depth != null) { + parameters.add("--depth"); + parameters.add(depth.getName()); + } + if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) { + parameters.add("-r"); + parameters.add(revision.toString()); + } + parameters.add("--xml"); + if (pegRevision != null && ! SVNRevision.UNDEFINED.equals(pegRevision) && ! SVNRevision.WORKING.equals(pegRevision)) { + parameters.add(path + "@" + pegRevision.toString()); + } else { + parameters.add(path); + } + } + @Override public void doInfo(SVNURL url, SVNRevision pegRevision, SVNRevision revision, boolean recursive, ISVNInfoHandler handler) throws SVNException { @@ -147,7 +174,20 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { @Override public void doInfo(SVNURL url, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, ISVNInfoHandler handler) throws SVNException { - throw new UnsupportedOperationException(); + String path = url.toDecodedString(); + List parameters = new ArrayList(); + + fillParameters(path, pegRevision, revision, depth, parameters); + try { + String exe = SvnApplicationSettings.getInstance().getCommandLinePath(); + SvnLineCommand.runWithAuthenticationAttempt(exe, + new File(exe), url, SvnCommandName.info, new SvnCommitRunner.CommandListener(null), + new IdeaSvnkitBasedAuthenticationCallback(SvnVcs.getInstance(myProject)), false, + ArrayUtil.toStringArray(parameters)); + } + catch (SvnBindException e) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); + } } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java index a1a31536c8a9..6341b7c0c160 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java @@ -15,6 +15,7 @@ */ package org.jetbrains.idea.svn.commandLine; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -48,6 +49,8 @@ import java.util.Map; * Time: 5:21 PM */ public class SvnCommandLineStatusClient implements SvnStatusClientI { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient"); + private final Project myProject; private final SvnCommandLineInfoClient myInfoClient; @@ -116,7 +119,8 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { parser.parse(new ByteArrayInputStream(result.getBytes(CharsetToolkit.UTF8_CHARSET)), svnHandl[0]); if (! svnHandl[0].isAnythingReported()) { if (! SvnUtil.isSvnVersioned(myProject, path)) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY)); + throw new SVNException( + SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY, "Command - " + command.getCommandText() + ". Result - " + result)); } } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java index 022130e4a9f6..841eebbcdea0 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java @@ -49,7 +49,7 @@ public class SvnInfoHandler extends DefaultHandler { public SvnInfoHandler(File base, final Consumer infoConsumer) { myBase = base; myInfoConsumer = infoConsumer; - myPending = new SvnInfoStructure(); + myPending = createPending(); myElementsMap = new HashMap>(); fillElements(); myParseStack = new ArrayList(); @@ -70,7 +70,14 @@ public class SvnInfoHandler extends DefaultHandler { myInfoConsumer.consume(info); } myResultsMap.put(info.getFile(), info); - myPending = new SvnInfoStructure(); + myPending = createPending(); + } + + private SvnInfoStructure createPending() { + SvnInfoStructure pending = new SvnInfoStructure(); + pending.myDepth = SVNDepth.INFINITY; + + return pending; } @Override @@ -252,6 +259,24 @@ public class SvnInfoHandler extends DefaultHandler { return new Url(); } }); + myElementsMap.put("relative-url", new Getter() { + @Override + public ElementHandlerBase get() { + return new RelativeUrl(); + } + }); + myElementsMap.put("lock", new Getter() { + @Override + public ElementHandlerBase get() { + return new Lock(); + } + }); + myElementsMap.put("created", new Getter() { + @Override + public ElementHandlerBase get() { + return new Date(); + } + }); myElementsMap.put("uuid", new Getter() { @Override public ElementHandlerBase get() { @@ -698,11 +723,34 @@ public class SvnInfoHandler extends DefaultHandler { } } + private static class RelativeUrl extends Url{ + @Override + public void characters(String s, SvnInfoStructure structure) throws SAXException { + structure.relativeUrl = s; + } + } + + private static class Lock extends ElementHandlerBase { + private Lock() { + super(new String[]{"created"}, new String[]{}); + } + + @Override + protected void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException { + // TODO: + } + + @Override + public void characters(String s, SvnInfoStructure structure) throws SAXException { + // TODO: + } + } + private static class Entry extends ElementHandlerBase { private final File myBase; private Entry(final File base) { - super(new String[]{"url","repository","wc-info","commit","conflict","tree-conflict"}, new String[]{}); + super(new String[]{"url", "relative-url", "lock", "repository","wc-info","commit","conflict","tree-conflict"}, new String[]{}); myBase = base; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoStructure.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoStructure.java index 0292b7d93614..1aa5248c1939 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoStructure.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoStructure.java @@ -34,6 +34,7 @@ import java.util.Date; */ public class SvnInfoStructure { public File myFile; + public String relativeUrl; public SVNURL myUrl; public SVNURL myRootURL; public long myRevision; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CreateBranchOrTagDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CreateBranchOrTagDialog.java index 62fc918d8a92..e1ad9157ce7b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CreateBranchOrTagDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CreateBranchOrTagDialog.java @@ -263,17 +263,11 @@ public class CreateBranchOrTagDialog extends DialogWrapper { super.init(); SvnVcs vcs = SvnVcs.getInstance(myProject); String revStr = ""; - try { - SVNWCClient client = vcs.createWCClient(); - SVNInfo info = client.doInfo(mySrcFile, SVNRevision.UNDEFINED); - if (info != null) { - mySrcURL = info.getURL() == null ? null : info.getURL().toString(); - revStr = String.valueOf(info.getRevision()); - myURL = mySrcURL; - } - } - catch (SVNException e) { - // + SVNInfo info = vcs.getInfo(mySrcFile); + if (info != null) { + mySrcURL = info.getURL() == null ? null : info.getURL().toString(); + revStr = String.valueOf(info.getRevision()); + myURL = mySrcURL; } if (myURL == null) { return; @@ -354,15 +348,8 @@ public class CreateBranchOrTagDialog extends DialogWrapper { return true; } else if (myWorkingCopyRadioButton.isSelected()) { - String srcUrl; - try { - SVNWCClient client = SvnVcs.getInstance(myProject).createWCClient(); - SVNInfo info = client.doInfo(mySrcFile, SVNRevision.UNDEFINED); - srcUrl = info != null && info.getURL() != null ? info.getURL().toString() : null; - } - catch (SVNException e) { - srcUrl = null; - } + SVNInfo info = SvnVcs.getInstance(myProject).getInfo(mySrcFile); + String srcUrl = info != null && info.getURL() != null ? info.getURL().toString() : null; if (srcUrl == null) { myErrorLabel.setText(SvnBundle.message("create.branch.no.working.copy.error", myWorkingCopyField.getText())); return false; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index 7ef0b2f3d0b6..3552853a8479 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -518,9 +518,8 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi revisionBefore = SVNRevision.create(revision); svnurl = SVNURL.parseURIEncoded(url); - final SVNWCClient client = myVcs.createWCClient(); - final SVNInfo info = client.doInfo(svnurl, SVNRevision.UNDEFINED, SVNRevision.HEAD); - targetInfo = client.doInfo(new File(file.getPath()), SVNRevision.UNDEFINED); + final SVNInfo info = myVcs.getInfo(svnurl, SVNRevision.HEAD); + targetInfo = myVcs.getInfo(new File(file.getPath())); if (info == null) { throw new VcsException("Can not get repository URL"); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnEditCommitMessageAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnEditCommitMessageAction.java index 5ca1150869ae..d67e29b598a0 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnEditCommitMessageAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnEditCommitMessageAction.java @@ -137,7 +137,7 @@ public class SvnEditCommitMessageAction extends AnAction { final String url = myLocation.getURL(); final SVNURL root; try { - root = SvnUtil.getRepositoryRoot(myVcs, SVNURL.parseURIEncoded(url), true); + root = SvnUtil.getRepositoryRoot(myVcs, SVNURL.parseURIEncoded(url)); if (root == null) { myException = new VcsException("Can not determine repository root for URL: " + url); return; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistorySession.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistorySession.java index e30f8ca216cb..171b39cad623 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistorySession.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistorySession.java @@ -20,21 +20,19 @@ import com.intellij.openapi.vcs.history.*; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnRevisionNumber; import org.jetbrains.idea.svn.SvnVcs; -import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNRevision; -import org.tmatesoft.svn.core.wc.SVNWCClient; import java.io.File; import java.util.List; /** -* Created with IntelliJ IDEA. -* User: Irina.Chernushina -* Date: 4/27/12 -* Time: 12:24 PM -* To change this template use File | Settings | File Templates. -*/ + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 4/27/12 + * Time: 12:24 PM + * To change this template use File | Settings | File Templates. + */ public class SvnHistorySession extends VcsAbstractHistorySession { private final SvnVcs myVcs; private final FilePath myCommittedPath; @@ -71,19 +69,8 @@ public class SvnHistorySession extends VcsAbstractHistorySession { } public static VcsRevisionNumber getCurrentCommittedRevision(final SvnVcs vcs, final File file) { - try { - SVNWCClient wcClient = vcs.createWCClient(); - SVNInfo info = wcClient.doInfo(file, SVNRevision.UNDEFINED); - if (info != null) { - return new SvnRevisionNumber(info.getCommittedRevision()); - } - else { - return null; - } - } - catch (SVNException e) { - return null; - } + SVNInfo info = vcs.getInfo(file); + return info != null ? new SvnRevisionNumber(info.getCommittedRevision()) : null; } public FilePath getCommittedPath() { @@ -101,7 +88,8 @@ public class SvnHistorySession extends VcsAbstractHistorySession { @Override public VcsHistorySession copy() { - return new SvnHistorySession(myVcs, getRevisionList(), myCommittedPath, myHaveMergeSources, getCurrentRevisionNumber(), true, myHasLocalSource); + return new SvnHistorySession(myVcs, getRevisionList(), myCommittedPath, myHaveMergeSources, getCurrentRevisionNumber(), true, + myHasLocalSource); } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/IntegratedSelectedOptionsDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/IntegratedSelectedOptionsDialog.java index 78718a7a0264..bfb9f1ff22c3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/IntegratedSelectedOptionsDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/IntegratedSelectedOptionsDialog.java @@ -251,19 +251,10 @@ public class IntegratedSelectedOptionsDialog extends DialogWrapper { @Nullable private static SVNURL realTargetUrl(final SvnVcs vcs, final WorkingCopyInfo info, final String targetBranchUrl) { - final SVNWCClient client = vcs.createWCClient(); - try { - final SVNInfo svnInfo = client.doInfo(new File(info.getLocalPath()), SVNRevision.UNDEFINED); - final SVNURL svnurl = svnInfo.getURL(); + final SVNInfo svnInfo = vcs.getInfo(info.getLocalPath()); + final SVNURL svnurl = svnInfo != null ? svnInfo.getURL() : null; - if ((svnurl != null) && (svnurl.toString().startsWith(targetBranchUrl))) { - return svnurl; - } - } - catch (SVNException e) { - // tracked by return value - } - return null; + return (svnurl != null) && (svnurl.toString().startsWith(targetBranchUrl)) ? svnurl : null; } @Nullable diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java index b6c6a898b85a..bc08fff144dc 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java @@ -238,12 +238,7 @@ public class BranchInfo { } private SVNInfo getInfo(final File pathFile) { - try { - return myClient.doInfo(pathFile, SVNRevision.UNDEFINED); - } catch (SVNException e) { - // - } - return null; + return myVcs.getInfo(pathFile); } private SvnMergeInfoCache.MergeCheckResult checkPathGoingUp(final long revisionAsked, final long targetRevision, final String branchRootPath, diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdatePanel.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdatePanel.java index ecc3fa6b5204..d6bdf63cafc8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdatePanel.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdatePanel.java @@ -109,17 +109,8 @@ public abstract class AbstractSvnUpdatePanel { @Nullable private SVNURL getUrlFor(@NotNull final FilePath root) { - try { - SVNWCClient wcClient = myVCS.createWCClient(); - final SVNInfo info = wcClient.doInfo(root.getIOFile(), SVNRevision.UNDEFINED); - if (info != null) { - return info.getURL(); - } - return null; - } - catch (SVNException e) { - return null; - } + final SVNInfo info = myVCS.getInfo(root.getIOFile()); + return info != null ? info.getURL() : null; } protected abstract JComponent getPanel(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/MergeRootInfo.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/MergeRootInfo.java index b8ea0520ebc2..96701b519111 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/MergeRootInfo.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/MergeRootInfo.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.svn.update; import org.jetbrains.idea.svn.SvnVcs; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.SVNWCClient; @@ -33,17 +34,9 @@ public class MergeRootInfo { myRevision1 = SVNRevision.HEAD; myRevision2 = SVNRevision.HEAD; - try { - SVNWCClient wcClient = vcs.createWCClient(); - final SVNURL url = wcClient.doInfo(file, SVNRevision.UNDEFINED).getURL(); - myUrl1 = url.toString(); - myUrl2 = url.toString(); - } - catch (SVNException e) { - myUrl1 = ""; - myUrl2 = ""; - } - + SVNInfo info = vcs.getInfo(file); + myUrl1 = info != null && info.getURL() != null ? info.getURL().toString() : ""; + myUrl2 = myUrl1; } public SVNURL getUrl1() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java index 80e43aaf7828..79190ebd541e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java @@ -33,7 +33,6 @@ import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.SVNUpdateClient; -import org.tmatesoft.svn.core.wc.SVNWCClient; import java.io.File; import java.util.ArrayList; @@ -104,12 +103,14 @@ public class SvnUpdateEnvironment extends AbstractSvnUpdateIntegrateEnvironment private SvnUpdateClientI createUpdateClient(SvnConfiguration configuration, File root, boolean isSwitch, SVNURL sourceUrl) { final SvnUpdateClientI updateClient; + boolean is18Format = myVcs.getWorkingCopyFormat(root) == WorkingCopyFormat.ONE_DOT_EIGHT; + // do not do from command line for switch now - if (! isSwitch && SvnConfiguration.UseAcceleration.commandLine.equals(configuration.myUseAcceleration) && + if (! isSwitch && (is18Format || SvnConfiguration.UseAcceleration.commandLine.equals(configuration.myUseAcceleration) && Svn17Detector.is17(myVcs.getProject(), root) && ( SvnAuthenticationManager.HTTP.equals(sourceUrl.getProtocol()) || SvnAuthenticationManager.HTTPS.equals(sourceUrl.getProtocol()) - )) { + ))) { updateClient = new SvnCommandLineUpdateClient(myVcs.getProject(), null); } else { updateClient = new SvnSvnkitUpdateClient(myVcs.createUpdateClient()); @@ -129,18 +130,8 @@ public class SvnUpdateEnvironment extends AbstractSvnUpdateIntegrateEnvironment @Nullable private static SVNURL getSourceUrl(final SvnVcs vcs, final File root) { - try { - SVNWCClient wcClient = vcs.createWCClient(); - final SVNInfo svnInfo = wcClient.doInfo(root, SVNRevision.UNDEFINED); - if (svnInfo != null) { - return svnInfo.getURL(); - } else { - return null; - } - } - catch (SVNException e) { - return null; - } + final SVNInfo svnInfo = vcs.getInfo(root); + return svnInfo != null ? svnInfo.getURL() : null; } public boolean validateOptions(final Collection roots) { @@ -193,9 +184,8 @@ public class SvnUpdateEnvironment extends AbstractSvnUpdateIntegrateEnvironment // false - do not do update private boolean checkAncestry(final File sourceFile, final SVNURL targetUrl, final SVNRevision targetRevision) throws SVNException { - final SVNWCClient client = myVcs.createWCClient(); - final SVNInfo sourceSvnInfo = client.doInfo(sourceFile, SVNRevision.UNDEFINED); - final SVNInfo targetSvnInfo = client.doInfo(targetUrl, SVNRevision.UNDEFINED, targetRevision); + final SVNInfo sourceSvnInfo = myVcs.getInfo(sourceFile); + final SVNInfo targetSvnInfo = myVcs.getInfo(targetUrl, targetRevision); if (sourceSvnInfo == null || targetSvnInfo == null) { // cannot check diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/UpdateRootInfo.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/UpdateRootInfo.java index 4852e9f6b95f..201260e232f2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/UpdateRootInfo.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/UpdateRootInfo.java @@ -31,20 +31,9 @@ public class UpdateRootInfo { public UpdateRootInfo(File file, SvnVcs vcs) { myRevision = SVNRevision.HEAD; - try { - SVNWCClient wcClient = vcs.createWCClient(); - SVNInfo info = wcClient.doInfo(file, SVNRevision.UNDEFINED); - if (info != null) { - final SVNURL url = info.getURL(); - myUrl = url.toString(); - } else { - myUrl = ""; - } - } - catch (SVNException e) { - myUrl = ""; - } + SVNInfo info = vcs.getInfo(file); + myUrl = info != null && info.getURL() != null ? info.getDepth().toString() : ""; } public SVNURL getUrl() { From f657dc811373e9c3f1dbda3353032352cdf70b2e Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 13 Aug 2013 18:33:09 +0400 Subject: [PATCH 02/30] IDEA-94942 Authentication updates Authentication for remote status command Result parsing for remote info command 2 way SSL support (could be issues with ordinary password entering after 2 way SSL) --- .../idea/svn/AuthenticationCallback.java | 2 +- .../idea/svn/commandLine/SvnCommand.java | 33 ++++- .../idea/svn/commandLine/SvnCommandName.java | 1 + .../idea/svn/commandLine/SvnLineCommand.java | 135 +++++++++++++----- .../idea/svn/SvnAuthenticationNotifier.java | 4 +- .../idea/svn/SvnRecursiveStatusWalker.java | 3 - ...IdeaSvnkitBasedAuthenticationCallback.java | 6 +- .../commandLine/SvnCommandLineInfoClient.java | 56 +++++--- .../SvnCommandLineStatusClient.java | 50 +++++-- 9 files changed, 213 insertions(+), 77 deletions(-) diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java index 26c0759c4b4b..473a422d6fb6 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java @@ -52,7 +52,7 @@ public interface AuthenticationCallback { */ boolean authenticateFor(@Nullable String realm, File base, boolean previousFailed, boolean passwordRequest); - SVNAuthentication requestCredentials(@Nullable SVNURL url); + SVNAuthentication requestCredentials(@Nullable SVNURL url, String type); /** * @return config directory if TMP was created diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java index 4e89ef1fca91..d16727d01969 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java @@ -16,6 +16,7 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.execution.process.CapturingProcessAdapter; import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessListener; @@ -38,6 +39,7 @@ import java.util.List; */ public abstract class SvnCommand { static final Logger LOG = Logger.getInstance(SvnCommand.class.getName()); + private final File myConfigDir; private boolean myIsDestroyed; private int myExitCode; @@ -48,10 +50,7 @@ public abstract class SvnCommand { private final Object myLock; private final EventDispatcher myListeners = EventDispatcher.create(ProcessEventListener.class); - - // todo check version - /*c:\Program Files (x86)\CollabNet\Subversion Client17>svn --version --quiet - 1.7.2*/ + private final SvnCommandName myCommandName; public SvnCommand(File workingDirectory, @NotNull SvnCommandName commandName, @NotNull @NonNls String exePath) { this(workingDirectory, commandName, exePath, null); @@ -59,15 +58,25 @@ public abstract class SvnCommand { public SvnCommand(File workingDirectory, @NotNull SvnCommandName commandName, @NotNull @NonNls String exePath, @Nullable File configDir) { + myCommandName = commandName; myLock = new Object(); myCommandLine = new GeneralCommandLine(); myWorkingDirectory = workingDirectory; myCommandLine.setExePath(exePath); myCommandLine.setWorkDirectory(workingDirectory); + myConfigDir = configDir; if (configDir != null) { myCommandLine.addParameters("--config-dir", configDir.getPath()); } - myCommandLine.addParameter(commandName.getName()); + if (!SvnCommandName.empty.equals(commandName)) { + myCommandLine.addParameter(commandName.getName()); + } + } + + public String[] getParameters() { + synchronized (myLock) { + return myCommandLine.getParametersList().getArray(); + } } public void start() { @@ -187,7 +196,15 @@ public abstract class SvnCommand { } public String getCommandText() { - return myCommandLine.getCommandLineString(); + synchronized (myLock) { + return myCommandLine.getCommandLineString(); + } + } + + public String getExePath() { + synchronized (myLock) { + return myCommandLine.getExePath(); + } } /** @@ -230,4 +247,8 @@ public abstract class SvnCommand { protected File getWorkingDirectory() { return myWorkingDirectory; } + + public SvnCommandName getCommandName() { + return myCommandName; + } } diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index 1b0f7a9b3b53..b605fee19e5c 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -22,6 +22,7 @@ package org.jetbrains.idea.svn.commandLine; * Time: 1:49 PM */ public enum SvnCommandName { + empty("", false), version("--version", false), info("info", false), st("st", false), diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java index ef87d953a632..a7feaad2a47f 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java @@ -33,8 +33,10 @@ import org.jetbrains.idea.svn.SvnBindUtil; import org.jetbrains.idea.svn.config.SvnBindException; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.auth.SVNAuthentication; import org.tmatesoft.svn.core.auth.SVNPasswordAuthentication; +import org.tmatesoft.svn.core.auth.SVNSSLAuthentication; import java.io.File; import java.io.IOException; @@ -77,7 +79,7 @@ public class SvnLineCommand extends SvnCommand { private final EventDispatcher myLineListeners; private final AtomicReference myExitCode; private final StringBuffer myErr; - private final StringBuffer myOut; + private final StringBuffer myStdOut; public SvnLineCommand(File workingDirectory, @NotNull SvnCommandName commandName, @NotNull @NonNls String exePath) { this(workingDirectory, commandName, exePath, null); @@ -88,7 +90,11 @@ public class SvnLineCommand extends SvnCommand { myLineListeners = EventDispatcher.create(LineProcessEventListener.class); myExitCode = new AtomicReference(); myErr = new StringBuffer(); - myOut = new StringBuffer(); + myStdOut = new StringBuffer(); + } + + public String getOutput() { + return myStdOut.toString(); } @Override @@ -102,18 +108,18 @@ public class SvnLineCommand extends SvnCommand { } } - public static void runWithAuthenticationAttempt(final String exePath, - final File firstFile, + public static SvnLineCommand runWithAuthenticationAttempt(final String exePath, + final File firstFile, SvnCommandName commandName, final LineCommandListener listener, @Nullable AuthenticationCallback authenticationCallback, String... parameters) throws SvnBindException { - runWithAuthenticationAttempt(exePath, firstFile, null, commandName, listener, authenticationCallback, false, parameters); + return runWithAuthenticationAttempt(exePath, firstFile, null, commandName, listener, authenticationCallback, false, parameters); } - public static void runWithAuthenticationAttempt(final String exePath, - final File firstFile, + public static SvnLineCommand runWithAuthenticationAttempt(final String exePath, + final File firstFile, final SVNURL url, SvnCommandName commandName, final LineCommandListener listener, @@ -159,7 +165,7 @@ public class SvnLineCommand extends SvnCommand { if (exitCode != 0) { throw new SvnBindException("Svn process exited with error code: " + exitCode); } - return; + return command; } } finally { if (authenticationCallback != null) { @@ -169,24 +175,10 @@ public class SvnLineCommand extends SvnCommand { } private static String[] updateParameters(AuthCallbackCase callback, String[] parameters) { - String[] result = parameters; + List p = new ArrayList(Arrays.asList(parameters)); - if (callback instanceof UsernamePasswordCallback && - ((UsernamePasswordCallback)callback).getAuthentication() instanceof SVNPasswordAuthentication) { - SVNPasswordAuthentication auth = (SVNPasswordAuthentication)((UsernamePasswordCallback)callback).getAuthentication(); - List p = new ArrayList(Arrays.asList(parameters)); - - p.add("--username"); - p.add(auth.getUserName()); - p.add("--password"); - p.add(auth.getPassword()); - if (!auth.isStorageAllowed()) { - p.add("--no-auth-cache"); - } - result = ArrayUtil.toStringArray(p); - } - - return result; + callback.updateParameters(p); + return ArrayUtil.toStringArray(p); } private static void writeIdeaConfig2SubversionConfig(@NotNull AuthenticationCallback authenticationCallback, @NotNull File base) throws SvnBindException { @@ -220,15 +212,30 @@ public class SvnLineCommand extends SvnCommand { if (errText.startsWith(UNABLE_TO_CONNECT) && errText.contains(CANNOT_AUTHENTICATE_TO_PROXY)) { return new ProxyCallback(callback, base); } + // http/https protocol invalid credentials if (errText.contains(AUTHENTICATION_FAILED_MESSAGE)) { return new UsernamePasswordCallback(callback, base, url); } + if (errText.contains("svn: E170001: Can't get password")) { + // svn protocol invalid credentials + return new UsernamePasswordCallback(callback, base, url); + } + // https one-way protocol untrusted server certificate + if (errText.contains("Server SSL certificate untrusted")) { + return new CertificateCallbackCase(callback, base); + } + // https two-way protocol invalid client certificate + if (errText.contains("Access to ") && errText.contains("forbidden")) { + return new TwoWaySslCallback(callback, base, url); + } return null; } + // Special callback for svn 1.8 credentials request as --non-interactive does not return + // authentication realm (just url) - so we could not create temp cache private static class UsernamePasswordCallback extends AuthCallbackCase { - private SVNAuthentication myAuthentication; - private SVNURL myUrl; + protected SVNAuthentication myAuthentication; + protected SVNURL myUrl; protected UsernamePasswordCallback(AuthenticationCallback callback, File base, SVNURL url) { super(callback, base); @@ -237,9 +244,29 @@ public class SvnLineCommand extends SvnCommand { @Override boolean getCredentials(String errText) throws SvnBindException { - myAuthentication = myAuthenticationCallback.requestCredentials(myUrl != null ? myUrl : parseUrlFromError(errText)); + myAuthentication = myAuthenticationCallback.requestCredentials(myUrl != null ? myUrl : parseUrlFromError(errText), + getType()); - return true; + return myAuthentication != null; + } + + public String getType() { + return ISVNAuthenticationManager.PASSWORD; + } + + @Override + public void updateParameters(List parameters) { + if (myAuthentication instanceof SVNPasswordAuthentication) { + SVNPasswordAuthentication auth = (SVNPasswordAuthentication)myAuthentication; + + parameters.add("--username"); + parameters.add(auth.getUserName()); + parameters.add("--password"); + parameters.add(auth.getPassword()); + if (!auth.isStorageAllowed()) { + parameters.add("--no-auth-cache"); + } + } } private SVNURL parseUrlFromError(String errorText) { @@ -262,10 +289,6 @@ public class SvnLineCommand extends SvnCommand { return null; } } - - public SVNAuthentication getAuthentication() { - return myAuthentication; - } } private static class ProxyCallback extends AuthCallbackCase { @@ -306,6 +329,8 @@ public class SvnLineCommand extends SvnCommand { } private static class CertificateCallbackCase extends AuthCallbackCase { + private boolean accepted; + private CertificateCallbackCase(AuthenticationCallback callback, File base) { super(callback, base); } @@ -323,11 +348,48 @@ public class SvnLineCommand extends SvnCommand { } realm = realm.substring(idx1 + 1, idx2); if (! myTried && myAuthenticationCallback.acceptSSLServerCertificate(myBase, realm)) { + accepted = true; myTried = true; return true; } throw new SvnBindException("Server SSL certificate rejected"); } + + @Override + public void updateParameters(List parameters) { + if (accepted) { + parameters.add("--trust-server-cert"); + } + } + } + + private static class TwoWaySslCallback extends UsernamePasswordCallback { + + protected TwoWaySslCallback(AuthenticationCallback callback, File base, SVNURL url) { + super(callback, base, url); + } + + @Override + public String getType() { + return ISVNAuthenticationManager.SSL; + } + + @Override + public void updateParameters(List parameters) { + if (myAuthentication instanceof SVNSSLAuthentication) { + SVNSSLAuthentication auth = (SVNSSLAuthentication)myAuthentication; + + // TODO: Seems that config option should be specified for concrete server and not for global group. + // as in that case it could be overriden by settings in config file + parameters.add("--config-option"); + parameters.add("servers:global:ssl-client-cert-file=" + auth.getCertificatePath()); + parameters.add("--config-option"); + parameters.add("servers:global:ssl-client-cert-password=" + auth.getPassword()); + if (!auth.isStorageAllowed()) { + parameters.add("--no-auth-cache"); + } + } + } } private static abstract class AuthCallbackCase { @@ -341,6 +403,9 @@ public class SvnLineCommand extends SvnCommand { } abstract boolean getCredentials(final String errText) throws SvnBindException; + + public void updateParameters(List parameters) { + } } private static void cleanup(String exePath, SvnCommandName commandName, File base) throws SvnBindException { @@ -414,7 +479,9 @@ public class SvnLineCommand extends SvnCommand { command.addLineListener(new LineProcessEventListener() { @Override public void onLineAvailable(String line, Key outputType) { - command.myOut.append(line); + if (ProcessOutputTypes.STDOUT.equals(outputType)) { + command.myStdOut.append(line); + } if (SvnCommand.LOG.isDebugEnabled()) { SvnCommand.LOG.debug("==> " + line); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java index 56e55bb86bdd..4efcce6f0db6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java @@ -350,7 +350,9 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl() { @Override public void run() throws SVNException { + // NOTE: DO NOT replace this call - SSL authentication highly tied to SVNKit myVcs.createWCClient(active).doInfo(myUrl, SVNRevision.UNDEFINED, SVNRevision.HEAD); + //myVcs.getInfo(myUrl, SVNRevision.HEAD, active); } } ); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java index 9c44ba0d0432..fd2e10915f01 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java @@ -102,6 +102,34 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { command.addParameters(parameters); SvnCommandLineStatusClient.changelistsToCommand(changeLists, command); + parseResult(handler, base, execute(command)); + } + + private String execute(SvnSimpleCommand command) throws SVNException { + try { + return command.run(); + } + catch (VcsException e) { + final String text = e.getMessage(); + final boolean notEmpty = !StringUtil.isEmptyOrSpaces(text); + if (notEmpty && text.contains("W155010")) { + // just null + return null; + } + // not a working copy exception + // "E155007: '' is not a working copy" + if (notEmpty && text.contains("is not a working copy")) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_WORKING_COPY), e); + } + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + } + } + + private void parseResult(final ISVNInfoHandler handler, File base, String result) throws SVNException { + if (StringUtil.isEmpty(result)) { + return; + } + final SvnInfoHandler[] infoHandler = new SvnInfoHandler[1]; infoHandler[0] = new SvnInfoHandler(base, new Consumer() { @Override @@ -116,10 +144,9 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { }); try { - final String result = command.run(); SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); - parser.parse(new ByteArrayInputStream(result.getBytes(CharsetToolkit.UTF8_CHARSET)), infoHandler[0]); + parser.parse(new ByteArrayInputStream(result.getBytes(CharsetToolkit.UTF8_CHARSET)), infoHandler[0]); } catch (SvnExceptionWrapper e) { throw (SVNException) e.getCause(); @@ -132,20 +159,6 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { catch (SAXException e) { throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); } - catch (VcsException e) { - final String text = e.getMessage(); - final boolean notEmpty = !StringUtil.isEmptyOrSpaces(text); - if (notEmpty && text.contains("W155010")) { - // just null - return; - } - // not a working copy exception - // "E155007: '' is not a working copy" - if (notEmpty && text.contains("is not a working copy")) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_WORKING_COPY), e); - } - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); - } } private void fillParameters(String path, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, Collection parameters) { @@ -180,10 +193,13 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { fillParameters(path, pegRevision, revision, depth, parameters); try { String exe = SvnApplicationSettings.getInstance().getCommandLinePath(); - SvnLineCommand.runWithAuthenticationAttempt(exe, - new File(exe), url, SvnCommandName.info, new SvnCommitRunner.CommandListener(null), - new IdeaSvnkitBasedAuthenticationCallback(SvnVcs.getInstance(myProject)), false, - ArrayUtil.toStringArray(parameters)); + SvnLineCommand command = SvnLineCommand.runWithAuthenticationAttempt(exe, + new File(exe), url, SvnCommandName.info, + new SvnCommitRunner.CommandListener(null), + new IdeaSvnkitBasedAuthenticationCallback( + SvnVcs.getInstance(myProject)), false, + ArrayUtil.toStringArray(parameters)); + parseResult(handler, new File(exe), command.getOutput()); } catch (SvnBindException e) { throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java index 6341b7c0c160..708fd65173d1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java @@ -23,7 +23,11 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.containers.Convertor; import org.jetbrains.idea.svn.SvnBindUtil; +import org.jetbrains.idea.svn.SvnCommitRunner; import org.jetbrains.idea.svn.SvnUtil; +import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; +import org.jetbrains.idea.svn.config.SvnBindException; import org.jetbrains.idea.svn.portable.PortableStatus; import org.jetbrains.idea.svn.portable.SvnExceptionWrapper; import org.jetbrains.idea.svn.portable.SvnStatusClientI; @@ -107,18 +111,48 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { final SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, base, SvnCommandName.st); putParameters(depth, remote, reportAll, includeIgnored, changeLists, command); - final SvnStatusHandler[] svnHandl = new SvnStatusHandler[1]; - svnHandl[0] = createStatusHandler(revision, handler, base, infoBase, svnHandl); + parseResult(path, revision, handler, base, infoBase, command, execute(command, base)); + return 0; + } + + private String execute(SvnSimpleCommand command, File base) throws SVNException { + String result; try { - final String result = command.run(); + // empty command name passed, as command name is already in command.getParameters() + SvnLineCommand lineCommand = SvnLineCommand + .runWithAuthenticationAttempt(command.getExePath(), base, SvnCommandName.empty, new SvnCommitRunner.CommandListener(null), + new IdeaSvnkitBasedAuthenticationCallback(SvnVcs.getInstance(myProject)), command.getParameters()); + result = lineCommand.getOutput(); + if (StringUtil.isEmptyOrSpaces(result)) { - throw new VcsException("Status request returned nothing for command: " + command.myCommandLine.getCommandLineString()); + throw new SvnBindException("Status request returned nothing for command: " + command.myCommandLine.getCommandLineString()); } + } + catch (SvnBindException e) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + } + return result; + } + + private void parseResult(File path, + SVNRevision revision, + ISVNStatusHandler handler, + File base, + SVNInfo infoBase, + SvnSimpleCommand command, String result) throws SVNException { + + if (StringUtil.isEmpty(result)) { + return; + } + + try { + final SvnStatusHandler[] svnHandl = new SvnStatusHandler[1]; + svnHandl[0] = createStatusHandler(revision, handler, base, infoBase, svnHandl); SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); parser.parse(new ByteArrayInputStream(result.getBytes(CharsetToolkit.UTF8_CHARSET)), svnHandl[0]); - if (! svnHandl[0].isAnythingReported()) { - if (! SvnUtil.isSvnVersioned(myProject, path)) { + if (!svnHandl[0].isAnythingReported()) { + if (!SvnUtil.isSvnVersioned(myProject, path)) { throw new SVNException( SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY, "Command - " + command.getCommandText() + ". Result - " + result)); } @@ -135,10 +169,6 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { catch (SAXException e) { throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); } - catch (VcsException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); - } - return 0; } private void putParameters(SVNDepth depth, From b083f313deea0404ae5b9b57aac8cf526bb87d6e Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 14 Aug 2013 12:09:17 +0400 Subject: [PATCH 03/30] IDEA-94942 Diff provider (without revision properties) Small command refactoring --- .../idea/svn/commandLine/SvnCommand.java | 7 + .../idea/svn/commandLine/SvnLineCommand.java | 4 - .../jetbrains/idea/svn/SvnDiffProvider.java | 131 ++++++++++-------- .../src/org/jetbrains/idea/svn/SvnUtil.java | 7 +- .../src/org/jetbrains/idea/svn/SvnVcs.java | 32 ++++- .../idea/svn/commandLine/CommandUtil.java | 46 ++++++ .../idea/svn/commandLine/SvnCatClient.java | 28 +++- .../commandLine/SvnCommandLineInfoClient.java | 17 +-- .../SvnCommandLineStatusClient.java | 19 +-- .../history/SvnRepositoryContentRevision.java | 35 ++++- 10 files changed, 218 insertions(+), 108 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java index d16727d01969..d219653fe514 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java @@ -47,6 +47,7 @@ public abstract class SvnCommand { private final File myWorkingDirectory; private Process myProcess; private OSProcessHandler myHandler; + private CapturingProcessAdapter outputAdapter; private final Object myLock; private final EventDispatcher myListeners = EventDispatcher.create(ProcessEventListener.class); @@ -121,10 +122,16 @@ public abstract class SvnCommand { } }; + outputAdapter = new CapturingProcessAdapter(); + myHandler.addProcessListener(outputAdapter); myHandler.addProcessListener(processListener); myHandler.startNotify(); } + public String getOutput() { + return outputAdapter.getOutput().getStdout(); + } + /** * Wait for process termination * @param timeout diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java index a7feaad2a47f..e40305d2575a 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java @@ -93,10 +93,6 @@ public class SvnLineCommand extends SvnCommand { myStdOut = new StringBuffer(); } - public String getOutput() { - return myStdOut.toString(); - } - @Override protected void processTerminated(int exitCode) { // force newline diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java index 2a8a00aa1ae6..bd1a6b66468e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java @@ -26,6 +26,7 @@ import com.intellij.openapi.vcs.history.VcsRevisionDescription; import com.intellij.openapi.vcs.history.VcsRevisionDescriptionImpl; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient; import org.jetbrains.idea.svn.history.LatestExistentSearcher; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; @@ -43,19 +44,12 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin { } public VcsRevisionNumber getCurrentRevision(VirtualFile file) { - final SVNWCClient client = myVcs.createWCClient(); - try { - final SVNInfo svnInfo = client.doInfo(new File(file.getPresentableUrl()), SVNRevision.UNDEFINED); - if (svnInfo == null) return null; - if (SVNRevision.UNDEFINED.equals(svnInfo.getCommittedRevision()) && svnInfo.getCopyFromRevision() != null) { - return new SvnRevisionNumber(svnInfo.getCopyFromRevision()); - } - return new SvnRevisionNumber(svnInfo.getRevision()); - } - catch (SVNException e) { - LOG.debug(e); // most likely the file is unversioned - return null; + final SVNInfo svnInfo = myVcs.getInfo(new File(file.getPresentableUrl())); + if (svnInfo == null) return null; + if (SVNRevision.UNDEFINED.equals(svnInfo.getCommittedRevision()) && svnInfo.getCopyFromRevision() != null) { + return new SvnRevisionNumber(svnInfo.getCopyFromRevision()); } + return new SvnRevisionNumber(svnInfo.getRevision()); } @Override @@ -65,19 +59,22 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin { } private VcsRevisionDescription getCurrentRevisionDescription(File path) { - final SVNWCClient client = myVcs.createWCClient(); - try { - final SVNInfo svnInfo = client.doInfo(path, SVNRevision.UNDEFINED); - - if (svnInfo.getCommittedRevision().equals(SVNRevision.UNDEFINED) && ! svnInfo.getCopyFromRevision().equals(SVNRevision.UNDEFINED) && + final SVNInfo svnInfo = myVcs.getInfo(path); + if (svnInfo == null) { + return null; + } + + if (svnInfo.getCommittedRevision().equals(SVNRevision.UNDEFINED) && !svnInfo.getCopyFromRevision().equals(SVNRevision.UNDEFINED) && svnInfo.getCopyFromURL() != null) { - SVNURL copyUrl = svnInfo.getCopyFromURL(); - String localPath = myVcs.getSvnFileUrlMapping().getLocalPath(copyUrl.toString()); - if (localPath != null) { - return getCurrentRevisionDescription(new File(localPath)); - } + SVNURL copyUrl = svnInfo.getCopyFromURL(); + String localPath = myVcs.getSvnFileUrlMapping().getLocalPath(copyUrl.toString()); + if (localPath != null) { + return getCurrentRevisionDescription(new File(localPath)); } - final String message = getProperties(client, path); + } + + try { + final String message = getProperties(path); return new VcsRevisionDescriptionImpl(new SvnRevisionNumber(svnInfo.getCommittedRevision()), svnInfo.getCommittedDate(), svnInfo.getAuthor(), message); } @@ -87,8 +84,10 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin { } } - private String getProperties(SVNWCClient client, File path) throws SVNException { + private String getProperties(File path) throws SVNException { + final SVNWCClient client = myVcs.createWCClient(); final String[] message = new String[1]; + client.doGetRevisionProperty(path, null, SVNRevision.BASE, new ISVNPropertyHandler() { @Override public void handleProperty(File path, SVNPropertyData property) throws SVNException { @@ -135,18 +134,45 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin { return SvnContentRevision.createBaseRevision(myVcs, filePath, svnRevision); } } + // not clear why we need it, with remote check.. - final SVNStatusClient client = myVcs.createStatusClient(); - try { - final SVNStatus svnStatus = client.doStatus(new File(selectedFile.getPresentableUrl()), false, false); - if (svnRevision.equals(svnStatus.getRevision())) { + SVNStatus svnStatus = getFileStatus(new File(selectedFile.getPresentableUrl()), false); + if (svnStatus != null && svnRevision.equals(svnStatus.getRevision())) { return SvnContentRevision.createBaseRevision(myVcs, filePath, svnRevision); - } + } + return SvnContentRevision.createRemote(myVcs, filePath, svnRevision); + } + + private SVNStatus getFileStatus(File file, boolean remote) { + WorkingCopyFormat format = myVcs.getWorkingCopyFormat(file); + + return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) ? getStatusCommandLine(file, remote) : getStatusWithSvnKit(file, remote); + } + + private SVNStatus getStatusWithSvnKit(File file, boolean remote) { + SVNStatus result = null; + + try { + result = myVcs.createStatusClient().doStatus(file, remote, false); } catch (SVNException e) { LOG.debug(e); // most likely the file is unversioned } - return SvnContentRevision.createRemote(myVcs, filePath, svnRevision); + + return result; + } + + private SVNStatus getStatusCommandLine(File file, boolean remote) { + SVNStatus result = null; + + try { + result = new SvnCommandLineStatusClient(myVcs.getProject()).doStatus(file, remote, false); + } + catch (SVNException e) { + LOG.debug(e); + } + + return result; } public ItemLatestState getLastRevision(FilePath filePath) { @@ -159,36 +185,29 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin { } private ItemLatestState getLastRevision(final File file) { - final SVNStatusClient client = myVcs.createStatusClient(); - try { - final SVNStatus svnStatus = client.doStatus(file, true); - if (svnStatus == null || itemExists(svnStatus) && SVNRevision.UNDEFINED.equals(svnStatus.getRemoteRevision())) { - // IDEADEV-21785 (no idea why this can happen) - final SVNInfo info = myVcs.createWCClient().doInfo(file, SVNRevision.HEAD); - if (info == null || info.getURL() == null) { - LOG.info("No SVN status returned for " + file.getPath()); - return defaultResult(); - } - return createResult(info.getCommittedRevision(), true, false); + final SVNStatus svnStatus = getFileStatus(file, true); + if (svnStatus == null || itemExists(svnStatus) && SVNRevision.UNDEFINED.equals(svnStatus.getRemoteRevision())) { + // IDEADEV-21785 (no idea why this can happen) + final SVNInfo info = myVcs.getInfo(file, SVNRevision.HEAD); + if (info == null || info.getURL() == null) { + LOG.info("No SVN status returned for " + file.getPath()); + return defaultResult(); } - final boolean exists = itemExists(svnStatus); - if (! exists) { - // get really latest revision - final LatestExistentSearcher searcher = new LatestExistentSearcher(myVcs, svnStatus.getURL()); - final long revision = searcher.getDeletionRevision(); + return createResult(info.getCommittedRevision(), true, false); + } + final boolean exists = itemExists(svnStatus); + if (! exists) { + // get really latest revision + final LatestExistentSearcher searcher = new LatestExistentSearcher(myVcs, svnStatus.getURL()); + final long revision = searcher.getDeletionRevision(); - return createResult(SVNRevision.create(revision), exists, false); - } - final SVNRevision remoteRevision = svnStatus.getRemoteRevision(); - if (remoteRevision != null) { - return createResult(remoteRevision, exists, false); - } - return createResult(svnStatus.getRevision(), exists, false); + return createResult(SVNRevision.create(revision), exists, false); } - catch (SVNException e) { - LOG.debug(e); // most likely the file is unversioned - return defaultResult(); + final SVNRevision remoteRevision = svnStatus.getRemoteRevision(); + if (remoteRevision != null) { + return createResult(remoteRevision, exists, false); } + return createResult(svnStatus.getRevision(), exists, false); } private boolean itemExists(SVNStatus svnStatus) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index b5d5b3152147..9f7b41aabf0b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -744,14 +744,13 @@ public class SvnUtil { WorkingCopyFormat format = vcs.getWorkingCopyFormat(file); return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) - ? getFileContentsCommandLine(vcs, file) + ? getFileContentsCommandLine(vcs, path, revision, pegRevision) : getFileContentWithSvnKit(vcs, path, isUrl, revision, pegRevision); } - private static byte[] getFileContentsCommandLine(SvnVcs vcs, File file) throws VcsException { - // TODO: Enhance command to use all parameters - isUrl, revision, pegRevision + private static byte[] getFileContentsCommandLine(SvnVcs vcs, String path, SVNRevision revision, SVNRevision pegRevision) throws VcsException { SvnCatClient client = new SvnCatClient(vcs.getProject()); - String content = client.getFileContents(file); + String content = client.getFileContents(path, pegRevision, revision); return CharsetToolkit.getUtf8Bytes(content); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index 1b0ed4cb9867..f3006ac61164 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -918,7 +918,7 @@ public class SvnVcs extends AbstractVcs { try { result = SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration.myUseAcceleration) - ? getInfoCommandLine(file) + ? getInfoCommandLine(file, SVNRevision.UNDEFINED) : getInfoSvnKit(file); } catch (SVNException e) { @@ -961,7 +961,22 @@ public class SvnVcs extends AbstractVcs { SVNInfo result = null; try { - result = format == WorkingCopyFormat.ONE_DOT_EIGHT ? getInfoCommandLine(ioFile) : runInfoCommand(ioFile); + result = format == WorkingCopyFormat.ONE_DOT_EIGHT ? getInfoCommandLine(ioFile, SVNRevision.UNDEFINED) : runInfoCommand(ioFile); + } + catch (SVNException e) { + handleInfoException(e); + } + + return result; + } + + @Nullable + public SVNInfo getInfo(@NotNull File ioFile, @NotNull SVNRevision revision) { + WorkingCopyFormat format = getWorkingCopyFormat(ioFile); + SVNInfo result = null; + + try { + result = format == WorkingCopyFormat.ONE_DOT_EIGHT ? getInfoCommandLine(ioFile, revision) : getInfoSvnKit(ioFile, revision); } catch (SVNException e) { handleInfoException(e); @@ -982,17 +997,20 @@ public class SvnVcs extends AbstractVcs { } private SVNInfo getInfoSvnKit(@NotNull File ioFile) throws SVNException { - SVNWCClient wcClient = createWCClient(); - SVNInfo info = wcClient.doInfo(ioFile, SVNRevision.UNDEFINED); + SVNInfo info = getInfoSvnKit(ioFile, SVNRevision.UNDEFINED); if (info == null || info.getRepositoryRootURL() == null) { - info = wcClient.doInfo(ioFile, SVNRevision.HEAD); + info = getInfoSvnKit(ioFile, SVNRevision.HEAD); } return info; } - private SVNInfo getInfoCommandLine(@NotNull File ioFile) throws SVNException { + private SVNInfo getInfoSvnKit(@NotNull File ioFile, SVNRevision revision) throws SVNException { + return createWCClient().doInfo(ioFile, revision); + } + + private SVNInfo getInfoCommandLine(@NotNull File ioFile, SVNRevision revision) throws SVNException { SvnCommandLineInfoClient client = new SvnCommandLineInfoClient(myProject); - return client.doInfo(ioFile, SVNRevision.UNDEFINED); + return client.doInfo(ioFile, revision); } private SvnWcClientI createInfoClient() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java new file mode 100644 index 000000000000..fbe44cebc6c3 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -0,0 +1,46 @@ +package org.jetbrains.idea.svn.commandLine; + +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.SvnApplicationSettings; +import org.jetbrains.idea.svn.SvnCommitRunner; +import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; +import org.jetbrains.idea.svn.config.SvnBindException; +import org.tmatesoft.svn.core.SVNErrorCode; +import org.tmatesoft.svn.core.SVNErrorMessage; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public class CommandUtil { + public static SvnLineCommand runSimple(SvnCommandName name, + SvnVcs vcs, + @Nullable SVNURL url, + List parameters) + throws SVNException { + String exe = SvnApplicationSettings.getInstance().getCommandLinePath(); + + try { + return SvnLineCommand + .runWithAuthenticationAttempt(exe, new File(vcs.getProject().getBasePath()), url, name, new SvnCommitRunner.CommandListener(null), + new IdeaSvnkitBasedAuthenticationCallback(vcs), false, ArrayUtil.toStringArray(parameters)); + } + catch (SvnBindException e) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + } + } + + public static SvnLineCommand runSimple(@NotNull SvnSimpleCommand command, SvnVcs vcs, @Nullable SVNURL url) throws SVNException { + // empty command name passed, as command name is already in command.getParameters() + return runSimple(SvnCommandName.empty, vcs, url, new ArrayList(Arrays.asList(command.getParameters()))); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java index 63cd7e2e6dc7..c1e5b8eecba2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java @@ -3,6 +3,9 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.SvnVcs; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.SVNRevision; import java.io.File; @@ -17,9 +20,28 @@ public class SvnCatClient { myProject = project; } - public String getFileContents(@NotNull File file) throws VcsException { + public String getFileContents(@NotNull String path, SVNRevision pegRevision, SVNRevision revision) throws VcsException { + // TODO: rewrite this to provide output as Stream SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, null, SvnCommandName.cat); - command.addParameters(file.getAbsolutePath()); - return command.run(); + fillParameters(path, pegRevision, revision, command); + + try { + return CommandUtil.runSimple(command, SvnVcs.getInstance(myProject), null).getOutput(); + } + catch (SVNException e) { + throw new VcsException(e); + } + } + + private void fillParameters(String path, SVNRevision pegRevision, SVNRevision revision, SvnSimpleCommand command) { + if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) { + command.addParameters("-r"); + command.addParameters(revision.toString()); + } + if (pegRevision != null && ! SVNRevision.UNDEFINED.equals(pegRevision) && ! SVNRevision.WORKING.equals(pegRevision)) { + command.addParameters(path + "@" + pegRevision.toString()); + } else { + command.addParameters(path); + } } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java index fd2e10915f01..1e421fdd097d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java @@ -191,19 +191,10 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { List parameters = new ArrayList(); fillParameters(path, pegRevision, revision, depth, parameters); - try { - String exe = SvnApplicationSettings.getInstance().getCommandLinePath(); - SvnLineCommand command = SvnLineCommand.runWithAuthenticationAttempt(exe, - new File(exe), url, SvnCommandName.info, - new SvnCommitRunner.CommandListener(null), - new IdeaSvnkitBasedAuthenticationCallback( - SvnVcs.getInstance(myProject)), false, - ArrayUtil.toStringArray(parameters)); - parseResult(handler, new File(exe), command.getOutput()); - } - catch (SvnBindException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); - } + File base = new File(myProject.getBasePath()); + String result = CommandUtil.runSimple(SvnCommandName.info, SvnVcs.getInstance(myProject), url, parameters).getOutput(); + + parseResult(handler, base, result); } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java index 708fd65173d1..4cd735c2f1e3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java @@ -116,22 +116,13 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { } private String execute(SvnSimpleCommand command, File base) throws SVNException { - String result; + String result = CommandUtil.runSimple(command, SvnVcs.getInstance(myProject), null).getOutput(); - try { - // empty command name passed, as command name is already in command.getParameters() - SvnLineCommand lineCommand = SvnLineCommand - .runWithAuthenticationAttempt(command.getExePath(), base, SvnCommandName.empty, new SvnCommitRunner.CommandListener(null), - new IdeaSvnkitBasedAuthenticationCallback(SvnVcs.getInstance(myProject)), command.getParameters()); - result = lineCommand.getOutput(); + if (StringUtil.isEmptyOrSpaces(result)) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL, "Status request returned nothing for command: " + + command.myCommandLine.getCommandLineString())); + } - if (StringUtil.isEmptyOrSpaces(result)) { - throw new SvnBindException("Status request returned nothing for command: " + command.myCommandLine.getCommandLineString()); - } - } - catch (SvnBindException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); - } return result; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryContentRevision.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryContentRevision.java index a668a54f953a..9f5c97bb04bd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryContentRevision.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryContentRevision.java @@ -38,15 +38,13 @@ import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.impl.ContentRevisionCache; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.SvnBundle; -import org.jetbrains.idea.svn.SvnRevisionNumber; -import org.jetbrains.idea.svn.SvnUtil; -import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.*; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.SVNRevision; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -108,7 +106,7 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC else { loader.run(); } - final SVNException exception = loader.getException(); + final Exception exception = loader.getException(); if (exception != null) { throw new VcsException(exception); } @@ -148,7 +146,7 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC private final String myPath; private final long myRevision; private final OutputStream myDst; - private SVNException myException; + private Exception myException; public ContentLoader(String path, OutputStream dst, long revision) { myPath = path; @@ -156,7 +154,7 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC myRevision = revision; } - public SVNException getException() { + public Exception getException() { return myException; } @@ -166,6 +164,29 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC progress.setText(SvnBundle.message("progress.text.loading.contents", myPath)); progress.setText2(SvnBundle.message("progress.text2.revision.information", myRevision)); } + WorkingCopyFormat format = myVcs.getWorkingCopyFormat(new File(getFullPath())); + if (WorkingCopyFormat.ONE_DOT_EIGHT.equals(format)) { + loadContentCommandLine(); + } + else { + loadContentWithSvnKit(); + } + } + + private void loadContentCommandLine() { + try { + byte[] contents = SvnUtil.getFileContents(myVcs, getFullPath(), true, SVNRevision.create(myRevision), SVNRevision.UNDEFINED); + myDst.write(contents); + } + catch (VcsException e) { + myException = e; + } + catch (IOException e) { + myException = e; + } + } + + private void loadContentWithSvnKit() { try { SVNRepository repository = myVcs.createRepository(getFullPath()); try { From 555d59727f4558a1c74b06adcfd88ba68d91ad33 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 14 Aug 2013 16:58:16 +0400 Subject: [PATCH 04/30] IDEA-94942 Fixing status, info commands to use correct arguments --- .../jetbrains/idea/svn/commandLine/CommandUtil.java | 13 ++++++++----- .../idea/svn/commandLine/SvnCatClient.java | 2 +- .../svn/commandLine/SvnCommandLineInfoClient.java | 8 ++------ .../svn/commandLine/SvnCommandLineStatusClient.java | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index fbe44cebc6c3..a51150ae4cec 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -22,16 +22,18 @@ import java.util.List; * @author Konstantin Kolosovsky. */ public class CommandUtil { - public static SvnLineCommand runSimple(SvnCommandName name, - SvnVcs vcs, + public static SvnLineCommand runSimple(@NotNull SvnCommandName name, + @NotNull SvnVcs vcs, + @Nullable File base, @Nullable SVNURL url, List parameters) throws SVNException { String exe = SvnApplicationSettings.getInstance().getCommandLinePath(); + base = base == null ? new File(exe) : base; try { return SvnLineCommand - .runWithAuthenticationAttempt(exe, new File(vcs.getProject().getBasePath()), url, name, new SvnCommitRunner.CommandListener(null), + .runWithAuthenticationAttempt(exe, base, url, name, new SvnCommitRunner.CommandListener(null), new IdeaSvnkitBasedAuthenticationCallback(vcs), false, ArrayUtil.toStringArray(parameters)); } catch (SvnBindException e) { @@ -39,8 +41,9 @@ public class CommandUtil { } } - public static SvnLineCommand runSimple(@NotNull SvnSimpleCommand command, SvnVcs vcs, @Nullable SVNURL url) throws SVNException { + public static SvnLineCommand runSimple(@NotNull SvnSimpleCommand command, @NotNull SvnVcs vcs, @Nullable File base, @Nullable SVNURL url) + throws SVNException { // empty command name passed, as command name is already in command.getParameters() - return runSimple(SvnCommandName.empty, vcs, url, new ArrayList(Arrays.asList(command.getParameters()))); + return runSimple(SvnCommandName.empty, vcs, base, url, new ArrayList(Arrays.asList(command.getParameters()))); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java index c1e5b8eecba2..f52b8728f34a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java @@ -26,7 +26,7 @@ public class SvnCatClient { fillParameters(path, pegRevision, revision, command); try { - return CommandUtil.runSimple(command, SvnVcs.getInstance(myProject), null).getOutput(); + return CommandUtil.runSimple(command, SvnVcs.getInstance(myProject), null, null).getOutput(); } catch (SVNException e) { throw new VcsException(e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java index 1e421fdd097d..7b86b8c5270b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java @@ -20,14 +20,10 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import org.jetbrains.idea.svn.SvnApplicationSettings; import org.jetbrains.idea.svn.SvnBindUtil; -import org.jetbrains.idea.svn.SvnCommitRunner; import org.jetbrains.idea.svn.SvnVcs; -import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; -import org.jetbrains.idea.svn.config.SvnBindException; import org.jetbrains.idea.svn.portable.SvnExceptionWrapper; import org.jetbrains.idea.svn.portable.SvnkitSvnWcClient; import org.tmatesoft.svn.core.*; @@ -191,8 +187,8 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { List parameters = new ArrayList(); fillParameters(path, pegRevision, revision, depth, parameters); - File base = new File(myProject.getBasePath()); - String result = CommandUtil.runSimple(SvnCommandName.info, SvnVcs.getInstance(myProject), url, parameters).getOutput(); + File base = new File(SvnApplicationSettings.getInstance().getCommandLinePath()); + String result = CommandUtil.runSimple(SvnCommandName.info, SvnVcs.getInstance(myProject), base, url, parameters).getOutput(); parseResult(handler, base, result); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java index 4cd735c2f1e3..35e8e9a2229c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java @@ -116,7 +116,7 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { } private String execute(SvnSimpleCommand command, File base) throws SVNException { - String result = CommandUtil.runSimple(command, SvnVcs.getInstance(myProject), null).getOutput(); + String result = CommandUtil.runSimple(command, SvnVcs.getInstance(myProject), base, null).getOutput(); if (StringUtil.isEmptyOrSpaces(result)) { throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL, "Status request returned nothing for command: " + From aba7390db7bb8ed10133d1453909e59da90559ce Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 14 Aug 2013 16:58:50 +0400 Subject: [PATCH 05/30] IDEA-94942 Add command refactored --- .../idea/svn/SvnFileSystemListener.java | 17 +++------- .../src/org/jetbrains/idea/svn/SvnVcs.java | 20 +++++++++++ .../org/jetbrains/idea/svn/add/AddClient.java | 16 +++++++++ .../CmdAddClient.java} | 17 +++++----- .../idea/svn/add/SvnKitAddClient.java | 27 +++++++++++++++ .../jetbrains/idea/svn/api/BaseSvnClient.java | 22 +++++++++++++ .../jetbrains/idea/svn/api/ClientFactory.java | 33 +++++++++++++++++++ .../idea/svn/api/CmdClientFactory.java | 20 +++++++++++ .../org/jetbrains/idea/svn/api/SvnClient.java | 15 +++++++++ .../idea/svn/api/SvnKitClientFactory.java | 20 +++++++++++ 10 files changed, 186 insertions(+), 21 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/add/AddClient.java rename plugins/svn4idea/src/org/jetbrains/idea/svn/{commandLine/SvnAddClient.java => add/CmdAddClient.java} (65%) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/add/SvnKitAddClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java index d61f3575afd8..65113dfe57e1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java @@ -44,7 +44,6 @@ import com.intellij.util.containers.MultiMap; import com.intellij.vcsUtil.ActionWithTempFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.commandLine.SvnAddClient; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.wc.*; @@ -791,17 +790,11 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws SVNException { - WorkingCopyFormat format = vcs.getWorkingCopyFormat(ioFile); - - if (WorkingCopyFormat.ONE_DOT_EIGHT.equals(format)) { - SvnAddClient client = new SvnAddClient(project); - try { - client.add(ioFile, null, false, false, true); - } catch(VcsException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); - } - } else { - wcClient.doAdd(ioFile, true, false, false, true); + try { + vcs.getFactory(ioFile).createAddClient().add(ioFile, null, false, false, true); + } + catch (VcsException e) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); } } }.execute(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index f3006ac61164..75156aa8fc8e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -68,6 +68,9 @@ import org.jetbrains.idea.svn.actions.CleanupWorker; import org.jetbrains.idea.svn.actions.ShowPropertiesDiffWithLocalAction; import org.jetbrains.idea.svn.actions.SvnMergeProvider; import org.jetbrains.idea.svn.annotate.SvnAnnotationProvider; +import org.jetbrains.idea.svn.api.ClientFactory; +import org.jetbrains.idea.svn.api.CmdClientFactory; +import org.jetbrains.idea.svn.api.SvnKitClientFactory; import org.jetbrains.idea.svn.checkin.SvnCheckinEnvironment; import org.jetbrains.idea.svn.checkout.SvnCheckoutProvider; import org.jetbrains.idea.svn.commandLine.SvnCommandLineInfoClient; @@ -197,6 +200,10 @@ public class SvnVcs extends AbstractVcs { }; private SvnCheckoutProvider myCheckoutProvider; + private final ClientFactory cmdClientFactory; + private final ClientFactory svnKitClientFactory; + + public void checkCommandLineVersion() { myChecker.checkExecutableAndNotifyIfNeeded(); } @@ -286,6 +293,8 @@ public class SvnVcs extends AbstractVcs { // remove used some time before old notification group ids correctNotificationIds(); myChecker = new SvnExecutableChecker(myProject); + cmdClientFactory = new CmdClientFactory(this); + svnKitClientFactory = new SvnKitClientFactory(this); } private void correctNotificationIds() { @@ -1337,4 +1346,15 @@ public class SvnVcs extends AbstractVcs { } return myCheckoutProvider; } + + public ClientFactory getFactory() { + return myConfiguration.myUseAcceleration.equals(SvnConfiguration.UseAcceleration.commandLine) ? cmdClientFactory : svnKitClientFactory; + } + + public ClientFactory getFactory(@NotNull File file) { + WorkingCopyFormat format = getWorkingCopyFormat(file); + // TODO: Add here direct calculation of svn root if format == UNKNOWN + + return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) ? cmdClientFactory : getFactory(); + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/AddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/AddClient.java new file mode 100644 index 000000000000..aef1f868dbff --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/AddClient.java @@ -0,0 +1,16 @@ +package org.jetbrains.idea.svn.add; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.SvnClient; +import org.tmatesoft.svn.core.SVNDepth; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public interface AddClient extends SvnClient { + + void add(@NotNull File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) throws VcsException; +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnAddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java similarity index 65% rename from plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnAddClient.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java index b8606d5914e2..4219816dcc92 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnAddClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java @@ -1,8 +1,11 @@ -package org.jetbrains.idea.svn.commandLine; +package org.jetbrains.idea.svn.add; -import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.commandLine.SvnCommandFactory; +import org.jetbrains.idea.svn.commandLine.SvnCommandName; +import org.jetbrains.idea.svn.commandLine.SvnSimpleCommand; import org.tmatesoft.svn.core.SVNDepth; import java.io.File; @@ -10,15 +13,11 @@ import java.io.File; /** * @author Konstantin Kolosovsky. */ -public class SvnAddClient { - private Project myProject; - - public SvnAddClient(@NotNull Project project) { - myProject = project; - } +public class CmdAddClient extends BaseSvnClient implements AddClient { + @Override public void add(@NotNull File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) throws VcsException { - SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, null, SvnCommandName.add); + SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myVcs.getProject(), null, SvnCommandName.add); command.addParameters(file.getAbsolutePath()); if (depth != null) { command.addParameters("--depth", depth.getName()); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/SvnKitAddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/SvnKitAddClient.java new file mode 100644 index 000000000000..03719ff00ff6 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/SvnKitAddClient.java @@ -0,0 +1,27 @@ +package org.jetbrains.idea.svn.add; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNException; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitAddClient extends BaseSvnClient implements AddClient { + @Override + public void add(@NotNull File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) throws VcsException { + try { + myVcs.createWCClient().doAdd(file, force, + false, // directory should already be created + makeParents, // not used but will be passed as makeParents value + SVNDepth.recurseFromDepth(depth)); + } + catch (SVNException e) { + throw new VcsException(e); + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java new file mode 100644 index 000000000000..54401cff68b1 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java @@ -0,0 +1,22 @@ +package org.jetbrains.idea.svn.api; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.SvnVcs; + +/** + * @author Konstantin Kolosovsky. + */ +public abstract class BaseSvnClient implements SvnClient { + protected SvnVcs myVcs; + + @NotNull + @Override + public SvnVcs getVcs() { + return myVcs; + } + + @Override + public void setVcs(@NotNull SvnVcs vcs) { + myVcs = vcs; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java new file mode 100644 index 000000000000..1cf037e232b6 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -0,0 +1,33 @@ +package org.jetbrains.idea.svn.api; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.add.AddClient; + +/** + * @author Konstantin Kolosovsky. + */ +public abstract class ClientFactory { + + @NotNull + protected SvnVcs myVcs; + + protected AddClient addClient; + + protected ClientFactory(@NotNull SvnVcs vcs) { + myVcs = vcs; + setup(); + } + + protected abstract void setup(); + + public AddClient createAddClient() { + return prepare(addClient); + } + + protected T prepare(T client) { + client.setVcs(myVcs); + + return client; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java new file mode 100644 index 000000000000..eb78b52a6694 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -0,0 +1,20 @@ +package org.jetbrains.idea.svn.api; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.add.CmdAddClient; + +/** + * @author Konstantin Kolosovsky. + */ +public class CmdClientFactory extends ClientFactory { + + public CmdClientFactory(@NotNull SvnVcs vcs) { + super(vcs); + } + + @Override + protected void setup() { + addClient = new CmdAddClient(); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnClient.java new file mode 100644 index 000000000000..90124f1cccb6 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnClient.java @@ -0,0 +1,15 @@ +package org.jetbrains.idea.svn.api; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.SvnVcs; + +/** + * @author Konstantin Kolosovsky. + */ +public interface SvnClient { + + @NotNull + SvnVcs getVcs(); + + void setVcs(@NotNull SvnVcs vcs); +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java new file mode 100644 index 000000000000..1d147f0103ce --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -0,0 +1,20 @@ +package org.jetbrains.idea.svn.api; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.add.SvnKitAddClient; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitClientFactory extends ClientFactory { + + public SvnKitClientFactory(@NotNull SvnVcs vcs) { + super(vcs); + } + + @Override + protected void setup() { + addClient = new SvnKitAddClient(); + } +} From ccf60853d6fc8315493e97c2ca7476b4a152ec7b Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 15 Aug 2013 13:56:31 +0400 Subject: [PATCH 06/30] IDEA-94942 "Subversion" -> "Show History" for files and folders --- .../idea/svn/commandLine/SvnCommandName.java | 3 +- .../src/org/jetbrains/idea/svn/SvnVcs.java | 11 +- .../jetbrains/idea/svn/api/ClientFactory.java | 6 + .../idea/svn/api/CmdClientFactory.java | 2 + .../idea/svn/api/SvnKitClientFactory.java | 2 + .../idea/svn/history/CmdHistoryClient.java | 230 ++++++++++++++++++ .../idea/svn/history/HistoryClient.java | 28 +++ .../idea/svn/history/SvnHistoryProvider.java | 60 ++--- .../idea/svn/history/SvnKitHistoryClient.java | 38 +++ 9 files changed, 330 insertions(+), 50 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/history/HistoryClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index b605fee19e5c..f8ec332804c5 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -30,7 +30,8 @@ public enum SvnCommandName { ci("commit", true), cleanup("cleanup", true), cat("cat", false), - add("add", true); + add("add", true), + log("log", false); private final String myName; private final boolean myWriteable; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index 75156aa8fc8e..26bbb6235629 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -941,16 +941,19 @@ public class SvnVcs extends AbstractVcs { return runInfoCommand(new File(file.getPath())); } - public SVNInfo getInfo(@NotNull SVNURL url, SVNRevision revision, ISVNAuthenticationManager manager) throws SVNException { + public SVNInfo getInfo(@NotNull SVNURL url, + SVNRevision pegRevision, + SVNRevision revision, + ISVNAuthenticationManager manager) throws SVNException { if (SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration.myUseAcceleration)) { - return createInfoClient().doInfo(url, SVNRevision.UNDEFINED, revision); + return createInfoClient().doInfo(url, pegRevision, revision); } else { - return (manager != null ? createWCClient(manager) : createWCClient()).doInfo(url, SVNRevision.UNDEFINED, SVNRevision.HEAD); + return (manager != null ? createWCClient(manager) : createWCClient()).doInfo(url, pegRevision, revision); } } public SVNInfo getInfo(@NotNull SVNURL url, SVNRevision revision) throws SVNException { - return getInfo(url, revision, null); + return getInfo(url, SVNRevision.UNDEFINED, revision, null); } @Nullable diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java index 1cf037e232b6..676895fbea4c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.AddClient; +import org.jetbrains.idea.svn.history.HistoryClient; /** * @author Konstantin Kolosovsky. @@ -13,6 +14,7 @@ public abstract class ClientFactory { protected SvnVcs myVcs; protected AddClient addClient; + protected HistoryClient historyClient; protected ClientFactory(@NotNull SvnVcs vcs) { myVcs = vcs; @@ -25,6 +27,10 @@ public abstract class ClientFactory { return prepare(addClient); } + public HistoryClient createHistoryClient() { + return prepare(historyClient); + } + protected T prepare(T client) { client.setVcs(myVcs); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java index eb78b52a6694..08be1ca5b6d0 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.CmdAddClient; +import org.jetbrains.idea.svn.history.CmdHistoryClient; /** * @author Konstantin Kolosovsky. @@ -16,5 +17,6 @@ public class CmdClientFactory extends ClientFactory { @Override protected void setup() { addClient = new CmdAddClient(); + historyClient = new CmdHistoryClient(); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java index 1d147f0103ce..a9a701be4ca7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.SvnKitAddClient; +import org.jetbrains.idea.svn.history.SvnKitHistoryClient; /** * @author Konstantin Kolosovsky. @@ -16,5 +17,6 @@ public class SvnKitClientFactory extends ClientFactory { @Override protected void setup() { addClient = new SvnKitAddClient(); + historyClient = new SvnKitHistoryClient(); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java new file mode 100644 index 000000000000..6dfdf68bc741 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java @@ -0,0 +1,230 @@ +package org.jetbrains.idea.svn.history; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.util.LineSeparator; +import com.intellij.util.containers.hash.HashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.commandLine.CommandUtil; +import org.jetbrains.idea.svn.commandLine.SvnCommandName; +import org.jetbrains.idea.svn.commandLine.SvnLineCommand; +import org.tmatesoft.svn.core.ISVNLogEntryHandler; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNLogEntry; +import org.tmatesoft.svn.core.SVNLogEntryPath; +import org.tmatesoft.svn.core.wc.SVNRevision; + +import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Konstantin Kolosovsky. + */ +public class CmdHistoryClient extends BaseSvnClient implements HistoryClient { + + private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.history.CmdHistoryClient"); + + private static final String LINES_SPLIT_WITH_EMPTY = " *(\r|\n|\r\n) *"; + + @Override + public void doLog(@NotNull File path, + @NotNull SVNRevision startRevision, + @NotNull SVNRevision endRevision, + @Nullable SVNRevision pegRevision, + boolean stopOnCopy, + boolean discoverChangedPaths, + boolean includeMergedRevisions, + long limit, + @Nullable String[] revisionProperties, + @Nullable ISVNLogEntryHandler handler) throws VcsException { + // TODO: add revision properties parameter if necessary + // TODO: svn log command supports --xml option - could update parsing to use xml format + // TODO: Check parsing when merge is supported and includeMergedRevisions=true is used + List parameters = + prepareCommand(path, startRevision, endRevision, pegRevision, stopOnCopy, discoverChangedPaths, includeMergedRevisions, limit); + + try { + SvnLineCommand command = CommandUtil.runSimple(SvnCommandName.log, myVcs, path, null, parameters); + // TODO: handler should be called in parallel with command execution, but this will be in other thread + // TODO: check if that is ok for current handler implementation + parseOutput(handler, command); + } + catch (SVNException e) { + throw new VcsException(e); + } + } + + private static void parseOutput(@Nullable ISVNLogEntryHandler handler, @NotNull SvnLineCommand command) + throws VcsException, SVNException { + Parser parser = new Parser(handler); + for (String line : command.getOutput().split(LINES_SPLIT_WITH_EMPTY)) { + parser.onLine(line); + } + } + + private static List prepareCommand(@NotNull File path, + @NotNull SVNRevision startRevision, + @NotNull SVNRevision endRevision, + @Nullable SVNRevision pegRevision, + boolean stopOnCopy, boolean discoverChangedPaths, boolean includeMergedRevisions, long limit) { + List parameters = new ArrayList(); + + parameters.add(path.getAbsolutePath() + (pegRevision != null ? "@" + pegRevision : "")); + parameters.add("--revision"); + parameters.add(startRevision + ":" + endRevision); + + put(parameters, stopOnCopy, "--stop-on-copy"); + put(parameters, discoverChangedPaths, "--verbose"); + put(parameters, includeMergedRevisions, "--use-merge-history"); + parameters.add("--limit"); + parameters.add(String.valueOf(limit)); + + return parameters; + } + + private static void put(@NotNull List parameters, boolean condition, @NotNull String value) { + if (condition) { + parameters.add(value); + } + } + + private static class Parser { + private static final String REVISION = "\\s*r(\\d+)\\s*"; + private static final String AUTHOR = "\\s*([^|]*)\\s*"; + private static final String DATE = "\\s*([^|]*)\\s*"; + private static final String MESSAGE_LINES = "\\s*(\\d+).*"; + + private static final Pattern ENTRY_START = Pattern.compile("-+"); + private static final Pattern DETAILS = Pattern.compile(REVISION + "\\|" + AUTHOR + "\\|" + DATE + "\\|" + MESSAGE_LINES); + + private static final String STATUS = "\\s*(\\w)"; + private static final String PATH = "\\s*(.*?)\\s*"; + private static final String COPY_FROM_PATH = "(/[^:]*)"; + private static final String COPY_FROM_REVISION = "(\\d+)\\))\\s*"; + private static final String COPY_FROM_INFO = "((\\(from " + COPY_FROM_PATH + ":" + COPY_FROM_REVISION + ")?"; + private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + PATH + COPY_FROM_INFO); + + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); + + ISVNLogEntryHandler handler; + + Entry entry; + boolean waitDetails; + boolean waitChangedPath; + boolean waitMessage; + + public Parser(@Nullable ISVNLogEntryHandler handler) { + this.handler = handler; + } + + public void onLine(@NotNull String line) throws VcsException, SVNException { + if (ENTRY_START.matcher(line).matches()) { + processEntryStart(); + } + else if (waitDetails) { + processDetails(line); + } + else if (waitMessage) { + processMessage(line); + } + else if (StringUtil.isEmpty(line.trim())) { + processChangedPathsFinished(); + } + else if (line.startsWith("Changed paths:")) { + processChangedPathsStarted(); + } + else if (waitChangedPath) { + processChangedPath(line); + } + else { + throw new VcsException("unknown state on line " + line); + } + } + + private void processChangedPath(@NotNull String line) throws VcsException { + Matcher matcher = CHANGED_PATH.matcher(line); + if (!matcher.matches()) { + throw new VcsException("changed path not found in " + line); + } + + String path = matcher.group(2); + char type = getType(matcher.group(1)); + String copyPath = matcher.group(5); + long copyRevision = !StringUtil.isEmpty(matcher.group(6)) ? Long.valueOf(matcher.group(6)) : 0; + + entry.changedPaths.put(path, new SVNLogEntryPath(path, type, copyPath, copyRevision)); + } + + private void processChangedPathsStarted() { + waitChangedPath = true; + } + + private void processChangedPathsFinished() { + waitChangedPath = false; + waitMessage = true; + } + + private void processMessage(@NotNull String line) { + entry.message.append(line); + entry.message.append(LineSeparator.LF.getSeparatorString()); + } + + private void processDetails(@NotNull String line) throws VcsException { + Matcher matcher = DETAILS.matcher(line); + if (!matcher.matches()) { + throw new VcsException("details not found in " + line); + } + entry.revision = Long.valueOf(matcher.group(1)); + entry.author = matcher.group(2).trim(); + entry.date = tryGetDate(matcher.group(3)); + + waitDetails = false; + } + + private void processEntryStart() throws SVNException { + if (entry != null) { + handler.handleLogEntry(entry.toLogEntry()); + } + entry = new Entry(); + waitDetails = true; + waitMessage = false; + } + + private static Date tryGetDate(@NotNull String value) { + Date result = null; + try { + result = DATE_FORMAT.parse(value); + } + catch (ParseException e) { + LOG.debug(e); + } + return result; + } + + private static char getType(@Nullable String type) { + return !StringUtil.isEmpty(type) ? type.charAt(0) : ' '; + } + + private static class Entry { + Map changedPaths = new HashMap(); + long revision; + String author; + Date date; + StringBuilder message = new StringBuilder(); + + private SVNLogEntry toLogEntry() { + return new SVNLogEntry(changedPaths, revision, author, date, message.toString()); + } + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/HistoryClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/HistoryClient.java new file mode 100644 index 000000000000..87e5e76556fa --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/HistoryClient.java @@ -0,0 +1,28 @@ +package org.jetbrains.idea.svn.history; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.SvnClient; +import org.tmatesoft.svn.core.ISVNLogEntryHandler; +import org.tmatesoft.svn.core.wc.SVNRevision; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public interface HistoryClient extends SvnClient { + + // TODO: Url is also supported as parameter in cmd - use Target class + void doLog(@NotNull File path, + @NotNull SVNRevision startRevision, + @NotNull SVNRevision endRevision, + @Nullable SVNRevision pegRevision, + boolean stopOnCopy, + boolean discoverChangedPaths, + boolean includeMergedRevisions, + long limit, + @Nullable String[] revisionProperties, + @Nullable ISVNLogEntryHandler handler) throws VcsException; +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index 4a2c8725a898..b5c372f41513 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -42,7 +42,6 @@ import org.jetbrains.idea.svn.*; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; -import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.*; import org.tmatesoft.svn.util.SVNLogType; @@ -50,7 +49,6 @@ import javax.swing.*; import javax.swing.table.TableCellRenderer; import java.awt.*; import java.awt.event.MouseEvent; -import java.io.File; import java.nio.charset.Charset; import java.util.Collections; import java.util.Date; @@ -285,16 +283,7 @@ public class SvnHistoryProvider @Override protected void preliminary() throws SVNException { - SVNWCClient wcClient = myVcs.createWCClient(); - myInfo = wcClient.doInfo(new File(myFile.getIOFile().getAbsolutePath()), SVNRevision.UNDEFINED); - wcClient.setEventHandler(new ISVNEventHandler() { - public void handleEvent(SVNEvent event, double progress) throws SVNException { - } - - public void checkCancelled() throws SVNCancelException { - myPI.checkCanceled(); - } - }); + myInfo = myVcs.getInfo(myFile.getIOFile()); if (myInfo == null || myInfo.getRepositoryRootURL() == null) { myException = new VcsException("File ''{0}'' is not under version control" + myFile.getIOFile()); return; @@ -319,14 +308,15 @@ public class SvnHistoryProvider myPI.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", myUrl)); } final SVNRevision pegRevision = myInfo.getRevision(); - SVNLogClient client = myVcs.createLogClient(); try { - // a bug noticed when testing: we should pass "limit + 1" to get "limit" rows - client - .doLog(new File[]{new File(myFile.getIOFile().getAbsolutePath())}, - myFrom == null ? SVNRevision.HEAD : myFrom, myTo == null ? SVNRevision.create(1) : myTo, myPeg, - false, true, myShowMergeSources && mySupport15, myLimit + 1, null, - new MyLogEntryHandler(myVcs, myUrl, pegRevision, relativeUrl, createConsumerAdapter(myConsumer), repoRootURL, myFile.getCharset())); + myVcs.getFactory(myFile.getIOFile()).createHistoryClient().doLog( + myFile.getIOFile(), + myFrom == null ? SVNRevision.HEAD : myFrom, + myTo == null ? SVNRevision.create(1) : myTo, myPeg, + false, true, myShowMergeSources && mySupport15, myLimit + 1, null, + new MyLogEntryHandler(myVcs, myUrl, pegRevision, relativeUrl, + createConsumerAdapter(myConsumer), + repoRootURL, myFile.getCharset())); } catch (SVNCancelException e) { // @@ -383,7 +373,6 @@ public class SvnHistoryProvider } } - SVNWCClient wcClient = myVcs.createWCClient(); final SVNURL svnurl = SVNURL.parseURIEncoded(myUrl); SVNRevision operationalFrom = myFrom == null ? SVNRevision.HEAD : myFrom; final SVNURL rootURL = getRepositoryRoot(svnurl, myFrom); @@ -395,6 +384,7 @@ public class SvnHistoryProvider if (myUrl.startsWith(root)) { relativeUrl = myUrl.substring(root.length()); } + // TODO: Update this call to myVcs.getFactory.createHistoryClient SVNLogClient client = myVcs.createLogClient(); // a bug noticed when testing: we should pass "limit + 1" to get "limit" rows client.doLog(svnurl, new String[]{}, myPeg == null ? myFrom : myPeg, @@ -420,6 +410,7 @@ public class SvnHistoryProvider relativeUrl = myUrl.substring(root.length()); } + // TODO: Update this call to myVcs.getFactory.createHistoryClient SVNLogClient client = myVcs.createLogClient(); final RepositoryLogEntryHandler repositoryLogEntryHandler = @@ -437,36 +428,15 @@ public class SvnHistoryProvider } private SVNURL getRepositoryRoot(SVNURL svnurl, SVNRevision operationalFrom) throws SVNException { - final SVNRepository repository = myVcs.createRepository(svnurl); - final SVNURL root = repository.getRepositoryRoot(false); - if (root == null) { - return repository.getRepositoryRoot(true); - } - return root; - /*final SVNWCClient wcClient = myVcs.createWCClient(); - try { - final SVNInfo info; - info = wcClient.doInfo(svnurl, myPeg, operationalFrom); - return info.getRepositoryRootURL(); - } - catch (SVNException e) { - try { - final SVNInfo info; - info = wcClient.doInfo(svnurl, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED); - return info.getRepositoryRootURL(); - } catch (SVNException e1) { - final SVNInfo info; - info = wcClient.doInfo(svnurl, SVNRevision.UNDEFINED, SVNRevision.HEAD); - return info.getRepositoryRootURL(); - } - }*/ + SVNInfo info = myVcs.getInfo(svnurl, SVNRevision.HEAD); + + return info != null ? info.getRepositoryRootURL() : null; } private boolean existsNow(SVNURL svnurl) { - final SVNWCClient wcClient = myVcs.createWCClient(); final SVNInfo info; try { - info = wcClient.doInfo(svnurl, SVNRevision.HEAD, SVNRevision.HEAD); + info = myVcs.getInfo(svnurl, SVNRevision.HEAD, SVNRevision.HEAD, null); } catch (SVNException e) { return false; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java new file mode 100644 index 000000000000..f9b0958dda3f --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java @@ -0,0 +1,38 @@ +package org.jetbrains.idea.svn.history; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.tmatesoft.svn.core.ISVNLogEntryHandler; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.SVNRevision; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitHistoryClient extends BaseSvnClient implements HistoryClient { + @Override + public void doLog(@NotNull File path, + @NotNull SVNRevision startRevision, + @NotNull SVNRevision endRevision, + @Nullable SVNRevision pegRevision, + boolean stopOnCopy, + boolean discoverChangedPaths, + boolean includeMergedRevisions, + long limit, + @Nullable String[] revisionProperties, + @Nullable ISVNLogEntryHandler handler) throws VcsException { + try { + // a bug noticed when testing: we should pass "limit + 1" to get "limit" rows + myVcs.createLogClient() + .doLog(new File[]{path}, startRevision, endRevision, pegRevision, stopOnCopy, discoverChangedPaths, includeMergedRevisions, limit, + revisionProperties, handler); + } + catch (SVNException e) { + throw new VcsException(e); + } + } +} From e05b576cd325b2c0d779743ce885105d6457280a Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 15 Aug 2013 17:33:29 +0400 Subject: [PATCH 07/30] IDEA-94942 "Add" action for files and directories --- .../openapi/util/text/StringUtil.java | 15 ++- .../idea/svn/SvnFileSystemListener.java | 2 +- .../src/org/jetbrains/idea/svn/SvnVcs.java | 8 +- .../jetbrains/idea/svn/actions/AddAction.java | 10 +- .../org/jetbrains/idea/svn/add/AddClient.java | 9 +- .../jetbrains/idea/svn/add/CmdAddClient.java | 104 +++++++++++++++--- .../idea/svn/add/SvnKitAddClient.java | 22 +++- .../svn/checkin/SvnCheckinEnvironment.java | 32 +++--- .../idea/svn/commandLine/CommandUtil.java | 53 +++++++++ .../UpdateOutputLineConverter.java | 26 +---- .../idea/svn/history/CmdHistoryClient.java | 22 +--- 11 files changed, 216 insertions(+), 87 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 82bd5a4a1f95..4f537d5b9daa 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -43,6 +43,7 @@ public class StringUtil extends StringUtilRt { @NonNls private static final String VOWELS = "aeiouy"; @NonNls private static final Pattern EOL_SPLIT_PATTERN = Pattern.compile(" *(\r|\n|\r\n)+ *"); + @NonNls private static final Pattern EOL_SPLIT_PATTERN_WITH_EMPTY = Pattern.compile(" *(\r|\n|\r\n) *"); public static final NotNullFunction QUOTER = new NotNullFunction() { @Override @@ -2133,7 +2134,19 @@ public class StringUtil extends StringUtilRt { */ @NotNull public static String[] splitByLines(@NotNull String string) { - return EOL_SPLIT_PATTERN.split(string); + return splitByLines(string, true); + } + + /** + * Splits string by lines. If several line separators are in a row corresponding empty lines + * are also added to result if {@code excludeEmptyStrings} is {@code false}. + * + * @param string String to split + * @return array of strings + */ + @NotNull + public static String[] splitByLines(@NotNull String string, boolean excludeEmptyStrings) { + return (excludeEmptyStrings ? EOL_SPLIT_PATTERN : EOL_SPLIT_PATTERN_WITH_EMPTY).split(string); } @NotNull diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java index 65113dfe57e1..0aa605e4bec6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java @@ -791,7 +791,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp @Override protected void executeImpl() throws SVNException { try { - vcs.getFactory(ioFile).createAddClient().add(ioFile, null, false, false, true); + vcs.getFactory(ioFile).createAddClient().add(ioFile, null, false, false, true, null); } catch (VcsException e) { throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index 26bbb6235629..b29315e633ab 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -1350,7 +1350,13 @@ public class SvnVcs extends AbstractVcs { return myCheckoutProvider; } - public ClientFactory getFactory() { + /** + * Should be private for now - to avoid usages of this method as it will not automatically + * detect svn 1.8 working copy format to guarantee command line client. + * + * @return + */ + private ClientFactory getFactory() { return myConfiguration.myUseAcceleration.equals(SvnConfiguration.UseAcceleration.commandLine) ? cmdClientFactory : svnKitClientFactory; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AddAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AddAction.java index 06c255b6ed38..7558a483fcd7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AddAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AddAction.java @@ -30,8 +30,6 @@ import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnStatusUtil; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.checkin.SvnCheckinEnvironment; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.wc.SVNWCClient; import java.util.*; @@ -68,8 +66,6 @@ public class AddAction extends BasicAction { ProjectLevelVcsManager manager = ProjectLevelVcsManager.getInstance(project); manager.startBackgroundVcsOperation(); try { - - SVNWCClient wcClient = activeVcs.createWCClient(); final Set additionallyDirty = new HashSet(); final FileStatusManager fileStatusManager = FileStatusManager.getInstance(project); for (VirtualFile item : items) { @@ -84,13 +80,13 @@ public class AddAction extends BasicAction { } } } - Collection exceptions = - SvnCheckinEnvironment.scheduleUnversionedFilesForAddition(wcClient, Arrays.asList(items), true); + Collection exceptions = + SvnCheckinEnvironment.scheduleUnversionedFilesForAddition(activeVcs, Arrays.asList(items), true); additionallyDirty.addAll(Arrays.asList(items)); markDirty(project, additionallyDirty); if (!exceptions.isEmpty()) { final Collection messages = new ArrayList(exceptions.size()); - for (SVNException exception : exceptions) { + for (VcsException exception : exceptions) { messages.add(exception.getMessage()); } throw new VcsException(messages); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/AddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/AddClient.java index aef1f868dbff..718a56dea9af 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/AddClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/AddClient.java @@ -2,8 +2,10 @@ package org.jetbrains.idea.svn.add; import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.SvnClient; import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; import java.io.File; @@ -12,5 +14,10 @@ import java.io.File; */ public interface AddClient extends SvnClient { - void add(@NotNull File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) throws VcsException; + void add(@NotNull File file, + @Nullable SVNDepth depth, + boolean makeParents, + boolean includeIgnored, + boolean force, + @Nullable ISVNEventHandler handler) throws VcsException; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java index 4219816dcc92..1e0993504526 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java @@ -1,36 +1,114 @@ package org.jetbrains.idea.svn.add; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.BaseSvnClient; -import org.jetbrains.idea.svn.commandLine.SvnCommandFactory; +import org.jetbrains.idea.svn.commandLine.CommandUtil; import org.jetbrains.idea.svn.commandLine.SvnCommandName; -import org.jetbrains.idea.svn.commandLine.SvnSimpleCommand; +import org.jetbrains.idea.svn.commandLine.SvnLineCommand; import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNEvent; +import org.tmatesoft.svn.core.wc.SVNStatusType; import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @author Konstantin Kolosovsky. */ public class CmdAddClient extends BaseSvnClient implements AddClient { + private static final double DEFAULT_PROGRESS = 0.0; + @Override - public void add(@NotNull File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) throws VcsException { - SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myVcs.getProject(), null, SvnCommandName.add); - command.addParameters(file.getAbsolutePath()); + public void add(@NotNull File file, + @Nullable SVNDepth depth, + boolean makeParents, + boolean includeIgnored, + boolean force, + @Nullable ISVNEventHandler handler) throws VcsException { + List parameters = prepareParameters(file, depth, makeParents, includeIgnored, force); + + try { + SvnLineCommand command = CommandUtil.runSimple(SvnCommandName.add, myVcs, null, null, parameters); + // TODO: handler should be called in parallel with command execution, but this will be in other thread + // TODO: check if that is ok for current handler implementation + // TODO: add possibility to invoke "handler.checkCancelled" - process should be killed + + parseOutput(command, handler); + } + catch (SVNException e) { + throw new VcsException(e); + } + } + + private void parseOutput(@NotNull SvnLineCommand command, @Nullable ISVNEventHandler handler) throws VcsException, SVNException { + if (StringUtil.isEmpty(command.getOutput())) { + // if file is versioned, adding it with "force" produces no output + // TODO: so handler will not be called - check if this compatible with svnkit + return; + } + + Parser parser = new Parser(handler); + for (String line : StringUtil.splitByLines(command.getOutput())) { + parser.onLine(line); + } + } + + private static List prepareParameters(File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) { + List parameters = new ArrayList(); + + parameters.add(file.getAbsolutePath()); if (depth != null) { - command.addParameters("--depth", depth.getName()); + parameters.add("--depth"); + parameters.add(depth.getName()); } - if (makeParents) { - command.addParameters("--parents"); + CommandUtil.put(parameters, makeParents, "--parents"); + CommandUtil.put(parameters, includeIgnored, "--no-ignore"); + CommandUtil.put(parameters, force, "--force"); + + return parameters; + } + + private static class Parser { + private static final String STATUS = "\\s*(\\w)"; + private static final String PATH = "\\s*(.*?)\\s*"; + private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + PATH); + + @Nullable + ISVNEventHandler handler; + + public Parser(@Nullable ISVNEventHandler handler) { + this.handler = handler; } - if (includeIgnored) { - command.addParameters("--no-ignore"); + + public void onLine(@NotNull String line) throws VcsException, SVNException { + Matcher matcher = CHANGED_PATH.matcher(line); + if (matcher.matches()) { + processChangedPath(matcher); + } + else { + throw new VcsException("unknown state on line " + line); + } } - if (force) { - command.addParameters("--force"); + + private void processChangedPath(@NotNull Matcher matcher) throws VcsException, SVNException { + SVNStatusType contentStatus = CommandUtil.getStatusType(matcher.group(1)); + String path = matcher.group(2); + + if (handler != null) { + // TODO: No suitable ways to create SVNEvent. This will be changed when removing SvnKit objects from interfaces. + handler.handleEvent( + new SVNEvent(new File(path), null, null, 0, contentStatus, null, null, null, null, null, null, null, null, null, null), + DEFAULT_PROGRESS); + } } - command.run(); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/SvnKitAddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/SvnKitAddClient.java index 03719ff00ff6..d6250c71f073 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/SvnKitAddClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/SvnKitAddClient.java @@ -2,9 +2,12 @@ package org.jetbrains.idea.svn.add; import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.BaseSvnClient; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNWCClient; import java.io.File; @@ -12,13 +15,22 @@ import java.io.File; * @author Konstantin Kolosovsky. */ public class SvnKitAddClient extends BaseSvnClient implements AddClient { + @Override - public void add(@NotNull File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) throws VcsException { + public void add(@NotNull File file, + @Nullable SVNDepth depth, + boolean makeParents, + boolean includeIgnored, + boolean force, + @Nullable ISVNEventHandler handler) throws VcsException { try { - myVcs.createWCClient().doAdd(file, force, - false, // directory should already be created - makeParents, // not used but will be passed as makeParents value - SVNDepth.recurseFromDepth(depth)); + SVNWCClient client = myVcs.createWCClient(); + + client.setEventHandler(handler); + client.doAdd(file, force, + false, // directory should already be created + makeParents, // not used but will be passed as makeParents value + SVNDepth.recurseFromDepth(depth)); } catch (SVNException e) { throw new VcsException(e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java index 16efee33ada9..f35e8d07a008 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java @@ -450,30 +450,22 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { } public List scheduleUnversionedFilesForAddition(List files) { - final List result = new ArrayList(); - final SVNWCClient wcClient = mySvnVcs.createWCClient(); - - final List exceptionList = scheduleUnversionedFilesForAddition(wcClient, files); - for (SVNException svnException : exceptionList) { - result.add(new VcsException(svnException)); - } - return result; + return scheduleUnversionedFilesForAddition(mySvnVcs, files); } - public static List scheduleUnversionedFilesForAddition(SVNWCClient wcClient, List files) { - return scheduleUnversionedFilesForAddition(wcClient, files, false); + public static List scheduleUnversionedFilesForAddition(@NotNull SvnVcs vcs, List files) { + return scheduleUnversionedFilesForAddition(vcs, files, false); } - public static List scheduleUnversionedFilesForAddition(SVNWCClient wcClient, List files, final boolean recursive) { - List exceptions = new ArrayList(); - + public static List scheduleUnversionedFilesForAddition(@NotNull SvnVcs vcs, List files, final boolean recursive) { Collections.sort(files, FilePathComparator.getInstance()); - wcClient.setEventHandler(new ISVNEventHandler() { + ISVNEventHandler eventHandler = new ISVNEventHandler() { @Override public void handleEvent(SVNEvent event, double progress) throws SVNException { final ProgressManager pm = ProgressManager.getInstance(); final ProgressIndicator pi = pm.getProgressIndicator(); + // TODO: pi is null here when invoking "Add" action if (pi != null && event.getFile() != null) { File file = event.getFile(); pi.setText(SvnBundle.message("progress.text2.adding", file.getName() + " (" + file.getParent() + ")")); @@ -488,12 +480,18 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { if (pi.isCanceled()) throw new SVNCancelException(); } } - }); + }; + + List exceptions = new ArrayList(); + for (VirtualFile file : files) { try { - wcClient.doAdd(new File(FileUtil.toSystemDependentName(file.getPath())), true, false, true, recursive); + File convertedFile = new File(FileUtil.toSystemDependentName(file.getPath())); + SVNDepth depth = recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY; + + vcs.getFactory(convertedFile).createAddClient().add(convertedFile, depth, true, false, true, eventHandler); } - catch (SVNException e) { + catch (VcsException e) { exceptions.add(e); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index a51150ae4cec..abd9c6f56f6b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -1,5 +1,6 @@ package org.jetbrains.idea.svn.commandLine; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,6 +13,7 @@ import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc.SVNStatusType; import java.io.File; import java.util.ArrayList; @@ -46,4 +48,55 @@ public class CommandUtil { // empty command name passed, as command name is already in command.getParameters() return runSimple(SvnCommandName.empty, vcs, base, url, new ArrayList(Arrays.asList(command.getParameters()))); } + + /** + * Puts given value to parameters if condition is satisfied + * + * @param parameters + * @param condition + * @param value + */ + public static void put(@NotNull List parameters, boolean condition, @NotNull String value) { + if (condition) { + parameters.add(value); + } + } + + /** + * Gets svn status represented by single character. + * + * @param type + * @return + */ + public static char getStatusChar(@Nullable String type) { + return !StringUtil.isEmpty(type) ? type.charAt(0) : ' '; + } + + @NotNull + public static SVNStatusType getStatusType(@Nullable String type) { + return getStatusType(getStatusChar(type)); + } + + @NotNull + public static SVNStatusType getStatusType(char first) { + final SVNStatusType contentsStatus; + if ('A' == first) { + contentsStatus = SVNStatusType.STATUS_ADDED; + } else if ('D' == first) { + contentsStatus = SVNStatusType.STATUS_DELETED; + } else if ('U' == first) { + contentsStatus = SVNStatusType.CHANGED; + } else if ('C' == first) { + contentsStatus = SVNStatusType.CONFLICTED; + } else if ('G' == first) { + contentsStatus = SVNStatusType.MERGED; + } else if ('R' == first) { + contentsStatus = SVNStatusType.STATUS_REPLACED; + } else if ('E' == first) { + contentsStatus = SVNStatusType.STATUS_OBSTRUCTED; + } else { + contentsStatus = SVNStatusType.STATUS_NORMAL; + } + return contentsStatus; + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java index 6536646374bd..ab43b605d747 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java @@ -103,9 +103,9 @@ public class UpdateOutputLineConverter { if (line.length() < 5) return null; final char first = line.charAt(0); if (' ' != first && ! ourActions.contains(first)) return null; - final SVNStatusType contentsStatus = getStatusType(first); + final SVNStatusType contentsStatus = CommandUtil.getStatusType(first); final char second = line.charAt(1); - final SVNStatusType propertiesStatus = getStatusType(second); + final SVNStatusType propertiesStatus = CommandUtil.getStatusType(second); final char lock = line.charAt(2); // dont know what to do with stolen lock info if (' ' != lock && 'B' != lock) return null; final char treeConflict = line.charAt(3); @@ -140,28 +140,6 @@ public class UpdateOutputLineConverter { null, action, expectedAction, null, null, null, null, null); } - private SVNStatusType getStatusType(char first) { - final SVNStatusType contentsStatus; - if ('A' == first) { - contentsStatus = SVNStatusType.STATUS_ADDED; - } else if ('D' == first) { - contentsStatus = SVNStatusType.STATUS_DELETED; - } else if ('U' == first) { - contentsStatus = SVNStatusType.CHANGED; - } else if ('C' == first) { - contentsStatus = SVNStatusType.CONFLICTED; - } else if ('G' == first) { - contentsStatus = SVNStatusType.MERGED; - } else if ('R' == first) { - contentsStatus = SVNStatusType.STATUS_REPLACED; - } else if ('E' == first) { - contentsStatus = SVNStatusType.STATUS_OBSTRUCTED; - } else { - contentsStatus = SVNStatusType.STATUS_NORMAL; - } - return contentsStatus; - } - @Nullable private long matchAndGetRevision(final Pattern pattern, final String line) { final Matcher matcher = pattern.matcher(line); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java index 6dfdf68bc741..0b507a63e54f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java @@ -34,8 +34,6 @@ public class CmdHistoryClient extends BaseSvnClient implements HistoryClient { private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.history.CmdHistoryClient"); - private static final String LINES_SPLIT_WITH_EMPTY = " *(\r|\n|\r\n) *"; - @Override public void doLog(@NotNull File path, @NotNull SVNRevision startRevision, @@ -67,7 +65,7 @@ public class CmdHistoryClient extends BaseSvnClient implements HistoryClient { private static void parseOutput(@Nullable ISVNLogEntryHandler handler, @NotNull SvnLineCommand command) throws VcsException, SVNException { Parser parser = new Parser(handler); - for (String line : command.getOutput().split(LINES_SPLIT_WITH_EMPTY)) { + for (String line : StringUtil.splitByLines(command.getOutput(), false)) { parser.onLine(line); } } @@ -83,21 +81,15 @@ public class CmdHistoryClient extends BaseSvnClient implements HistoryClient { parameters.add("--revision"); parameters.add(startRevision + ":" + endRevision); - put(parameters, stopOnCopy, "--stop-on-copy"); - put(parameters, discoverChangedPaths, "--verbose"); - put(parameters, includeMergedRevisions, "--use-merge-history"); + CommandUtil.put(parameters, stopOnCopy, "--stop-on-copy"); + CommandUtil.put(parameters, discoverChangedPaths, "--verbose"); + CommandUtil.put(parameters, includeMergedRevisions, "--use-merge-history"); parameters.add("--limit"); parameters.add(String.valueOf(limit)); return parameters; } - private static void put(@NotNull List parameters, boolean condition, @NotNull String value) { - if (condition) { - parameters.add(value); - } - } - private static class Parser { private static final String REVISION = "\\s*r(\\d+)\\s*"; private static final String AUTHOR = "\\s*([^|]*)\\s*"; @@ -158,7 +150,7 @@ public class CmdHistoryClient extends BaseSvnClient implements HistoryClient { } String path = matcher.group(2); - char type = getType(matcher.group(1)); + char type = CommandUtil.getStatusChar(matcher.group(1)); String copyPath = matcher.group(5); long copyRevision = !StringUtil.isEmpty(matcher.group(6)) ? Long.valueOf(matcher.group(6)) : 0; @@ -211,10 +203,6 @@ public class CmdHistoryClient extends BaseSvnClient implements HistoryClient { return result; } - private static char getType(@Nullable String type) { - return !StringUtil.isEmpty(type) ? type.charAt(0) : ' '; - } - private static class Entry { Map changedPaths = new HashMap(); long revision; From 1236be5472e66712561f11d43f323f43c0312d0d Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 15 Aug 2013 21:01:04 +0400 Subject: [PATCH 08/30] IDEA-94942 Small refactoring and fixes after review --- .../idea/svn/AuthenticationCallback.java | 9 +++ .../idea/svn/commandLine/SvnCommand.java | 9 +++ .../idea/svn/commandLine/SvnCommandName.java | 1 + .../idea/svn/commandLine/SvnLineCommand.java | 58 ++++++++++--------- ...IdeaSvnkitBasedAuthenticationCallback.java | 1 + .../idea/svn/commandLine/CommandUtil.java | 2 +- 6 files changed, 53 insertions(+), 27 deletions(-) diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java index 473a422d6fb6..da99d854e13b 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java @@ -52,6 +52,15 @@ public interface AuthenticationCallback { */ boolean authenticateFor(@Nullable String realm, File base, boolean previousFailed, boolean passwordRequest); + /** + * Provides authentication information to access given url by authentication protocol identified by type. + * For instance, username/password for http/svn protocols. SSL client certificate for two way SSL protocol. + * + * @param url url to item in repository + * @param type authentication protocol type with svn specific values, like "svn.simple" for http. + * @return + */ + @Nullable SVNAuthentication requestCredentials(@Nullable SVNURL url, String type); /** diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java index d219653fe514..1eb18ad669e9 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java @@ -80,6 +80,15 @@ public abstract class SvnCommand { } } + /** + * Indicates if process was destroyed "manually" by command execution logic. + * + * @return + */ + public boolean isManuallyDestroyed() { + return myIsDestroyed; + } + public void start() { synchronized (myLock) { checkNotStarted(); diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index f8ec332804c5..70e288764447 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -22,6 +22,7 @@ package org.jetbrains.idea.svn.commandLine; * Time: 1:49 PM */ public enum SvnCommandName { + // TODO: temporary command for "more smooth" converting between simple commands and line commands empty("", false), version("--version", false), info("info", false), diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java index e40305d2575a..aa8f88d61c4c 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java @@ -59,6 +59,7 @@ import java.util.regex.Pattern; * honestly stolen from GitLineHandler */ public class SvnLineCommand extends SvnCommand { + public static final String AUTHENTICATION_REALM = "Authentication realm:"; public static final String CERTIFICATE_ERROR = "Error validating server certificate for"; public static final String PASSPHRASE_FOR = "Passphrase for"; @@ -66,6 +67,13 @@ public class SvnLineCommand extends SvnCommand { public static final String CANNOT_AUTHENTICATE_TO_PROXY = "Could not authenticate to proxy server"; public static final String AUTHENTICATION_FAILED_MESSAGE = "Authentication failed"; + private static final String INVALID_CREDENTIALS_FOR_SVN_PROTOCOL = "svn: E170001: Can't get password"; + private static final String UNTRUSTED_SERVER_CERTIFICATE = "Server SSL certificate untrusted"; + private static final String ACCESS_TO_PREFIX = "Access to "; + private static final String FORBIDDEN_STATUS = "forbidden"; + + private static final Pattern UNABLE_TO_CONNECT_TO_URL_PATTERN = Pattern.compile("Unable to connect to a repository at URL '(.*)'"); + // kept for exact text //public static final String CLIENT_CERTIFICATE_FILENAME = "Client certificate filename:"; /** @@ -106,22 +114,21 @@ public class SvnLineCommand extends SvnCommand { public static SvnLineCommand runWithAuthenticationAttempt(final String exePath, final File firstFile, - SvnCommandName commandName, - final LineCommandListener listener, - @Nullable AuthenticationCallback authenticationCallback, - String... parameters) throws SvnBindException { - return runWithAuthenticationAttempt(exePath, firstFile, null, commandName, listener, authenticationCallback, false, parameters); + SvnCommandName commandName, + final LineCommandListener listener, + @Nullable AuthenticationCallback authenticationCallback, + String... parameters) throws SvnBindException { + return runWithAuthenticationAttempt(exePath, firstFile, null, commandName, listener, authenticationCallback, parameters); } public static SvnLineCommand runWithAuthenticationAttempt(final String exePath, final File firstFile, - final SVNURL url, - SvnCommandName commandName, - final LineCommandListener listener, - @Nullable AuthenticationCallback authenticationCallback, - boolean needCleanup, - String... parameters) throws SvnBindException { + final SVNURL url, + SvnCommandName commandName, + final LineCommandListener listener, + @Nullable AuthenticationCallback authenticationCallback, + String... parameters) throws SvnBindException { File base = firstFile != null ? (firstFile.isDirectory() ? firstFile : firstFile.getParentFile()) : null; base = SvnBindUtil.correctUpToExistingParent(base); @@ -143,9 +150,7 @@ public class SvnLineCommand extends SvnCommand { if (authenticationCallback != null) { final AuthCallbackCase callback = createCallback(errText, authenticationCallback, base, url); if (callback != null) { - if (needCleanup) { - cleanup(exePath, commandName, base); - } + cleanup(exePath, command, base); if (callback.getCredentials(errText)) { if (authenticationCallback.getSpecialConfigDir() != null) { configDir = authenticationCallback.getSpecialConfigDir(); @@ -212,16 +217,16 @@ public class SvnLineCommand extends SvnCommand { if (errText.contains(AUTHENTICATION_FAILED_MESSAGE)) { return new UsernamePasswordCallback(callback, base, url); } - if (errText.contains("svn: E170001: Can't get password")) { + if (errText.contains(INVALID_CREDENTIALS_FOR_SVN_PROTOCOL)) { // svn protocol invalid credentials return new UsernamePasswordCallback(callback, base, url); } // https one-way protocol untrusted server certificate - if (errText.contains("Server SSL certificate untrusted")) { + if (errText.contains(UNTRUSTED_SERVER_CERTIFICATE)) { return new CertificateCallbackCase(callback, base); } // https two-way protocol invalid client certificate - if (errText.contains("Access to ") && errText.contains("forbidden")) { + if (errText.contains(ACCESS_TO_PREFIX) && errText.contains(FORBIDDEN_STATUS)) { return new TwoWaySslCallback(callback, base, url); } return null; @@ -266,8 +271,7 @@ public class SvnLineCommand extends SvnCommand { } private SVNURL parseUrlFromError(String errorText) { - Pattern pattern = Pattern.compile("Unable to connect to a repository at URL '(.*)'"); - Matcher matcher = pattern.matcher(errorText); + Matcher matcher = UNABLE_TO_CONNECT_TO_URL_PATTERN.matcher(errorText); String urlValue = null; if (matcher.find()) { @@ -279,7 +283,7 @@ public class SvnLineCommand extends SvnCommand { private SVNURL parseUrl(String urlValue) { try { - return SVNURL.parseURIDecoded(urlValue); + return SVNURL.parseURIEncoded(urlValue); } catch (SVNException e) { return null; @@ -305,7 +309,8 @@ public class SvnLineCommand extends SvnCommand { @Override boolean getCredentials(String errText) throws SvnBindException { - final String realm = errText.startsWith(AUTHENTICATION_REALM) ? cutFirstLine(errText).substring(AUTHENTICATION_REALM.length()).trim() : null; + final String realm = + errText.startsWith(AUTHENTICATION_REALM) ? cutFirstLine(errText).substring(AUTHENTICATION_REALM.length()).trim() : null; final boolean isPassword = StringUtil.containsIgnoreCase(errText, "password"); if (myTried) { myAuthenticationCallback.clearPassiveCredentials(realm, myBase, isPassword); @@ -404,15 +409,16 @@ public class SvnLineCommand extends SvnCommand { } } - private static void cleanup(String exePath, SvnCommandName commandName, File base) throws SvnBindException { + private static void cleanup(String exePath, SvnCommand command, File base) throws SvnBindException { File wcRoot = SvnBindUtil.getWcRoot(base); if (wcRoot == null) throw new SvnBindException("Can not find working copy root for: " + base.getPath()); - //cleanup -> check command type - if (commandName.isWriteable()) { - final SvnSimpleCommand command = new SvnSimpleCommand(wcRoot, SvnCommandName.cleanup, exePath); + // TODO: could be issues with fake "empty" command as it is not writable - but only read commands currently use "empty" command + // TODO: and "empty" command will be removed shortly + if (command.isManuallyDestroyed() && command.getCommandName().isWriteable()) { + final SvnSimpleCommand cleanupCommand = new SvnSimpleCommand(wcRoot, SvnCommandName.cleanup, exePath); try { - command.run(); + cleanupCommand.run(); } catch (VcsException e) { throw new SvnBindException(e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java index be422e83ac0a..46a4e4264cc0 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java @@ -77,6 +77,7 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall return new CredentialsAuthenticator(myVcs).tryAuthenticate(realm, url, file, previousFailed, passwordRequest); } + @Nullable @Override public SVNAuthentication requestCredentials(@Nullable SVNURL url, String type) { return url != null ? myVcs.getSvnConfiguration().getInteractiveManager(myVcs).getProvider().requestClientAuthentication( diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index abd9c6f56f6b..30fb68f37fb5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -36,7 +36,7 @@ public class CommandUtil { try { return SvnLineCommand .runWithAuthenticationAttempt(exe, base, url, name, new SvnCommitRunner.CommandListener(null), - new IdeaSvnkitBasedAuthenticationCallback(vcs), false, ArrayUtil.toStringArray(parameters)); + new IdeaSvnkitBasedAuthenticationCallback(vcs), ArrayUtil.toStringArray(parameters)); } catch (SvnBindException e) { throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); From d6e4e3860079234871a7a58abea4a68ae92395d7 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 16 Aug 2013 10:58:18 +0400 Subject: [PATCH 09/30] IDEA-94942 Fixed "add" action output parsing for binary files --- .../src/org/jetbrains/idea/svn/add/CmdAddClient.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java index 1e0993504526..c637eac967a0 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java @@ -78,9 +78,10 @@ public class CmdAddClient extends BaseSvnClient implements AddClient { } private static class Parser { - private static final String STATUS = "\\s*(\\w)"; + private static final String STATUS = "\\s*(\\w)\\s*"; + private static final String OPTIONAL_FILE_TYPE = "(\\(.*\\))?"; private static final String PATH = "\\s*(.*?)\\s*"; - private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + PATH); + private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + OPTIONAL_FILE_TYPE + PATH); @Nullable ISVNEventHandler handler; @@ -101,7 +102,7 @@ public class CmdAddClient extends BaseSvnClient implements AddClient { private void processChangedPath(@NotNull Matcher matcher) throws VcsException, SVNException { SVNStatusType contentStatus = CommandUtil.getStatusType(matcher.group(1)); - String path = matcher.group(2); + String path = matcher.group(3); if (handler != null) { // TODO: No suitable ways to create SVNEvent. This will be changed when removing SvnKit objects from interfaces. From c928fe5dc70802639efd5642e29ef4dba8fe9ca8 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 16 Aug 2013 12:00:19 +0400 Subject: [PATCH 10/30] IDEA-94942 Force command line client usage if working copy of svn 1.8 format detected --- .../idea/svn/ForNestedRootChecker.java | 2 +- .../idea/svn/SvnFileUrlMappingImpl.java | 2 +- .../src/org/jetbrains/idea/svn/SvnVcs.java | 21 ++++++++++++------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/ForNestedRootChecker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/ForNestedRootChecker.java index 660edef07f08..6a62276b3a1a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/ForNestedRootChecker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/ForNestedRootChecker.java @@ -56,7 +56,7 @@ public class ForNestedRootChecker { @Nullable public Real createReal(final VirtualFile file, final VirtualFile vcsRoot) { - final SVNInfo info = myVcs.runInfoCommand(file); + final SVNInfo info = myVcs.getInfo(file); if (info == null || info.getRepositoryRootURL() == null || info.getURL() == null) { return null; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java index 711bb8045f91..68e7c07848c2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java @@ -538,7 +538,7 @@ public class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentState if (copyRoot == null || vcsRoot == null) continue; final SvnVcs vcs = SvnVcs.getInstance(myProject); - final SVNInfo svnInfo = vcs.runInfoCommand(copyRoot); + final SVNInfo svnInfo = vcs.getInfo(copyRoot); if ((svnInfo == null) || (svnInfo.getRepositoryRootURL() == null)) continue; final RootUrlInfo info = diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index b29315e633ab..907cdcbb8dee 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -922,7 +922,14 @@ public class SvnVcs extends AbstractVcs { return new File(file, pathToDirProps); } - public SVNInfo runInfoCommand(final File file) { + /** + * Provides info either with command line or SvnKit based on project settings. + * Call this method only if failed to detect working copy format by any other means. + * + * @param file + * @return + */ + private SVNInfo runInfoCommand(@NotNull final File file) { SVNInfo result = null; try { @@ -937,10 +944,6 @@ public class SvnVcs extends AbstractVcs { return result; } - public SVNInfo runInfoCommand(final VirtualFile file) { - return runInfoCommand(new File(file.getPath())); - } - public SVNInfo getInfo(@NotNull SVNURL url, SVNRevision pegRevision, SVNRevision revision, @@ -1031,8 +1034,13 @@ public class SvnVcs extends AbstractVcs { public WorkingCopyFormat getWorkingCopyFormat(@NotNull File ioFile) { RootUrlInfo rootInfo = getSvnFileUrlMapping().getWcRootForFilePath(ioFile); + WorkingCopyFormat format = rootInfo != null ? rootInfo.getFormat() : WorkingCopyFormat.UNKNOWN; - return rootInfo != null ? rootInfo.getFormat() : WorkingCopyFormat.UNKNOWN; + if (WorkingCopyFormat.UNKNOWN.equals(format)) { + format = SvnFormatSelector.findRootAndGetFormat(ioFile); + } + + return format; } public void refreshSSLProperty() { @@ -1362,7 +1370,6 @@ public class SvnVcs extends AbstractVcs { public ClientFactory getFactory(@NotNull File file) { WorkingCopyFormat format = getWorkingCopyFormat(file); - // TODO: Add here direct calculation of svn root if format == UNKNOWN return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) ? cmdClientFactory : getFactory(); } From 0f66f9d9052d4590dad566f65571502967730f50 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 19 Aug 2013 11:56:43 +0400 Subject: [PATCH 11/30] IDEA-94942 Logging and comments for some commands --- .../src/org/jetbrains/idea/svn/commandLine/SvnCommand.java | 2 ++ .../idea/svn/commandLine/SvnCommandLineInfoClient.java | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java index 1eb18ad669e9..9e355e56f4d6 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java @@ -47,6 +47,8 @@ public abstract class SvnCommand { private final File myWorkingDirectory; private Process myProcess; private OSProcessHandler myHandler; + // TODO: Try to implement commands in a way that they manually indicate if they need full output - to prevent situations + // TODO: when large amount of data needs to be stored instead of just sequential processing. private CapturingProcessAdapter outputAdapter; private final Object myLock; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java index 7b86b8c5270b..586aae567d5d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java @@ -145,14 +145,18 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { parser.parse(new ByteArrayInputStream(result.getBytes(CharsetToolkit.UTF8_CHARSET)), infoHandler[0]); } catch (SvnExceptionWrapper e) { + LOG.info("info output " + result); throw (SVNException) e.getCause(); } catch (IOException e) { + LOG.info("info output " + result); throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); } catch (ParserConfigurationException e) { + LOG.info("info output " + result); throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); } catch (SAXException e) { + LOG.info("info output " + result); throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); } } From e06a3466f15c2b89b098d4ca4f34517ec27d0aa1 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 19 Aug 2013 14:04:13 +0400 Subject: [PATCH 12/30] IDEA-94942 Revert action Fixed status command for single file Fixed status result parsing for normal (non-modified versioned) file --- .../idea/svn/commandLine/SvnCommandName.java | 5 +- .../idea/svn/SvnFileSystemListener.java | 83 +++++------- .../src/org/jetbrains/idea/svn/SvnVcs.java | 22 +++- .../jetbrains/idea/svn/add/CmdAddClient.java | 9 +- .../jetbrains/idea/svn/api/ClientFactory.java | 20 ++- .../idea/svn/api/CmdClientFactory.java | 4 + .../idea/svn/api/SvnKitClientFactory.java | 4 + .../idea/svn/commandLine/CommandUtil.java | 22 +++- .../SvnCommandLineStatusClient.java | 39 ++++-- .../SvnCommandLineUpdateClient.java | 6 +- .../idea/svn/portable/PortableStatus.java | 13 ++ .../idea/svn/revert/CmdRevertClient.java | 123 ++++++++++++++++++ .../idea/svn/revert/RevertClient.java | 18 +++ .../idea/svn/revert/SvnKitRevertClient.java | 31 +++++ .../svn/rollback/SvnRollbackEnvironment.java | 49 ++++--- .../idea/svn/update/SvnUpdateEnvironment.java | 2 +- 16 files changed, 349 insertions(+), 101 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/revert/RevertClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/revert/SvnKitRevertClient.java diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index 70e288764447..37eac203ff8d 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -32,8 +32,9 @@ public enum SvnCommandName { cleanup("cleanup", true), cat("cat", false), add("add", true), - log("log", false); - + log("log", false), + revert("revert", true); + private final String myName; private final boolean myWriteable; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java index 0aa605e4bec6..dc4f20ce51ab 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java @@ -286,23 +286,12 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } if (undo) { myUndoingMove = true; - final SVNWCClient wcClient = vcs.createWCClient(); - new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws SVNException { - wcClient.doRevert(dst, true); - } - }.execute(); + createRevertAction(vcs, dst, true).execute(); copyUnversionedMembersOfDirectory(src, dst); if (srcStatus == null || SvnVcs.svnStatusIsUnversioned(srcStatus)) { FileUtil.delete(src); } else { - new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws SVNException { - wcClient.doRevert(src, true); - } - }.execute(); + createRevertAction(vcs, src, true).execute(); } restoreFromUndoStorage(dst); } else { @@ -461,7 +450,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp * deleted: do nothing, return true (strange) */ public boolean delete(VirtualFile file) throws IOException { - SvnVcs vcs = getVCS(file); + final SvnVcs vcs = getVCS(file); if (vcs != null && SvnUtil.isAdminDirectory(file)) { return true; } @@ -473,12 +462,8 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp if (! SvnUtil.isSvnVersioned(vcs.getProject(), ioFile.getParentFile())) { return false; } - try { - if (SVNWCUtil.isWorkingCopyRoot(ioFile)) { - return false; - } - } catch (SVNException e) { - // + if (SvnUtil.isWorkingCopyRoot(ioFile)) { + return false; } SVNStatus status = getFileStatus(vcs, ioFile); @@ -504,13 +489,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } if (SvnVcs.svnStatusIs(status, SVNStatusType.STATUS_ADDED)) { try { - final SVNWCClient wcClient = vcs.createWCClient(); - new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws SVNException { - wcClient.doRevert(ioFile, false); - } - }.execute(); + createRevertAction(vcs, ioFile, false).execute(); } catch (SVNException e) { // ignore @@ -526,6 +505,21 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } } + @NotNull + private RepeatSvnActionThroughBusy createRevertAction(@NotNull final SvnVcs vcs, @NotNull final File file, final boolean recursive) { + return new RepeatSvnActionThroughBusy() { + @Override + protected void executeImpl() throws SVNException { + try { + vcs.getFactory(file).createRevertClient().revert(new File[]{file}, SVNDepth.fromRecurse(recursive), null); + } + catch (VcsException e) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); + } + } + }; + } + private boolean isAboveSourceOfCopyOrMove(final Project p, File ioFile) { for (MovedFileInfo file : myMovedFiles) { if (FileUtil.isAncestor(ioFile, file.mySrc, false)) return true; @@ -580,7 +574,6 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp if (! SvnUtil.isSvnVersioned(vcs.getProject(), ioDir) && ! pendingAdd) { return false; } - final SVNWCClient wcClient = vcs.createWCClient(); final File targetFile = new File(ioDir, name); SVNStatus status = getFileStatus(vcs, targetFile); @@ -600,12 +593,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } try { if (isUndo(vcs)) { - new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws SVNException { - wcClient.doRevert(targetFile, false); - } - }.execute(); + createRevertAction(vcs, targetFile, false).execute(); return true; } myAddedFiles.putValue(vcs.getProject(), new AddedFileInfo(dir, name, null, recursive)); @@ -980,18 +968,15 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp private void fillDeletedFiles(Project project, List> deletedFiles, Collection deleteAnyway) throws SVNException { final SvnVcs vcs = SvnVcs.getInstance(project); - final SVNStatusClient sc = vcs.createStatusClient(); final Collection files = myDeletedFiles.remove(project); for (final File file : files) { - boolean isAdded = false; - final SVNStatus status; - status = new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws SVNException { - myT = sc.doStatus(file, false); - } - }.compute(); - isAdded = SVNStatusType.STATUS_ADDED.equals(status.getNodeStatus()); + final SVNStatus status = new RepeatSvnActionThroughBusy() { + @Override + protected void executeImpl() throws SVNException { + myT = vcs.getFactory(file).createStatusClient().doStatus(file, false); + } + }.compute(); + boolean isAdded = SVNStatusType.STATUS_ADDED.equals(status.getNodeStatus()); final FilePath filePath = VcsContextFactory.SERVICE.getInstance().createFilePathOn(file); if (isAdded) { deleteAnyway.add(filePath); @@ -1036,18 +1021,12 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } @Nullable - private static SVNStatus getFileStatus(SvnVcs vcs, File file) { - SVNStatusClient stClient = vcs.createStatusClient(); - return getFileStatus(file, stClient); - } - - @Nullable - private static SVNStatus getFileStatus(final File file, final SVNStatusClient stClient) { + private static SVNStatus getFileStatus(@NotNull final SvnVcs vcs, @NotNull final File file) { try { return new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws SVNException { - myT = stClient.doStatus(file, false); + myT = vcs.getFactory(file).createStatusClient().doStatus(file, false); } }.compute(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index 907cdcbb8dee..3ad265cfa110 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -200,8 +200,8 @@ public class SvnVcs extends AbstractVcs { }; private SvnCheckoutProvider myCheckoutProvider; - private final ClientFactory cmdClientFactory; - private final ClientFactory svnKitClientFactory; + private ClientFactory cmdClientFactory; + private ClientFactory svnKitClientFactory; public void checkCommandLineVersion() { @@ -293,8 +293,6 @@ public class SvnVcs extends AbstractVcs { // remove used some time before old notification group ids correctNotificationIds(); myChecker = new SvnExecutableChecker(myProject); - cmdClientFactory = new CmdClientFactory(this); - svnKitClientFactory = new SvnKitClientFactory(this); } private void correctNotificationIds() { @@ -492,6 +490,9 @@ public class SvnVcs extends AbstractVcs { myChecker.checkExecutableAndNotifyIfNeeded(); } + cmdClientFactory = new CmdClientFactory(this); + svnKitClientFactory = new SvnKitClientFactory(this); + // do one time after project loaded StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() { @Override @@ -1359,13 +1360,20 @@ public class SvnVcs extends AbstractVcs { } /** - * Should be private for now - to avoid usages of this method as it will not automatically + * Try to avoid usages of this method (for now) as it could not correctly for all cases * detect svn 1.8 working copy format to guarantee command line client. * + * For instance, when working copies of several formats are presented in project + * (though it seems to be rather unlikely case). + * * @return */ - private ClientFactory getFactory() { - return myConfiguration.myUseAcceleration.equals(SvnConfiguration.UseAcceleration.commandLine) ? cmdClientFactory : svnKitClientFactory; + public ClientFactory getFactory() { + // check working copy format of project directory + WorkingCopyFormat format = getWorkingCopyFormat(new File(getProject().getBaseDir().getPath())); + + return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) || + myConfiguration.myUseAcceleration.equals(SvnConfiguration.UseAcceleration.commandLine) ? cmdClientFactory : svnKitClientFactory; } public ClientFactory getFactory(@NotNull File file) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java index c637eac967a0..ee5acf028e70 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java @@ -49,7 +49,7 @@ public class CmdAddClient extends BaseSvnClient implements AddClient { } } - private void parseOutput(@NotNull SvnLineCommand command, @Nullable ISVNEventHandler handler) throws VcsException, SVNException { + private static void parseOutput(@NotNull SvnLineCommand command, @Nullable ISVNEventHandler handler) throws VcsException, SVNException { if (StringUtil.isEmpty(command.getOutput())) { // if file is versioned, adding it with "force" produces no output // TODO: so handler will not be called - check if this compatible with svnkit @@ -65,11 +65,8 @@ public class CmdAddClient extends BaseSvnClient implements AddClient { private static List prepareParameters(File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) { List parameters = new ArrayList(); - parameters.add(file.getAbsolutePath()); - if (depth != null) { - parameters.add("--depth"); - parameters.add(depth.getName()); - } + CommandUtil.put(parameters, file); + CommandUtil.put(parameters, depth); CommandUtil.put(parameters, makeParents, "--parents"); CommandUtil.put(parameters, includeIgnored, "--no-ignore"); CommandUtil.put(parameters, force, "--force"); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java index 676895fbea4c..1f7b8c8c7085 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -4,6 +4,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.AddClient; import org.jetbrains.idea.svn.history.HistoryClient; +import org.jetbrains.idea.svn.portable.SvnStatusClientI; +import org.jetbrains.idea.svn.revert.RevertClient; /** * @author Konstantin Kolosovsky. @@ -15,6 +17,8 @@ public abstract class ClientFactory { protected AddClient addClient; protected HistoryClient historyClient; + protected RevertClient revertClient; + protected SvnStatusClientI statusClient; protected ClientFactory(@NotNull SvnVcs vcs) { myVcs = vcs; @@ -23,15 +27,29 @@ public abstract class ClientFactory { protected abstract void setup(); + @NotNull public AddClient createAddClient() { return prepare(addClient); } + @NotNull public HistoryClient createHistoryClient() { return prepare(historyClient); } - protected T prepare(T client) { + @NotNull + public RevertClient createRevertClient() { + return prepare(revertClient); + } + + @NotNull + public SvnStatusClientI createStatusClient() { + // TODO: Update this in same like other clients - move to corresponding package, rename clients + return statusClient; + } + + @NotNull + protected T prepare(@NotNull T client) { client.setVcs(myVcs); return client; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java index 08be1ca5b6d0..ecd8387347cc 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -3,7 +3,9 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.CmdAddClient; +import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient; import org.jetbrains.idea.svn.history.CmdHistoryClient; +import org.jetbrains.idea.svn.revert.CmdRevertClient; /** * @author Konstantin Kolosovsky. @@ -18,5 +20,7 @@ public class CmdClientFactory extends ClientFactory { protected void setup() { addClient = new CmdAddClient(); historyClient = new CmdHistoryClient(); + revertClient = new CmdRevertClient(); + statusClient = new SvnCommandLineStatusClient(myVcs.getProject()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java index a9a701be4ca7..20798240a173 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -4,6 +4,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.SvnKitAddClient; import org.jetbrains.idea.svn.history.SvnKitHistoryClient; +import org.jetbrains.idea.svn.portable.SvnkitSvnStatusClient; +import org.jetbrains.idea.svn.revert.SvnKitRevertClient; /** * @author Konstantin Kolosovsky. @@ -18,5 +20,7 @@ public class SvnKitClientFactory extends ClientFactory { protected void setup() { addClient = new SvnKitAddClient(); historyClient = new SvnKitHistoryClient(); + revertClient = new SvnKitRevertClient(); + statusClient = new SvnkitSvnStatusClient(myVcs.createStatusClient()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index 30fb68f37fb5..75cfcfbcfd0b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -9,10 +9,7 @@ import org.jetbrains.idea.svn.SvnCommitRunner; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; import org.jetbrains.idea.svn.config.SvnBindException; -import org.tmatesoft.svn.core.SVNErrorCode; -import org.tmatesoft.svn.core.SVNErrorMessage; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.SVNStatusType; import java.io.File; @@ -62,6 +59,23 @@ public class CommandUtil { } } + public static void put(@NotNull List parameters, @NotNull File path) { + parameters.add(path.getAbsolutePath()); + } + + public static void put(@NotNull List parameters, @NotNull File... paths) { + for (File path : paths) { + put(parameters, path); + } + } + + public static void put(@NotNull List parameters, @Nullable SVNDepth depth) { + if (depth != null) { + parameters.add("--depth"); + parameters.add(depth.getName()); + } + } + /** * Gets svn status represented by single character. * diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java index 35e8e9a2229c..19e51e95da24 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java @@ -17,17 +17,15 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.containers.Convertor; +import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnBindUtil; -import org.jetbrains.idea.svn.SvnCommitRunner; import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; -import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; -import org.jetbrains.idea.svn.config.SvnBindException; import org.jetbrains.idea.svn.portable.PortableStatus; import org.jetbrains.idea.svn.portable.SvnExceptionWrapper; import org.jetbrains.idea.svn.portable.SvnStatusClientI; @@ -109,7 +107,7 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { final SVNInfo infoBase = myInfoClient.doInfo(base, revision); final SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, base, SvnCommandName.st); - putParameters(depth, remote, reportAll, includeIgnored, changeLists, command); + putParameters(path, depth, remote, reportAll, includeIgnored, changeLists, command); parseResult(path, revision, handler, base, infoBase, command, execute(command, base)); return 0; @@ -126,7 +124,7 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { return result; } - private void parseResult(File path, + private void parseResult(final File path, SVNRevision revision, ISVNStatusHandler handler, File base, @@ -146,6 +144,24 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { if (!SvnUtil.isSvnVersioned(myProject, path)) { throw new SVNException( SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY, "Command - " + command.getCommandText() + ". Result - " + result)); + } else { + // return status indicating "NORMAL" state + // typical output would be like + // + // + // + // so it does not contain any element and current parsing logic returns null + + PortableStatus status = new PortableStatus(); + status.setPath(path.getAbsolutePath()); + status.setContentsStatus(SVNStatusType.STATUS_NORMAL); + status.setInfoGetter(new Getter() { + @Override + public SVNInfo get() { + return createInfoGetter(null).convert(path); + } + }); + handler.handleStatus(status); } } } @@ -162,12 +178,13 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { } } - private void putParameters(SVNDepth depth, + private void putParameters(@NotNull File path, SVNDepth depth, boolean remote, boolean reportAll, boolean includeIgnored, Collection changeLists, SvnSimpleCommand command) { + command.addParameters(path.getAbsolutePath()); if (depth != null) { command.addParameters("--depth", depth.getName()); } @@ -196,7 +213,11 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { final SVNInfo infoBase, final SvnStatusHandler[] svnHandl) { final SvnStatusHandler.ExternalDataCallback callback = createStatusCallback(handler, base, infoBase, svnHandl); - return new SvnStatusHandler(callback, base, new Convertor() { + return new SvnStatusHandler(callback, base, createInfoGetter(revision)); + } + + private Convertor createInfoGetter(final SVNRevision revision) { + return new Convertor() { @Override public SVNInfo convert(File o) { try { @@ -206,7 +227,7 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { throw new SvnExceptionWrapper(e); } } - }); + }; } public static SvnStatusHandler.ExternalDataCallback createStatusCallback(final ISVNStatusHandler handler, diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java index c0e9c8e79fa2..2d0410b2d056 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java @@ -49,9 +49,9 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient { private final VirtualFile myCommonAncestor; private boolean myIgnoreExternals; - public SvnCommandLineUpdateClient(final Project project, VirtualFile commonAncestor) { - super(SvnVcs.getInstance(project).createUpdateClient()); - myProject = project; + public SvnCommandLineUpdateClient(final SvnVcs vcs, VirtualFile commonAncestor) { + super(vcs.createUpdateClient()); + myProject = vcs.getProject(); myCommonAncestor = commonAncestor; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java index 184d5598f9fe..5683c6baa00e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java @@ -117,6 +117,7 @@ public class PortableStatus extends SVNStatus { return null; } }; + // TODO: Update working copy format detection setWorkingCopyFormat(WorkingCopyFormat.ONE_DOT_SEVEN.getFormat()); } @@ -241,6 +242,18 @@ public class PortableStatus extends SVNStatus { return url == null ? null : url.toString(); } + @Override + public SVNURL getURL() { + SVNURL url = super.getURL(); + + if (url == null) { + SVNInfo info = initInfo(); + url = info != null ? info.getURL() : url; + } + + return url; + } + @Override public SVNRevision getRevision() { final SVNRevision revision = super.getRevision(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java new file mode 100644 index 000000000000..573920d3ad9d --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java @@ -0,0 +1,123 @@ +package org.jetbrains.idea.svn.revert; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.commandLine.CommandUtil; +import org.jetbrains.idea.svn.commandLine.SvnCommand; +import org.jetbrains.idea.svn.commandLine.SvnCommandName; +import org.jetbrains.idea.svn.commandLine.SvnLineCommand; +import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNEvent; +import org.tmatesoft.svn.core.wc.SVNEventAction; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Konstantin Kolosovsky. + */ +public class CmdRevertClient extends BaseSvnClient implements RevertClient { + + private static final double DEFAULT_PROGRESS = 0.0; + + @Override + public void revert(@NotNull File[] paths, @Nullable SVNDepth depth, @Nullable ISVNEventHandler handler) throws VcsException { + List parameters = prepareParameters(paths, depth); + + try { + SvnLineCommand command = CommandUtil.runSimple(SvnCommandName.revert, myVcs, null, null, parameters); + // TODO: handler should be called in parallel with command execution, but this will be in other thread + // TODO: check if that is ok for current handler implementation + // TODO: add possibility to invoke "handler.checkCancelled" - process should be killed + + parseOutput(command, handler); + } + catch (SVNException e) { + throw new VcsException(e); + } + } + + private static void parseOutput(@NotNull SvnCommand command, @Nullable ISVNEventHandler handler) throws VcsException, SVNException { + if (StringUtil.isEmpty(command.getOutput())) { + // if file is versioned, adding it with "force" produces no output + // TODO: so handler will not be called - check if this compatible with svnkit + return; + } + + Parser parser = new Parser(handler); + for (String line : StringUtil.splitByLines(command.getOutput())) { + parser.onLine(line); + } + } + + private static List prepareParameters(File[] paths, SVNDepth depth) { + ArrayList parameters = new ArrayList(); + + CommandUtil.put(parameters, paths); + CommandUtil.put(parameters, depth); + + return parameters; + } + + private static class Parser { + private static final String STATUS = "\\s*(.+?)\\s*"; + private static final String PATH = "\\s*\'(.*?)\'\\s*"; + private static final String OPTIONAL_COMMENT = "(.*)"; + private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + PATH + OPTIONAL_COMMENT); + + @Nullable + ISVNEventHandler handler; + + public Parser(@Nullable ISVNEventHandler handler) { + this.handler = handler; + } + + public void onLine(@NotNull String line) throws VcsException, SVNException { + Matcher matcher = CHANGED_PATH.matcher(line); + if (matcher.matches()) { + processChangedPath(matcher); + } + else { + throw new VcsException("unknown state on line " + line); + } + } + + private void processChangedPath(@NotNull Matcher matcher) throws VcsException, SVNException { + String statusMessage = matcher.group(1); + String path = matcher.group(2); + + if (handler != null) { + // TODO: No suitable ways to create SVNEvent. This will be changed when removing SvnKit objects from interfaces. + handler.handleEvent( + new SVNEvent(new File(path), null, null, 0, null, null, null, null, createAction(statusMessage), null, null, null, null, null, + null), + DEFAULT_PROGRESS); + } + } + + @Nullable + public static SVNEventAction createAction(@NotNull String code) { + SVNEventAction result = null; + + if ("Reverted".equals(code)) { + result = SVNEventAction.REVERT; + } + else if ("Failed to revert".equals(code)) { + result = SVNEventAction.FAILED_REVERT; + } + else if ("Skipped".equals(code)) { + result = SVNEventAction.SKIP; + } + + return result; + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/RevertClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/RevertClient.java new file mode 100644 index 000000000000..053de373bc0a --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/RevertClient.java @@ -0,0 +1,18 @@ +package org.jetbrains.idea.svn.revert; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.SvnClient; +import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public interface RevertClient extends SvnClient { + + void revert(@NotNull File[] paths, @Nullable SVNDepth depth, @Nullable ISVNEventHandler handler) throws VcsException; +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/SvnKitRevertClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/SvnKitRevertClient.java new file mode 100644 index 000000000000..17c725cf58f6 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/SvnKitRevertClient.java @@ -0,0 +1,31 @@ +package org.jetbrains.idea.svn.revert; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNWCClient; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitRevertClient extends BaseSvnClient implements RevertClient { + + @Override + public void revert(@NotNull File[] paths, @Nullable SVNDepth depth, @Nullable ISVNEventHandler handler) throws VcsException { + SVNWCClient client = myVcs.createWCClient(); + + client.setEventHandler(handler); + try { + client.doRevert(paths, depth, null); + } + catch (SVNException e) { + throw new VcsException(e); + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java index 265d4ca5b9e5..4140ca75a717 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java @@ -28,6 +28,7 @@ import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.revert.RevertClient; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.*; @@ -74,8 +75,7 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { checker.gather(changes); exceptions.addAll(checker.getExceptions()); - final SVNWCClient client = mySvnVcs.createWCClient(); - client.setEventHandler(new ISVNEventHandler() { + ISVNEventHandler revertHandler = new ISVNEventHandler() { public void handleEvent(SVNEvent event, double progress) { if (event.getAction() == SVNEventAction.REVERT) { final File file = event.getFile(); @@ -91,7 +91,7 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { public void checkCancelled() { listener.checkCanceled(); } - }); + }; final List fromToModified = new ArrayList(); final MultiMap properties = new MultiMap(); @@ -99,7 +99,7 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { // adds (deletes) // deletes (adds) // modifications - final Reverter reverter = new Reverter(client, exceptions); + final Reverter reverter = new Reverter(mySvnVcs.getFactory().createRevertClient(), revertHandler, exceptions); reverter.revert(checker.getForAdds(), true); reverter.revert(checker.getForDeletes(), true); final List edits = checker.getForEdits(); @@ -256,24 +256,36 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { } private static class Reverter { - private final SVNWCClient myClient; + private final RevertClient myClient; + private ISVNEventHandler myHandler; private final List myExceptions; - private Reverter(SVNWCClient client, List exceptions) { + private Reverter(RevertClient client, ISVNEventHandler handler, List exceptions) { myClient = client; + myHandler = handler; myExceptions = exceptions; } public void revert(final File[] files, final boolean recursive) { if (files.length == 0) return; try { - myClient.doRevert(files, recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY, null); + myClient.revert(files, recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY, myHandler); } - catch (SVNException e) { - if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_NOT_DIRECTORY) { - // skip errors on unversioned resources. - myExceptions.add(new VcsException(e)); + catch (VcsException e) { + processRevertError(e); + } + } + + private void processRevertError(@NotNull VcsException e) { + if (e.getCause() instanceof SVNException) { + SVNException cause = (SVNException)e.getCause(); + + // skip errors on unversioned resources. + if (cause.getErrorMessage().getErrorCode() != SVNErrorCode.WC_NOT_DIRECTORY) { + myExceptions.add(e); } + } else { + myExceptions.add(e); } } } @@ -294,18 +306,17 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { } private void revertFileOrDir(File file) throws SVNException, VcsException { - final SVNWCClient wcClient = mySvnVcs.createWCClient(); - SVNInfo info = wcClient.doInfo(file, SVNRevision.UNDEFINED); + SVNInfo info = mySvnVcs.getInfo(file); if (info != null) { if (info.getKind() == SVNNodeKind.FILE) { - wcClient.doRevert(file, false); + doRevert(file, false); } else { if (SVNProperty.SCHEDULE_ADD.equals(info.getSchedule())) { - wcClient.doRevert(file, true); + doRevert(file, true); } else { boolean under17Copy = isUnder17Copy(file, info); if (under17Copy) { - wcClient.doRevert(file, true); + doRevert(file, true); } else { // do update to restore missing directory. mySvnVcs.createUpdateClient().doUpdate(file, SVNRevision.HEAD, true); @@ -317,10 +328,16 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { } } + private void doRevert(@NotNull File path, boolean recursive) throws VcsException { + mySvnVcs.getFactory(path).createRevertClient().revert(new File[]{path}, SVNDepth.fromRecurse(recursive), null); + } + private boolean isUnder17Copy(final File file, final SVNInfo info) throws VcsException { final RootsToWorkingCopies copies = mySvnVcs.getRootsToWorkingCopies(); WorkingCopy copy = copies.getMatchingCopy(info.getURL()); if (copy == null) { + // TODO: Why null could be here? + // TODO: Think we could just rewrite it with mySvnVcs.getWorkingCopyFormat(file) SVNStatus status = null; try { status = mySvnVcs.createStatusClient().doStatus(file, false); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java index 79190ebd541e..eb2833f7a3ce 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java @@ -111,7 +111,7 @@ public class SvnUpdateEnvironment extends AbstractSvnUpdateIntegrateEnvironment SvnAuthenticationManager.HTTP.equals(sourceUrl.getProtocol()) || SvnAuthenticationManager.HTTPS.equals(sourceUrl.getProtocol()) ))) { - updateClient = new SvnCommandLineUpdateClient(myVcs.getProject(), null); + updateClient = new SvnCommandLineUpdateClient(myVcs, null); } else { updateClient = new SvnSvnkitUpdateClient(myVcs.createUpdateClient()); } From c28c127861ae1aa04ed9836bccda8528dc5f290c Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 19 Aug 2013 15:51:59 +0400 Subject: [PATCH 13/30] IDEA-94942 Short add, revert commands refactoring --- .../jetbrains/idea/svn/add/CmdAddClient.java | 77 ++++--------------- .../idea/svn/api/FileStatusResultParser.java | 64 +++++++++++++++ .../idea/svn/commandLine/CommandUtil.java | 26 +++++++ .../idea/svn/revert/CmdRevertClient.java | 74 ++++-------------- 4 files changed, 122 insertions(+), 119 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/api/FileStatusResultParser.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java index ee5acf028e70..c7866713c9c1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java @@ -1,15 +1,14 @@ package org.jetbrains.idea.svn.add; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; +import com.intellij.util.containers.Convertor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.api.FileStatusResultParser; import org.jetbrains.idea.svn.commandLine.CommandUtil; import org.jetbrains.idea.svn.commandLine.SvnCommandName; -import org.jetbrains.idea.svn.commandLine.SvnLineCommand; import org.tmatesoft.svn.core.SVNDepth; -import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.ISVNEventHandler; import org.tmatesoft.svn.core.wc.SVNEvent; import org.tmatesoft.svn.core.wc.SVNStatusType; @@ -25,7 +24,10 @@ import java.util.regex.Pattern; */ public class CmdAddClient extends BaseSvnClient implements AddClient { - private static final double DEFAULT_PROGRESS = 0.0; + private static final String STATUS = "\\s*(\\w)\\s*"; + private static final String OPTIONAL_FILE_TYPE = "(\\(.*\\))?"; + private static final String PATH = "\\s*(.*?)\\s*"; + private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + OPTIONAL_FILE_TYPE + PATH); @Override public void add(@NotNull File file, @@ -36,30 +38,10 @@ public class CmdAddClient extends BaseSvnClient implements AddClient { @Nullable ISVNEventHandler handler) throws VcsException { List parameters = prepareParameters(file, depth, makeParents, includeIgnored, force); - try { - SvnLineCommand command = CommandUtil.runSimple(SvnCommandName.add, myVcs, null, null, parameters); - // TODO: handler should be called in parallel with command execution, but this will be in other thread - // TODO: check if that is ok for current handler implementation - // TODO: add possibility to invoke "handler.checkCancelled" - process should be killed - - parseOutput(command, handler); - } - catch (SVNException e) { - throw new VcsException(e); - } - } - - private static void parseOutput(@NotNull SvnLineCommand command, @Nullable ISVNEventHandler handler) throws VcsException, SVNException { - if (StringUtil.isEmpty(command.getOutput())) { - // if file is versioned, adding it with "force" produces no output - // TODO: so handler will not be called - check if this compatible with svnkit - return; - } - - Parser parser = new Parser(handler); - for (String line : StringUtil.splitByLines(command.getOutput())) { - parser.onLine(line); - } + // TODO: handler should be called in parallel with command execution, but this will be in other thread + // TODO: check if that is ok for current handler implementation + // TODO: add possibility to invoke "handler.checkCancelled" - process should be killed + CommandUtil.execute(myVcs, SvnCommandName.add, parameters, new FileStatusResultParser(CHANGED_PATH, handler, new AddStatusConvertor())); } private static List prepareParameters(File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) { @@ -74,39 +56,14 @@ public class CmdAddClient extends BaseSvnClient implements AddClient { return parameters; } - private static class Parser { - private static final String STATUS = "\\s*(\\w)\\s*"; - private static final String OPTIONAL_FILE_TYPE = "(\\(.*\\))?"; - private static final String PATH = "\\s*(.*?)\\s*"; - private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + OPTIONAL_FILE_TYPE + PATH); + private static class AddStatusConvertor implements Convertor { + @Override + public SVNEvent convert(Matcher o) { + SVNStatusType contentStatus = CommandUtil.getStatusType(o.group(1)); + String path = o.group(3); - @Nullable - ISVNEventHandler handler; - - public Parser(@Nullable ISVNEventHandler handler) { - this.handler = handler; - } - - public void onLine(@NotNull String line) throws VcsException, SVNException { - Matcher matcher = CHANGED_PATH.matcher(line); - if (matcher.matches()) { - processChangedPath(matcher); - } - else { - throw new VcsException("unknown state on line " + line); - } - } - - private void processChangedPath(@NotNull Matcher matcher) throws VcsException, SVNException { - SVNStatusType contentStatus = CommandUtil.getStatusType(matcher.group(1)); - String path = matcher.group(3); - - if (handler != null) { - // TODO: No suitable ways to create SVNEvent. This will be changed when removing SvnKit objects from interfaces. - handler.handleEvent( - new SVNEvent(new File(path), null, null, 0, contentStatus, null, null, null, null, null, null, null, null, null, null), - DEFAULT_PROGRESS); - } + return new SVNEvent(new File(path), null, null, 0, contentStatus, null, null, null, null, null, null, null, + null, null, null); } } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/FileStatusResultParser.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/FileStatusResultParser.java new file mode 100644 index 000000000000..66e588c41c11 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/FileStatusResultParser.java @@ -0,0 +1,64 @@ +package org.jetbrains.idea.svn.api; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.util.containers.Convertor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNEvent; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Konstantin Kolosovsky. + */ +public class FileStatusResultParser { + + private static final double DEFAULT_PROGRESS = 0.0; + + @NotNull + private Pattern myLinePattern; + + @Nullable + private ISVNEventHandler handler; + + @NotNull + private Convertor myConvertor; + + public FileStatusResultParser(@NotNull Pattern linePattern, + @Nullable ISVNEventHandler handler, + @NotNull Convertor convertor) { + myLinePattern = linePattern; + this.handler = handler; + myConvertor = convertor; + } + + public void parse(@NotNull String output) throws VcsException, SVNException { + if (StringUtil.isEmpty(output)) { + return; + } + + for (String line : StringUtil.splitByLines(output)) { + onLine(line); + } + } + + public void onLine(@NotNull String line) throws VcsException, SVNException { + Matcher matcher = myLinePattern.matcher(line); + if (matcher.matches()) { + process(matcher); + } + else { + throw new VcsException("unknown state on line " + line); + } + } + + public void process(@NotNull Matcher matcher) throws VcsException, SVNException { + if (handler != null) { + handler.handleEvent(myConvertor.convert(matcher), DEFAULT_PROGRESS); + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index 75cfcfbcfd0b..cac5cb3fce10 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -1,12 +1,14 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsException; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnApplicationSettings; import org.jetbrains.idea.svn.SvnCommitRunner; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.api.FileStatusResultParser; import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; import org.jetbrains.idea.svn.config.SvnBindException; import org.tmatesoft.svn.core.*; @@ -76,6 +78,30 @@ public class CommandUtil { } } + + /** + * Utility method for running commands changing certain file status information. + * // TODO: Should be replaced with non-static analogue. + * + * @param vcs + * @param name + * @param parameters + * @param parser + * @throws VcsException + */ + public static void execute(@NotNull SvnVcs vcs, @NotNull SvnCommandName name, @NotNull List parameters, @NotNull FileStatusResultParser parser) + throws VcsException { + try { + SvnLineCommand command = runSimple(name, vcs, null, null, parameters); + + parser.parse(command.getOutput()); + } + catch (SVNException e) { + throw new VcsException(e); + } + } + + /** * Gets svn status represented by single character. * diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java index 573920d3ad9d..53c998f001a6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java @@ -1,16 +1,14 @@ package org.jetbrains.idea.svn.revert; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; +import com.intellij.util.containers.Convertor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.api.FileStatusResultParser; import org.jetbrains.idea.svn.commandLine.CommandUtil; -import org.jetbrains.idea.svn.commandLine.SvnCommand; import org.jetbrains.idea.svn.commandLine.SvnCommandName; -import org.jetbrains.idea.svn.commandLine.SvnLineCommand; import org.tmatesoft.svn.core.SVNDepth; -import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.ISVNEventHandler; import org.tmatesoft.svn.core.wc.SVNEvent; import org.tmatesoft.svn.core.wc.SVNEventAction; @@ -26,36 +24,20 @@ import java.util.regex.Pattern; */ public class CmdRevertClient extends BaseSvnClient implements RevertClient { - private static final double DEFAULT_PROGRESS = 0.0; + private static final String STATUS = "\\s*(.+?)\\s*"; + private static final String PATH = "\\s*\'(.*?)\'\\s*"; + private static final String OPTIONAL_COMMENT = "(.*)"; + private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + PATH + OPTIONAL_COMMENT); @Override public void revert(@NotNull File[] paths, @Nullable SVNDepth depth, @Nullable ISVNEventHandler handler) throws VcsException { List parameters = prepareParameters(paths, depth); - try { - SvnLineCommand command = CommandUtil.runSimple(SvnCommandName.revert, myVcs, null, null, parameters); - // TODO: handler should be called in parallel with command execution, but this will be in other thread - // TODO: check if that is ok for current handler implementation - // TODO: add possibility to invoke "handler.checkCancelled" - process should be killed - - parseOutput(command, handler); - } - catch (SVNException e) { - throw new VcsException(e); - } - } - - private static void parseOutput(@NotNull SvnCommand command, @Nullable ISVNEventHandler handler) throws VcsException, SVNException { - if (StringUtil.isEmpty(command.getOutput())) { - // if file is versioned, adding it with "force" produces no output - // TODO: so handler will not be called - check if this compatible with svnkit - return; - } - - Parser parser = new Parser(handler); - for (String line : StringUtil.splitByLines(command.getOutput())) { - parser.onLine(line); - } + // TODO: handler should be called in parallel with command execution, but this will be in other thread + // TODO: check if that is ok for current handler implementation + // TODO: add possibility to invoke "handler.checkCancelled" - process should be killed + CommandUtil + .execute(myVcs, SvnCommandName.revert, parameters, new FileStatusResultParser(CHANGED_PATH, handler, new RevertStatusConvertor())); } private static List prepareParameters(File[] paths, SVNDepth depth) { @@ -67,40 +49,14 @@ public class CmdRevertClient extends BaseSvnClient implements RevertClient { return parameters; } - private static class Parser { - private static final String STATUS = "\\s*(.+?)\\s*"; - private static final String PATH = "\\s*\'(.*?)\'\\s*"; - private static final String OPTIONAL_COMMENT = "(.*)"; - private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + PATH + OPTIONAL_COMMENT); + private static class RevertStatusConvertor implements Convertor { - @Nullable - ISVNEventHandler handler; - - public Parser(@Nullable ISVNEventHandler handler) { - this.handler = handler; - } - - public void onLine(@NotNull String line) throws VcsException, SVNException { - Matcher matcher = CHANGED_PATH.matcher(line); - if (matcher.matches()) { - processChangedPath(matcher); - } - else { - throw new VcsException("unknown state on line " + line); - } - } - - private void processChangedPath(@NotNull Matcher matcher) throws VcsException, SVNException { + public SVNEvent convert(@NotNull Matcher matcher) { String statusMessage = matcher.group(1); String path = matcher.group(2); - if (handler != null) { - // TODO: No suitable ways to create SVNEvent. This will be changed when removing SvnKit objects from interfaces. - handler.handleEvent( - new SVNEvent(new File(path), null, null, 0, null, null, null, null, createAction(statusMessage), null, null, null, null, null, - null), - DEFAULT_PROGRESS); - } + return new SVNEvent(new File(path), null, null, 0, null, null, null, null, createAction(statusMessage), null, null, null, null, null, + null); } @Nullable From e197c08e2a5976ebdaa57d81c4ab03fe8c6165a0 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 19 Aug 2013 18:21:14 +0400 Subject: [PATCH 14/30] IDEA-94942 Fixed authentication for svn protocol --- .../src/org/jetbrains/idea/svn/SvnBindClient.java | 8 ++++++-- .../src/org/jetbrains/idea/svn/SvnCommitRunner.java | 6 ++++-- .../idea/svn/commandLine/SvnLineCommand.java | 13 ++----------- .../idea/svn/checkin/SvnCheckinEnvironment.java | 9 ++++++++- .../jetbrains/idea/svn/commandLine/CommandUtil.java | 8 ++++++++ .../svn/commandLine/SvnCommandLineUpdateClient.java | 2 +- .../jetbrains/idea/svn/portable/PortableStatus.java | 12 ++++++++++++ 7 files changed, 41 insertions(+), 17 deletions(-) diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindClient.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindClient.java index c155b78ddc53..d0bf3a086d5c 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindClient.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindClient.java @@ -15,7 +15,9 @@ */ package org.jetbrains.idea.svn; +import com.intellij.util.containers.Convertor; import org.tigris.subversion.javahl.*; +import org.tmatesoft.svn.core.SVNURL; import java.io.OutputStream; import java.util.Map; @@ -30,9 +32,11 @@ public class SvnBindClient implements SVNClientInterface { private final String myExecutablePath; private CommitEventHandler myHandler; private AuthenticationCallback myAuthenticationCallback; + private Convertor myUrlProvider; - public SvnBindClient(String path) { + public SvnBindClient(String path, Convertor urlProvider) { myExecutablePath = path; + myUrlProvider = urlProvider; } @Override @@ -317,7 +321,7 @@ public class SvnBindClient implements SVNClientInterface { String[] changelists, Map revpropTable) throws ClientException { final long commit = new SvnCommitRunner(myExecutablePath, myHandler, myAuthenticationCallback). - commit(path, message, depth, noUnlock, keepChangelist, changelists, revpropTable); + commit(path, message, depth, noUnlock, keepChangelist, changelists, revpropTable, myUrlProvider); if (commit < 0) { throw new BindClientException("Wrong committed revision number: " + commit, null, -1); } diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java index 23645129e600..2ca314b02da7 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java @@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.Convertor; import org.apache.subversion.javahl.types.Revision; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -29,6 +30,7 @@ import org.jetbrains.idea.svn.commandLine.SvnLineCommand; import org.jetbrains.idea.svn.config.SvnBindException; import org.tigris.subversion.javahl.BindClientException; import org.tigris.subversion.javahl.ClientException; +import org.tmatesoft.svn.core.SVNURL; import java.io.File; import java.util.*; @@ -57,7 +59,7 @@ public class SvnCommitRunner { boolean noUnlock, boolean keepChangelist, String[] changelists, - Map revpropTable) throws ClientException { + Map revpropTable, Convertor urlProvider) throws ClientException { if (paths.length == 0) return Revision.SVN_INVALID_REVNUM; final List parameters = new ArrayList(); @@ -85,7 +87,7 @@ public class SvnCommitRunner { parameters.addAll(Arrays.asList(paths)); try { - SvnLineCommand.runWithAuthenticationAttempt(myExePath, new File(paths[0]), SvnCommandName.ci, + SvnLineCommand.runWithAuthenticationAttempt(myExePath, new File(paths[0]), urlProvider.convert(paths), SvnCommandName.ci, myCommandListener, myAuthenticationCallback, ArrayUtil.toStringArray(parameters)); } catch (SvnBindException e) { diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java index aa8f88d61c4c..b84166a7152c 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java @@ -112,16 +112,6 @@ public class SvnLineCommand extends SvnCommand { } } - public static SvnLineCommand runWithAuthenticationAttempt(final String exePath, - final File firstFile, - SvnCommandName commandName, - final LineCommandListener listener, - @Nullable AuthenticationCallback authenticationCallback, - String... parameters) throws SvnBindException { - return runWithAuthenticationAttempt(exePath, firstFile, null, commandName, listener, authenticationCallback, parameters); - } - - public static SvnLineCommand runWithAuthenticationAttempt(final String exePath, final File firstFile, final SVNURL url, @@ -338,7 +328,8 @@ public class SvnLineCommand extends SvnCommand { @Override public boolean getCredentials(final String errText) throws SvnBindException { - String realm = cutFirstLine(errText).substring(CERTIFICATE_ERROR.length()); + // parse realm from error text + String realm = errText; final int idx1 = realm.indexOf('\''); if (idx1 == -1) { throw new SvnBindException("Can not detect authentication realm name: " + errText); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java index f35e8d07a008..eca20c8a92b3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java @@ -256,7 +256,14 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { }); final IdeaSvnkitBasedAuthenticationCallback authenticationCallback = new IdeaSvnkitBasedAuthenticationCallback(mySvnVcs); try { - final SvnBindClient client = new SvnBindClient(SvnApplicationSettings.getInstance().getCommandLinePath()); + final SvnBindClient client = new SvnBindClient(SvnApplicationSettings.getInstance().getCommandLinePath(), new Convertor() { + @Override + public SVNURL convert(String[] o) { + SVNInfo info = o.length > 0 ? mySvnVcs.getInfo(o[0]) : null; + + return info != null ? info.getURL() : null; + } + }); client.setAuthenticationCallback(authenticationCallback); client.setHandler(new IdeaCommitHandler(ProgressManager.getInstance().getProgressIndicator())); final long revision = client.commit(ArrayUtil.toStringArray(paths), comment, false, false); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index cac5cb3fce10..e8362e57e499 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -12,6 +12,7 @@ import org.jetbrains.idea.svn.api.FileStatusResultParser; import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; import org.jetbrains.idea.svn.config.SvnBindException; import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNStatusType; import java.io.File; @@ -32,6 +33,13 @@ public class CommandUtil { String exe = SvnApplicationSettings.getInstance().getCommandLinePath(); base = base == null ? new File(exe) : base; + if (url == null) { + // TODO: or take it from RootUrlInfo + SVNInfo info = vcs.getInfo(vcs.getProject().getBaseDir()); + + url = info != null ? info.getURL() : null; + } + try { return SvnLineCommand .runWithAuthenticationAttempt(exe, base, url, name, new SvnCommitRunner.CommandListener(null), diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java index 2d0410b2d056..3c4fe3684e1b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java @@ -166,7 +166,7 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient { } }; SvnLineCommand.runWithAuthenticationAttempt(SvnApplicationSettings.getInstance().getCommandLinePath(), - base, SvnCommandName.up, listener, + base, info.getURL(), SvnCommandName.up, listener, new IdeaSvnkitBasedAuthenticationCallback(SvnVcs.getInstance(myProject)), ArrayUtil.toStringArray(parameters)); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java index 5683c6baa00e..9799cf7ae4a4 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java @@ -254,6 +254,18 @@ public class PortableStatus extends SVNStatus { return url; } + @Override + public File getFile() { + File file = super.getFile(); + + if (file == null) { + SVNInfo info = initInfo(); + file = info != null ? info.getFile() : file; + } + + return file; + } + @Override public SVNRevision getRevision() { final SVNRevision revision = super.getRevision(); From a5f7e7c5698fee2b3166005bdce24b785271d8ac Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 19 Aug 2013 18:41:10 +0400 Subject: [PATCH 15/30] IDEA-94942 Delete action --- .../idea/svn/commandLine/SvnCommandName.java | 3 +- .../idea/svn/SvnFileSystemListener.java | 33 ++++++++++--------- .../jetbrains/idea/svn/api/ClientFactory.java | 7 ++++ .../idea/svn/api/CmdClientFactory.java | 2 ++ .../idea/svn/api/SvnKitClientFactory.java | 2 ++ .../svn/checkin/SvnCheckinEnvironment.java | 9 +++-- .../idea/svn/commandLine/CommandUtil.java | 11 +++++-- .../idea/svn/delete/CmdDeleteClient.java | 27 +++++++++++++++ .../idea/svn/delete/DeleteClient.java | 15 +++++++++ .../idea/svn/delete/SvnKitDeleteClient.java | 24 ++++++++++++++ 10 files changed, 109 insertions(+), 24 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/delete/CmdDeleteClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/delete/DeleteClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/delete/SvnKitDeleteClient.java diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index 37eac203ff8d..43f08451f06d 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -33,7 +33,8 @@ public enum SvnCommandName { cat("cat", false), add("add", true), log("log", false), - revert("revert", true); + revert("revert", true), + delete("delete", true); private final String myName; private final boolean myWriteable; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java index dc4f20ce51ab..65afe16e868e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java @@ -280,7 +280,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp ourStatusesForUndoMove.add(SVNStatusType.STATUS_ADDED); } - private boolean for17move(SvnVcs vcs, final File src, final File dst, boolean undo, SVNStatus srcStatus) throws SVNException { + private boolean for17move(final SvnVcs vcs, final File src, final File dst, boolean undo, SVNStatus srcStatus) throws SVNException { if (srcStatus != null && srcStatus.getCopyFromURL() == null) { undo = false; } @@ -305,13 +305,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp catch (IOException e) { throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); } - final SVNWCClient wcClient = vcs.createWCClient(); - new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws SVNException { - wcClient.doDelete(src, true, false); - } - }.execute(); + createDeleteAction(vcs, src, true).execute(); return false; } moveFileWithSvn(vcs, src, dst); @@ -520,6 +514,21 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp }; } + @NotNull + private RepeatSvnActionThroughBusy createDeleteAction(@NotNull final SvnVcs vcs, @NotNull final File file, final boolean force) { + return new RepeatSvnActionThroughBusy() { + @Override + protected void executeImpl() throws SVNException { + try { + vcs.getFactory(file).createDeleteClient().delete(file, force); + } + catch (VcsException e) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); + } + } + }; + } + private boolean isAboveSourceOfCopyOrMove(final Project p, File ioFile) { for (MovedFileInfo file : myMovedFiles) { if (FileUtil.isAncestor(ioFile, file.mySrc, false)) return true; @@ -905,17 +914,11 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp final List exceptions) { return new Runnable() { public void run() { - final SVNWCClient wcClient = vcs.createWCClient(); for(FilePath file: filesToProcess) { VirtualFile vFile = file.getVirtualFile(); // for deleted directories final File ioFile = new File(file.getPath()); try { - new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws SVNException { - wcClient.doDelete(ioFile, true, false); - } - }.execute(); + createDeleteAction(vcs, ioFile, true).execute(); if (vFile != null && vFile.isValid() && vFile.isDirectory()) { vFile.refresh(true, true); VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(vFile); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java index 1f7b8c8c7085..31e0a85f5209 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.AddClient; +import org.jetbrains.idea.svn.delete.DeleteClient; import org.jetbrains.idea.svn.history.HistoryClient; import org.jetbrains.idea.svn.portable.SvnStatusClientI; import org.jetbrains.idea.svn.revert.RevertClient; @@ -18,6 +19,7 @@ public abstract class ClientFactory { protected AddClient addClient; protected HistoryClient historyClient; protected RevertClient revertClient; + protected DeleteClient deleteClient; protected SvnStatusClientI statusClient; protected ClientFactory(@NotNull SvnVcs vcs) { @@ -48,6 +50,11 @@ public abstract class ClientFactory { return statusClient; } + @NotNull + public DeleteClient createDeleteClient() { + return prepare(deleteClient); + } + @NotNull protected T prepare(@NotNull T client) { client.setVcs(myVcs); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java index ecd8387347cc..0b10e3367e6b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.CmdAddClient; import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient; +import org.jetbrains.idea.svn.delete.CmdDeleteClient; import org.jetbrains.idea.svn.history.CmdHistoryClient; import org.jetbrains.idea.svn.revert.CmdRevertClient; @@ -21,6 +22,7 @@ public class CmdClientFactory extends ClientFactory { addClient = new CmdAddClient(); historyClient = new CmdHistoryClient(); revertClient = new CmdRevertClient(); + deleteClient = new CmdDeleteClient(); statusClient = new SvnCommandLineStatusClient(myVcs.getProject()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java index 20798240a173..98170197c2a2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.SvnKitAddClient; +import org.jetbrains.idea.svn.delete.SvnKitDeleteClient; import org.jetbrains.idea.svn.history.SvnKitHistoryClient; import org.jetbrains.idea.svn.portable.SvnkitSvnStatusClient; import org.jetbrains.idea.svn.revert.SvnKitRevertClient; @@ -21,6 +22,7 @@ public class SvnKitClientFactory extends ClientFactory { addClient = new SvnKitAddClient(); historyClient = new SvnKitHistoryClient(); revertClient = new SvnKitRevertClient(); + deleteClient = new SvnKitDeleteClient(); statusClient = new SvnkitSvnStatusClient(myVcs.createStatusClient()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java index eca20c8a92b3..265bb94bc102 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java @@ -441,15 +441,14 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { public List scheduleMissingFileForDeletion(List filePaths) { List exceptions = new ArrayList(); - final SVNWCClient wcClient = mySvnVcs.createWCClient(); - List files = ChangesUtil.filePathsToFiles(filePaths); + for (File file : files) { try { - wcClient.doDelete(file, true, false); + mySvnVcs.getFactory(file).createDeleteClient().delete(file, true); } - catch (SVNException e) { - exceptions.add(new VcsException(e)); + catch (VcsException e) { + exceptions.add(e); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index e8362e57e499..1dff4a059a15 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -97,12 +97,17 @@ public class CommandUtil { * @param parser * @throws VcsException */ - public static void execute(@NotNull SvnVcs vcs, @NotNull SvnCommandName name, @NotNull List parameters, @NotNull FileStatusResultParser parser) - throws VcsException { + public static void execute(@NotNull SvnVcs vcs, + @NotNull SvnCommandName name, + @NotNull List parameters, + @Nullable FileStatusResultParser parser) + throws VcsException { try { SvnLineCommand command = runSimple(name, vcs, null, null, parameters); - parser.parse(command.getOutput()); + if (parser != null) { + parser.parse(command.getOutput()); + } } catch (SVNException e) { throw new VcsException(e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/CmdDeleteClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/CmdDeleteClient.java new file mode 100644 index 000000000000..1712ae15395b --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/CmdDeleteClient.java @@ -0,0 +1,27 @@ +package org.jetbrains.idea.svn.delete; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.commandLine.CommandUtil; +import org.jetbrains.idea.svn.commandLine.SvnCommandName; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public class CmdDeleteClient extends BaseSvnClient implements DeleteClient { + + @Override + public void delete(@NotNull File path, boolean force) throws VcsException { + List parameters = new ArrayList(); + + CommandUtil.put(parameters, path); + CommandUtil.put(parameters, force, "--force"); + + CommandUtil.execute(myVcs, SvnCommandName.delete, parameters, null); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/DeleteClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/DeleteClient.java new file mode 100644 index 000000000000..23a1cf97cb31 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/DeleteClient.java @@ -0,0 +1,15 @@ +package org.jetbrains.idea.svn.delete; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.SvnClient; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public interface DeleteClient extends SvnClient { + + void delete(@NotNull File path, boolean force) throws VcsException; +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/SvnKitDeleteClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/SvnKitDeleteClient.java new file mode 100644 index 000000000000..c97cfd2a44bb --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/SvnKitDeleteClient.java @@ -0,0 +1,24 @@ +package org.jetbrains.idea.svn.delete; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.tmatesoft.svn.core.SVNException; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitDeleteClient extends BaseSvnClient implements DeleteClient { + + @Override + public void delete(@NotNull File path, boolean force) throws VcsException { + try { + myVcs.createWCClient().doDelete(path, force, false); + } + catch (SVNException e) { + throw new VcsException(e); + } + } +} From 71384c1cdcba6db0fe8e14e5370aad1cfed7b2b0 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 19 Aug 2013 20:29:30 +0400 Subject: [PATCH 16/30] IDEA-94942 Copy and move actions --- .../idea/svn/commandLine/SvnCommandName.java | 4 +- .../idea/svn/SvnChangelistListener.java | 6 +-- .../idea/svn/SvnFileSystemListener.java | 39 ++++++++++++------- .../jetbrains/idea/svn/api/ClientFactory.java | 6 +++ .../idea/svn/api/CmdClientFactory.java | 2 + .../idea/svn/api/SvnKitClientFactory.java | 2 + .../idea/svn/commandLine/SvnInfoHandler.java | 33 +++++++++++++++- .../idea/svn/copy/CmdCopyMoveClient.java | 30 ++++++++++++++ .../idea/svn/copy/CopyMoveClient.java | 15 +++++++ .../idea/svn/copy/SvnKitCopyMoveClient.java | 28 +++++++++++++ .../idea/svn/delete/CmdDeleteClient.java | 2 + 11 files changed, 147 insertions(+), 20 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CmdCopyMoveClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CopyMoveClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/copy/SvnKitCopyMoveClient.java diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index 43f08451f06d..d78ca2643d3f 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -34,7 +34,9 @@ public enum SvnCommandName { add("add", true), log("log", false), revert("revert", true), - delete("delete", true); + delete("delete", true), + copy("copy", true), + move("move", true); private final String myName; private final boolean myWriteable; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangelistListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangelistListener.java index ee326a42afb2..51d5dc486c51 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangelistListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangelistListener.java @@ -176,11 +176,9 @@ public class SvnChangelistListener implements ChangeListListener { } @Nullable - public static String getCurrentMapping(final Project project, final File file) { - final SvnVcs vcs = SvnVcs.getInstance(project); - final SVNStatusClient statusClient = vcs.createStatusClient(); + public static String getCurrentMapping(final SvnVcs vcs, final File file) { try { - final SVNStatus status = statusClient.doStatus(file, false); + final SVNStatus status = vcs.getFactory(file).createStatusClient().doStatus(file, false); return status == null ? null : status.getChangelistName(); } catch (SVNException e) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java index 65afe16e868e..d290f5f6c301 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java @@ -241,10 +241,11 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp long srcTime = src.lastModified(); try { final boolean isUndo = isUndo(vcs); - final String list = isUndo ? null : SvnChangelistListener.getCurrentMapping(vcs.getProject(), src); + final String list = isUndo ? null : SvnChangelistListener.getCurrentMapping(vcs, src); - final boolean is17 = SvnUtil.is17CopyPart(src); - if (is17) { + WorkingCopyFormat format = vcs.getWorkingCopyFormat(src); + final boolean is17OrLater = WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) || WorkingCopyFormat.ONE_DOT_SEVEN.equals(format); + if (is17OrLater) { SVNStatus srcStatus = getFileStatus(vcs, src); final File toDir = dst.getParentFile(); SVNStatus dstStatus = getFileStatus(vcs, toDir); @@ -313,13 +314,16 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp return false; } - public static void moveFileWithSvn(SvnVcs vcs, File src, final File dst) throws SVNException { - final SVNCopyClient copyClient = vcs.createCopyClient(); - final SVNCopySource svnCopySource = new SVNCopySource(SVNRevision.UNDEFINED, SVNRevision.WORKING, src); + public static void moveFileWithSvn(final SvnVcs vcs, final File src, final File dst) throws SVNException { new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws SVNException { - copyClient.doCopy(new SVNCopySource[]{svnCopySource}, dst, true, false, true); + try { + vcs.getFactory(src).createCopyMoveClient().copy(src, dst, false, true); + } + catch (VcsException e) { + wrapAndThrow(e); + } } }.execute(); } @@ -508,7 +512,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp vcs.getFactory(file).createRevertClient().revert(new File[]{file}, SVNDepth.fromRecurse(recursive), null); } catch (VcsException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); + wrapAndThrow(e); } } }; @@ -523,12 +527,17 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp vcs.getFactory(file).createDeleteClient().delete(file, force); } catch (VcsException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); + wrapAndThrow(e); } } }; } + private static void wrapAndThrow(VcsException e) throws SVNException { + // TODO: probably we should wrap into new exception only if e.getCause is not SVNException + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); + } + private boolean isAboveSourceOfCopyOrMove(final Project p, File ioFile) { for (MovedFileInfo file : myMovedFiles) { if (FileUtil.isAncestor(ioFile, file.mySrc, false)) return true; @@ -753,8 +762,6 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp return new Runnable() { @Override public void run() { - final SVNWCClient wcClient = vcs.createWCClient(); - final SVNCopyClient copyClient = vcs.createCopyClient(); for(VirtualFile file: filesToProcess) { final File ioFile = new File(file.getPath()); try { @@ -765,11 +772,15 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp protected void executeInternal() throws VcsException { try { // not recursive - final SVNCopySource[] copySource = {new SVNCopySource(SVNRevision.WORKING, SVNRevision.WORKING, copyFrom)}; new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws SVNException { - copyClient.doCopy(copySource, ioFile, false, true, true); + try { + vcs.getFactory(copyFrom).createCopyMoveClient().copy(copyFrom, ioFile, true, false); + } + catch (VcsException e) { + wrapAndThrow(e); + } } }.execute(); } @@ -791,7 +802,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp vcs.getFactory(ioFile).createAddClient().add(ioFile, null, false, false, true, null); } catch (VcsException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); + wrapAndThrow(e); } } }.execute(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java index 31e0a85f5209..f68b05fa3bd2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.AddClient; +import org.jetbrains.idea.svn.copy.CopyMoveClient; import org.jetbrains.idea.svn.delete.DeleteClient; import org.jetbrains.idea.svn.history.HistoryClient; import org.jetbrains.idea.svn.portable.SvnStatusClientI; @@ -21,6 +22,7 @@ public abstract class ClientFactory { protected RevertClient revertClient; protected DeleteClient deleteClient; protected SvnStatusClientI statusClient; + protected CopyMoveClient copyMoveClient; protected ClientFactory(@NotNull SvnVcs vcs) { myVcs = vcs; @@ -55,6 +57,10 @@ public abstract class ClientFactory { return prepare(deleteClient); } + public CopyMoveClient createCopyMoveClient() { + return prepare(copyMoveClient); + } + @NotNull protected T prepare(@NotNull T client) { client.setVcs(myVcs); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java index 0b10e3367e6b..c6d4a8793ee2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.CmdAddClient; import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient; +import org.jetbrains.idea.svn.copy.CmdCopyMoveClient; import org.jetbrains.idea.svn.delete.CmdDeleteClient; import org.jetbrains.idea.svn.history.CmdHistoryClient; import org.jetbrains.idea.svn.revert.CmdRevertClient; @@ -23,6 +24,7 @@ public class CmdClientFactory extends ClientFactory { historyClient = new CmdHistoryClient(); revertClient = new CmdRevertClient(); deleteClient = new CmdDeleteClient(); + copyMoveClient = new CmdCopyMoveClient(); statusClient = new SvnCommandLineStatusClient(myVcs.getProject()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java index 98170197c2a2..16a60ce2c562 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.SvnKitAddClient; +import org.jetbrains.idea.svn.copy.SvnKitCopyMoveClient; import org.jetbrains.idea.svn.delete.SvnKitDeleteClient; import org.jetbrains.idea.svn.history.SvnKitHistoryClient; import org.jetbrains.idea.svn.portable.SvnkitSvnStatusClient; @@ -23,6 +24,7 @@ public class SvnKitClientFactory extends ClientFactory { historyClient = new SvnKitHistoryClient(); revertClient = new SvnKitRevertClient(); deleteClient = new SvnKitDeleteClient(); + copyMoveClient = new SvnKitCopyMoveClient(); statusClient = new SvnkitSvnStatusClient(myVcs.createStatusClient()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java index 841eebbcdea0..99fc499c35c7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java @@ -295,6 +295,18 @@ public class SvnInfoHandler extends DefaultHandler { return new WcInfo(); } }); + myElementsMap.put("moved-to", new Getter() { + @Override + public ElementHandlerBase get() { + return new MovedPath(); + } + }); + myElementsMap.put("moved-from", new Getter() { + @Override + public ElementHandlerBase get() { + return new MovedPath(); + } + }); myElementsMap.put("wcroot-abspath", new Getter() { @Override public ElementHandlerBase get() { @@ -523,6 +535,25 @@ public class SvnInfoHandler extends DefaultHandler { } } + /** + * "moved-from" and "moved-to" elements are represented by this class. + */ + private static class MovedPath extends ElementHandlerBase { + + private MovedPath() { + super(new String[]{}, new String[]{}); + } + + @Override + protected void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException { + } + + @Override + public void characters(String s, SvnInfoStructure structure) throws SAXException { + // TODO: is there some field to initialize from this value? + } + } + private static class TextUpdated extends ElementHandlerBase { private TextUpdated() { super(new String[]{}, new String[]{}); @@ -642,7 +673,7 @@ public class SvnInfoHandler extends DefaultHandler { private static class WcInfo extends ElementHandlerBase { private WcInfo() { super(new String[]{"wcroot-abspath", "schedule", "depth", "text-updated", "checksum", "changelist", "copy-from-url", - "copy-from-rev"}, new String[]{}); + "copy-from-rev", "moved-to", "moved-from"}, new String[]{}); } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CmdCopyMoveClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CmdCopyMoveClient.java new file mode 100644 index 000000000000..eceef14d994d --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CmdCopyMoveClient.java @@ -0,0 +1,30 @@ +package org.jetbrains.idea.svn.copy; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.commandLine.CommandUtil; +import org.jetbrains.idea.svn.commandLine.SvnCommandName; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public class CmdCopyMoveClient extends BaseSvnClient implements CopyMoveClient { + + @Override + public void copy(@NotNull File src, @NotNull File dst, boolean makeParents, boolean isMove) throws VcsException { + List parameters = new ArrayList(); + + CommandUtil.put(parameters, src); + CommandUtil.put(parameters, dst); + CommandUtil.put(parameters, makeParents, "--parents"); + + // for now parsing of the output is not required as command is executed only for one file + // and will be either successful or exception will be thrown + CommandUtil.execute(myVcs, isMove ? SvnCommandName.move : SvnCommandName.copy, parameters, null); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CopyMoveClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CopyMoveClient.java new file mode 100644 index 000000000000..ec48107c8223 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CopyMoveClient.java @@ -0,0 +1,15 @@ +package org.jetbrains.idea.svn.copy; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.SvnClient; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public interface CopyMoveClient extends SvnClient { + + void copy(@NotNull File src, @NotNull File dst, boolean makeParents, boolean isMove) throws VcsException; +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/copy/SvnKitCopyMoveClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/copy/SvnKitCopyMoveClient.java new file mode 100644 index 000000000000..ea84bc6f0816 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/copy/SvnKitCopyMoveClient.java @@ -0,0 +1,28 @@ +package org.jetbrains.idea.svn.copy; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.SVNCopySource; +import org.tmatesoft.svn.core.wc.SVNRevision; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitCopyMoveClient extends BaseSvnClient implements CopyMoveClient { + + @Override + public void copy(@NotNull File src, @NotNull File dst, boolean makeParents, boolean isMove) throws VcsException { + final SVNCopySource copySource = new SVNCopySource(isMove ? SVNRevision.UNDEFINED : SVNRevision.WORKING, SVNRevision.WORKING, src); + + try { + myVcs.createCopyClient().doCopy(new SVNCopySource[]{copySource}, dst, isMove, makeParents, true); + } + catch (SVNException e) { + throw new VcsException(e); + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/CmdDeleteClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/CmdDeleteClient.java index 1712ae15395b..5fc26acfb1d3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/CmdDeleteClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/delete/CmdDeleteClient.java @@ -22,6 +22,8 @@ public class CmdDeleteClient extends BaseSvnClient implements DeleteClient { CommandUtil.put(parameters, path); CommandUtil.put(parameters, force, "--force"); + // for now parsing of the output is not required as command is executed only for one file + // and will be either successful or exception will be thrown CommandUtil.execute(myVcs, SvnCommandName.delete, parameters, null); } } From d880599f29223beda53fe731910185fc58fd5992 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 20 Aug 2013 13:40:26 +0400 Subject: [PATCH 17/30] IDEA-94942 Small text fixes Ignoring tests for old/not used functionality --- .../svn/SvnAbstractWriteOperationLocks.java | 1 + .../src/org/jetbrains/idea/svn/SvnProxies.java | 1 + .../idea/svn/SvnTestWriteOperationLocks.java | 1 + .../idea/svn/SvnWriteOperationLocks.java | 1 + .../jetbrains/idea/svn/SvnExternalTests.java | 17 +++++++++++++---- .../org/jetbrains/idea/svn/SvnLockingTest.java | 3 +++ 6 files changed, 20 insertions(+), 4 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAbstractWriteOperationLocks.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAbstractWriteOperationLocks.java index b4fd10492dfb..29e87422bb53 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAbstractWriteOperationLocks.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAbstractWriteOperationLocks.java @@ -36,6 +36,7 @@ import java.util.concurrent.locks.ReentrantLock; * Date: 10/19/12 * Time: 12:09 PM */ +// TODO: Such locking functionality is not required anymore. Likely to be removed (together with SvnProxies). public abstract class SvnAbstractWriteOperationLocks { private final long myTimeout; private final static Map myLockMap = new HashMap(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnProxies.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnProxies.java index 97b87efaa7f9..fcac3966c2d6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnProxies.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnProxies.java @@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicReference; * Date: 10/19/12 * Time: 4:22 PM */ +// TODO: Likely to be removed (together with SvnAbstractWriteOperationLocks). public class SvnProxies { private final SvnAbstractWriteOperationLocks myLocks; private final AtomicReference> myChangelist; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnTestWriteOperationLocks.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnTestWriteOperationLocks.java index 853e995ca219..efea2f93de08 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnTestWriteOperationLocks.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnTestWriteOperationLocks.java @@ -25,6 +25,7 @@ import java.io.File; * Date: 10/23/12 * Time: 2:31 PM */ +// TODO: Used only in SvnLockingTest which is not required anymore. Likely to be removed. public class SvnTestWriteOperationLocks extends SvnAbstractWriteOperationLocks { private final WorkingCopy myWorkingCopy; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnWriteOperationLocks.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnWriteOperationLocks.java index 36e0b08c5a86..ca97edb1c228 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnWriteOperationLocks.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnWriteOperationLocks.java @@ -30,6 +30,7 @@ import java.io.File; * Date: 10/23/12 * Time: 2:29 PM */ +// TODO: Such locking functionality is not required anymore. Likely to be removed. public class SvnWriteOperationLocks extends SvnAbstractWriteOperationLocks { private final RootsToWorkingCopies myRootsToWorkingCopies; diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnExternalTests.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnExternalTests.java index 500acbdff4c9..3e3b2fda1665 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnExternalTests.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnExternalTests.java @@ -27,6 +27,7 @@ import com.intellij.openapi.vcs.changes.ChangeListManagerImpl; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ui.UIUtil; import junit.framework.Assert; import org.junit.Test; @@ -171,8 +172,7 @@ public class SvnExternalTests extends Svn17TestCase { private void updatedCreatedExternalFromIDEAImpl() { final File sourceDir = new File(myWorkingCopyDir.getPath(), "source"); - ProjectLevelVcsManager.getInstance(myProject).setDirectoryMappings( - Arrays.asList(new VcsDirectoryMapping(FileUtil.toSystemIndependentName(sourceDir.getPath()), myVcs.getName()))); + setNewDirectoryMappings(sourceDir); imitUpdate(myProject); final File externalFile = new File(sourceDir, "external/t11.txt"); @@ -180,6 +180,16 @@ public class SvnExternalTests extends Svn17TestCase { Assert.assertNotNull(externalVf); } + private void setNewDirectoryMappings(final File sourceDir) { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + ProjectLevelVcsManager.getInstance(myProject).setDirectoryMappings( + Arrays.asList(new VcsDirectoryMapping(FileUtil.toSystemIndependentName(sourceDir.getPath()), myVcs.getName()))); + } + }); + } + @Test public void testUncommittedExternalStatus() throws Exception { prepareExternal(false, true, false); @@ -221,8 +231,7 @@ public class SvnExternalTests extends Svn17TestCase { private void uncommittedExternalCopyIsDetectedImpl() { final File sourceDir = new File(myWorkingCopyDir.getPath(), "source"); - ProjectLevelVcsManager.getInstance(myProject).setDirectoryMappings( - Arrays.asList(new VcsDirectoryMapping(FileUtil.toSystemIndependentName(sourceDir.getPath()), myVcs.getName()))); + setNewDirectoryMappings(sourceDir); imitUpdate(myProject); refreshSvnMappingsSynchronously(); diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnLockingTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnLockingTest.java index 171bb1c35cb8..7c32af921f56 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnLockingTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnLockingTest.java @@ -22,6 +22,7 @@ import com.intellij.util.concurrency.Semaphore; import junit.framework.Assert; import junit.framework.TestCase; import org.junit.Before; +import org.junit.Ignore; import org.tmatesoft.sqljet.core.SqlJetException; import org.tmatesoft.sqljet.core.table.ISqlJetBusyHandler; import org.tmatesoft.sqljet.core.table.ISqlJetTransaction; @@ -42,6 +43,8 @@ import java.util.concurrent.atomic.AtomicBoolean; * Date: 10/23/12 * Time: 2:27 PM */ +// TODO: Locking functionality which is tested by this test is not required anymore. Likely test needs to be removed. +@Ignore public class SvnLockingTest extends TestCase { private File myWorkingCopyRoot; private SvnTestWriteOperationLocks myLocks; From 928c01e169959c247ba82fd147a584120093e299 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 7 Aug 2013 13:39:36 +0400 Subject: [PATCH 18/30] IDEA-94942 - Basic svn 1.8 test support --- .../testData18/svn/bin/windows/svn.exe | Bin 0 -> 228864 bytes plugins/svn4idea/testData18/svn/newrepo.zip | Bin 0 -> 20570 bytes .../org/jetbrains/idea/SvnTestCase.java | 40 +++++++++++++++--- .../jetbrains/idea/svn/IgnoredFilesTest.java | 1 + ...vnChangesCorrectlyRefreshedNativeTest.java | 2 +- .../org/jetbrains/idea/svn/SvnCommitTest.java | 3 +- .../idea/svn/SvnNativeClientAuthTest.java | 2 +- ...vnChangesCorrectlyRefreshedNativeTest.java | 2 +- .../jetbrains/idea/svn18/Svn18TestSuite.java | 33 +++++++++++++++ 9 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 plugins/svn4idea/testData18/svn/bin/windows/svn.exe create mode 100644 plugins/svn4idea/testData18/svn/newrepo.zip create mode 100644 plugins/svn4idea/testSource/org/jetbrains/idea/svn18/Svn18TestSuite.java diff --git a/plugins/svn4idea/testData18/svn/bin/windows/svn.exe b/plugins/svn4idea/testData18/svn/bin/windows/svn.exe new file mode 100644 index 0000000000000000000000000000000000000000..827753f442aa2cd93c89c030fe4798b5b3a026d1 GIT binary patch literal 228864 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 Y6OY{WQG9uHJ)*!P3Ou5~e<%h14~eB>aR2}S literal 0 HcmV?d00001 diff --git a/plugins/svn4idea/testData18/svn/newrepo.zip b/plugins/svn4idea/testData18/svn/newrepo.zip new file mode 100644 index 0000000000000000000000000000000000000000..fd9a577a39a0924e362304bd54d76eb36973d255 GIT binary patch literal 20570 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 literal 0 HcmV?d00001 diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/SvnTestCase.java b/plugins/svn4idea/testSource/org/jetbrains/idea/SvnTestCase.java index 14d1b4c42897..d5a55520adae 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/SvnTestCase.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/SvnTestCase.java @@ -78,13 +78,19 @@ import static org.junit.Assert.assertTrue; * @author yole */ public abstract class SvnTestCase extends AbstractJunitVcsTestCase { + + public static String ourGlobalTestDataDir; + public static Boolean ourGlobalUseNativeAcceleration; + protected TempDirTestFixture myTempDirFixture; protected String myRepoUrl; protected TestClientRunner myRunner; protected String myWcRootName; - protected boolean myUseNativeAcceleration = new GregorianCalendar().get(Calendar.HOUR_OF_DAY) % 2 == 0; + // TODO: Change this to explicitly run either with native acceleration or not. + // properties set through run configurations or different runners (like Suite) could be used + private boolean myUseNativeAcceleration = new GregorianCalendar().get(Calendar.HOUR_OF_DAY) % 2 == 0; - protected final String myTestDataDir; + private String myTestDataDir; private File myRepoRoot; private File myWcRoot; private ChangeListManagerGate myGate; @@ -118,7 +124,13 @@ public abstract class SvnTestCase extends AbstractJunitVcsTestCase { @Before public void setUp() throws Exception { - System.out.println("Native client for status: " + myUseNativeAcceleration); + System.out.println("Native client for status: " + isUseNativeAcceleration()); + + String property = System.getProperty("svn.test.data.directory"); + if (!StringUtil.isEmpty(property)) { + myTestDataDir = property; + } + UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { @@ -138,7 +150,7 @@ public abstract class SvnTestCase extends AbstractJunitVcsTestCase { myPluginRoot = new File(rootPath).getParentFile().getParentFile().getParentFile(); } - File svnBinDir = new File(myPluginRoot, myTestDataDir + "/svn/bin"); + File svnBinDir = new File(myPluginRoot, getTestDataDir() + "/svn/bin"); File svnExecutable = null; if (SystemInfo.isWindows) { svnExecutable = new File(svnBinDir, "windows/svn.exe"); @@ -156,7 +168,7 @@ public abstract class SvnTestCase extends AbstractJunitVcsTestCase { ? createClientRunner(Collections.singletonMap("DYLD_LIBRARY_PATH", myClientBinaryPath.getPath())) : createClientRunner(); - ZipUtil.extract(new File(myPluginRoot, myTestDataDir + "/svn/newrepo.zip"), myRepoRoot, null); + ZipUtil.extract(new File(myPluginRoot, getTestDataDir() + "/svn/newrepo.zip"), myRepoRoot, null); myWcRoot = new File(myTempDirFixture.getTempDirPath(), myWcRootName); assert myWcRoot.mkdir() || myWcRoot.isDirectory() : myWcRoot; @@ -205,7 +217,7 @@ public abstract class SvnTestCase extends AbstractJunitVcsTestCase { @Override protected void projectCreated() { - if (myUseNativeAcceleration) { + if (isUseNativeAcceleration()) { SvnConfiguration.getInstance(myProject).myUseAcceleration = SvnConfiguration.UseAcceleration.commandLine; SvnApplicationSettings.getInstance().setCommandLinePath(myClientBinaryPath + File.separator + "svn"); } @@ -319,6 +331,22 @@ public abstract class SvnTestCase extends AbstractJunitVcsTestCase { //clManager.ensureUpToDate(false); } + public String getTestDataDir() { + return StringUtil.isEmpty(ourGlobalTestDataDir) ? myTestDataDir : ourGlobalTestDataDir; + } + + public void setTestDataDir(String testDataDir) { + myTestDataDir = testDataDir; + } + + public boolean isUseNativeAcceleration() { + return ourGlobalUseNativeAcceleration != null ? ourGlobalUseNativeAcceleration : myUseNativeAcceleration; + } + + public void setUseNativeAcceleration(boolean useNativeAcceleration) { + myUseNativeAcceleration = useNativeAcceleration; + } + protected class SubTree { public VirtualFile myRootDir; public VirtualFile mySourceDir; diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/IgnoredFilesTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/IgnoredFilesTest.java index 270e6d49c607..bded7affdf2c 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/IgnoredFilesTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/IgnoredFilesTest.java @@ -54,6 +54,7 @@ public class IgnoredFilesTest extends Svn17TestCase { @Before public void setUp() throws Exception { + super.setUp(); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedNativeTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedNativeTest.java index a9c1074a3d94..6153d658767b 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedNativeTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedNativeTest.java @@ -34,7 +34,7 @@ public class SvnChangesCorrectlyRefreshedNativeTest extends Svn17TestCase { @Override public void setUp() throws Exception { - myUseNativeAcceleration = true; + setUseNativeAcceleration(true); super.setUp(); clManager = ChangeListManager.getInstance(myProject); diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCommitTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCommitTest.java index f4da04ea201a..f18b6a578ecb 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCommitTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCommitTest.java @@ -465,7 +465,7 @@ public class SvnCommitTest extends Svn17TestCase { return feedback; } - private void checkinFile(VirtualFile file, FileStatus status) { + protected void checkinFile(VirtualFile file, FileStatus status) { final Change change = myChangeListManager.getChange(file); Assert.assertNotNull(change); Assert.assertEquals(status, change.getFileStatus()); @@ -478,6 +478,7 @@ public class SvnCommitTest extends Svn17TestCase { } protected void run2variants(final MyRunner runner) throws Exception { + // TODO: Change this to run different variants separately. See SvnTestCase.myUseAcceleration. setNativeAcceleration(false); runner.run(); runner.cleanup(); diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java index 61aca5670867..b6d6ae104bbc 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java @@ -72,7 +72,7 @@ public class SvnNativeClientAuthTest extends Svn17TestCase { @Before public void setUp() throws Exception { super.setUp(); - final File certFile = new File(myPluginRoot, myTestDataDir + "/svn/____.pfx"); + final File certFile = new File(myPluginRoot, getTestDataDir() + "/svn/____.pfx"); setNativeAcceleration(true); myVcs = SvnVcs.getInstance(myProject); // replace authentication provider so that pass credentials without dialogs diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnChangesCorrectlyRefreshedNativeTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnChangesCorrectlyRefreshedNativeTest.java index 205733657075..8939f1cbf164 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnChangesCorrectlyRefreshedNativeTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnChangesCorrectlyRefreshedNativeTest.java @@ -49,7 +49,7 @@ public class SvnChangesCorrectlyRefreshedNativeTest extends Svn17TestCase { @Override public void setUp() throws Exception { - myUseNativeAcceleration = true; + setUseNativeAcceleration(true); super.setUp(); clManager = ChangeListManager.getInstance(myProject); diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn18/Svn18TestSuite.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn18/Svn18TestSuite.java new file mode 100644 index 000000000000..a7019738b9b5 --- /dev/null +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn18/Svn18TestSuite.java @@ -0,0 +1,33 @@ +package org.jetbrains.idea.svn18; + +import org.jetbrains.idea.SvnTestCase; +import org.jetbrains.idea.svn.*; +import org.junit.ClassRule; +import org.junit.rules.ExternalResource; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * @author Konstantin Kolosovsky. + */ +// TODO: Add svn clients for mac and linux +@RunWith(Suite.class) +@Suite.SuiteClasses({SvnAddTest.class, SvnDeleteTest.class}) +public class Svn18TestSuite { + + @ClassRule + public static TestRule configuration = new ExternalResource() { + @Override + protected void before() throws Throwable { + SvnTestCase.ourGlobalTestDataDir = "testData18"; + SvnTestCase.ourGlobalUseNativeAcceleration = true; + } + + @Override + protected void after() { + SvnTestCase.ourGlobalTestDataDir = null; + SvnTestCase.ourGlobalUseNativeAcceleration = null; + } + }; +} From 6c36a9358d242a1203ffe5dc0d8b7b7a6fef1191 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 20 Aug 2013 20:36:26 +0400 Subject: [PATCH 19/30] IDEA-112184 Added logging to detect authentication issues --- .../IdeaSvnkitBasedAuthenticationCallback.java | 11 +++++++++-- .../idea/svn/checkin/SvnCheckinEnvironment.java | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java index 46a4e4264cc0..a07f5fe971a0 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java @@ -80,8 +80,15 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall @Nullable @Override public SVNAuthentication requestCredentials(@Nullable SVNURL url, String type) { - return url != null ? myVcs.getSvnConfiguration().getInteractiveManager(myVcs).getProvider().requestClientAuthentication( - type, url, url.toDecodedString(), null, null, true) : null; + SVNAuthentication authentication = + url != null ? myVcs.getSvnConfiguration().getInteractiveManager(myVcs).getProvider().requestClientAuthentication( + type, url, url.toDecodedString(), null, null, true) : null; + + if (authentication == null) { + LOG.warn("Could not get authentication. Type - " + type + ", Url - " + url); + } + + return authentication; } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java index 265bb94bc102..fc4f98d34d56 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java @@ -261,6 +261,10 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { public SVNURL convert(String[] o) { SVNInfo info = o.length > 0 ? mySvnVcs.getInfo(o[0]) : null; + if (info == null || info.getURL() == null) { + LOG.warn("Could not resolve repository url for commit. Paths - " + Arrays.toString(o)); + } + return info != null ? info.getURL() : null; } }); From cef0440f47e2ff4c8d8d46c027d3c34861c66ba4 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 21 Aug 2013 15:06:00 +0400 Subject: [PATCH 20/30] IDEA-94942 "bindSvn" module classes moved to "svn4idea" SvnBindClient unsupported methods will be removed in next commit (to track change like "rename" instead of "delete" + "add" to preserve history) --- .idea/modules.xml | 1 - build/scripts/layouts.gant | 3 - plugins/svn4idea/bindSvn/bindSvn.iml | 36 --- plugins/svn4idea/bindSvn/lib/javahl.jar | Bin 168896 -> 0 bytes plugins/svn4idea/bindSvn/lib/javahlsrc.zip | Bin 210516 -> 0 bytes .../idea/svn/status/LockWrapper.java | 121 -------- .../javahl/BindClientException.java | 47 ---- .../idea/svn/checkin/IdeaCommitHandler.java | 4 +- ...IdeaSvnkitBasedAuthenticationCallback.java | 1 + .../svn/checkin/SvnCheckinEnvironment.java | 6 +- .../commandLine}/AuthenticationCallback.java | 2 +- .../idea/svn/commandLine/CommandUtil.java | 2 - .../svn/commandLine}/CommitEventHandler.java | 2 +- .../svn/commandLine}/CommitEventType.java | 2 +- .../svn/commandLine/LineCommandListener.java | 0 .../idea/svn/commandLine}/SvnBindClient.java | 262 +++++++++--------- .../svn/commandLine}/SvnBindException.java | 20 +- .../idea/svn/commandLine}/SvnBindUtil.java | 2 +- .../idea/svn/commandLine/SvnCommand.java | 0 .../commandLine/SvnCommandLineInfoClient.java | 1 - .../SvnCommandLineStatusClient.java | 1 - .../SvnCommandLineUpdateClient.java | 1 - .../idea/svn/commandLine/SvnCommandName.java | 0 .../svn/commandLine}/SvnCommitRunner.java | 26 +- .../idea/svn/commandLine/SvnLineCommand.java | 3 - .../svn/commandLine/SvnSimpleCommand.java | 0 plugins/svn4idea/svn4idea-tests.iml | 1 - plugins/svn4idea/svn4idea.iml | 10 - 28 files changed, 149 insertions(+), 405 deletions(-) delete mode 100644 plugins/svn4idea/bindSvn/bindSvn.iml delete mode 100644 plugins/svn4idea/bindSvn/lib/javahl.jar delete mode 100644 plugins/svn4idea/bindSvn/lib/javahlsrc.zip delete mode 100644 plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/status/LockWrapper.java delete mode 100644 plugins/svn4idea/bindSvn/src/org/tigris/subversion/javahl/BindClientException.java rename plugins/svn4idea/{bindSvn/src/org/jetbrains/idea/svn => src/org/jetbrains/idea/svn/commandLine}/AuthenticationCallback.java (99%) rename plugins/svn4idea/{bindSvn/src/org/jetbrains/idea/svn => src/org/jetbrains/idea/svn/commandLine}/CommitEventHandler.java (95%) rename plugins/svn4idea/{bindSvn/src/org/jetbrains/idea/svn => src/org/jetbrains/idea/svn/commandLine}/CommitEventType.java (96%) rename plugins/svn4idea/{bindSvn => }/src/org/jetbrains/idea/svn/commandLine/LineCommandListener.java (100%) rename plugins/svn4idea/{bindSvn/src/org/jetbrains/idea/svn => src/org/jetbrains/idea/svn/commandLine}/SvnBindClient.java (94%) rename plugins/svn4idea/{bindSvn/src/org/jetbrains/idea/svn/config => src/org/jetbrains/idea/svn/commandLine}/SvnBindException.java (68%) rename plugins/svn4idea/{bindSvn/src/org/jetbrains/idea/svn => src/org/jetbrains/idea/svn/commandLine}/SvnBindUtil.java (98%) rename plugins/svn4idea/{bindSvn => }/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java (100%) rename plugins/svn4idea/{bindSvn => }/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java (100%) rename plugins/svn4idea/{bindSvn/src/org/jetbrains/idea/svn => src/org/jetbrains/idea/svn/commandLine}/SvnCommitRunner.java (87%) rename plugins/svn4idea/{bindSvn => }/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java (99%) rename plugins/svn4idea/{bindSvn => }/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java (100%) diff --git a/.idea/modules.xml b/.idea/modules.xml index bacca10b849f..d1b6f797a7d1 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -16,7 +16,6 @@ - diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index b7475ea9be3d..54fb1d765e2c 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -321,9 +321,6 @@ public def layoutCommunityPlugins(String home) { } layoutPlugin("svn4idea") { - jar("bindSvn.jar") { - module("bindSvn") - } fileset(dir: "$home/plugins/svn4idea/lib", excludes: "**/svnkitsrc.zip") } diff --git a/plugins/svn4idea/bindSvn/bindSvn.iml b/plugins/svn4idea/bindSvn/bindSvn.iml deleted file mode 100644 index fa6b992f74e3..000000000000 --- a/plugins/svn4idea/bindSvn/bindSvn.iml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/svn4idea/bindSvn/lib/javahl.jar b/plugins/svn4idea/bindSvn/lib/javahl.jar deleted file mode 100644 index a0c5370065af734c4bf41755dc270e8942ed4874..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168896 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 diff --git a/plugins/svn4idea/bindSvn/lib/javahlsrc.zip b/plugins/svn4idea/bindSvn/lib/javahlsrc.zip deleted file mode 100644 index 9c50118203b7979d0c6309c00293bdaa47853ae2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 210516 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®3JqGO4z6N*YyIr@{VQ{ilV+XUGC05Rv9;2Fz_g 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 constructor = org.tigris.subversion.javahl.Lock.class.getConstructor(Lock.class); - constructor.setAccessible(true); - return constructor.newInstance(newLock); - } - catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - catch (InstantiationException e) { - throw new RuntimeException(e); - } - catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } -} diff --git a/plugins/svn4idea/bindSvn/src/org/tigris/subversion/javahl/BindClientException.java b/plugins/svn4idea/bindSvn/src/org/tigris/subversion/javahl/BindClientException.java deleted file mode 100644 index f8acc17d0558..000000000000 --- a/plugins/svn4idea/bindSvn/src/org/tigris/subversion/javahl/BindClientException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.tigris.subversion.javahl; - -import org.jetbrains.annotations.NotNull; - -/** - * Created with IntelliJ IDEA. - * User: Irina.Chernushina - * Date: 2/25/13 - * Time: 6:29 PM - */ -public class BindClientException extends ClientException { - private Throwable myCause; - - public BindClientException(String message, String source, int aprError) { - super(message, source, aprError); - } - - public BindClientException(org.apache.subversion.javahl.ClientException ex) { - super(ex); - } - - public static BindClientException create(@NotNull final Throwable t, final int code) { - final BindClientException exception = new BindClientException(t.getMessage(), null, code); - exception.myCause = t; - return exception; - } - - @Override - public Throwable getCause() { - return myCause; - } -} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaCommitHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaCommitHandler.java index 3bd8256e7b02..5ac6b967777e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaCommitHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaCommitHandler.java @@ -16,8 +16,8 @@ package org.jetbrains.idea.svn.checkin; import com.intellij.openapi.progress.ProgressIndicator; -import org.jetbrains.idea.svn.CommitEventHandler; -import org.jetbrains.idea.svn.CommitEventType; +import org.jetbrains.idea.svn.commandLine.CommitEventHandler; +import org.jetbrains.idea.svn.commandLine.CommitEventType; import org.jetbrains.idea.svn.SvnBundle; import java.io.File; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java index a07f5fe971a0..f765595745b3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java @@ -28,6 +28,7 @@ import com.intellij.util.net.HttpConfigurable; import com.intellij.util.proxy.CommonProxy; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.commandLine.AuthenticationCallback; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.auth.*; import org.tmatesoft.svn.core.internal.util.SVNBase64; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java index fc4f98d34d56..c7d2d4b41bf2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java @@ -48,8 +48,8 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.commandLine.SvnBindClient; import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient; -import org.tigris.subversion.javahl.ClientException; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.*; @@ -273,8 +273,8 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { final long revision = client.commit(ArrayUtil.toStringArray(paths), comment, false, false); reportCommittedRevisions(feedback, String.valueOf(revision)); } - catch (ClientException e) { - exception.add(new VcsException(e)); + catch (VcsException e) { + exception.add(e); } finally { authenticationCallback.reset(); } diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthenticationCallback.java similarity index 99% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthenticationCallback.java index da99d854e13b..1944749f3608 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthenticationCallback.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn; +package org.jetbrains.idea.svn.commandLine; import org.jetbrains.annotations.Nullable; import org.tmatesoft.svn.core.SVNURL; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index 1dff4a059a15..e18f64f2c94b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -6,11 +6,9 @@ import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnApplicationSettings; -import org.jetbrains.idea.svn.SvnCommitRunner; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.api.FileStatusResultParser; import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; -import org.jetbrains.idea.svn.config.SvnBindException; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNStatusType; diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/CommitEventHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommitEventHandler.java similarity index 95% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/CommitEventHandler.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommitEventHandler.java index 7f3bcf3bf4a5..d74884073863 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/CommitEventHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommitEventHandler.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn; +package org.jetbrains.idea.svn.commandLine; import java.io.File; diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/CommitEventType.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommitEventType.java similarity index 96% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/CommitEventType.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommitEventType.java index 46609e40532c..87dc212d0341 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/CommitEventType.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommitEventType.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn; +package org.jetbrains.idea.svn.commandLine; /** * Created with IntelliJ IDEA. diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/LineCommandListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/LineCommandListener.java similarity index 100% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/LineCommandListener.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/LineCommandListener.java diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindClient.java similarity index 94% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindClient.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindClient.java index d0bf3a086d5c..b0d9689c6c0f 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindClient.java @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn; +package org.jetbrains.idea.svn.commandLine; +import com.intellij.openapi.vcs.VcsException; import com.intellij.util.containers.Convertor; import org.tigris.subversion.javahl.*; import org.tmatesoft.svn.core.SVNURL; @@ -28,7 +29,7 @@ import java.util.Map; * Date: 2/5/13 * Time: 3:08 PM */ -public class SvnBindClient implements SVNClientInterface { +public class SvnBindClient { private final String myExecutablePath; private CommitEventHandler myHandler; private AuthenticationCallback myAuthenticationCallback; @@ -39,53 +40,53 @@ public class SvnBindClient implements SVNClientInterface { myUrlProvider = urlProvider; } - @Override + public void dispose() { } - @Override + public Version getVersion() { // todo real version throw new UnsupportedOperationException(); } - @Override + public String getAdminDirectoryName() { throw new UnsupportedOperationException(); } - @Override + public boolean isAdminDirectory(String name) { throw new UnsupportedOperationException(); } - @Override + public String getLastPath() { throw new UnsupportedOperationException(); } - @Override + public Status singleStatus(String path, boolean onServer) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public Status[] status(String path, boolean descend, boolean onServer, boolean getAll) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public Status[] status(String path, boolean descend, boolean onServer, boolean getAll, boolean noIgnore) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public Status[] status(String path, boolean descend, boolean onServer, boolean getAll, boolean noIgnore, boolean ignoreExternals) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void status(String path, int depth, boolean onServer, @@ -97,17 +98,17 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public DirEntry[] list(String url, Revision revision, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public DirEntry[] list(String url, Revision revision, Revision pegRevision, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void list(String url, Revision revision, Revision pegRevision, @@ -118,38 +119,38 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void username(String username) { throw new UnsupportedOperationException(); } - @Override + public void password(String password) { throw new UnsupportedOperationException(); } - @Override + public void setPrompt(PromptUserPassword prompt) { throw new UnsupportedOperationException(); } - @Override + public LogMessage[] logMessages(String path, Revision revisionStart, Revision revisionEnd) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public LogMessage[] logMessages(String path, Revision revisionStart, Revision revisionEnd, boolean stopOnCopy) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public LogMessage[] logMessages(String path, Revision revisionStart, Revision revisionEnd, boolean stopOnCopy, boolean discoverPath) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public LogMessage[] logMessages(String path, Revision revisionStart, Revision revisionEnd, @@ -159,7 +160,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void logMessages(String path, Revision pegRevision, Revision revisionStart, @@ -173,7 +174,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void logMessages(String path, Revision pegRevision, RevisionRange[] ranges, @@ -186,12 +187,12 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public long checkout(String moduleName, String destPath, Revision revision, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public long checkout(String moduleName, String destPath, Revision revision, @@ -201,7 +202,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public long checkout(String moduleName, String destPath, Revision revision, @@ -212,77 +213,77 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void notification(Notify notify) { throw new UnsupportedOperationException(); } - @Override + public void notification2(Notify2 notify) { throw new UnsupportedOperationException(); } - @Override + public void setConflictResolver(ConflictResolverCallback listener) { throw new UnsupportedOperationException(); } - @Override + public void setProgressListener(ProgressListener listener) { throw new UnsupportedOperationException(); } - @Override + public void commitMessageHandler(CommitMessage messageHandler) { throw new UnsupportedOperationException(); } - @Override + public void remove(String[] path, String message, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void remove(String[] path, String message, boolean force, boolean keepLocal, Map revpropTable) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void revert(String path, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void revert(String path, int depth, String[] changelists) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void add(String path, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void add(String path, boolean recurse, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void add(String path, int depth, boolean force, boolean noIgnores, boolean addParents) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public long update(String path, Revision revision, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public long[] update(String[] path, Revision revision, boolean recurse, boolean ignoreExternals) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public long update(String path, Revision revision, int depth, @@ -292,7 +293,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public long[] update(String[] path, Revision revision, int depth, @@ -302,33 +303,30 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override - public long commit(String[] path, String message, boolean recurse) throws ClientException { + public long commit(String[] path, String message, boolean recurse) throws VcsException { return commit(path, message, recurse? 3 : 0, false, false, null, null); } - @Override - public long commit(String[] path, String message, boolean recurse, boolean noUnlock) throws ClientException { + public long commit(String[] path, String message, boolean recurse, boolean noUnlock) throws VcsException { return commit(path, message, recurse? 3 : 0, noUnlock, false, null, null); } - @Override public long commit(String[] path, String message, int depth, boolean noUnlock, boolean keepChangelist, String[] changelists, - Map revpropTable) throws ClientException { + Map revpropTable) throws VcsException { final long commit = new SvnCommitRunner(myExecutablePath, myHandler, myAuthenticationCallback). commit(path, message, depth, noUnlock, keepChangelist, changelists, revpropTable, myUrlProvider); if (commit < 0) { - throw new BindClientException("Wrong committed revision number: " + commit, null, -1); + throw new VcsException("Wrong committed revision number: " + commit); } return commit; } - @Override + public void copy(CopySource[] sources, String destPath, String message, @@ -339,18 +337,18 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void copy(CopySource[] sources, String destPath, String message, boolean copyAsChild, boolean makeParents, Map revpropTable) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void copy(String srcPath, String destPath, String message, Revision revision) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void move(String[] srcPaths, String destPath, String message, @@ -361,47 +359,47 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void move(String srcPath, String destPath, String message, Revision ignored, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void move(String srcPath, String destPath, String message, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void mkdir(String[] path, String message, boolean makeParents, Map revpropTable) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void mkdir(String[] path, String message) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void cleanup(String path) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void resolve(String path, int depth, int conflictResult) throws SubversionException { throw new UnsupportedOperationException(); } - @Override + public void resolved(String path, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public long doExport(String srcPath, String destPath, Revision revision, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public long doExport(String srcPath, String destPath, Revision revision, @@ -413,7 +411,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public long doExport(String srcPath, String destPath, Revision revision, @@ -425,12 +423,12 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public long doSwitch(String path, String url, Revision revision, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public long doSwitch(String path, String url, Revision revision, @@ -442,12 +440,12 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void doImport(String path, String url, String message, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void doImport(String path, String url, String message, @@ -458,18 +456,18 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public String[] suggestMergeSources(String path, Revision pegRevision) throws SubversionException { throw new UnsupportedOperationException(); } - @Override + public void merge(String path1, Revision revision1, String path2, Revision revision2, String localPath, boolean force, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void merge(String path1, Revision revision1, String path2, @@ -482,7 +480,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void merge(String path1, Revision revision1, String path2, @@ -496,7 +494,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void merge(String path, Revision pegRevision, Revision revision1, @@ -509,7 +507,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void merge(String path, Revision pegRevision, RevisionRange[] revisions, @@ -522,17 +520,17 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void mergeReintegrate(String path, Revision pegRevision, String localPath, boolean dryRun) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public Mergeinfo getMergeinfo(String path, Revision pegRevision) throws SubversionException { throw new UnsupportedOperationException(); } - @Override + public void getMergeinfoLog(int kind, String pathOrUrl, Revision pegRevision, @@ -545,7 +543,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void getMergeinfoLog(int kind, String pathOrUrl, Revision pegRevision, @@ -557,13 +555,13 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void diff(String target1, Revision revision1, String target2, Revision revision2, String outFileName, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void diff(String target1, Revision revision1, String target2, @@ -576,7 +574,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void diff(String target1, Revision revision1, String target2, @@ -592,7 +590,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void diff(String target1, Revision revision1, String target2, @@ -607,7 +605,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void diff(String target, Revision pegRevision, Revision startRevision, @@ -620,7 +618,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void diff(String target, Revision pegRevision, Revision startRevision, @@ -636,7 +634,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void diff(String target, Revision pegRevision, Revision startRevision, @@ -651,7 +649,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void diffSummarize(String target1, Revision revision1, String target2, @@ -663,7 +661,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void diffSummarize(String target, Revision pegRevision, Revision startRevision, @@ -675,163 +673,163 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public PropertyData[] properties(String path) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public PropertyData[] properties(String path, Revision revision) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public PropertyData[] properties(String path, Revision revision, Revision pegRevision) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void properties(String path, Revision revision, Revision pegRevision, int depth, String[] changelists, ProplistCallback callback) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertySet(String path, String name, String value, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertySet(String path, String name, String value, boolean recurse, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertySet(String path, String name, byte[] value, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertySet(String path, String name, byte[] value, boolean recurse, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertySet(String path, String name, String value, int depth, String[] changelists, boolean force, Map revpropTable) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertyRemove(String path, String name, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertyRemove(String path, String name, int depth, String[] changelists) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertyCreate(String path, String name, String value, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertyCreate(String path, String name, String value, boolean recurse, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertyCreate(String path, String name, byte[] value, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertyCreate(String path, String name, byte[] value, boolean recurse, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void propertyCreate(String path, String name, String value, int depth, String[] changelists, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public PropertyData revProperty(String path, String name, Revision rev) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public PropertyData[] revProperties(String path, Revision rev) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void setRevProperty(String path, String name, Revision rev, String value, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void setRevProperty(String path, String name, Revision rev, String value, String originalValue, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public PropertyData propertyGet(String path, String name) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public PropertyData propertyGet(String path, String name, Revision revision) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public PropertyData propertyGet(String path, String name, Revision revision, Revision pegRevision) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public byte[] fileContent(String path, Revision revision) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public byte[] fileContent(String path, Revision revision, Revision pegRevision) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void streamFileContent(String path, Revision revision, Revision pegRevision, int bufferSize, OutputStream stream) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void relocate(String from, String to, String path, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public byte[] blame(String path, Revision revisionStart, Revision revisionEnd) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void blame(String path, Revision revisionStart, Revision revisionEnd, BlameCallback callback) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void blame(String path, Revision pegRevision, Revision revisionStart, Revision revisionEnd, BlameCallback callback) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void blame(String path, Revision pegRevision, Revision revisionStart, @@ -842,7 +840,7 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void blame(String path, Revision pegRevision, Revision revisionStart, @@ -853,68 +851,68 @@ public class SvnBindClient implements SVNClientInterface { throw new UnsupportedOperationException(); } - @Override + public void setConfigDirectory(String configDir) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public String getConfigDirectory() throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void cancelOperation() throws ClientException { throw new UnsupportedOperationException(); } - @Override + public Info info(String path) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void addToChangelist(String[] paths, String changelist, int depth, String[] changelists) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void removeFromChangelists(String[] paths, int depth, String[] changelists) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void getChangelists(String rootPath, String[] changelists, int depth, ChangelistCallback callback) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void lock(String[] path, String comment, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void unlock(String[] path, boolean force) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public Info2[] info2(String pathOrUrl, Revision revision, Revision pegRevision, boolean recurse) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void info2(String pathOrUrl, Revision revision, Revision pegRevision, int depth, String[] changelists, InfoCallback callback) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public String getVersionInfo(String path, String trailUrl, boolean lastChanged) throws ClientException { throw new UnsupportedOperationException(); } - @Override + public void upgrade(String path) throws ClientException { throw new UnsupportedOperationException(); } diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/config/SvnBindException.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java similarity index 68% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/config/SvnBindException.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java index 8957843e911c..524b928eae92 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/config/SvnBindException.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn.config; +package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.vcs.VcsException; -import java.util.Collection; - /** * Created with IntelliJ IDEA. * User: Irina.Chernushina @@ -32,23 +30,7 @@ public class SvnBindException extends VcsException { super(message); } - public SvnBindException(Throwable throwable, boolean isWarning) { - super(throwable, isWarning); - } - public SvnBindException(Throwable throwable) { super(throwable); } - - public SvnBindException(String message, Throwable cause) { - super(message, cause); - } - - public SvnBindException(String message, boolean isWarning) { - super(message, isWarning); - } - - public SvnBindException(Collection messages) { - super(messages); - } } diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindUtil.java similarity index 98% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindUtil.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindUtil.java index 1fec6b3bf865..d10be8fd9611 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn; +package org.jetbrains.idea.svn.commandLine; import java.io.File; import java.text.DateFormat; diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java similarity index 100% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java index 586aae567d5d..8e0ca2b14a87 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java @@ -22,7 +22,6 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.Consumer; import org.jetbrains.idea.svn.SvnApplicationSettings; -import org.jetbrains.idea.svn.SvnBindUtil; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.portable.SvnExceptionWrapper; import org.jetbrains.idea.svn.portable.SvnkitSvnWcClient; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java index 19e51e95da24..52e597910f23 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java @@ -23,7 +23,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.containers.Convertor; import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.svn.SvnBindUtil; import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.portable.PortableStatus; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java index 3c4fe3684e1b..c1ba46959532 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java @@ -24,7 +24,6 @@ import com.intellij.util.ArrayUtil; import org.jetbrains.idea.svn.SvnApplicationSettings; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; -import org.jetbrains.idea.svn.config.SvnBindException; import org.jetbrains.idea.svn.portable.SvnSvnkitUpdateClient; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.*; diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java similarity index 100% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommitRunner.java similarity index 87% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommitRunner.java index 2ca314b02da7..83f6ec156cf1 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommitRunner.java @@ -13,23 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn; +package org.jetbrains.idea.svn.commandLine; import com.intellij.execution.process.ProcessOutputTypes; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsException; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.Convertor; import org.apache.subversion.javahl.types.Revision; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.commandLine.LineCommandListener; -import org.jetbrains.idea.svn.commandLine.SvnCommandName; -import org.jetbrains.idea.svn.commandLine.SvnLineCommand; -import org.jetbrains.idea.svn.config.SvnBindException; -import org.tigris.subversion.javahl.BindClientException; -import org.tigris.subversion.javahl.ClientException; import org.tmatesoft.svn.core.SVNURL; import java.io.File; @@ -44,7 +39,7 @@ import java.util.*; public class SvnCommitRunner { private final String myExePath; @Nullable private final AuthenticationCallback myAuthenticationCallback; - private static final Logger LOG = Logger.getInstance("org.jetbrains.idea.svn.SvnCommitRunner"); + private static final Logger LOG = Logger.getInstance("org.jetbrains.idea.svn.commandLine.SvnCommitRunner"); private SvnCommitRunner.CommandListener myCommandListener; public SvnCommitRunner(@NotNull String path, @Nullable CommitEventHandler handler, @Nullable AuthenticationCallback authenticationCallback) { @@ -59,7 +54,7 @@ public class SvnCommitRunner { boolean noUnlock, boolean keepChangelist, String[] changelists, - Map revpropTable, Convertor urlProvider) throws ClientException { + Map revpropTable, Convertor urlProvider) throws VcsException { if (paths.length == 0) return Revision.SVN_INVALID_REVNUM; final List parameters = new ArrayList(); @@ -86,13 +81,8 @@ public class SvnCommitRunner { Arrays.sort(paths); parameters.addAll(Arrays.asList(paths)); - try { - SvnLineCommand.runWithAuthenticationAttempt(myExePath, new File(paths[0]), urlProvider.convert(paths), SvnCommandName.ci, - myCommandListener, myAuthenticationCallback, ArrayUtil.toStringArray(parameters)); - } - catch (SvnBindException e) { - throw BindClientException.create(e, Revision.SVN_INVALID_REVNUM); - } + SvnLineCommand.runWithAuthenticationAttempt(myExePath, new File(paths[0]), urlProvider.convert(paths), SvnCommandName.ci, + myCommandListener, myAuthenticationCallback, ArrayUtil.toStringArray(parameters)); myCommandListener.throwExceptionIfOccurred(); return myCommandListener.getCommittedRevision(); @@ -108,9 +98,9 @@ public class SvnCommitRunner { myHandler = handler; } - public void throwExceptionIfOccurred() throws BindClientException { + public void throwExceptionIfOccurred() throws VcsException { if (myException != null) { - throw BindClientException.create(myException, Revision.SVN_INVALID_REVNUM); + throw myException; } } diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java similarity index 99% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java index b84166a7152c..58bc3eea880f 100644 --- a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java @@ -28,9 +28,6 @@ import com.intellij.util.EventDispatcher; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.AuthenticationCallback; -import org.jetbrains.idea.svn.SvnBindUtil; -import org.jetbrains.idea.svn.config.SvnBindException; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java similarity index 100% rename from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java rename to plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java diff --git a/plugins/svn4idea/svn4idea-tests.iml b/plugins/svn4idea/svn4idea-tests.iml index 9a537c253abf..0b826ed87489 100644 --- a/plugins/svn4idea/svn4idea-tests.iml +++ b/plugins/svn4idea/svn4idea-tests.iml @@ -38,7 +38,6 @@ - diff --git a/plugins/svn4idea/svn4idea.iml b/plugins/svn4idea/svn4idea.iml index 4f0d931cd13f..53dd66166d64 100644 --- a/plugins/svn4idea/svn4idea.iml +++ b/plugins/svn4idea/svn4idea.iml @@ -76,16 +76,6 @@ - - - - - - - - - - From 040f405654a3f794affee4222906d9af26f3ae86 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 21 Aug 2013 15:10:15 +0400 Subject: [PATCH 21/30] IDEA-94942 SvnBindClient - unsupported methods removed --- .../idea/svn/commandLine/SvnBindClient.java | 860 ------------------ 1 file changed, 860 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindClient.java index b0d9689c6c0f..8f14cb269179 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindClient.java @@ -17,10 +17,8 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.containers.Convertor; -import org.tigris.subversion.javahl.*; import org.tmatesoft.svn.core.SVNURL; -import java.io.OutputStream; import java.util.Map; /** @@ -40,273 +38,6 @@ public class SvnBindClient { myUrlProvider = urlProvider; } - - public void dispose() { - } - - - public Version getVersion() { - // todo real version - throw new UnsupportedOperationException(); - } - - - public String getAdminDirectoryName() { - throw new UnsupportedOperationException(); - } - - - public boolean isAdminDirectory(String name) { - throw new UnsupportedOperationException(); - } - - - public String getLastPath() { - throw new UnsupportedOperationException(); - } - - - public Status singleStatus(String path, boolean onServer) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public Status[] status(String path, boolean descend, boolean onServer, boolean getAll) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public Status[] status(String path, boolean descend, boolean onServer, boolean getAll, boolean noIgnore) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public Status[] status(String path, boolean descend, boolean onServer, boolean getAll, boolean noIgnore, boolean ignoreExternals) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void status(String path, - int depth, - boolean onServer, - boolean getAll, - boolean noIgnore, - boolean ignoreExternals, - String[] changelists, - StatusCallback callback) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public DirEntry[] list(String url, Revision revision, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public DirEntry[] list(String url, Revision revision, Revision pegRevision, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void list(String url, - Revision revision, - Revision pegRevision, - int depth, - int direntFields, - boolean fetchLocks, - ListCallback callback) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void username(String username) { - throw new UnsupportedOperationException(); - } - - - public void password(String password) { - throw new UnsupportedOperationException(); - } - - - public void setPrompt(PromptUserPassword prompt) { - throw new UnsupportedOperationException(); - } - - - public LogMessage[] logMessages(String path, Revision revisionStart, Revision revisionEnd) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public LogMessage[] logMessages(String path, Revision revisionStart, Revision revisionEnd, boolean stopOnCopy) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public LogMessage[] logMessages(String path, Revision revisionStart, Revision revisionEnd, boolean stopOnCopy, boolean discoverPath) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public LogMessage[] logMessages(String path, - Revision revisionStart, - Revision revisionEnd, - boolean stopOnCopy, - boolean discoverPath, - long limit) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void logMessages(String path, - Revision pegRevision, - Revision revisionStart, - Revision revisionEnd, - boolean stopOnCopy, - boolean discoverPath, - boolean includeMergedRevisions, - String[] revProps, - long limit, - LogMessageCallback callback) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void logMessages(String path, - Revision pegRevision, - RevisionRange[] ranges, - boolean stopOnCopy, - boolean discoverPath, - boolean includeMergedRevisions, - String[] revProps, - long limit, - LogMessageCallback callback) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long checkout(String moduleName, String destPath, Revision revision, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long checkout(String moduleName, - String destPath, - Revision revision, - Revision pegRevision, - boolean recurse, - boolean ignoreExternals) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long checkout(String moduleName, - String destPath, - Revision revision, - Revision pegRevision, - int depth, - boolean ignoreExternals, - boolean allowUnverObstructions) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void notification(Notify notify) { - throw new UnsupportedOperationException(); - } - - - public void notification2(Notify2 notify) { - throw new UnsupportedOperationException(); - } - - - public void setConflictResolver(ConflictResolverCallback listener) { - throw new UnsupportedOperationException(); - } - - - public void setProgressListener(ProgressListener listener) { - throw new UnsupportedOperationException(); - } - - - public void commitMessageHandler(CommitMessage messageHandler) { - throw new UnsupportedOperationException(); - } - - - public void remove(String[] path, String message, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void remove(String[] path, String message, boolean force, boolean keepLocal, Map revpropTable) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void revert(String path, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void revert(String path, int depth, String[] changelists) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void add(String path, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void add(String path, boolean recurse, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void add(String path, int depth, boolean force, boolean noIgnores, boolean addParents) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long update(String path, Revision revision, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long[] update(String[] path, Revision revision, boolean recurse, boolean ignoreExternals) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long update(String path, - Revision revision, - int depth, - boolean depthIsSticky, - boolean ignoreExternals, - boolean allowUnverObstructions) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long[] update(String[] path, - Revision revision, - int depth, - boolean depthIsSticky, - boolean ignoreExternals, - boolean allowUnverObstructions) throws ClientException { - throw new UnsupportedOperationException(); - } - - public long commit(String[] path, String message, boolean recurse) throws VcsException { - return commit(path, message, recurse? 3 : 0, false, false, null, null); - } - public long commit(String[] path, String message, boolean recurse, boolean noUnlock) throws VcsException { return commit(path, message, recurse? 3 : 0, noUnlock, false, null, null); } @@ -326,597 +57,6 @@ public class SvnBindClient { return commit; } - - public void copy(CopySource[] sources, - String destPath, - String message, - boolean copyAsChild, - boolean makeParents, - boolean ignoreExternals, - Map revpropTable) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void copy(CopySource[] sources, String destPath, String message, boolean copyAsChild, boolean makeParents, Map revpropTable) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void copy(String srcPath, String destPath, String message, Revision revision) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void move(String[] srcPaths, - String destPath, - String message, - boolean force, - boolean moveAsChild, - boolean makeParents, - Map revpropTable) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void move(String srcPath, String destPath, String message, Revision ignored, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void move(String srcPath, String destPath, String message, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void mkdir(String[] path, String message, boolean makeParents, Map revpropTable) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void mkdir(String[] path, String message) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void cleanup(String path) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void resolve(String path, int depth, int conflictResult) throws SubversionException { - throw new UnsupportedOperationException(); - } - - - public void resolved(String path, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long doExport(String srcPath, String destPath, Revision revision, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long doExport(String srcPath, - String destPath, - Revision revision, - Revision pegRevision, - boolean force, - boolean ignoreExternals, - boolean recurse, - String nativeEOL) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long doExport(String srcPath, - String destPath, - Revision revision, - Revision pegRevision, - boolean force, - boolean ignoreExternals, - int depth, - String nativeEOL) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long doSwitch(String path, String url, Revision revision, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public long doSwitch(String path, - String url, - Revision revision, - Revision pegRevision, - int depth, - boolean depthIsSticky, - boolean ignoreExternals, - boolean allowUnverObstructions) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void doImport(String path, String url, String message, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void doImport(String path, - String url, - String message, - int depth, - boolean noIgnore, - boolean ignoreUnknownNodeTypes, - Map revpropTable) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public String[] suggestMergeSources(String path, Revision pegRevision) throws SubversionException { - throw new UnsupportedOperationException(); - } - - - public void merge(String path1, Revision revision1, String path2, Revision revision2, String localPath, boolean force, boolean recurse) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void merge(String path1, - Revision revision1, - String path2, - Revision revision2, - String localPath, - boolean force, - boolean recurse, - boolean ignoreAncestry, - boolean dryRun) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void merge(String path1, - Revision revision1, - String path2, - Revision revision2, - String localPath, - boolean force, - int depth, - boolean ignoreAncestry, - boolean dryRun, - boolean recordOnly) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void merge(String path, - Revision pegRevision, - Revision revision1, - Revision revision2, - String localPath, - boolean force, - boolean recurse, - boolean ignoreAncestry, - boolean dryRun) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void merge(String path, - Revision pegRevision, - RevisionRange[] revisions, - String localPath, - boolean force, - int depth, - boolean ignoreAncestry, - boolean dryRun, - boolean recordOnly) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void mergeReintegrate(String path, Revision pegRevision, String localPath, boolean dryRun) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public Mergeinfo getMergeinfo(String path, Revision pegRevision) throws SubversionException { - throw new UnsupportedOperationException(); - } - - - public void getMergeinfoLog(int kind, - String pathOrUrl, - Revision pegRevision, - String mergeSourceUrl, - Revision srcPegRevision, - boolean discoverChangedPaths, - int depth, - String[] revProps, - LogMessageCallback callback) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void getMergeinfoLog(int kind, - String pathOrUrl, - Revision pegRevision, - String mergeSourceUrl, - Revision srcPegRevision, - boolean discoverChangedPaths, - String[] revProps, - LogMessageCallback callback) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void diff(String target1, Revision revision1, String target2, Revision revision2, String outFileName, boolean recurse) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void diff(String target1, - Revision revision1, - String target2, - Revision revision2, - String outFileName, - boolean recurse, - boolean ignoreAncestry, - boolean noDiffDeleted, - boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void diff(String target1, - Revision revision1, - String target2, - Revision revision2, - String relativeToDir, - String outFileName, - int depth, - String[] changelists, - boolean ignoreAncestry, - boolean noDiffDeleted, - boolean force, - boolean copiesAsAdds) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void diff(String target1, - Revision revision1, - String target2, - Revision revision2, - String relativeToDir, - String outFileName, - int depth, - String[] changelists, - boolean ignoreAncestry, - boolean noDiffDeleted, - boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void diff(String target, - Revision pegRevision, - Revision startRevision, - Revision endRevision, - String outFileName, - boolean recurse, - boolean ignoreAncestry, - boolean noDiffDeleted, - boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void diff(String target, - Revision pegRevision, - Revision startRevision, - Revision endRevision, - String relativeToDir, - String outFileName, - int depth, - String[] changelists, - boolean ignoreAncestry, - boolean noDiffDeleted, - boolean force, - boolean copiesAsAdds) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void diff(String target, - Revision pegRevision, - Revision startRevision, - Revision endRevision, - String relativeToDir, - String outFileName, - int depth, - String[] changelists, - boolean ignoreAncestry, - boolean noDiffDeleted, - boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void diffSummarize(String target1, - Revision revision1, - String target2, - Revision revision2, - int depth, - String[] changelists, - boolean ignoreAncestry, - DiffSummaryReceiver receiver) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void diffSummarize(String target, - Revision pegRevision, - Revision startRevision, - Revision endRevision, - int depth, - String[] changelists, - boolean ignoreAncestry, - DiffSummaryReceiver receiver) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public PropertyData[] properties(String path) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public PropertyData[] properties(String path, Revision revision) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public PropertyData[] properties(String path, Revision revision, Revision pegRevision) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void properties(String path, Revision revision, Revision pegRevision, int depth, String[] changelists, ProplistCallback callback) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertySet(String path, String name, String value, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertySet(String path, String name, String value, boolean recurse, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertySet(String path, String name, byte[] value, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertySet(String path, String name, byte[] value, boolean recurse, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertySet(String path, String name, String value, int depth, String[] changelists, boolean force, Map revpropTable) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertyRemove(String path, String name, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertyRemove(String path, String name, int depth, String[] changelists) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertyCreate(String path, String name, String value, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertyCreate(String path, String name, String value, boolean recurse, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertyCreate(String path, String name, byte[] value, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertyCreate(String path, String name, byte[] value, boolean recurse, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void propertyCreate(String path, String name, String value, int depth, String[] changelists, boolean force) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public PropertyData revProperty(String path, String name, Revision rev) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public PropertyData[] revProperties(String path, Revision rev) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void setRevProperty(String path, String name, Revision rev, String value, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void setRevProperty(String path, String name, Revision rev, String value, String originalValue, boolean force) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public PropertyData propertyGet(String path, String name) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public PropertyData propertyGet(String path, String name, Revision revision) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public PropertyData propertyGet(String path, String name, Revision revision, Revision pegRevision) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public byte[] fileContent(String path, Revision revision) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public byte[] fileContent(String path, Revision revision, Revision pegRevision) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void streamFileContent(String path, Revision revision, Revision pegRevision, int bufferSize, OutputStream stream) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void relocate(String from, String to, String path, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public byte[] blame(String path, Revision revisionStart, Revision revisionEnd) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void blame(String path, Revision revisionStart, Revision revisionEnd, BlameCallback callback) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void blame(String path, Revision pegRevision, Revision revisionStart, Revision revisionEnd, BlameCallback callback) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void blame(String path, - Revision pegRevision, - Revision revisionStart, - Revision revisionEnd, - boolean ignoreMimeType, - boolean includeMergedRevisions, - BlameCallback2 callback) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void blame(String path, - Revision pegRevision, - Revision revisionStart, - Revision revisionEnd, - boolean ignoreMimeType, - boolean includeMergedRevisions, - BlameCallback3 callback) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void setConfigDirectory(String configDir) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public String getConfigDirectory() throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void cancelOperation() throws ClientException { - throw new UnsupportedOperationException(); - } - - - public Info info(String path) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void addToChangelist(String[] paths, String changelist, int depth, String[] changelists) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void removeFromChangelists(String[] paths, int depth, String[] changelists) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void getChangelists(String rootPath, String[] changelists, int depth, ChangelistCallback callback) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void lock(String[] path, String comment, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void unlock(String[] path, boolean force) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public Info2[] info2(String pathOrUrl, Revision revision, Revision pegRevision, boolean recurse) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void info2(String pathOrUrl, Revision revision, Revision pegRevision, int depth, String[] changelists, InfoCallback callback) - throws ClientException { - throw new UnsupportedOperationException(); - } - - - public String getVersionInfo(String path, String trailUrl, boolean lastChanged) throws ClientException { - throw new UnsupportedOperationException(); - } - - - public void upgrade(String path) throws ClientException { - throw new UnsupportedOperationException(); - } - public void setHandler(CommitEventHandler handler) { myHandler = handler; } From 8091bb0d38b85b2ab9bf80d74071360c32b84eb3 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 22 Aug 2013 12:07:22 +0400 Subject: [PATCH 22/30] IDEA-94942 Implemented file conflicts resolving Updated "svn info" result parsing --- .../idea/svn/actions/MarkResolvedAction.java | 22 +++--- .../idea/svn/actions/SvnMergeProvider.java | 71 ++++++++++--------- .../jetbrains/idea/svn/api/ClientFactory.java | 8 +++ .../idea/svn/api/CmdClientFactory.java | 2 + .../idea/svn/api/SvnKitClientFactory.java | 2 + .../commandLine/SvnCommandLineInfoClient.java | 9 ++- .../idea/svn/commandLine/SvnCommandName.java | 3 +- .../idea/svn/commandLine/SvnInfoHandler.java | 43 ++++++++--- .../idea/svn/conflict/CmdConflictClient.java | 33 +++++++++ .../idea/svn/conflict/ConflictClient.java | 15 ++++ .../svn/conflict/SvnKitConflictClient.java | 25 +++++++ 11 files changed, 178 insertions(+), 55 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/CmdConflictClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/ConflictClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/SvnKitConflictClient.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/MarkResolvedAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/MarkResolvedAction.java index 87b36970228b..d65c6d3c9c20 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/MarkResolvedAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/MarkResolvedAction.java @@ -19,6 +19,7 @@ package org.jetbrains.idea.svn.actions; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vcs.AbstractVcs; @@ -32,8 +33,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnStatusUtil; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.conflict.ConflictClient; import org.jetbrains.idea.svn.dialogs.SelectFilesDialog; -import org.tmatesoft.svn.core.SVNDepth; +import org.jetbrains.idea.svn.portable.SvnStatusClientI; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.*; @@ -42,6 +44,8 @@ import java.util.Collection; import java.util.TreeSet; public class MarkResolvedAction extends BasicAction { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.actions.MarkResolvedAction"); + protected String getActionName(AbstractVcs vcs) { return SvnBundle.message("action.name.mark.resolved"); } @@ -88,15 +92,13 @@ public class MarkResolvedAction extends BasicAction { } pathsArray = dialog.getSelectedPaths(); try { - SVNWCClient wcClient = vcs.createWCClient(); for (String path : pathsArray) { File ioFile = new File(path); - wcClient.doResolve(ioFile, SVNDepth.EMPTY, SVNConflictChoice.MERGED); + ConflictClient client = vcs.getFactory(ioFile).createConflictClient(); + + client.resolve(ioFile, true); } } - catch (SVNException e) { - throw new VcsException(e); - } finally { for (VirtualFile file : files) { VcsDirtyScopeManager.getInstance(project).fileDirty(file); @@ -115,10 +117,12 @@ public class MarkResolvedAction extends BasicAction { private static Collection collectResolvablePaths(final SvnVcs vcs, VirtualFile[] files) { final Collection target = new TreeSet(); - SVNStatusClient stClient = vcs.createStatusClient(); for (VirtualFile file : files) { try { - stClient.doStatus(new File(file.getPath()), true, false, false, false, new ISVNStatusHandler() { + File path = new File(file.getPath()); + SvnStatusClientI client = vcs.getFactory(path).createStatusClient(); + + client.doStatus(path, true, false, false, false, new ISVNStatusHandler() { public void handleStatus(SVNStatus status) { if (status.getContentsStatus() == SVNStatusType.STATUS_CONFLICTED || status.getPropertiesStatus() == SVNStatusType.STATUS_CONFLICTED) { @@ -128,7 +132,7 @@ public class MarkResolvedAction extends BasicAction { }); } catch (SVNException e) { - // + LOG.warn(e); } } return target; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java index 4c582d01557d..406a5bd0fc0c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java @@ -27,8 +27,8 @@ import com.intellij.vcsUtil.VcsRunnable; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnRevisionNumber; +import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; -import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.SVNPropertyValue; @@ -57,38 +57,34 @@ public class SvnMergeProvider implements MergeProvider { final MergeData data = new MergeData(); VcsRunnable runnable = new VcsRunnable() { public void run() throws VcsException { - SvnVcs vcs = SvnVcs.getInstance(myProject); File oldFile = null; File newFile = null; File workingFile = null; - SVNWCClient client; boolean mergeCase = false; - try { - client = vcs.createWCClient(); - SVNInfo info = client.doInfo(new File(file.getPath()), SVNRevision.UNDEFINED); - if (info != null) { - oldFile = info.getConflictOldFile(); - newFile = info.getConflictNewFile(); - workingFile = info.getConflictWrkFile(); - mergeCase = workingFile == null || workingFile.getName().contains("working"); - // for debug - if (workingFile == null) { - LOG.info("Null working file when merging text conflict for " + file.getPath() + " old file: " + oldFile + " new file: " + newFile); - } - if (mergeCase) { - // this is merge case - oldFile = info.getConflictNewFile(); - newFile = info.getConflictOldFile(); - workingFile = info.getConflictWrkFile(); - } - data.LAST_REVISION_NUMBER = new SvnRevisionNumber(info.getRevision()); + SvnVcs vcs = SvnVcs.getInstance(myProject); + SVNInfo info = vcs.getInfo(file); + + if (info != null) { + oldFile = info.getConflictOldFile(); + newFile = info.getConflictNewFile(); + workingFile = info.getConflictWrkFile(); + mergeCase = workingFile == null || workingFile.getName().contains("working"); + // for debug + if (workingFile == null) { + LOG.info("Null working file when merging text conflict for " + file.getPath() + " old file: " + oldFile + " new file: " + newFile); } - } - catch (SVNException e) { - throw new VcsException(e); + if (mergeCase) { + // this is merge case + oldFile = info.getConflictNewFile(); + newFile = info.getConflictOldFile(); + workingFile = info.getConflictWrkFile(); + } + data.LAST_REVISION_NUMBER = new SvnRevisionNumber(info.getRevision()); + } else { + throw new VcsException("Could not get info for " + file.getPath()); } if (oldFile == null || newFile == null || workingFile == null) { - ByteArrayOutputStream bos = getBaseRevisionContents(client, file); + ByteArrayOutputStream bos = getBaseRevisionContents(vcs, file); data.ORIGINAL = bos.toByteArray(); data.LAST = bos.toByteArray(); data.CURRENT = readFile(new File(file.getPath())); @@ -99,7 +95,7 @@ public class SvnMergeProvider implements MergeProvider { data.CURRENT = readFile(workingFile); } if (mergeCase) { - final ByteArrayOutputStream contents = getBaseRevisionContents(vcs.createWCClient(), file); + final ByteArrayOutputStream contents = getBaseRevisionContents(vcs, file); if (! Arrays.equals(contents.toByteArray(), data.ORIGINAL)) { // swap base and server: another order of merge arguments byte[] original = data.ORIGINAL; @@ -114,13 +110,17 @@ public class SvnMergeProvider implements MergeProvider { return data; } - private ByteArrayOutputStream getBaseRevisionContents(SVNWCClient client, VirtualFile file) { + private ByteArrayOutputStream getBaseRevisionContents(SvnVcs vcs, VirtualFile file) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { - client.doGetFileContents(new File(file.getPath()), SVNRevision.UNDEFINED, SVNRevision.BASE, true, bos); + byte[] contents = SvnUtil.getFileContents(vcs, file.getPath(), false, SVNRevision.BASE, SVNRevision.UNDEFINED); + bos.write(contents); } - catch (SVNException e) { - // + catch (VcsException e) { + LOG.warn(e); + } + catch (IOException e) { + LOG.warn(e); } return bos; } @@ -135,13 +135,14 @@ public class SvnMergeProvider implements MergeProvider { } public void conflictResolvedForFile(VirtualFile file) { + // TODO: Add possibility to resolve content conflicts separately from property conflicts. SvnVcs vcs = SvnVcs.getInstance(myProject); + File path = new File(file.getPath()); try { - SVNWCClient client = vcs.createWCClient(); - client.doResolve(new File(file.getPath()), SVNDepth.EMPTY, true, false, SVNConflictChoice.MERGED); + vcs.getFactory(path).createConflictClient().resolve(path, false); } - catch (SVNException e) { - // + catch (VcsException e) { + LOG.warn(e); } // the .mine/.r## files have been deleted final VirtualFile parent = file.getParent(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java index f68b05fa3bd2..513e30a22a26 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.AddClient; +import org.jetbrains.idea.svn.conflict.ConflictClient; import org.jetbrains.idea.svn.copy.CopyMoveClient; import org.jetbrains.idea.svn.delete.DeleteClient; import org.jetbrains.idea.svn.history.HistoryClient; @@ -23,6 +24,7 @@ public abstract class ClientFactory { protected DeleteClient deleteClient; protected SvnStatusClientI statusClient; protected CopyMoveClient copyMoveClient; + protected ConflictClient conflictClient; protected ClientFactory(@NotNull SvnVcs vcs) { myVcs = vcs; @@ -57,10 +59,16 @@ public abstract class ClientFactory { return prepare(deleteClient); } + @NotNull public CopyMoveClient createCopyMoveClient() { return prepare(copyMoveClient); } + @NotNull + public ConflictClient createConflictClient() { + return prepare(conflictClient); + } + @NotNull protected T prepare(@NotNull T client) { client.setVcs(myVcs); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java index c6d4a8793ee2..f78750e9e4bf 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.CmdAddClient; import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient; +import org.jetbrains.idea.svn.conflict.CmdConflictClient; import org.jetbrains.idea.svn.copy.CmdCopyMoveClient; import org.jetbrains.idea.svn.delete.CmdDeleteClient; import org.jetbrains.idea.svn.history.CmdHistoryClient; @@ -25,6 +26,7 @@ public class CmdClientFactory extends ClientFactory { revertClient = new CmdRevertClient(); deleteClient = new CmdDeleteClient(); copyMoveClient = new CmdCopyMoveClient(); + conflictClient = new CmdConflictClient(); statusClient = new SvnCommandLineStatusClient(myVcs.getProject()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java index 16a60ce2c562..c165773795e2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.SvnKitAddClient; +import org.jetbrains.idea.svn.conflict.SvnKitConflictClient; import org.jetbrains.idea.svn.copy.SvnKitCopyMoveClient; import org.jetbrains.idea.svn.delete.SvnKitDeleteClient; import org.jetbrains.idea.svn.history.SvnKitHistoryClient; @@ -25,6 +26,7 @@ public class SvnKitClientFactory extends ClientFactory { revertClient = new SvnKitRevertClient(); deleteClient = new SvnKitDeleteClient(); copyMoveClient = new SvnKitCopyMoveClient(); + conflictClient = new SvnKitConflictClient(); statusClient = new SvnkitSvnStatusClient(myVcs.createStatusClient()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java index 8e0ca2b14a87..4ef2e9283a7d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java @@ -114,7 +114,14 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { // not a working copy exception // "E155007: '' is not a working copy" if (notEmpty && text.contains("is not a working copy")) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_WORKING_COPY), e); + if (StringUtil.isNotEmpty(command.getOutput())) { + // workaround: as in subversion 1.8 "svn info" on a working copy root outputs such error for parent folder, + // if there are files with conflicts. + // but the requested info is still in the output except root closing tag + return command.getOutput() + ""; + } else { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_WORKING_COPY), e); + } } throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index d78ca2643d3f..721226b326fa 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -36,7 +36,8 @@ public enum SvnCommandName { revert("revert", true), delete("delete", true), copy("copy", true), - move("move", true); + move("move", true), + resolve("resolve", true); private final String myName; private final boolean myWriteable; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java index 99fc499c35c7..d8dbb6c19f67 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNNodeKind; @@ -97,16 +98,13 @@ public class SvnInfoHandler extends DefaultHandler { public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { assertSAX(! myParseStack.isEmpty()); ElementHandlerBase current = myParseStack.get(myParseStack.size() - 1); - if (mySb.length() > 0) { - current.characters(mySb.toString().trim(), myPending); - mySb.setLength(0); - } while (true) { final boolean createNewChild = current.startElement(uri, localName, qName, attributes); if (createNewChild) { assertSAX(myElementsMap.containsKey(qName)); final ElementHandlerBase newChild = myElementsMap.get(qName).get(); + newChild.setParent(current); newChild.updateInfo(attributes, myPending); myParseStack.add(newChild); return; @@ -122,6 +120,18 @@ public class SvnInfoHandler extends DefaultHandler { } } + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + ElementHandlerBase current = myParseStack.get(myParseStack.size() - 1); + String value = mySb.toString().trim(); + + if (!StringUtil.isEmpty(value)) { + current.characters(value, myPending); + } + + mySb.setLength(0); + } + @Override public void characters(char[] ch, int start, int length) throws SAXException { assertSAX(! myParseStack.isEmpty()); @@ -332,6 +342,12 @@ public class SvnInfoHandler extends DefaultHandler { @Override protected void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException { + // TODO: Currently information for conflict (not tree-conflict) available in svn 1.8 is not used + // TODO: And it also not suite well for SVNKit api + if (getParent() instanceof Conflict) { + return; + } + final String side = attributes.getValue("side"); if ("source-left".equals(side)) { final SvnInfoStructure.ConflictVersion conflictVersion = new SvnInfoStructure.ConflictVersion(); @@ -419,7 +435,7 @@ public class SvnInfoHandler extends DefaultHandler { @Override public void characters(String s, SvnInfoStructure structure) throws SAXException { - structure.myConflictWorking = s; + structure.myConflictNew = new File(s).getName(); } } @@ -434,7 +450,7 @@ public class SvnInfoHandler extends DefaultHandler { @Override public void characters(String s, SvnInfoStructure structure) throws SAXException { - structure.myConflictNew = s; + structure.myConflictWorking = new File(s).getName(); } } @@ -449,14 +465,13 @@ public class SvnInfoHandler extends DefaultHandler { @Override public void characters(String s, SvnInfoStructure structure) throws SAXException { - // todo path? or plus base - structure.myConflictOld = s; + structure.myConflictOld = new File(s).getName(); } } private static class Conflict extends ElementHandlerBase { private Conflict() { - super(new String[]{"prev-base-file","prev-wc-file","cur-base-file","prop-file"}, new String[]{}); + super(new String[]{"prev-base-file","prev-wc-file","cur-base-file","prop-file"}, new String[]{"version"}); } @Override @@ -842,12 +857,22 @@ public class SvnInfoHandler extends DefaultHandler { private abstract static class ElementHandlerBase { private final Set myAwaitedChildren; private final Set myAwaitedChildrenMultiple; + private ElementHandlerBase parent; ElementHandlerBase(String[] awaitedChildren, String[] awaitedChildrenMultiple) { myAwaitedChildren = new HashSet(Arrays.asList(awaitedChildren)); myAwaitedChildrenMultiple = new HashSet(Arrays.asList(awaitedChildrenMultiple)); } + @NotNull + public ElementHandlerBase getParent() { + return parent; + } + + public void setParent(@NotNull ElementHandlerBase parent) { + this.parent = parent; + } + protected abstract void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException; public boolean startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/CmdConflictClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/CmdConflictClient.java new file mode 100644 index 000000000000..79614a24f554 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/CmdConflictClient.java @@ -0,0 +1,33 @@ +package org.jetbrains.idea.svn.conflict; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.commandLine.CommandUtil; +import org.jetbrains.idea.svn.commandLine.SvnCommandName; +import org.tmatesoft.svn.core.SVNDepth; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public class CmdConflictClient extends BaseSvnClient implements ConflictClient { + + // TODO: Add possibility to resolve content conflicts separately from property conflicts. + @Override + public void resolve(@NotNull File path, boolean resolvePropertyConflicts) throws VcsException { + List parameters = new ArrayList(); + + CommandUtil.put(parameters, path); + CommandUtil.put(parameters, SVNDepth.EMPTY); + parameters.add("--accept"); + parameters.add("working"); + + // for now parsing of the output is not required as command is executed only for one file + // and will be either successful or exception will be thrown + CommandUtil.execute(myVcs, SvnCommandName.resolve, parameters, null); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/ConflictClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/ConflictClient.java new file mode 100644 index 000000000000..812fdef5621b --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/ConflictClient.java @@ -0,0 +1,15 @@ +package org.jetbrains.idea.svn.conflict; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.SvnClient; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public interface ConflictClient extends SvnClient { + + void resolve(@NotNull File path, boolean resolvePropertyConflicts) throws VcsException; +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/SvnKitConflictClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/SvnKitConflictClient.java new file mode 100644 index 000000000000..33ee0f870c95 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/SvnKitConflictClient.java @@ -0,0 +1,25 @@ +package org.jetbrains.idea.svn.conflict; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.SVNConflictChoice; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitConflictClient extends BaseSvnClient implements ConflictClient { + @Override + public void resolve(@NotNull File path, boolean resolvePropertyConflicts) throws VcsException { + try { + myVcs.createWCClient().doResolve(path, SVNDepth.EMPTY, true, resolvePropertyConflicts, SVNConflictChoice.MERGED); + } + catch (SVNException e) { + throw new VcsException(e); + } + } +} From 0e41cad8cb13b286f853a18f8b9fbef54e74ddc3 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 22 Aug 2013 12:58:16 +0400 Subject: [PATCH 23/30] IDEA-94942 Simple property client to fix SvnMergeProvider.isBinary implementation --- .../idea/svn/actions/SvnMergeProvider.java | 13 +++--- .../jetbrains/idea/svn/api/ClientFactory.java | 7 +++ .../idea/svn/api/CmdClientFactory.java | 2 + .../idea/svn/api/SvnKitClientFactory.java | 2 + .../idea/svn/commandLine/CommandUtil.java | 22 ++++++++-- .../idea/svn/commandLine/SvnCommandName.java | 3 +- .../idea/svn/history/CmdHistoryClient.java | 2 +- .../svn/properties/CmdPropertyClient.java | 43 +++++++++++++++++++ .../idea/svn/properties/PropertyClient.java | 21 +++++++++ .../svn/properties/SvnKitPropertyClient.java | 30 +++++++++++++ .../properties/SvnPropDetailsProvider.java | 25 ----------- 11 files changed, 134 insertions(+), 36 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java delete mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnPropDetailsProvider.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java index 406a5bd0fc0c..b8528917e069 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java @@ -29,7 +29,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnRevisionNumber; import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; -import org.tmatesoft.svn.core.SVNException; +import org.jetbrains.idea.svn.properties.PropertyClient; import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.SVNPropertyValue; import org.tmatesoft.svn.core.wc.*; @@ -153,17 +153,20 @@ public class SvnMergeProvider implements MergeProvider { public boolean isBinary(@NotNull final VirtualFile file) { SvnVcs vcs = SvnVcs.getInstance(myProject); + try { - SVNWCClient client = vcs.createWCClient(); File ioFile = new File(file.getPath()); - SVNPropertyData svnPropertyData = client.doGetProperty(ioFile, SVNProperty.MIME_TYPE, SVNRevision.UNDEFINED, SVNRevision.WORKING); + PropertyClient client = vcs.getFactory(ioFile).createPropertyClient(); + + SVNPropertyData svnPropertyData = client.getProperty(ioFile, SVNProperty.MIME_TYPE, SVNRevision.UNDEFINED, SVNRevision.WORKING); if (svnPropertyData != null && SVNProperty.isBinaryMimeType(SVNPropertyValue.getPropertyAsString(svnPropertyData.getValue()))) { return true; } } - catch (SVNException e) { - // + catch (VcsException e) { + LOG.warn(e); } + return false; } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java index 513e30a22a26..303738de828c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -8,6 +8,7 @@ import org.jetbrains.idea.svn.copy.CopyMoveClient; import org.jetbrains.idea.svn.delete.DeleteClient; import org.jetbrains.idea.svn.history.HistoryClient; import org.jetbrains.idea.svn.portable.SvnStatusClientI; +import org.jetbrains.idea.svn.properties.PropertyClient; import org.jetbrains.idea.svn.revert.RevertClient; /** @@ -25,6 +26,7 @@ public abstract class ClientFactory { protected SvnStatusClientI statusClient; protected CopyMoveClient copyMoveClient; protected ConflictClient conflictClient; + protected PropertyClient propertyClient; protected ClientFactory(@NotNull SvnVcs vcs) { myVcs = vcs; @@ -69,6 +71,11 @@ public abstract class ClientFactory { return prepare(conflictClient); } + @NotNull + public PropertyClient createPropertyClient() { + return prepare(propertyClient); + } + @NotNull protected T prepare(@NotNull T client) { client.setVcs(myVcs); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java index f78750e9e4bf..5ac6f2da1655 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -8,6 +8,7 @@ import org.jetbrains.idea.svn.conflict.CmdConflictClient; import org.jetbrains.idea.svn.copy.CmdCopyMoveClient; import org.jetbrains.idea.svn.delete.CmdDeleteClient; import org.jetbrains.idea.svn.history.CmdHistoryClient; +import org.jetbrains.idea.svn.properties.CmdPropertyClient; import org.jetbrains.idea.svn.revert.CmdRevertClient; /** @@ -27,6 +28,7 @@ public class CmdClientFactory extends ClientFactory { deleteClient = new CmdDeleteClient(); copyMoveClient = new CmdCopyMoveClient(); conflictClient = new CmdConflictClient(); + propertyClient = new CmdPropertyClient(); statusClient = new SvnCommandLineStatusClient(myVcs.getProject()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java index c165773795e2..ac9e4afa3f55 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -8,6 +8,7 @@ import org.jetbrains.idea.svn.copy.SvnKitCopyMoveClient; import org.jetbrains.idea.svn.delete.SvnKitDeleteClient; import org.jetbrains.idea.svn.history.SvnKitHistoryClient; import org.jetbrains.idea.svn.portable.SvnkitSvnStatusClient; +import org.jetbrains.idea.svn.properties.SvnKitPropertyClient; import org.jetbrains.idea.svn.revert.SvnKitRevertClient; /** @@ -27,6 +28,7 @@ public class SvnKitClientFactory extends ClientFactory { deleteClient = new SvnKitDeleteClient(); copyMoveClient = new SvnKitCopyMoveClient(); conflictClient = new SvnKitConflictClient(); + propertyClient = new SvnKitPropertyClient(); statusClient = new SvnkitSvnStatusClient(myVcs.createStatusClient()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index e18f64f2c94b..bb5d5408095f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -11,6 +11,7 @@ import org.jetbrains.idea.svn.api.FileStatusResultParser; import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.SVNInfo; +import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.SVNStatusType; import java.io.File; @@ -71,6 +72,17 @@ public class CommandUtil { parameters.add(path.getAbsolutePath()); } + public static void put(@NotNull List parameters, @NotNull File path, @Nullable SVNRevision pegRevision) { + StringBuilder builder = new StringBuilder(path.getAbsolutePath()); + + if (pegRevision != null && !SVNRevision.UNDEFINED.equals(pegRevision)) { + builder.append("@"); + builder.append(pegRevision); + } + + parameters.add(builder.toString()); + } + public static void put(@NotNull List parameters, @NotNull File... paths) { for (File path : paths) { put(parameters, path); @@ -95,10 +107,10 @@ public class CommandUtil { * @param parser * @throws VcsException */ - public static void execute(@NotNull SvnVcs vcs, - @NotNull SvnCommandName name, - @NotNull List parameters, - @Nullable FileStatusResultParser parser) + public static SvnCommand execute(@NotNull SvnVcs vcs, + @NotNull SvnCommandName name, + @NotNull List parameters, + @Nullable FileStatusResultParser parser) throws VcsException { try { SvnLineCommand command = runSimple(name, vcs, null, null, parameters); @@ -106,6 +118,8 @@ public class CommandUtil { if (parser != null) { parser.parse(command.getOutput()); } + + return command; } catch (SVNException e) { throw new VcsException(e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index 721226b326fa..df2baf7bacde 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -37,7 +37,8 @@ public enum SvnCommandName { delete("delete", true), copy("copy", true), move("move", true), - resolve("resolve", true); + resolve("resolve", true), + propget("propget", false); private final String myName; private final boolean myWriteable; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java index 0b507a63e54f..4e0499cb4177 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java @@ -77,7 +77,7 @@ public class CmdHistoryClient extends BaseSvnClient implements HistoryClient { boolean stopOnCopy, boolean discoverChangedPaths, boolean includeMergedRevisions, long limit) { List parameters = new ArrayList(); - parameters.add(path.getAbsolutePath() + (pegRevision != null ? "@" + pegRevision : "")); + CommandUtil.put(parameters, path, pegRevision); parameters.add("--revision"); parameters.add(startRevision + ":" + endRevision); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java new file mode 100644 index 000000000000..2629ed49c1be --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java @@ -0,0 +1,43 @@ +package org.jetbrains.idea.svn.properties; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.commandLine.CommandUtil; +import org.jetbrains.idea.svn.commandLine.SvnCommand; +import org.jetbrains.idea.svn.commandLine.SvnCommandName; +import org.tmatesoft.svn.core.SVNPropertyValue; +import org.tmatesoft.svn.core.wc.SVNPropertyData; +import org.tmatesoft.svn.core.wc.SVNRevision; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { + + @Override + public SVNPropertyData getProperty(@NotNull File path, + @NotNull String property, + @Nullable SVNRevision pegRevision, + @Nullable SVNRevision revision) + throws VcsException { + List parameters = new ArrayList(); + + parameters.add(property); + CommandUtil.put(parameters, path, pegRevision); + if (revision != null && !SVNRevision.UNDEFINED.equals(revision) && !SVNRevision.WORKING.equals(revision)) { + parameters.add("--revision"); + parameters.add(revision.toString()); + } + + SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.propget, parameters, null); + + return new SVNPropertyData(property, SVNPropertyValue.create(StringUtil.nullize(command.getOutput())), null); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java new file mode 100644 index 000000000000..1d151e24008e --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java @@ -0,0 +1,21 @@ +package org.jetbrains.idea.svn.properties; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.SvnClient; +import org.tmatesoft.svn.core.wc.SVNPropertyData; +import org.tmatesoft.svn.core.wc.SVNRevision; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public interface PropertyClient extends SvnClient { + + SVNPropertyData getProperty(@NotNull final File path, + @NotNull final String property, + @Nullable SVNRevision pegRevision, + @Nullable SVNRevision revision) throws VcsException; +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java new file mode 100644 index 000000000000..1795422a1225 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java @@ -0,0 +1,30 @@ +package org.jetbrains.idea.svn.properties; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.SVNPropertyData; +import org.tmatesoft.svn.core.wc.SVNRevision; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClient { + + @Override + public SVNPropertyData getProperty(@NotNull File path, + @NotNull String property, + @Nullable SVNRevision pegRevision, + @Nullable SVNRevision revision) throws VcsException { + try { + return myVcs.createWCClient().doGetProperty(path, property, pegRevision, revision); + } + catch (SVNException e) { + throw new VcsException(e); + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnPropDetailsProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnPropDetailsProvider.java deleted file mode 100644 index 683024679277..000000000000 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnPropDetailsProvider.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.idea.svn.properties; - -/** - * Created with IntelliJ IDEA. - * User: Irina.Chernushina - * Date: 2/12/12 - * Time: 8:40 PM - */ -public class SvnPropDetailsProvider { -} From 64706df47dbd7b32d3c7e58020901cb033151d60 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 22 Aug 2013 13:06:32 +0400 Subject: [PATCH 24/30] IDEA-112184 --- .../org/jetbrains/idea/svn/commandLine/SvnLineCommand.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java index 58bc3eea880f..8919c9e3547e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java @@ -64,10 +64,11 @@ public class SvnLineCommand extends SvnCommand { public static final String CANNOT_AUTHENTICATE_TO_PROXY = "Could not authenticate to proxy server"; public static final String AUTHENTICATION_FAILED_MESSAGE = "Authentication failed"; - private static final String INVALID_CREDENTIALS_FOR_SVN_PROTOCOL = "svn: E170001: Can't get password"; + private static final String INVALID_CREDENTIALS_FOR_SVN_PROTOCOL = "svn: E170001: Can't get"; private static final String UNTRUSTED_SERVER_CERTIFICATE = "Server SSL certificate untrusted"; private static final String ACCESS_TO_PREFIX = "Access to "; private static final String FORBIDDEN_STATUS = "forbidden"; + private static final String PASSWORD_STRING = "password"; private static final Pattern UNABLE_TO_CONNECT_TO_URL_PATTERN = Pattern.compile("Unable to connect to a repository at URL '(.*)'"); @@ -204,7 +205,8 @@ public class SvnLineCommand extends SvnCommand { if (errText.contains(AUTHENTICATION_FAILED_MESSAGE)) { return new UsernamePasswordCallback(callback, base, url); } - if (errText.contains(INVALID_CREDENTIALS_FOR_SVN_PROTOCOL)) { + // messages could be "Can't get password", "Can't get username or password" + if (errText.contains(INVALID_CREDENTIALS_FOR_SVN_PROTOCOL) && errText.contains(PASSWORD_STRING)) { // svn protocol invalid credentials return new UsernamePasswordCallback(callback, base, url); } From 3c948a876ff2574d180a2adee6c6c61568efbcb3 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 22 Aug 2013 13:09:27 +0400 Subject: [PATCH 25/30] IDEA-94942 Code cleanup - unused parameters removed --- .../idea/svn/update/AbstractUpdateIntegrateCrawler.java | 6 ++---- .../jetbrains/idea/svn/update/SvnIntegrateEnvironment.java | 5 +---- .../org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java | 5 +---- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractUpdateIntegrateCrawler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractUpdateIntegrateCrawler.java index e9e7b0b5f897..826f7532b3a0 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractUpdateIntegrateCrawler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractUpdateIntegrateCrawler.java @@ -59,7 +59,7 @@ public abstract class AbstractUpdateIntegrateCrawler implements SvnWCRootCrawler SVNUpdateClient client = myVcs.createUpdateClient(); client.setEventHandler(myHandler); - long rev = doUpdate(root, client); + long rev = doUpdate(root); if (rev < 0 && !isMerge()) { throw new SVNException(SVNErrorMessage.create(SVNErrorCode.UNKNOWN, SvnBundle.message("exception.text.root.was.not.properly.updated", root))); @@ -73,9 +73,7 @@ public abstract class AbstractUpdateIntegrateCrawler implements SvnWCRootCrawler protected abstract void showProgressMessage(ProgressIndicator progress, File root); - protected abstract long doUpdate( - File root, - SVNUpdateClient client) throws SVNException; + protected abstract long doUpdate(File root) throws SVNException; protected abstract boolean isMerge(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnIntegrateEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnIntegrateEnvironment.java index 9e8a5991f41c..9f4a95f7016f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnIntegrateEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnIntegrateEnvironment.java @@ -91,10 +91,7 @@ public class SvnIntegrateEnvironment extends AbstractSvnUpdateIntegrateEnvironme } } - protected long doUpdate( - final File root, - final SVNUpdateClient client) throws - SVNException { + protected long doUpdate(final File root) throws SVNException { final SvnConfiguration svnConfig = SvnConfiguration.getInstance(myVcs.getProject()); MergeRootInfo info = svnConfig.getMergeRootInfo(root, myVcs); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java index eb2833f7a3ce..5d2d4153be50 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java @@ -75,10 +75,7 @@ public class SvnUpdateEnvironment extends AbstractSvnUpdateIntegrateEnvironment progress.setText(SvnBundle.message("progress.text.updating", root.getAbsolutePath())); } - protected long doUpdate( - final File root, - final SVNUpdateClient client) throws - SVNException { + protected long doUpdate(final File root) throws SVNException { final long rev; final SvnConfiguration configuration = SvnConfiguration.getInstance(myVcs.getProject()); From 6e6972a91223136b48bcf8694bdfb57fefe7dd53 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 23 Aug 2013 14:51:39 +0400 Subject: [PATCH 26/30] IDEA-94942 Annotate action --- .../jetbrains/idea/svn/SvnDiffProvider.java | 36 ++--- .../idea/svn/actions/SvnMergeProvider.java | 2 +- .../idea/svn/annotate/AnnotateClient.java | 24 ++++ .../idea/svn/annotate/CmdAnnotateClient.java | 126 ++++++++++++++++++ .../svn/annotate/SvnAnnotationProvider.java | 110 ++++++++------- .../svn/annotate/SvnKitAnnotateClient.java | 42 ++++++ .../jetbrains/idea/svn/api/ClientFactory.java | 7 + .../idea/svn/api/CmdClientFactory.java | 2 + .../idea/svn/api/SvnKitClientFactory.java | 2 + .../idea/svn/commandLine/CommandUtil.java | 31 ++++- .../idea/svn/commandLine/SvnCommandName.java | 3 +- .../idea/svn/history/CmdHistoryClient.java | 11 +- .../idea/svn/history/SvnKitHistoryClient.java | 10 +- .../svn/properties/CmdPropertyClient.java | 32 ++++- .../idea/svn/properties/PropertyClient.java | 2 + .../svn/properties/SvnKitPropertyClient.java | 40 +++++- 16 files changed, 390 insertions(+), 90 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/AnnotateClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/CmdAnnotateClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnKitAnnotateClient.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java index bd1a6b66468e..813d41c48e24 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java @@ -17,6 +17,7 @@ package org.jetbrains.idea.svn; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.actions.VcsContextFactory; import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.diff.DiffMixin; @@ -29,6 +30,7 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient; import org.jetbrains.idea.svn.history.LatestExistentSearcher; import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNPropertyValue; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.*; @@ -74,43 +76,21 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin { } try { - final String message = getProperties(path); + final String message = getCommitMessage(path); return new VcsRevisionDescriptionImpl(new SvnRevisionNumber(svnInfo.getCommittedRevision()), svnInfo.getCommittedDate(), svnInfo.getAuthor(), message); } - catch (SVNException e) { + catch (VcsException e) { LOG.debug(e); // most likely the file is unversioned return null; } } - private String getProperties(File path) throws SVNException { - final SVNWCClient client = myVcs.createWCClient(); - final String[] message = new String[1]; + private String getCommitMessage(File path) throws VcsException { + SVNPropertyData property = + myVcs.getFactory(path).createPropertyClient().getProperty(path, COMMIT_MESSAGE, true, null, SVNRevision.BASE); - client.doGetRevisionProperty(path, null, SVNRevision.BASE, new ISVNPropertyHandler() { - @Override - public void handleProperty(File path, SVNPropertyData property) throws SVNException { - handle(property); - } - - @Override - public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException { - handle(property); - } - - @Override - public void handleProperty(long revision, SVNPropertyData property) throws SVNException { - handle(property); - } - - private void handle(SVNPropertyData data) { - if (COMMIT_MESSAGE.equals(data.getName())) { - message[0] = data.getValue().getString(); - } - } - }); - return message[0]; + return property != null ? SVNPropertyValue.getPropertyAsString(property.getValue()) : null; } private static ItemLatestState defaultResult() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java index b8528917e069..644bb2142c77 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java @@ -158,7 +158,7 @@ public class SvnMergeProvider implements MergeProvider { File ioFile = new File(file.getPath()); PropertyClient client = vcs.getFactory(ioFile).createPropertyClient(); - SVNPropertyData svnPropertyData = client.getProperty(ioFile, SVNProperty.MIME_TYPE, SVNRevision.UNDEFINED, SVNRevision.WORKING); + SVNPropertyData svnPropertyData = client.getProperty(ioFile, SVNProperty.MIME_TYPE, false, SVNRevision.UNDEFINED, SVNRevision.WORKING); if (svnPropertyData != null && SVNProperty.isBinaryMimeType(SVNPropertyValue.getPropertyAsString(svnPropertyData.getValue()))) { return true; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/AnnotateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/AnnotateClient.java new file mode 100644 index 000000000000..df30cfd89ae2 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/AnnotateClient.java @@ -0,0 +1,24 @@ +package org.jetbrains.idea.svn.annotate; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.SvnClient; +import org.tmatesoft.svn.core.wc.ISVNAnnotateHandler; +import org.tmatesoft.svn.core.wc.SVNDiffOptions; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; + +/** + * @author Konstantin Kolosovsky. + */ +public interface AnnotateClient extends SvnClient { + + void annotate(@NotNull SvnTarget target, + @NotNull SVNRevision startRevision, + @NotNull SVNRevision endRevision, + @Nullable SVNRevision pegRevision, + boolean includeMergedRevisions, + @Nullable SVNDiffOptions diffOptions, + @Nullable ISVNAnnotateHandler handler) throws VcsException; +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/CmdAnnotateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/CmdAnnotateClient.java new file mode 100644 index 000000000000..d29d40eca84a --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/CmdAnnotateClient.java @@ -0,0 +1,126 @@ +package org.jetbrains.idea.svn.annotate; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.commandLine.CommandUtil; +import org.jetbrains.idea.svn.commandLine.SvnCommand; +import org.jetbrains.idea.svn.commandLine.SvnCommandName; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.ISVNAnnotateHandler; +import org.tmatesoft.svn.core.wc.SVNDiffOptions; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public class CmdAnnotateClient extends BaseSvnClient implements AnnotateClient { + + @Override + public void annotate(@NotNull SvnTarget target, + @NotNull SVNRevision startRevision, + @NotNull SVNRevision endRevision, + @Nullable SVNRevision pegRevision, + boolean includeMergedRevisions, + @Nullable SVNDiffOptions diffOptions, + @Nullable final ISVNAnnotateHandler handler) throws VcsException { + // TODO: after merge remove setting includeMergedRevisions to false and update parsing + includeMergedRevisions = false; + + List parameters = new ArrayList(); + CommandUtil.put(parameters, target.getPathOrUrlString(), pegRevision); + parameters.add("--revision"); + parameters.add(startRevision + ":" + endRevision); + CommandUtil.put(parameters, includeMergedRevisions, "--use-merge-history"); + CommandUtil.put(parameters, diffOptions); + parameters.add("--xml"); + + SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.blame, parameters, null); + + parseOutput(command.getOutput(), handler); + } + + public void parseOutput(@NotNull String output, @Nullable ISVNAnnotateHandler handler) throws VcsException { + try { + JAXBContext context = JAXBContext.newInstance(BlameInfo.class); + Unmarshaller unmarshaller = context.createUnmarshaller(); + BlameInfo info = (BlameInfo)unmarshaller.unmarshal(new StringReader(output)); + + if (handler != null && info != null && info.target != null && info.target.lineEntries != null) { + for (LineEntry entry : info.target.lineEntries) { + invokeHandler(handler, entry); + } + } + } + catch (JAXBException e) { + throw new VcsException(e); + } + catch (SVNException e) { + throw new VcsException(e); + } + } + + private static void invokeHandler(ISVNAnnotateHandler handler, LineEntry entry) throws SVNException { + // line numbers in our api start from 0 - not from 1 like in svn output + handler.handleLine(entry.date(), entry.revision(), entry.author(), null, null, 0, null, null, entry.lineNumber - 1); + } + + @XmlRootElement(name = "blame") + public static class BlameInfo { + + @XmlElement(name = "target") + public TargetEntry target; + } + + public static class TargetEntry { + + @XmlElement(name = "entry") + List lineEntries; + } + + public static class LineEntry { + + @XmlAttribute(name = "line-number") + public int lineNumber; + + @XmlElement(name = "commit") + public CommitEntry commit; + + public long revision() { + return commit != null ? commit.revision : 0; + } + + public String author() { + return commit != null ? commit.author : null; + } + + public Date date() { + return commit != null ? commit.date : null; + } + } + + public static class CommitEntry { + + @XmlAttribute(name = "revision") + public long revision; + + @XmlElement(name = "author") + public String author; + + @XmlElement(name = "date") + public Date date; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java index 93c55a1331da..a94dbbb2e04b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java @@ -32,14 +32,16 @@ import com.intellij.openapi.vcs.history.*; import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.history.HistoryClient; import org.jetbrains.idea.svn.history.SvnChangeList; import org.jetbrains.idea.svn.history.SvnFileRevision; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.*; +import org.tmatesoft.svn.core.wc2.SvnTarget; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; @@ -89,9 +91,8 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn final String contents; if (loadExternally) { - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - myVcs.createWCClient().doGetFileContents(ioFile, SVNRevision.UNDEFINED, SVNRevision.BASE, true, buffer); - contents = LoadTextUtil.getTextByBinaryPresentation(buffer.toByteArray(), file, false, false).toString(); + byte[] data = SvnUtil.getFileContents(myVcs, ioFile.getAbsolutePath(), false, SVNRevision.BASE, SVNRevision.UNDEFINED); + contents = LoadTextUtil.getTextByBinaryPresentation(data, file, false, false).toString(); } else { final byte[] bytes = VcsHistoryUtil.loadRevisionContent(revision); contents = LoadTextUtil.getTextByBinaryPresentation(bytes, file, false, false).toString(); @@ -106,8 +107,6 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn } final String url = info.getURL() == null ? null : info.getURL().toString(); - SVNLogClient client = myVcs.createLogClient(); - setLogClientOptions(client); SVNRevision endRevision = ((SvnFileRevision) revision).getRevision(); if (SVNRevision.WORKING.equals(endRevision)) { endRevision = info.getRevision(); @@ -123,12 +122,19 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn SvnUtil.checkRepositoryVersion15(myVcs, url); final SVNRevision svnRevision = ((SvnRevisionNumber)revision.getRevisionNumber()).getRevision(); - final MySteppedLogGetter logGetter = new MySteppedLogGetter(myVcs, ioFile, progress, client, endRevision, result, url, calculateMergeinfo, file.getCharset()); + final MySteppedLogGetter logGetter = new MySteppedLogGetter( + myVcs, ioFile, progress, + myVcs.getFactory(ioFile).createHistoryClient(), endRevision, result, + url, calculateMergeinfo, file.getCharset()); + logGetter.go(); final LinkedList rp = logGetter.getRevisionPoints(); + // TODO: only 2 elements will be in rp and for loop will be executed only once - probably rewrite with Pair + AnnotateClient annotateClient = myVcs.getFactory(ioFile).createAnnotateClient(); for (int i = 0; i < rp.size() - 1; i++) { - client.doAnnotate(ioFile, svnRevision, rp.get(i + 1), rp.get(i), true, calculateMergeinfo, annotateHandler, null); + annotateClient.annotate(SvnTarget.fromFile(ioFile), rp.get(i + 1), rp.get(i), svnRevision, calculateMergeinfo, + getLogClientOptions(myVcs), annotateHandler); } if (rp.get(1).getNumber() > 0) { @@ -136,31 +142,15 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn } annotation[0] = result; } - catch (SVNException e) { - if (SVNErrorCode.FS_NOT_FOUND.equals(e.getErrorMessage().getErrorCode())) { - final CommittedChangesProvider provider = myVcs.getCommittedChangesProvider(); - try { - final Pair pair = provider.getOneList(file, revision.getRevisionNumber()); - if (pair != null && info != null && pair.getSecond() != null && ! Comparing.equal(pair.getSecond().getIOFile(), ioFile)) { - annotation[0] = annotateNonExisting(pair, revision, info, file.getCharset(), file); - return; - } - } - catch (VcsException e1) { - exception[0] = e1; - } - catch (SVNException e1) { - exception[0] = new VcsException(e); - } - catch (IOException e1) { - exception[0] = new VcsException(e); - } - } - exception[0] = new VcsException(e); - } catch (IOException e) { + catch (IOException e) { exception[0] = new VcsException(e); } catch (VcsException e) { - exception[0] = e; + if (e.getCause() instanceof SVNException) { + handleSvnException(ioFile, info, (SVNException)e.getCause(), file, revision, annotation, exception); + } + else { + exception[0] = e; + } } } }; @@ -176,6 +166,35 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn return annotation[0]; } + private void handleSvnException(File ioFile, + SVNInfo info, + SVNException e, + VirtualFile file, + VcsFileRevision revision, + FileAnnotation[] annotation, VcsException[] exception) { + // TODO: Check how this scenario could be reproduced by user and what changes needs to be done for command line client + if (SVNErrorCode.FS_NOT_FOUND.equals(e.getErrorMessage().getErrorCode())) { + final CommittedChangesProvider provider = myVcs.getCommittedChangesProvider(); + try { + final Pair pair = provider.getOneList(file, revision.getRevisionNumber()); + if (pair != null && info != null && pair.getSecond() != null && ! Comparing.equal(pair.getSecond().getIOFile(), ioFile)) { + annotation[0] = annotateNonExisting(pair, revision, info, file.getCharset(), file); + return; + } + } + catch (VcsException e1) { + exception[0] = e1; + } + catch (SVNException e1) { + exception[0] = new VcsException(e); + } + catch (IOException e1) { + exception[0] = new VcsException(e); + } + } + exception[0] = new VcsException(e); + } + public static File getCommonAncestor(final File file1, final File file2) throws IOException { if (FileUtil.filesEqual(file1, file2)) return file1; final File can1 = file1.getCanonicalFile(); @@ -223,21 +242,18 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn wasUrl = wasUrl.appendPath(string, true); } - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); final SVNRevision svnRevision = ((SvnRevisionNumber)revision.getRevisionNumber()).getRevision(); - myVcs.createWCClient().doGetFileContents(wasUrl, svnRevision, svnRevision, true, buffer); - final String contents = LoadTextUtil.getTextByBinaryPresentation(buffer.toByteArray(), - charset == null ? CharsetToolkit.UTF8_CHARSET : charset).toString(); - SVNLogClient client = myVcs.createLogClient(); - setLogClientOptions(client); + byte[] data = SvnUtil.getFileContents(myVcs, wasUrl.toString(), true, svnRevision, svnRevision); + final String contents = LoadTextUtil.getTextByBinaryPresentation(data, charset == null ? CharsetToolkit.UTF8_CHARSET : charset).toString(); final SvnRemoteFileAnnotation result = new SvnRemoteFileAnnotation(myVcs, contents, revision.getRevisionNumber(), pair.getFirst(), pair.getSecond().getPath(), current); final ISVNAnnotateHandler annotateHandler = createAnnotationHandler(ProgressManager.getInstance().getProgressIndicator(), result); final boolean calculateMergeinfo = SvnConfiguration.getInstance(myVcs.getProject()).SHOW_MERGE_SOURCES_IN_ANNOTATE && SvnUtil.checkRepositoryVersion15(myVcs, wasUrl.toString()); - client.doAnnotate(wasUrl, svnRevision, SVNRevision.create(1), svnRevision, true, calculateMergeinfo, annotateHandler, null); - + AnnotateClient client = myVcs.getFactory().createAnnotateClient(); + client.annotate(SvnTarget.fromURL(wasUrl), SVNRevision.create(1), svnRevision, svnRevision, calculateMergeinfo, + getLogClientOptions(myVcs), annotateHandler); return result; } @@ -368,14 +384,14 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn private final SvnVcs myVcs; private final File myIoFile; private final ProgressIndicator myProgress; - private final SVNLogClient myClient; + private final HistoryClient myClient; private final SVNRevision myEndRevision; private final boolean myCalculateMergeinfo; private final SvnFileAnnotation myResult; private final String myUrl; private final Charset myCharset; - private MySteppedLogGetter(final SvnVcs vcs, final File ioFile, final ProgressIndicator progress, final SVNLogClient client, + private MySteppedLogGetter(final SvnVcs vcs, final File ioFile, final ProgressIndicator progress, final HistoryClient client, final SVNRevision endRevision, final SvnFileAnnotation result, final String url, @@ -393,7 +409,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn myRevisionPoints = new LinkedList(); } - public void go() throws SVNException { + public void go() throws VcsException { final int maxAnnotateRevisions = SvnConfiguration.getInstance(myVcs.getProject()).getMaxAnnotateRevisions(); boolean longHistory = true; if (maxAnnotateRevisions == -1) { @@ -435,8 +451,8 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn myRevisionPoints.add(SVNRevision.create(0)); } - private void doLog(final boolean includeMerged, final SVNRevision truncateTo, final int max) throws SVNException { - myClient.doLog(new File[]{myIoFile}, myEndRevision, truncateTo == null ? SVNRevision.create(1L) : truncateTo, + private void doLog(final boolean includeMerged, final SVNRevision truncateTo, final int max) throws VcsException { + myClient.doLog(myIoFile, myEndRevision, truncateTo == null ? SVNRevision.create(1L) : truncateTo, SVNRevision.UNDEFINED, false, false, includeMerged, max, null, new ISVNLogEntryHandler() { public void handleLogEntry(SVNLogEntry logEntry) { @@ -462,9 +478,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn return true; } - private void setLogClientOptions(final SVNLogClient client) { - if (SvnConfiguration.getInstance(myVcs.getProject()).IGNORE_SPACES_IN_ANNOTATE) { - client.setDiffOptions(new SVNDiffOptions(true, true, true)); - } + private static SVNDiffOptions getLogClientOptions(@NotNull SvnVcs vcs) { + return SvnConfiguration.getInstance(vcs.getProject()).IGNORE_SPACES_IN_ANNOTATE ? new SVNDiffOptions(true, true, true) : null; } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnKitAnnotateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnKitAnnotateClient.java new file mode 100644 index 000000000000..315178c9079e --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnKitAnnotateClient.java @@ -0,0 +1,42 @@ +package org.jetbrains.idea.svn.annotate; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.ISVNAnnotateHandler; +import org.tmatesoft.svn.core.wc.SVNDiffOptions; +import org.tmatesoft.svn.core.wc.SVNLogClient; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitAnnotateClient extends BaseSvnClient implements AnnotateClient { + + @Override + public void annotate(@NotNull SvnTarget target, + @NotNull SVNRevision startRevision, + @NotNull SVNRevision endRevision, + @Nullable SVNRevision pegRevision, + boolean includeMergedRevisions, + @Nullable SVNDiffOptions diffOptions, + @Nullable ISVNAnnotateHandler handler) throws VcsException { + try { + SVNLogClient client = myVcs.createLogClient(); + + client.setDiffOptions(diffOptions); + if (target.isFile()) { + client.doAnnotate(target.getFile(), pegRevision, startRevision, endRevision, true, includeMergedRevisions, handler, null); + } + else { + client.doAnnotate(target.getURL(), pegRevision, startRevision, endRevision, true, includeMergedRevisions, handler, null); + } + } + catch (SVNException e) { + throw new VcsException(e); + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java index 303738de828c..5db8a9bf707e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.AddClient; +import org.jetbrains.idea.svn.annotate.AnnotateClient; import org.jetbrains.idea.svn.conflict.ConflictClient; import org.jetbrains.idea.svn.copy.CopyMoveClient; import org.jetbrains.idea.svn.delete.DeleteClient; @@ -20,6 +21,7 @@ public abstract class ClientFactory { protected SvnVcs myVcs; protected AddClient addClient; + protected AnnotateClient annotateClient; protected HistoryClient historyClient; protected RevertClient revertClient; protected DeleteClient deleteClient; @@ -40,6 +42,11 @@ public abstract class ClientFactory { return prepare(addClient); } + @NotNull + public AnnotateClient createAnnotateClient() { + return prepare(annotateClient); + } + @NotNull public HistoryClient createHistoryClient() { return prepare(historyClient); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java index 5ac6f2da1655..650107c0f564 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.CmdAddClient; +import org.jetbrains.idea.svn.annotate.CmdAnnotateClient; import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient; import org.jetbrains.idea.svn.conflict.CmdConflictClient; import org.jetbrains.idea.svn.copy.CmdCopyMoveClient; @@ -23,6 +24,7 @@ public class CmdClientFactory extends ClientFactory { @Override protected void setup() { addClient = new CmdAddClient(); + annotateClient = new CmdAnnotateClient(); historyClient = new CmdHistoryClient(); revertClient = new CmdRevertClient(); deleteClient = new CmdDeleteClient(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java index ac9e4afa3f55..714bab338d30 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -3,6 +3,7 @@ package org.jetbrains.idea.svn.api; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.SvnKitAddClient; +import org.jetbrains.idea.svn.annotate.SvnKitAnnotateClient; import org.jetbrains.idea.svn.conflict.SvnKitConflictClient; import org.jetbrains.idea.svn.copy.SvnKitCopyMoveClient; import org.jetbrains.idea.svn.delete.SvnKitDeleteClient; @@ -23,6 +24,7 @@ public class SvnKitClientFactory extends ClientFactory { @Override protected void setup() { addClient = new SvnKitAddClient(); + annotateClient = new SvnKitAnnotateClient(); historyClient = new SvnKitHistoryClient(); revertClient = new SvnKitRevertClient(); deleteClient = new SvnKitDeleteClient(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index bb5d5408095f..cc6364189020 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -10,6 +10,7 @@ import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.api.FileStatusResultParser; import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.wc.SVNDiffOptions; import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.SVNStatusType; @@ -73,9 +74,13 @@ public class CommandUtil { } public static void put(@NotNull List parameters, @NotNull File path, @Nullable SVNRevision pegRevision) { - StringBuilder builder = new StringBuilder(path.getAbsolutePath()); + put(parameters, path.getAbsolutePath(), pegRevision); + } - if (pegRevision != null && !SVNRevision.UNDEFINED.equals(pegRevision)) { + public static void put(@NotNull List parameters, @NotNull String path, @Nullable SVNRevision pegRevision) { + StringBuilder builder = new StringBuilder(path); + + if (pegRevision != null && !SVNRevision.UNDEFINED.equals(pegRevision) && pegRevision.getNumber() > 0) { builder.append("@"); builder.append(pegRevision); } @@ -96,6 +101,28 @@ public class CommandUtil { } } + public static void put(@NotNull List parameters, @Nullable SVNDiffOptions diffOptions) { + if (diffOptions != null) { + StringBuilder builder = new StringBuilder(); + + if (diffOptions.isIgnoreAllWhitespace()) { + builder.append(" --ignore-space-change"); + } + if (diffOptions.isIgnoreAmountOfWhitespace()) { + builder.append(" --ignore-all-space"); + } + if (diffOptions.isIgnoreEOLStyle()) { + builder.append(" --ignore-eol-style"); + } + + String value = builder.toString().trim(); + + if (!StringUtil.isEmpty(value)) { + parameters.add("--extensions"); + parameters.add(value); + } + } + } /** * Utility method for running commands changing certain file status information. diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index df2baf7bacde..c19ea283bbd1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -38,7 +38,8 @@ public enum SvnCommandName { copy("copy", true), move("move", true), resolve("resolve", true), - propget("propget", false); + propget("propget", false), + blame("blame", false); private final String myName; private final boolean myWriteable; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java index 4e0499cb4177..3948ddee57b7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java @@ -47,7 +47,10 @@ public class CmdHistoryClient extends BaseSvnClient implements HistoryClient { @Nullable ISVNLogEntryHandler handler) throws VcsException { // TODO: add revision properties parameter if necessary // TODO: svn log command supports --xml option - could update parsing to use xml format - // TODO: Check parsing when merge is supported and includeMergedRevisions=true is used + + // TODO: after merge remove setting includeMergedRevisions to false and update parsing + includeMergedRevisions = false; + List parameters = prepareCommand(path, startRevision, endRevision, pegRevision, stopOnCopy, discoverChangedPaths, includeMergedRevisions, limit); @@ -84,8 +87,10 @@ public class CmdHistoryClient extends BaseSvnClient implements HistoryClient { CommandUtil.put(parameters, stopOnCopy, "--stop-on-copy"); CommandUtil.put(parameters, discoverChangedPaths, "--verbose"); CommandUtil.put(parameters, includeMergedRevisions, "--use-merge-history"); - parameters.add("--limit"); - parameters.add(String.valueOf(limit)); + if (limit > 0) { + parameters.add("--limit"); + parameters.add(String.valueOf(limit)); + } return parameters; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java index f9b0958dda3f..6d412853400e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.BaseSvnClient; import org.tmatesoft.svn.core.ISVNLogEntryHandler; import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.SVNLogClient; import org.tmatesoft.svn.core.wc.SVNRevision; import java.io.File; @@ -26,10 +27,11 @@ public class SvnKitHistoryClient extends BaseSvnClient implements HistoryClient @Nullable String[] revisionProperties, @Nullable ISVNLogEntryHandler handler) throws VcsException { try { - // a bug noticed when testing: we should pass "limit + 1" to get "limit" rows - myVcs.createLogClient() - .doLog(new File[]{path}, startRevision, endRevision, pegRevision, stopOnCopy, discoverChangedPaths, includeMergedRevisions, limit, - revisionProperties, handler); + // TODO: a bug noticed when testing: we should pass "limit + 1" to get "limit" rows + SVNLogClient client = myVcs.createLogClient(); + + client.doLog(new File[]{path}, startRevision, endRevision, pegRevision, stopOnCopy, discoverChangedPaths, includeMergedRevisions, + limit, revisionProperties, handler); } catch (SVNException e) { throw new VcsException(e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java index 2629ed49c1be..98d88dddd85d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java @@ -9,6 +9,7 @@ import org.jetbrains.idea.svn.commandLine.CommandUtil; import org.jetbrains.idea.svn.commandLine.SvnCommand; import org.jetbrains.idea.svn.commandLine.SvnCommandName; import org.tmatesoft.svn.core.SVNPropertyValue; +import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNPropertyData; import org.tmatesoft.svn.core.wc.SVNRevision; @@ -21,9 +22,11 @@ import java.util.List; */ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { + @Nullable @Override public SVNPropertyData getProperty(@NotNull File path, @NotNull String property, + boolean revisionProperty, @Nullable SVNRevision pegRevision, @Nullable SVNRevision revision) throws VcsException { @@ -31,13 +34,38 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { parameters.add(property); CommandUtil.put(parameters, path, pegRevision); - if (revision != null && !SVNRevision.UNDEFINED.equals(revision) && !SVNRevision.WORKING.equals(revision)) { + if (!revisionProperty) { + if (revision != null && !SVNRevision.UNDEFINED.equals(revision) && !SVNRevision.WORKING.equals(revision)) { + parameters.add("--revision"); + parameters.add(revision.toString()); + } + } else { + long revisionNumber = resolveRevisionNumber(path, revision); + + parameters.add("--revprop"); parameters.add("--revision"); - parameters.add(revision.toString()); + parameters.add(String.valueOf(revisionNumber)); } SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.propget, parameters, null); return new SVNPropertyData(property, SVNPropertyValue.create(StringUtil.nullize(command.getOutput())), null); } + + private long resolveRevisionNumber(@NotNull File path, @Nullable SVNRevision revision) throws VcsException { + long result = revision != null ? revision.getNumber() : -1; + + // base should be resolved manually - could not set revision to BASE to get revision property + if (SVNRevision.BASE.equals(revision)) { + SVNInfo info = myVcs.getInfo(path, SVNRevision.BASE); + + result = info != null ? info.getRevision().getNumber() : -1; + } + + if (result == -1) { + throw new VcsException("Could not determine revision number for file " + path + " and revision " + revision); + } + + return result; + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java index 1d151e24008e..118a397eb23e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java @@ -14,8 +14,10 @@ import java.io.File; */ public interface PropertyClient extends SvnClient { + @Nullable SVNPropertyData getProperty(@NotNull final File path, @NotNull final String property, + boolean revisionProperty, @Nullable SVNRevision pegRevision, @Nullable SVNRevision revision) throws VcsException; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java index 1795422a1225..1c3c23619074 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java @@ -5,8 +5,11 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.BaseSvnClient; import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc.ISVNPropertyHandler; import org.tmatesoft.svn.core.wc.SVNPropertyData; import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc.SVNWCClient; import java.io.File; @@ -15,16 +18,51 @@ import java.io.File; */ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClient { + @Nullable @Override public SVNPropertyData getProperty(@NotNull File path, @NotNull String property, + boolean revisionProperty, @Nullable SVNRevision pegRevision, @Nullable SVNRevision revision) throws VcsException { try { - return myVcs.createWCClient().doGetProperty(path, property, pegRevision, revision); + if (!revisionProperty) { + return myVcs.createWCClient().doGetProperty(path, property, pegRevision, revision); + } else { + return getRevisionProperty(path, property, revision); + } } catch (SVNException e) { throw new VcsException(e); } } + + private SVNPropertyData getRevisionProperty(@NotNull File path, @NotNull final String property, @Nullable SVNRevision revision) throws SVNException{ + final SVNWCClient client = myVcs.createWCClient(); + final SVNPropertyData[] result = new SVNPropertyData[1]; + + client.doGetRevisionProperty(path, null, revision, new ISVNPropertyHandler() { + @Override + public void handleProperty(File path, SVNPropertyData property) throws SVNException { + handle(property); + } + + @Override + public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException { + handle(property); + } + + @Override + public void handleProperty(long revision, SVNPropertyData property) throws SVNException { + handle(property); + } + + private void handle(@NotNull SVNPropertyData data) { + if (property.equals(data.getName())) { + result[0] = data; + } + } + }); + return result[0]; + } } From edc34973889a7b1f247365e454a8665dbac65a72 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 23 Aug 2013 19:31:03 +0400 Subject: [PATCH 27/30] IDEA-94942 Content retrieval from svn refactored to ClientFactory model --- .../idea/svn/SvnContentRevision.java | 4 +- .../src/org/jetbrains/idea/svn/SvnUtil.java | 72 ++++--------------- .../idea/svn/actions/SvnMergeProvider.java | 5 +- .../svn/annotate/SvnAnnotationProvider.java | 4 +- .../jetbrains/idea/svn/api/ClientFactory.java | 7 ++ .../idea/svn/api/CmdClientFactory.java | 2 + .../idea/svn/api/SvnKitClientFactory.java | 2 + .../idea/svn/commandLine/CommandUtil.java | 3 +- .../idea/svn/commandLine/SvnCatClient.java | 47 ------------ .../idea/svn/content/CmdContentClient.java | 43 +++++++++++ .../idea/svn/content/ContentClient.java | 17 +++++ .../content/FileTooBigRuntimeException.java | 7 ++ .../idea/svn/content/SvnKitContentClient.java | 61 ++++++++++++++++ .../idea/svn/history/SvnFileRevision.java | 3 +- .../idea/svn/history/SvnHistoryProvider.java | 2 +- .../history/SvnRepositoryContentRevision.java | 30 +------- 16 files changed, 170 insertions(+), 139 deletions(-) delete mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/content/ContentClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/content/FileTooBigRuntimeException.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/content/SvnKitContentClient.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnContentRevision.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnContentRevision.java index 38c099ba4136..cff64beea8b2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnContentRevision.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnContentRevision.java @@ -31,6 +31,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.SVNStatus; +import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; import java.io.IOException; @@ -113,7 +114,8 @@ public class SvnContentRevision implements ContentRevision, MarkerVcsContentRevi if (lock.exists()) { throw new VcsException("Can not access file base revision contents: administrative area is locked"); } - return SvnUtil.getFileContents(myVcs, file.getPath(), false, myUseBaseRevision ? SVNRevision.BASE : myRevision, SVNRevision.UNDEFINED); + return SvnUtil.getFileContents(myVcs, SvnTarget.fromFile(file), myUseBaseRevision ? SVNRevision.BASE : myRevision, + SVNRevision.UNDEFINED); } @NotNull diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index 9f7b41aabf0b..be8f609c341a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -30,18 +30,16 @@ import com.intellij.openapi.vcs.AbstractVcsHelper; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangesUtil; -import com.intellij.openapi.vcs.impl.ContentRevisionCache; import com.intellij.openapi.vfs.*; import com.intellij.openapi.wm.impl.status.StatusBarUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.Convertor; import com.intellij.util.containers.MultiMap; -import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.ClientFactory; import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; -import org.jetbrains.idea.svn.commandLine.SvnCatClient; import org.jetbrains.idea.svn.dialogs.LockDialog; import org.tmatesoft.sqljet.core.SqlJetException; import org.tmatesoft.sqljet.core.table.SqlJetDb; @@ -53,11 +51,9 @@ import org.tmatesoft.svn.core.io.SVNCapability; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.*; import org.tmatesoft.svn.core.wc2.SvnOperationFactory; +import org.tmatesoft.svn.core.wc2.SvnTarget; -import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.IOException; -import java.io.OutputStream; import java.util.*; public class SvnUtil { @@ -736,62 +732,24 @@ public class SvnUtil { return result; } - public static byte[] getFileContents(final SvnVcs vcs, final String path, final boolean isUrl, final SVNRevision revision, - final SVNRevision pegRevision) + public static byte[] getFileContents(@NotNull final SvnVcs vcs, + @NotNull final SvnTarget target, + @Nullable final SVNRevision revision, + @Nullable final SVNRevision pegRevision) throws VcsException { + ClientFactory factory = target.isFile() ? vcs.getFactory(target.getFile()) : vcs.getFactory(); - File file = new File(path); - WorkingCopyFormat format = vcs.getWorkingCopyFormat(file); - - return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) - ? getFileContentsCommandLine(vcs, path, revision, pegRevision) - : getFileContentWithSvnKit(vcs, path, isUrl, revision, pegRevision); + return factory.createContentClient().getContent(target, revision, pegRevision); } - private static byte[] getFileContentsCommandLine(SvnVcs vcs, String path, SVNRevision revision, SVNRevision pegRevision) throws VcsException { - SvnCatClient client = new SvnCatClient(vcs.getProject()); - String content = client.getFileContents(path, pegRevision, revision); - - return CharsetToolkit.getUtf8Bytes(content); - } - - private static byte[] getFileContentWithSvnKit(SvnVcs vcs, String path, boolean isUrl, SVNRevision revision, SVNRevision pegRevision) - throws VcsException { - final int maxSize = VcsUtil.getMaxVcsLoadedFileSize(); - ByteArrayOutputStream buffer = new ByteArrayOutputStream() { - @Override - public synchronized void write(int b) { - if (size() > maxSize) throw new FileTooBigRuntimeException(); - super.write(b); - } - - @Override - public synchronized void write(byte[] b, int off, int len) { - if (size() > maxSize) throw new FileTooBigRuntimeException(); - super.write(b, off, len); - } - - @Override - public synchronized void writeTo(OutputStream out) throws IOException { - if (size() > maxSize) throw new FileTooBigRuntimeException(); - super.writeTo(out); - } - }; - SVNWCClient wcClient = vcs.createWCClient(); + public static SVNURL parseUrl(@NotNull String url) { try { - if (isUrl) { - wcClient.doGetFileContents(SVNURL.parseURIEncoded(path), pegRevision, revision, true, buffer); - } else { - wcClient.doGetFileContents(new File(path), pegRevision, revision, true, buffer); - } - ContentRevisionCache.checkContentsSize(path, buffer.size()); - } catch (FileTooBigRuntimeException e) { - ContentRevisionCache.checkContentsSize(path, buffer.size()); - } catch (SVNException e) { - throw new VcsException(e); + return SVNURL.parseURIEncoded(url); + } + catch (SVNException e) { + IllegalArgumentException runtimeException = new IllegalArgumentException(); + runtimeException.initCause(e); + throw runtimeException; } - return buffer.toByteArray(); } - - private static class FileTooBigRuntimeException extends RuntimeException {} } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java index 644bb2142c77..3130dc948c13 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java @@ -33,6 +33,7 @@ import org.jetbrains.idea.svn.properties.PropertyClient; import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.SVNPropertyValue; import org.tmatesoft.svn.core.wc.*; +import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.ByteArrayOutputStream; import java.io.File; @@ -110,10 +111,10 @@ public class SvnMergeProvider implements MergeProvider { return data; } - private ByteArrayOutputStream getBaseRevisionContents(SvnVcs vcs, VirtualFile file) { + private ByteArrayOutputStream getBaseRevisionContents(@NotNull SvnVcs vcs, @NotNull VirtualFile file) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { - byte[] contents = SvnUtil.getFileContents(vcs, file.getPath(), false, SVNRevision.BASE, SVNRevision.UNDEFINED); + byte[] contents = SvnUtil.getFileContents(vcs, SvnTarget.fromFile(new File(file.getPath())), SVNRevision.BASE, SVNRevision.UNDEFINED); bos.write(contents); } catch (VcsException e) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java index a94dbbb2e04b..cd43da7c4d20 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java @@ -91,7 +91,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn final String contents; if (loadExternally) { - byte[] data = SvnUtil.getFileContents(myVcs, ioFile.getAbsolutePath(), false, SVNRevision.BASE, SVNRevision.UNDEFINED); + byte[] data = SvnUtil.getFileContents(myVcs, SvnTarget.fromFile(ioFile), SVNRevision.BASE, SVNRevision.UNDEFINED); contents = LoadTextUtil.getTextByBinaryPresentation(data, file, false, false).toString(); } else { final byte[] bytes = VcsHistoryUtil.loadRevisionContent(revision); @@ -243,7 +243,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn } final SVNRevision svnRevision = ((SvnRevisionNumber)revision.getRevisionNumber()).getRevision(); - byte[] data = SvnUtil.getFileContents(myVcs, wasUrl.toString(), true, svnRevision, svnRevision); + byte[] data = SvnUtil.getFileContents(myVcs, SvnTarget.fromURL(wasUrl), svnRevision, svnRevision); final String contents = LoadTextUtil.getTextByBinaryPresentation(data, charset == null ? CharsetToolkit.UTF8_CHARSET : charset).toString(); final SvnRemoteFileAnnotation result = new SvnRemoteFileAnnotation(myVcs, contents, revision.getRevisionNumber(), pair.getFirst(), pair.getSecond().getPath(), current); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java index 5db8a9bf707e..b85121637e6a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -5,6 +5,7 @@ import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.AddClient; import org.jetbrains.idea.svn.annotate.AnnotateClient; import org.jetbrains.idea.svn.conflict.ConflictClient; +import org.jetbrains.idea.svn.content.ContentClient; import org.jetbrains.idea.svn.copy.CopyMoveClient; import org.jetbrains.idea.svn.delete.DeleteClient; import org.jetbrains.idea.svn.history.HistoryClient; @@ -22,6 +23,7 @@ public abstract class ClientFactory { protected AddClient addClient; protected AnnotateClient annotateClient; + protected ContentClient contentClient; protected HistoryClient historyClient; protected RevertClient revertClient; protected DeleteClient deleteClient; @@ -47,6 +49,11 @@ public abstract class ClientFactory { return prepare(annotateClient); } + @NotNull + public ContentClient createContentClient() { + return prepare(contentClient); + } + @NotNull public HistoryClient createHistoryClient() { return prepare(historyClient); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java index 650107c0f564..ca4088b6a733 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -6,6 +6,7 @@ import org.jetbrains.idea.svn.add.CmdAddClient; import org.jetbrains.idea.svn.annotate.CmdAnnotateClient; import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient; import org.jetbrains.idea.svn.conflict.CmdConflictClient; +import org.jetbrains.idea.svn.content.CmdContentClient; import org.jetbrains.idea.svn.copy.CmdCopyMoveClient; import org.jetbrains.idea.svn.delete.CmdDeleteClient; import org.jetbrains.idea.svn.history.CmdHistoryClient; @@ -25,6 +26,7 @@ public class CmdClientFactory extends ClientFactory { protected void setup() { addClient = new CmdAddClient(); annotateClient = new CmdAnnotateClient(); + contentClient = new CmdContentClient(); historyClient = new CmdHistoryClient(); revertClient = new CmdRevertClient(); deleteClient = new CmdDeleteClient(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java index 714bab338d30..7e1951893969 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -5,6 +5,7 @@ import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.SvnKitAddClient; import org.jetbrains.idea.svn.annotate.SvnKitAnnotateClient; import org.jetbrains.idea.svn.conflict.SvnKitConflictClient; +import org.jetbrains.idea.svn.content.SvnKitContentClient; import org.jetbrains.idea.svn.copy.SvnKitCopyMoveClient; import org.jetbrains.idea.svn.delete.SvnKitDeleteClient; import org.jetbrains.idea.svn.history.SvnKitHistoryClient; @@ -25,6 +26,7 @@ public class SvnKitClientFactory extends ClientFactory { protected void setup() { addClient = new SvnKitAddClient(); annotateClient = new SvnKitAnnotateClient(); + contentClient = new SvnKitContentClient(); historyClient = new SvnKitHistoryClient(); revertClient = new SvnKitRevertClient(); deleteClient = new SvnKitDeleteClient(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index cc6364189020..313168a875ee 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -80,7 +80,8 @@ public class CommandUtil { public static void put(@NotNull List parameters, @NotNull String path, @Nullable SVNRevision pegRevision) { StringBuilder builder = new StringBuilder(path); - if (pegRevision != null && !SVNRevision.UNDEFINED.equals(pegRevision) && pegRevision.getNumber() > 0) { + if (pegRevision != null && !SVNRevision.UNDEFINED.equals(pegRevision) && !SVNRevision.WORKING.equals(pegRevision) && + pegRevision.getNumber() > 0) { builder.append("@"); builder.append(pegRevision); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java deleted file mode 100644 index f52b8728f34a..000000000000 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCatClient.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.jetbrains.idea.svn.commandLine; - -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vcs.VcsException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.svn.SvnVcs; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.wc.SVNRevision; - -import java.io.File; - -/** - * @author Konstantin Kolosovsky. - */ -public class SvnCatClient { - - private Project myProject; - - public SvnCatClient(@NotNull Project project) { - myProject = project; - } - - public String getFileContents(@NotNull String path, SVNRevision pegRevision, SVNRevision revision) throws VcsException { - // TODO: rewrite this to provide output as Stream - SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, null, SvnCommandName.cat); - fillParameters(path, pegRevision, revision, command); - - try { - return CommandUtil.runSimple(command, SvnVcs.getInstance(myProject), null, null).getOutput(); - } - catch (SVNException e) { - throw new VcsException(e); - } - } - - private void fillParameters(String path, SVNRevision pegRevision, SVNRevision revision, SvnSimpleCommand command) { - if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) { - command.addParameters("-r"); - command.addParameters(revision.toString()); - } - if (pegRevision != null && ! SVNRevision.UNDEFINED.equals(pegRevision) && ! SVNRevision.WORKING.equals(pegRevision)) { - command.addParameters(path + "@" + pegRevision.toString()); - } else { - command.addParameters(path); - } - } -} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java new file mode 100644 index 000000000000..494b7123125e --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java @@ -0,0 +1,43 @@ +package org.jetbrains.idea.svn.content; + +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.impl.ContentRevisionCache; +import com.intellij.openapi.vfs.CharsetToolkit; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.commandLine.*; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public class CmdContentClient extends BaseSvnClient implements ContentClient { + + @Override + public byte[] getContent(@NotNull SvnTarget target, @Nullable SVNRevision revision, @Nullable SVNRevision pegRevision) + throws VcsException, FileTooBigRuntimeException { + // TODO: rewrite this to provide output as Stream + // TODO: rewrite without conversion from String to byte[] + // TODO: Also implement max size constraint like in SvnKitContentClient + List parameters = new ArrayList(); + + CommandUtil.put(parameters, target.getPathOrUrlString(), pegRevision); + if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) { + parameters.add("--revision"); + parameters.add(revision.toString()); + } + + SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.cat, parameters, null); + + byte[] bytes = CharsetToolkit.getUtf8Bytes(command.getOutput()); + + ContentRevisionCache.checkContentsSize(target.getPathOrUrlString(), bytes.length); + + return bytes; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/content/ContentClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/ContentClient.java new file mode 100644 index 000000000000..3654d09c88bc --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/ContentClient.java @@ -0,0 +1,17 @@ +package org.jetbrains.idea.svn.content; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.SvnClient; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; + +/** + * @author Konstantin Kolosovsky. + */ +public interface ContentClient extends SvnClient { + + byte[] getContent(@NotNull SvnTarget target, @Nullable SVNRevision revision, @Nullable SVNRevision pegRevision) + throws VcsException, FileTooBigRuntimeException; +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/content/FileTooBigRuntimeException.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/FileTooBigRuntimeException.java new file mode 100644 index 000000000000..0a0e585069a6 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/FileTooBigRuntimeException.java @@ -0,0 +1,7 @@ +package org.jetbrains.idea.svn.content; + +/** + * @author Konstantin Kolosovsky. + */ +public class FileTooBigRuntimeException extends RuntimeException { +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/content/SvnKitContentClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/SvnKitContentClient.java new file mode 100644 index 000000000000..d5916970e320 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/SvnKitContentClient.java @@ -0,0 +1,61 @@ +package org.jetbrains.idea.svn.content; + +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.impl.ContentRevisionCache; +import com.intellij.vcsUtil.VcsUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc.SVNWCClient; +import org.tmatesoft.svn.core.wc2.SvnTarget; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitContentClient extends BaseSvnClient implements ContentClient { + + @Override + public byte[] getContent(@NotNull SvnTarget target, @Nullable SVNRevision revision, @Nullable SVNRevision pegRevision) + throws VcsException, FileTooBigRuntimeException { + final int maxSize = VcsUtil.getMaxVcsLoadedFileSize(); + ByteArrayOutputStream buffer = new ByteArrayOutputStream() { + @Override + public synchronized void write(int b) { + if (size() > maxSize) throw new FileTooBigRuntimeException(); + super.write(b); + } + + @Override + public synchronized void write(byte[] b, int off, int len) { + if (size() > maxSize) throw new FileTooBigRuntimeException(); + super.write(b, off, len); + } + + @Override + public synchronized void writeTo(OutputStream out) throws IOException { + if (size() > maxSize) throw new FileTooBigRuntimeException(); + super.writeTo(out); + } + }; + SVNWCClient wcClient = myVcs.createWCClient(); + try { + if (target.isURL()) { + wcClient.doGetFileContents(target.getURL(), pegRevision, revision, true, buffer); + } else { + wcClient.doGetFileContents(target.getFile(), pegRevision, revision, true, buffer); + } + ContentRevisionCache.checkContentsSize(target.getPathOrUrlString(), buffer.size()); + } catch (FileTooBigRuntimeException e) { + ContentRevisionCache.checkContentsSize(target.getPathOrUrlString(), buffer.size()); + } catch (SVNException e) { + throw new VcsException(e); + } + return buffer.toByteArray(); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnFileRevision.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnFileRevision.java index bcb40a034ac9..046e16c148a4 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnFileRevision.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnFileRevision.java @@ -33,6 +33,7 @@ import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; import org.tmatesoft.svn.core.SVNLogEntry; import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.IOException; import java.nio.charset.Charset; @@ -211,7 +212,7 @@ public class SvnFileRevision implements VcsFileRevision { } try { - myContents = SvnUtil.getFileContents(myVCS, myURL, true, myRevision, myPegRevision); + myContents = SvnUtil.getFileContents(myVCS, SvnTarget.fromURL(SvnUtil.parseUrl(myURL)), myRevision, myPegRevision); } catch (VcsException e) { myException = e; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index b5c372f41513..36d682500788 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -285,7 +285,7 @@ public class SvnHistoryProvider protected void preliminary() throws SVNException { myInfo = myVcs.getInfo(myFile.getIOFile()); if (myInfo == null || myInfo.getRepositoryRootURL() == null) { - myException = new VcsException("File ''{0}'' is not under version control" + myFile.getIOFile()); + myException = new VcsException("File " + myFile.getPath() + " is not under version control"); return; } if (myInfo.getURL() == null) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryContentRevision.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryContentRevision.java index 9f5c97bb04bd..b01308f76c13 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryContentRevision.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryContentRevision.java @@ -40,11 +40,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -164,18 +163,10 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC progress.setText(SvnBundle.message("progress.text.loading.contents", myPath)); progress.setText2(SvnBundle.message("progress.text2.revision.information", myRevision)); } - WorkingCopyFormat format = myVcs.getWorkingCopyFormat(new File(getFullPath())); - if (WorkingCopyFormat.ONE_DOT_EIGHT.equals(format)) { - loadContentCommandLine(); - } - else { - loadContentWithSvnKit(); - } - } - private void loadContentCommandLine() { try { - byte[] contents = SvnUtil.getFileContents(myVcs, getFullPath(), true, SVNRevision.create(myRevision), SVNRevision.UNDEFINED); + byte[] contents = SvnUtil.getFileContents(myVcs, SvnTarget.fromURL(SvnUtil.parseUrl(getFullPath())), SVNRevision.create(myRevision), + SVNRevision.UNDEFINED); myDst.write(contents); } catch (VcsException e) { @@ -185,21 +176,6 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC myException = e; } } - - private void loadContentWithSvnKit() { - try { - SVNRepository repository = myVcs.createRepository(getFullPath()); - try { - repository.getFile("", myRevision, null, myDst); - } - finally { - repository.closeSession(); - } - } - catch (SVNException e) { - myException = e; - } - } } public String getFullPath() { From a5f3011ff0d68bfd7dc50121071231d4468a967e Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 26 Aug 2013 13:07:06 +0400 Subject: [PATCH 28/30] IDEA-94942 Short refactoring (removed duplication) --- .../idea/svn/commandLine/CommandUtil.java | 9 +++- .../commandLine/SvnCommandLineInfoClient.java | 20 ++----- .../SvnCommandLineUpdateClient.java | 53 +++++++++---------- .../UpdateOutputLineConverter.java | 2 + .../idea/svn/content/CmdContentClient.java | 6 +-- .../svn/properties/CmdPropertyClient.java | 14 ++--- 6 files changed, 44 insertions(+), 60 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index 313168a875ee..0e7566bc7f9b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -96,12 +96,19 @@ public class CommandUtil { } public static void put(@NotNull List parameters, @Nullable SVNDepth depth) { - if (depth != null) { + if (depth != null && !SVNDepth.UNKNOWN.equals(depth)) { parameters.add("--depth"); parameters.add(depth.getName()); } } + public static void put(@NotNull List parameters, @Nullable SVNRevision revision) { + if (revision != null && !SVNRevision.UNDEFINED.equals(revision) && !SVNRevision.WORKING.equals(revision) && revision.getNumber() >= 0) { + parameters.add("--revision"); + parameters.add(revision.toString()); + } + } + public static void put(@NotNull List parameters, @Nullable SVNDiffOptions diffOptions) { if (diffOptions != null) { StringBuilder builder = new StringBuilder(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java index 4ef2e9283a7d..c9f10a3d45ab 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java @@ -82,7 +82,7 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { // very unrealistic throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), new RuntimeException("Can not find existing parent file")); } - issueCommand(path.getPath(), pegRevision, revision, depth, changeLists, handler, base); + issueCommand(path.getAbsolutePath(), pegRevision, revision, depth, changeLists, handler, base); } private void issueCommand(String path, SVNRevision pegRevision, @@ -167,21 +167,11 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { } } - private void fillParameters(String path, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, Collection parameters) { - if (depth != null) { - parameters.add("--depth"); - parameters.add(depth.getName()); - } - if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) { - parameters.add("-r"); - parameters.add(revision.toString()); - } + private void fillParameters(String path, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, List parameters) { + CommandUtil.put(parameters, depth); + CommandUtil.put(parameters, revision); + CommandUtil.put(parameters, path, pegRevision); parameters.add("--xml"); - if (pegRevision != null && ! SVNRevision.UNDEFINED.equals(pegRevision) && ! SVNRevision.WORKING.equals(pegRevision)) { - parameters.add(path + "@" + pegRevision.toString()); - } else { - parameters.add(path); - } } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java index c1ba46959532..e0834c2f116f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java @@ -87,35 +87,7 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient { File base = myCommonAncestor == null ? paths[0] : new File(myCommonAncestor.getPath()); base = base.isDirectory() ? base : base.getParentFile(); - final List parameters = new ArrayList(); - if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) { - parameters.add("-r"); - parameters.add(revision.toString()); - } - // unknown depth is not used any more for 1.7 -> why? - if (depth != null && ! SVNDepth.UNKNOWN.equals(depth)) { - parameters.add("--depth"); - parameters.add(depth.toString()); - } - if (allowUnversionedObstructions) { - parameters.add("--force"); - } - if (depthIsSticky && depth != null) {// !!! not sure, but not used - parameters.add("--set-depth"); - parameters.add(depth.toString()); - } - if (makeParents) { - parameters.add("--parents"); - } - if (myIgnoreExternals) { - parameters.add("--ignore-externals"); - } - parameters.add("--accept"); - parameters.add("postpone"); - - for (File path : paths) { - parameters.add(path.getPath()); - } + final List parameters = prepareParameters(paths, revision, depth, allowUnversionedObstructions, depthIsSticky, makeParents); final AtomicReference excRef = new AtomicReference(); final ISVNEventHandler handler = getEventHandler(); @@ -179,6 +151,29 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient { return updatedToRevision.get(); } + private List prepareParameters(File[] paths, + SVNRevision revision, + SVNDepth depth, + boolean allowUnversionedObstructions, + boolean depthIsSticky, boolean makeParents) { + List parameters = new ArrayList(); + + CommandUtil.put(parameters, revision); + CommandUtil.put(parameters, depth); + CommandUtil.put(parameters, allowUnversionedObstructions, "--force"); + if (depthIsSticky && depth != null) {// !!! not sure, but not used + parameters.add("--set-depth"); + parameters.add(depth.toString()); + } + CommandUtil.put(parameters, makeParents, "--parents"); + CommandUtil.put(parameters, myIgnoreExternals, "--ignore-externals"); + parameters.add("--accept"); + parameters.add("postpone"); + CommandUtil.put(parameters, paths); + + return parameters; + } + private void checkForException(final StringBuffer sbError) throws SVNException { if (sbError.length() == 0) return; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java index ab43b605d747..8700c363f460 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java @@ -62,6 +62,8 @@ public class UpdateOutputLineConverter { } public SVNEvent convert(final String line) { + // TODO: Add direct processing of "Summary of conflicts" lines at the end of "svn update" output (if there are conflicts). + // TODO: Now it works ok because parseNormalLine could not determine necessary statuses from that and further lines if (StringUtil.isEmptyOrSpaces(line)) return null; if (line.startsWith(UPDATING)) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java index 494b7123125e..c822fe0a1f48 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java @@ -25,12 +25,8 @@ public class CmdContentClient extends BaseSvnClient implements ContentClient { // TODO: rewrite without conversion from String to byte[] // TODO: Also implement max size constraint like in SvnKitContentClient List parameters = new ArrayList(); - CommandUtil.put(parameters, target.getPathOrUrlString(), pegRevision); - if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) { - parameters.add("--revision"); - parameters.add(revision.toString()); - } + CommandUtil.put(parameters, revision); SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.cat, parameters, null); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java index 98d88dddd85d..4720b33d9d37 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java @@ -35,16 +35,10 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { parameters.add(property); CommandUtil.put(parameters, path, pegRevision); if (!revisionProperty) { - if (revision != null && !SVNRevision.UNDEFINED.equals(revision) && !SVNRevision.WORKING.equals(revision)) { - parameters.add("--revision"); - parameters.add(revision.toString()); - } + CommandUtil.put(parameters, revision); } else { - long revisionNumber = resolveRevisionNumber(path, revision); - parameters.add("--revprop"); - parameters.add("--revision"); - parameters.add(String.valueOf(revisionNumber)); + CommandUtil.put(parameters, resolveRevisionNumber(path, revision)); } SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.propget, parameters, null); @@ -52,7 +46,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { return new SVNPropertyData(property, SVNPropertyValue.create(StringUtil.nullize(command.getOutput())), null); } - private long resolveRevisionNumber(@NotNull File path, @Nullable SVNRevision revision) throws VcsException { + private SVNRevision resolveRevisionNumber(@NotNull File path, @Nullable SVNRevision revision) throws VcsException { long result = revision != null ? revision.getNumber() : -1; // base should be resolved manually - could not set revision to BASE to get revision property @@ -66,6 +60,6 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { throw new VcsException("Could not determine revision number for file " + path + " and revision " + revision); } - return result; + return SVNRevision.create(result); } } From 9bef3a27973a8ca09be4297bccf2c21a71e38183 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 26 Aug 2013 14:23:27 +0400 Subject: [PATCH 29/30] IDEA-94942 Updated cleanup behavior after previous command failed --- .../src/org/jetbrains/idea/svn/SvnUtil.java | 2 ++ .../idea/svn/commandLine/SvnBindUtil.java | 24 +------------------ .../idea/svn/commandLine/SvnLineCommand.java | 9 ++++--- 3 files changed, 9 insertions(+), 26 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index be8f609c341a..7cd6bdd91d3f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -57,6 +57,8 @@ import java.io.File; import java.util.*; public class SvnUtil { + // TODO: ASP.NET hack behavior should be supported - http://svn.apache.org/repos/asf/subversion/trunk/notes/asp-dot-net-hack.txt + // TODO: Remember this when moving out SVNKit classes. @NonNls public static final String SVN_ADMIN_DIR_NAME = SVNFileUtil.getAdminDirectoryName(); @NonNls public static final String ENTRIES_FILE_NAME = "entries"; @NonNls public static final String WC_DB_FILE_NAME = "wc.db"; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindUtil.java index d10be8fd9611..7d663bae65b5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindUtil.java @@ -31,16 +31,7 @@ import java.util.Locale; * Time: 4:56 PM */ public class SvnBindUtil { - /** - * SVN_ASP_DOT_NET_HACK allows use of an alternate name for Subversion working copy - * administrative directories on Windows (which were formerly always - * named ".svn"), by setting the SVN_ASP_DOT_NET_HACK environment variable. - * When the variable is set (to any value), the administrative directory - * will be "_svn" instead of ".svn". - * - * http://svn.apache.org/repos/asf/subversion/trunk/notes/asp-dot-net-hack.txt - */ - public static final String ADM_NAME = System.getenv("SVN_ASP_DOT_NET_HACK") != null ? "_svn" : ".svn"; + private final static List ourFormats = new ArrayList(); static { @@ -88,17 +79,4 @@ public class SvnBindUtil { } return null; } - - public static File getWcRoot(File base) { - File current = base; - while (current != null) { - if (getWcDbUnder(current).exists()) return current; - current = current.getParentFile(); - } - return null; - } - - public static File getWcDbUnder(final File file) { - return new File(file, ADM_NAME + File.separator + "wc.db"); - } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java index 8919c9e3547e..a34e5cf2f406 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java @@ -28,6 +28,7 @@ import com.intellij.util.EventDispatcher; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.SvnUtil; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; @@ -400,12 +401,14 @@ public class SvnLineCommand extends SvnCommand { } private static void cleanup(String exePath, SvnCommand command, File base) throws SvnBindException { - File wcRoot = SvnBindUtil.getWcRoot(base); - if (wcRoot == null) throw new SvnBindException("Can not find working copy root for: " + base.getPath()); - // TODO: could be issues with fake "empty" command as it is not writable - but only read commands currently use "empty" command // TODO: and "empty" command will be removed shortly if (command.isManuallyDestroyed() && command.getCommandName().isWriteable()) { + File wcRoot = SvnUtil.getWorkingCopyRootNew(base); + if (wcRoot == null) { + throw new SvnBindException("Can not find working copy root for: " + base.getPath()); + } + final SvnSimpleCommand cleanupCommand = new SvnSimpleCommand(wcRoot, SvnCommandName.cleanup, exePath); try { cleanupCommand.run(); From ed88487c92af40c612c575be1d757c2d16b3e347 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 26 Aug 2013 16:08:59 +0400 Subject: [PATCH 30/30] IDEA-94942 Provide detailed error messages to user instead of general ones --- .../idea/svn/SvnFileSystemListener.java | 6 +- .../idea/svn/api/FileStatusResultParser.java | 12 ++-- .../idea/svn/commandLine/CommandUtil.java | 58 ++++++++++++------- .../commandLine/SvnCommandLineInfoClient.java | 12 ++-- .../SvnCommandLineStatusClient.java | 6 +- 5 files changed, 57 insertions(+), 37 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java index d290f5f6c301..da1adc60327c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java @@ -304,7 +304,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp copyFileOrDir(src, dst); } catch (IOException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e); } createDeleteAction(vcs, src, true).execute(); return false; @@ -341,7 +341,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp copyFileOrDir(src, dst); } catch (IOException e) { - exc[0] = new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + exc[0] = new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e); return false; } } @@ -535,7 +535,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp private static void wrapAndThrow(VcsException e) throws SVNException { // TODO: probably we should wrap into new exception only if e.getCause is not SVNException - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL, e), e); } private boolean isAboveSourceOfCopyOrMove(final Project p, File ioFile) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/FileStatusResultParser.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/FileStatusResultParser.java index 66e588c41c11..fc202c265a6a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/FileStatusResultParser.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/FileStatusResultParser.java @@ -36,7 +36,7 @@ public class FileStatusResultParser { myConvertor = convertor; } - public void parse(@NotNull String output) throws VcsException, SVNException { + public void parse(@NotNull String output) throws VcsException { if (StringUtil.isEmpty(output)) { return; } @@ -46,7 +46,7 @@ public class FileStatusResultParser { } } - public void onLine(@NotNull String line) throws VcsException, SVNException { + public void onLine(@NotNull String line) throws VcsException { Matcher matcher = myLinePattern.matcher(line); if (matcher.matches()) { process(matcher); @@ -56,9 +56,13 @@ public class FileStatusResultParser { } } - public void process(@NotNull Matcher matcher) throws VcsException, SVNException { + public void process(@NotNull Matcher matcher) throws VcsException { if (handler != null) { - handler.handleEvent(myConvertor.convert(matcher), DEFAULT_PROGRESS); + try { + handler.handleEvent(myConvertor.convert(matcher), DEFAULT_PROGRESS); + } catch (SVNException e) { + throw new VcsException(e); + } } } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index 0e7566bc7f9b..737d8a85b60b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -30,15 +30,9 @@ public class CommandUtil { @Nullable SVNURL url, List parameters) throws SVNException { - String exe = SvnApplicationSettings.getInstance().getCommandLinePath(); - base = base == null ? new File(exe) : base; - - if (url == null) { - // TODO: or take it from RootUrlInfo - SVNInfo info = vcs.getInfo(vcs.getProject().getBaseDir()); - - url = info != null ? info.getURL() : null; - } + String exe = resolveExePath(); + base = resolveBaseDirectory(base, exe); + url = resolveRepositoryUrl(vcs, url); try { return SvnLineCommand @@ -46,10 +40,31 @@ public class CommandUtil { new IdeaSvnkitBasedAuthenticationCallback(vcs), ArrayUtil.toStringArray(parameters)); } catch (SvnBindException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e); } } + @Nullable + private static SVNURL resolveRepositoryUrl(@NotNull SvnVcs vcs, @Nullable SVNURL url) { + if (url == null) { + // TODO: or take it from RootUrlInfo + SVNInfo info = vcs.getInfo(vcs.getProject().getBaseDir()); + + url = info != null ? info.getURL() : null; + } + return url; + } + + @NotNull + private static File resolveBaseDirectory(@Nullable File base, @NotNull String defaultBase) { + return base == null ? new File(defaultBase) : base; + } + + @NotNull + private static String resolveExePath() { + return SvnApplicationSettings.getInstance().getCommandLinePath(); + } + public static SvnLineCommand runSimple(@NotNull SvnSimpleCommand command, @NotNull SvnVcs vcs, @Nullable File base, @Nullable SVNURL url) throws SVNException { // empty command name passed, as command name is already in command.getParameters() @@ -146,22 +161,23 @@ public class CommandUtil { @NotNull SvnCommandName name, @NotNull List parameters, @Nullable FileStatusResultParser parser) - throws VcsException { - try { - SvnLineCommand command = runSimple(name, vcs, null, null, parameters); + throws VcsException { + String exe = resolveExePath(); + File base = resolveBaseDirectory(null, exe); + SVNURL url = resolveRepositoryUrl(vcs, null); - if (parser != null) { - parser.parse(command.getOutput()); - } + SvnLineCommand command = SvnLineCommand.runWithAuthenticationAttempt( + exe, base, url, name, new SvnCommitRunner.CommandListener(null), + new IdeaSvnkitBasedAuthenticationCallback(vcs), + ArrayUtil.toStringArray(parameters)); - return command; - } - catch (SVNException e) { - throw new VcsException(e); + if (parser != null) { + parser.parse(command.getOutput()); } + + return command; } - /** * Gets svn status represented by single character. * diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java index c9f10a3d45ab..47b6b5234396 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java @@ -80,7 +80,7 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { base = SvnBindUtil.correctUpToExistingParent(base); if (base == null) { // very unrealistic - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), new RuntimeException("Can not find existing parent file")); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Can not find existing parent file")); } issueCommand(path.getAbsolutePath(), pegRevision, revision, depth, changeLists, handler, base); } @@ -120,10 +120,10 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { // but the requested info is still in the output except root closing tag return command.getOutput() + ""; } else { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_WORKING_COPY), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_WORKING_COPY, e), e); } } - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e); } } @@ -155,15 +155,15 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient { throw (SVNException) e.getCause(); } catch (IOException e) { LOG.info("info output " + result); - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e); } catch (ParserConfigurationException e) { LOG.info("info output " + result); - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e); } catch (SAXException e) { LOG.info("info output " + result); - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java index 52e597910f23..c1429be699af 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java @@ -167,13 +167,13 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { catch (SvnExceptionWrapper e) { throw (SVNException) e.getCause(); } catch (IOException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e); } catch (ParserConfigurationException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e); } catch (SAXException e) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e); } }