Merge branch 'svn1_8_new' phpstorm/130.1775
authorKonstantin Kolosovsky <konstantin.kolosovsky@jetbrains.com>
Tue, 27 Aug 2013 09:56:56 +0000 (13:56 +0400)
committerKonstantin Kolosovsky <konstantin.kolosovsky@jetbrains.com>
Tue, 27 Aug 2013 09:56:56 +0000 (13:56 +0400)
123 files changed:
.idea/modules.xml
build/scripts/layouts.gant
platform/util/src/com/intellij/openapi/util/text/StringUtil.java
plugins/svn4idea/bindSvn/bindSvn.iml [deleted file]
plugins/svn4idea/bindSvn/lib/javahl.jar [deleted file]
plugins/svn4idea/bindSvn/lib/javahlsrc.zip [deleted file]
plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindClient.java [deleted file]
plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/status/LockWrapper.java [deleted file]
plugins/svn4idea/bindSvn/src/org/tigris/subversion/javahl/BindClientException.java [deleted file]
plugins/svn4idea/src/org/jetbrains/idea/svn/ForNestedRootChecker.java
plugins/svn4idea/src/org/jetbrains/idea/svn/RootsToWorkingCopies.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAbstractWriteOperationLocks.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProvider.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangelistListener.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnContentRevision.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListener.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFormatSelector.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnProxies.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnTestWriteOperationLocks.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java
plugins/svn4idea/src/org/jetbrains/idea/svn/SvnWriteOperationLocks.java
plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopyFormat.java
plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AddAction.java
plugins/svn4idea/src/org/jetbrains/idea/svn/actions/MarkResolvedAction.java
plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java
plugins/svn4idea/src/org/jetbrains/idea/svn/add/AddClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/add/CmdAddClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/add/SvnKitAddClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/AnnotateClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/CmdAnnotateClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java
plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnKitAnnotateClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/api/FileStatusResultParser.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultConfigLoader.java
plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java
plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaCommitHandler.java
plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/IdeaSvnkitBasedAuthenticationCallback.java
plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthenticationCallback.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/AuthenticationCallback.java with 87% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommitEventHandler.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/CommitEventHandler.java with 95% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommitEventType.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/CommitEventType.java with 96% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/LineCommandListener.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/LineCommandListener.java with 100% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/config/SvnBindException.java with 68% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindUtil.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindUtil.java with 73% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommand.java with 81% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineInfoClient.java
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineUpdateClient.java
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java with 75% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommitRunner.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnCommitRunner.java with 86% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoHandler.java
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnInfoStructure.java
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnLineCommand.java with 66% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java [moved from plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/commandLine/SvnSimpleCommand.java with 97% similarity]
plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java
plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/CmdConflictClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/ConflictClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/SvnKitConflictClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/content/ContentClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/content/FileTooBigRuntimeException.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/content/SvnKitContentClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CmdCopyMoveClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CopyMoveClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/copy/SvnKitCopyMoveClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/delete/CmdDeleteClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/delete/DeleteClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/delete/SvnKitDeleteClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CreateBranchOrTagDialog.java
plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/history/HistoryClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java
plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnEditCommitMessageAction.java
plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnFileRevision.java
plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java
plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistorySession.java
plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryContentRevision.java
plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/IntegratedSelectedOptionsDialog.java
plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java
plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java
plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnPropDetailsProvider.java [deleted file]
plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/revert/RevertClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/revert/SvnKitRevertClient.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java
plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdatePanel.java
plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractUpdateIntegrateCrawler.java
plugins/svn4idea/src/org/jetbrains/idea/svn/update/MergeRootInfo.java
plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnIntegrateEnvironment.java
plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java
plugins/svn4idea/src/org/jetbrains/idea/svn/update/UpdateRootInfo.java
plugins/svn4idea/svn4idea-tests.iml
plugins/svn4idea/svn4idea.iml
plugins/svn4idea/testData18/svn/bin/windows/svn.exe [new file with mode: 0644]
plugins/svn4idea/testData18/svn/newrepo.zip [new file with mode: 0644]
plugins/svn4idea/testSource/org/jetbrains/idea/SvnTestCase.java
plugins/svn4idea/testSource/org/jetbrains/idea/svn/IgnoredFilesTest.java
plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedNativeTest.java
plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCommitTest.java
plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnExternalTests.java
plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnLockingTest.java
plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java
plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnChangesCorrectlyRefreshedNativeTest.java
plugins/svn4idea/testSource/org/jetbrains/idea/svn18/Svn18TestSuite.java [new file with mode: 0644]

index fe96de58545d0c85e31d9220ed51d59bc91a9d7f..d0662cd6e07d1df0adfa62ae2c13ace01ef04dc6 100644 (file)
@@ -16,7 +16,6 @@
       <module fileurl="file://$PROJECT_DIR$/plugins/ant/jps-plugin/ant-jps-plugin.iml" filepath="$PROJECT_DIR$/plugins/ant/jps-plugin/ant-jps-plugin.iml" group="plugins" />
       <module fileurl="file://$PROJECT_DIR$/jps/antLayout/antlayout.iml" filepath="$PROJECT_DIR$/jps/antLayout/antlayout.iml" group="jps" />
       <module fileurl="file://$PROJECT_DIR$/plugins/google-app-engine/runtime/appEngine-runtime.iml" filepath="$PROJECT_DIR$/plugins/google-app-engine/runtime/appEngine-runtime.iml" group="plugins/GAE" />
-      <module fileurl="file://$PROJECT_DIR$/plugins/svn4idea/bindSvn/bindSvn.iml" filepath="$PROJECT_DIR$/plugins/svn4idea/bindSvn/bindSvn.iml" group="plugins/VCS" />
       <module fileurl="file://$PROJECT_DIR$/platform/boot/boot.iml" filepath="$PROJECT_DIR$/platform/boot/boot.iml" group="platform" />
       <module fileurl="file://$PROJECT_DIR$/platform/bootstrap/bootstrap.iml" filepath="$PROJECT_DIR$/platform/bootstrap/bootstrap.iml" group="platform" />
       <module fileurl="file://$PROJECT_DIR$/build/build.iml" filepath="$PROJECT_DIR$/build/build.iml" />
index db7427247f458b5fc1ee1539d84804593e260e90..655b0b560cd6114ab4f050c919f72c81adcd19d4 100644 (file)
@@ -323,9 +323,6 @@ public def layoutCommunityPlugins(String home) {
     }
 
     layoutPlugin("svn4idea") {
-      jar("bindSvn.jar") {
-        module("bindSvn")
-      }
       fileset(dir: "$home/plugins/svn4idea/lib", excludes: "**/svnkitsrc.zip")
     }
 
index afafbafdcdb720e79cf45f5cf75a237b2ecde5d2..eb99bbd45c57e7599be746264ab8b48b62bf4033 100644 (file)
@@ -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<String, String> QUOTER = new NotNullFunction<String, String>() {
     @Override
@@ -2132,7 +2133,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/bindSvn/bindSvn.iml b/plugins/svn4idea/bindSvn/bindSvn.iml
deleted file mode 100644 (file)
index 846587c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="JAVA_MODULE" version="4">
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="module" module-name="platform-api" />
-    <orderEntry type="module" module-name="vcs-api" />
-    <orderEntry type="module-library">
-      <library>
-        <CLASSES>
-          <root url="jar://$MODULE_DIR$/lib/javahl.jar!/" />
-        </CLASSES>
-        <JAVADOC />
-        <SOURCES>
-          <root url="jar://$MODULE_DIR$/lib/javahlsrc.zip!/src" />
-        </SOURCES>
-      </library>
-    </orderEntry>
-  </component>
-</module>
-
diff --git a/plugins/svn4idea/bindSvn/lib/javahl.jar b/plugins/svn4idea/bindSvn/lib/javahl.jar
deleted file mode 100644 (file)
index a0c5370..0000000
Binary files a/plugins/svn4idea/bindSvn/lib/javahl.jar and /dev/null differ
diff --git a/plugins/svn4idea/bindSvn/lib/javahlsrc.zip b/plugins/svn4idea/bindSvn/lib/javahlsrc.zip
deleted file mode 100644 (file)
index 9c50118..0000000
Binary files a/plugins/svn4idea/bindSvn/lib/javahlsrc.zip and /dev/null differ
diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindClient.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/SvnBindClient.java
deleted file mode 100644 (file)
index c155b78..0000000
+++ /dev/null
@@ -1,925 +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.jetbrains.idea.svn;
-
-import org.tigris.subversion.javahl.*;
-
-import java.io.OutputStream;
-import java.util.Map;
-
-/**
- * Created with IntelliJ IDEA.
- * User: Irina.Chernushina
- * Date: 2/5/13
- * Time: 3:08 PM
- */
-public class SvnBindClient implements SVNClientInterface {
-  private final String myExecutablePath;
-  private CommitEventHandler myHandler;
-  private AuthenticationCallback myAuthenticationCallback;
-
-  public SvnBindClient(String path) {
-    myExecutablePath = path;
-  }
-
-  @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,
-                     boolean getAll,
-                     boolean noIgnore,
-                     boolean ignoreExternals,
-                     String[] changelists,
-                     StatusCallback callback) throws ClientException {
-    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,
-                   int depth,
-                   int direntFields,
-                   boolean fetchLocks,
-                   ListCallback callback) throws ClientException {
-    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,
-                                  boolean stopOnCopy,
-                                  boolean discoverPath,
-                                  long limit) throws ClientException {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  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();
-  }
-
-  @Override
-  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();
-  }
-
-  @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,
-                       Revision pegRevision,
-                       boolean recurse,
-                       boolean ignoreExternals) throws ClientException {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  public long checkout(String moduleName,
-                       String destPath,
-                       Revision revision,
-                       Revision pegRevision,
-                       int depth,
-                       boolean ignoreExternals,
-                       boolean allowUnverObstructions) throws ClientException {
-    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,
-                     boolean depthIsSticky,
-                     boolean ignoreExternals,
-                     boolean allowUnverObstructions) throws ClientException {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  public long[] update(String[] path,
-                       Revision revision,
-                       int depth,
-                       boolean depthIsSticky,
-                       boolean ignoreExternals,
-                       boolean allowUnverObstructions) throws ClientException {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  public long commit(String[] path, String message, boolean recurse) throws ClientException {
-    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 {
-    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 {
-    final long commit = new SvnCommitRunner(myExecutablePath, myHandler, myAuthenticationCallback).
-        commit(path, message, depth, noUnlock, keepChangelist, changelists, revpropTable);
-    if (commit < 0) {
-      throw new BindClientException("Wrong committed revision number: " + commit, null, -1);
-    }
-    return commit;
-  }
-
-  @Override
-  public void copy(CopySource[] sources,
-                   String destPath,
-                   String message,
-                   boolean copyAsChild,
-                   boolean makeParents,
-                   boolean ignoreExternals,
-                   Map revpropTable) throws ClientException {
-    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,
-                   boolean force,
-                   boolean moveAsChild,
-                   boolean makeParents,
-                   Map revpropTable) throws ClientException {
-    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,
-                       Revision pegRevision,
-                       boolean force,
-                       boolean ignoreExternals,
-                       boolean recurse,
-                       String nativeEOL) throws ClientException {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  public long doExport(String srcPath,
-                       String destPath,
-                       Revision revision,
-                       Revision pegRevision,
-                       boolean force,
-                       boolean ignoreExternals,
-                       int depth,
-                       String nativeEOL) throws ClientException {
-    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,
-                       Revision pegRevision,
-                       int depth,
-                       boolean depthIsSticky,
-                       boolean ignoreExternals,
-                       boolean allowUnverObstructions) throws ClientException {
-    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,
-                       int depth,
-                       boolean noIgnore,
-                       boolean ignoreUnknownNodeTypes,
-                       Map revpropTable) throws ClientException {
-    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,
-                    Revision revision2,
-                    String localPath,
-                    boolean force,
-                    boolean recurse,
-                    boolean ignoreAncestry,
-                    boolean dryRun) throws ClientException {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  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();
-  }
-
-  @Override
-  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();
-  }
-
-  @Override
-  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();
-  }
-
-  @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,
-                              String mergeSourceUrl,
-                              Revision srcPegRevision,
-                              boolean discoverChangedPaths,
-                              int depth,
-                              String[] revProps,
-                              LogMessageCallback callback) throws ClientException {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  public void getMergeinfoLog(int kind,
-                              String pathOrUrl,
-                              Revision pegRevision,
-                              String mergeSourceUrl,
-                              Revision srcPegRevision,
-                              boolean discoverChangedPaths,
-                              String[] revProps,
-                              LogMessageCallback callback) throws ClientException {
-    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,
-                   Revision revision2,
-                   String outFileName,
-                   boolean recurse,
-                   boolean ignoreAncestry,
-                   boolean noDiffDeleted,
-                   boolean force) throws ClientException {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  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();
-  }
-
-  @Override
-  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();
-  }
-
-  @Override
-  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();
-  }
-
-  @Override
-  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();
-  }
-
-  @Override
-  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();
-  }
-
-  @Override
-  public void diffSummarize(String target1,
-                            Revision revision1,
-                            String target2,
-                            Revision revision2,
-                            int depth,
-                            String[] changelists,
-                            boolean ignoreAncestry,
-                            DiffSummaryReceiver receiver) throws ClientException {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  public void diffSummarize(String target,
-                            Revision pegRevision,
-                            Revision startRevision,
-                            Revision endRevision,
-                            int depth,
-                            String[] changelists,
-                            boolean ignoreAncestry,
-                            DiffSummaryReceiver receiver) throws ClientException {
-    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,
-                    Revision revisionEnd,
-                    boolean ignoreMimeType,
-                    boolean includeMergedRevisions,
-                    BlameCallback2 callback) throws ClientException {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  public void blame(String path,
-                    Revision pegRevision,
-                    Revision revisionStart,
-                    Revision revisionEnd,
-                    boolean ignoreMimeType,
-                    boolean includeMergedRevisions,
-                    BlameCallback3 callback) throws ClientException {
-    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();
-  }
-
-  public void setHandler(CommitEventHandler handler) {
-    myHandler = handler;
-  }
-
-  public void setAuthenticationCallback(AuthenticationCallback authenticationCallback) {
-    myAuthenticationCallback = authenticationCallback;
-  }
-}
diff --git a/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/status/LockWrapper.java b/plugins/svn4idea/bindSvn/src/org/jetbrains/idea/svn/status/LockWrapper.java
deleted file mode 100644 (file)
index f4e0f4c..0000000
+++ /dev/null
@@ -1,121 +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.jetbrains.idea.svn.status;
-
-import org.apache.subversion.javahl.types.Lock;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Date;
-
-/**
- * Created with IntelliJ IDEA.
- * User: Irina.Chernushina
- * Date: 2/21/12
- * Time: 2:33 PM
- */
-public class LockWrapper {
-  private String myPath;
-  private String myID;
-  private String myOwner;
-  private String myComment;
-  private Date myCreationDate;
-  private Date myExpirationDate;
-
-  public LockWrapper(String path, String ID, String owner, String comment, Date creationDate, Date expirationDate) {
-    myPath = path;
-    myID = ID;
-    myOwner = owner;
-    myComment = comment;
-    myCreationDate = creationDate;
-    myExpirationDate = expirationDate;
-  }
-
-  public LockWrapper() {
-  }
-
-  public String getPath() {
-    return myPath;
-  }
-
-  public void setPath(String path) {
-    myPath = path;
-  }
-
-  public String getID() {
-    return myID;
-  }
-
-  public void setID(String ID) {
-    myID = ID;
-  }
-
-  public String getOwner() {
-    return myOwner;
-  }
-
-  public void setOwner(String owner) {
-    myOwner = owner;
-  }
-
-  public String getComment() {
-    return myComment;
-  }
-
-  public void setComment(String comment) {
-    myComment = comment;
-  }
-
-  public Date getCreationDate() {
-    return myCreationDate;
-  }
-
-  public void setCreationDate(Date creationDate) {
-    myCreationDate = creationDate;
-  }
-
-  public Date getExpirationDate() {
-    return myExpirationDate;
-  }
-
-  public void setExpirationDate(Date expirationDate) {
-    myExpirationDate = expirationDate;
-  }
-
-  public org.tigris.subversion.javahl.Lock create() {
-    final Date creation = getCreationDate();
-    final Date expiration = getExpirationDate();
-    final Lock newLock = new Lock(getOwner(), getPath(), getID(), getComment(), creation == null ? 0 : creation.getTime(),
-                               expiration == null ? 0 : expiration.getTime());
-    try {
-      final Constructor<org.tigris.subversion.javahl.Lock> 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 (file)
index f8acc17..0000000
+++ /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;
-  }
-}
index 4559a3e603e2bcc2a1de87a3910617a7828d6d97..6a62276b3a1adf25164702777c998cd7cef793be 100644 (file)
@@ -49,11 +49,9 @@ public class ForNestedRootChecker {
 
   private static class UrlConstructor {
     final SvnVcs myVcs;
-    final SVNWCClient myClient;
 
     private UrlConstructor(final SvnVcs vcs) {
       myVcs = vcs;
-      myClient = myVcs.createWCClient();
     }
 
     @Nullable
index 6cd0df2744d14235041b309b06cfa296cf42a324..5ca7f9eaa39b6530323c41e6ea2c597db60ebe14 100644 (file)
@@ -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() {
index b4fd10492dfb39fea8ed47a58b30134175f4ca92..29e87422bb53298032f259380044e3793904a3c9 100644 (file)
@@ -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<String, Lock> myLockMap = new HashMap<String, Lock>();
index 8a94f0076acfcd0e3905697ce6436e0346b6165f..4efcce6f0db62ec103cc8e28d4a6ebf75d389d43 100644 (file)
@@ -350,7 +350,9 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
     }
     SvnInteractiveAuthenticationProvider.clearCallState();
     try {
+      // start svnkit authentication cycle
       SvnVcs.getInstance(project).createWCClient(manager).doInfo(url, SVNRevision.UNDEFINED, SVNRevision.HEAD);
+      //SvnVcs.getInstance(project).getInfo(url, SVNRevision.HEAD, manager);
     } catch (SVNAuthenticationException e) {
       log(e);
       return false;
index c306386eb0f896eca8169bc41497376a4d03c25c..61a5bb26f6636ac14fd869161c38c721da0af21c 100644 (file)
@@ -537,6 +537,7 @@ dialog.show.svn.map.table.version14.text=1.4
 dialog.show.svn.map.table.version15.text=1.5
 dialog.show.svn.map.table.version16.text=1.6
 dialog.show.svn.map.table.version17.text=1.7
+dialog.show.svn.map.table.version18.text=1.8
 action.change.wcopy.format.task.title=Convert working copy format
 action.change.wcopy.format.task.progress.text=Converting working copy at {0} format from {1} to {2}
 action.change.wcopy.format.after.change.settings=Selected working copy format ({0}) is older than upgrade mode selected in Project Settings ({1}).\
index dc8cbb1cce8b7812ff7e122609257a0e766f567f..b28ebd53dde26db56458d98325765742543c40f4 100644 (file)
@@ -85,7 +85,7 @@ public class SvnChangeProvider implements ChangeProvider {
       statusReceiver.addListener(context);
       statusReceiver.addListener(nestedCopiesBuilder);
 
-      final SvnRecursiveStatusWalker walker = new SvnRecursiveStatusWalker(myVcs.getProject(), statusReceiver.getMulticaster(), partner);
+      final SvnRecursiveStatusWalker walker = new SvnRecursiveStatusWalker(myVcs, statusReceiver.getMulticaster(), partner);
 
       for (FilePath path : zipper.getRecursiveDirs()) {
         walker.go(path, SVNDepth.INFINITY);
@@ -180,7 +180,7 @@ public class SvnChangeProvider implements ChangeProvider {
   public void getChanges(final FilePath path, final boolean recursive, final ChangelistBuilder builder) throws SVNException {
     final SvnChangeProviderContext context = new SvnChangeProviderContext(myVcs, builder, null);
     final StatusWalkerPartnerImpl partner = new StatusWalkerPartnerImpl(myVcs, ProgressManager.getInstance().getProgressIndicator());
-    final SvnRecursiveStatusWalker walker = new SvnRecursiveStatusWalker(myVcs.getProject(), context, partner);
+    final SvnRecursiveStatusWalker walker = new SvnRecursiveStatusWalker(myVcs, context, partner);
     walker.go(path, recursive ? SVNDepth.INFINITY : SVNDepth.IMMEDIATES);
     processCopiedAndDeleted(context, null);
   }
index 40c34d394590d4aef28c063269bf4ca08a65078c..9689dcee4a719cecf2d57cc69d91186c3524fda1 100644 (file)
@@ -259,23 +259,15 @@ class SvnChangeProviderContext implements StatusReceiver {
   
   public void addModifiedNotSavedChange(final VirtualFile file) throws SVNException {
     final FilePath filePath = new FilePathImpl(file);
-    final SVNInfo svnInfo;
-    try {
-      svnInfo = myVcs.createWCClient().doInfo(new File(file.getPath()), SVNRevision.UNDEFINED);
+    final SVNInfo svnInfo = myVcs.getInfo(file);
+
+    if (svnInfo != null) {
+      final SVNStatus svnStatus = new SVNStatus();
+      svnStatus.setRevision(svnInfo.getRevision());
+      myChangelistBuilder.processChangeInList(
+        createChange(SvnContentRevision.createBaseRevision(myVcs, filePath, svnInfo.getRevision()), CurrentContentRevision.create(filePath),
+                     FileStatus.MODIFIED, svnStatus), (String)null, SvnVcs.getKey());
     }
-    catch (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)) {
-        return;
-      }
-      throw e;
-    }
-    final SVNStatus svnStatus = new SVNStatus();
-    svnStatus.setRevision(svnInfo.getRevision());
-    myChangelistBuilder.processChangeInList(createChange(SvnContentRevision.createBaseRevision(myVcs, filePath, svnInfo.getRevision()),
-                                             CurrentContentRevision.create(filePath), FileStatus.MODIFIED, svnStatus), (String) null,
-                                            SvnVcs.getKey());
   }
 
   private void checkSwitched(final FilePath filePath, final ChangelistBuilder builder, final SVNStatus status,
index ee326a42afb2145b8a1599f5cfa63d244c318e1f..51d5dc486c517b4ff3f699ae126e12ce0199e584 100644 (file)
@@ -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) {
index e4f0e7c8ae7e74386a3a6d26562adccd8df55ac0..55f7512fbb81ebba8e96c986cf6d7b16af4e8935 100644 (file)
@@ -18,7 +18,7 @@
         <properties/>
         <border type="none"/>
         <children>
-          <grid id="2ae3a" layout-manager="GridLayoutManager" row-count="6" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+          <grid id="2ae3a" layout-manager="GridLayoutManager" row-count="5" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
             <margin top="0" left="0" bottom="0" right="0"/>
             <constraints>
               <tabbedpane title="General"/>
@@ -29,7 +29,7 @@
               <grid id="a4729" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
                 <margin top="0" left="0" bottom="0" right="0"/>
                 <constraints>
-                  <grid row="3" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                  <grid row="2" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
                 </constraints>
                 <properties/>
                 <border type="none"/>
@@ -87,7 +87,7 @@
               </grid>
               <component id="df054" class="javax.swing.JCheckBox" binding="myUseDefaultCheckBox">
                 <constraints>
-                  <grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                  <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
                 </constraints>
                 <properties>
                   <text resource-bundle="org/jetbrains/idea/svn/SvnBundle" key="checkbox.configure.use.system.default.configuration.directory"/>
@@ -96,7 +96,7 @@
               <grid id="137aa" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
                 <margin top="0" left="0" bottom="0" right="0"/>
                 <constraints>
-                  <grid row="5" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                  <grid row="4" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
                 </constraints>
                 <properties/>
                 <border type="none"/>
               </grid>
               <hspacer id="e8f24">
                 <constraints>
-                  <grid row="5" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                  <grid row="4" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
                 </constraints>
               </hspacer>
               <vspacer id="aa6b2">
                 <constraints>
-                  <grid row="4" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+                  <grid row="3" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
                 </constraints>
               </vspacer>
-              <component id="300b5" class="javax.swing.JLabel">
-                <constraints>
-                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-                </constraints>
-                <properties>
-                  <text value="Subversion 1.7 Acceleration"/>
-                </properties>
-              </component>
               <grid id="12735" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
                 <margin top="0" left="0" bottom="0" right="0"/>
                 <constraints>
-                  <grid row="1" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                  <grid row="0" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
                 </constraints>
                 <properties/>
                 <border type="none"/>
                 <children>
                   <component id="3ecd1" class="com.intellij.ui.components.JBCheckBox" binding="myWithCommandLineClient">
                     <constraints>
-                      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="2" use-parent-layout="false"/>
+                      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
                     </constraints>
                     <properties>
-                      <text value="with command line client:"/>
+                      <margin top="2" left="3" bottom="2" right="3"/>
+                      <text value="Use command line client:"/>
                     </properties>
                   </component>
                   <component id="44a8" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myCommandLineClient">
index 38c099ba4136e4f1c27b1720320fd6d13870d809..cff64beea8b2a31d6676f6db9fa436b2c2936fcb 100644 (file)
@@ -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
index 2a8a00aa1ae60a6721c35108df5dd362c8ca8548..813d41c48e2486fc395755c2b2d470433431a0db 100644 (file)
@@ -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;
@@ -26,8 +27,10 @@ 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.SVNPropertyValue;
 import org.tmatesoft.svn.core.SVNURL;
 import org.tmatesoft.svn.core.wc.*;
 
@@ -43,19 +46,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,53 +61,36 @@ 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 = 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(SVNWCClient client, File path) throws SVNException {
-    final String[] message = new String[1];
-    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 String getCommitMessage(File path) throws VcsException {
+    SVNPropertyData property =
+      myVcs.getFactory(path).createPropertyClient().getProperty(path, COMMIT_MESSAGE, true, null, SVNRevision.BASE);
 
-      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() {
@@ -135,18 +114,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 +165,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) {
index 062c412f2336bdea9f03510b8b8c0035df7f1134..da1adc60327c6770ccbd43266c8de1ea7d3aa4b5 100644 (file)
@@ -44,10 +44,7 @@ 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.tmatesoft.svn.core.*;
 import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
 import org.tmatesoft.svn.core.wc.*;
 
@@ -160,10 +157,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 +172,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) {
@@ -244,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);
@@ -283,29 +281,18 @@ 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;
     }
     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 {
@@ -317,15 +304,9 @@ 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);
         }
-        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);
@@ -333,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();
   }
@@ -357,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;
             }
           }
@@ -464,7 +448,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;
     }
@@ -476,12 +460,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);
@@ -507,13 +487,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
@@ -529,6 +503,41 @@ 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) {
+          wrapAndThrow(e);
+        }
+      }
+    };
+  }
+
+  @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) {
+          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), e);
+  }
+
   private boolean isAboveSourceOfCopyOrMove(final Project p, File ioFile) {
     for (MovedFileInfo file : myMovedFiles) {
       if (FileUtil.isAncestor(ioFile, file.mySrc, false)) return true;
@@ -583,7 +592,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);
 
@@ -603,12 +611,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));
@@ -759,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 {
@@ -771,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();
                     }
@@ -793,7 +798,12 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
               new RepeatSvnActionThroughBusy() {
                 @Override
                 protected void executeImpl() throws SVNException {
-                  wcClient.doAdd(ioFile, true, false, false, true);
+                  try {
+                    vcs.getFactory(ioFile).createAddClient().add(ioFile, null, false, false, true, null);
+                  }
+                  catch (VcsException e) {
+                    wrapAndThrow(e);
+                  }
                 }
               }.execute();
             }
@@ -915,17 +925,11 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
                                         final List<VcsException> 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);
@@ -978,18 +982,15 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
   private void fillDeletedFiles(Project project, List<Pair<FilePath, WorkingCopyFormat>> deletedFiles, Collection<FilePath> deleteAnyway)
     throws SVNException {
     final SvnVcs vcs = SvnVcs.getInstance(project);
-    final SVNStatusClient sc = vcs.createStatusClient();
     final Collection<File> 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);
@@ -1034,18 +1035,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();
     }
index 46545c43a4cc7fc5c4ea4b6729f3b5f3b212f1ef..68e7c07848c236ea0dbdffd3b2bb603202e5dbc4 100644 (file)
@@ -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));
           }
         }
       }
@@ -541,8 +541,9 @@ public class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentState
       final SVNInfo svnInfo = vcs.getInfo(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);
     }
   }
index 94d21dbbbd9df8545c7e037464deba5929853689..77783badc2f85a496bc950f7dc65b27b1b5aadb2 100644 (file)
@@ -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;
index 97b87efaa7f95744fc7884593f35e40aa4cae9d5..fcac3966c2d6c8d70711a9560531765746312aba 100644 (file)
@@ -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<LearningProxy<SVNChangelistClientI, SVNException>> myChangelist;
index 4a49dc16a15301b6cf6c97ec0693f90c9418a6a8..8b518199f5be20c3a045738b277c07a675e7a333 100644 (file)
@@ -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<MyItem> 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<MyItem>();
@@ -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,20 +142,20 @@ public class SvnRecursiveStatusWalker {
       return myDepth;
     }
 
-    public SvnStatusClientI getClient() {
-      return mySvnClient;
-    }
-    
     public SvnStatusClientI getClient(final File file) {
-      if (! SVNDepth.INFINITY.equals(myDepth)) {
-        return mySvnClient;
+      WorkingCopyFormat format = myVcs.getWorkingCopyFormat(file);
+
+      if (format == WorkingCopyFormat.ONE_DOT_EIGHT) {
+        return myCommandLineClient;
       }
+
       // check format
       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 +190,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 +232,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 +299,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);
           }
index 853e995ca219968f96788efa8d2739927d7ebfbf..efea2f93de08bc03bbaf7cefc6f72409240698da 100644 (file)
@@ -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;
 
index 0c049ac4671d716d8f4333d59a35569f17144d32..7cd6bdd91d3facfdd624bfed39902365f61526c7 100644 (file)
@@ -30,21 +30,19 @@ 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.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;
 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.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;
@@ -53,14 +51,14 @@ 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 {
+  // 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";
@@ -71,13 +69,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<VirtualFile> crawlWCRoots(final Project project, File path, SvnWCRootCrawler callback, ProgressIndicator progress) {
@@ -123,15 +117,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<String, File> getLocationInfoForModule(final SvnVcs vcs, File path, ProgressIndicator progress) {
@@ -288,7 +275,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 +341,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<String, File> myLocations;
@@ -371,15 +408,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 +420,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 +437,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 +452,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 +565,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 +599,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 +653,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 +671,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));
@@ -703,44 +734,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 {
-    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);
-      }
+    ClientFactory factory = target.isFile() ? vcs.getFactory(target.getFile()) : vcs.getFactory();
 
-      @Override
-      public synchronized void write(byte[] b, int off, int len) {
-        if (size() > maxSize) throw new FileTooBigRuntimeException();
-        super.write(b, off, len);
-      }
+    return factory.createContentClient().getContent(target, revision, pegRevision);
+  }
 
-      @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 {}
 }
index 748fc86c694c4f19c2e84d0d5dc8849f92526a75..3ad265cfa110a7207aa40159234e32460639632a 100644 (file)
@@ -68,8 +68,12 @@ 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;
 import org.jetbrains.idea.svn.commandLine.SvnExecutableChecker;
 import org.jetbrains.idea.svn.dialogs.SvnBranchPointsCalculator;
 import org.jetbrains.idea.svn.dialogs.WCInfo;
@@ -79,6 +83,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;
@@ -195,6 +200,10 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
   };
   private SvnCheckoutProvider myCheckoutProvider;
 
+  private ClientFactory cmdClientFactory;
+  private ClientFactory svnKitClientFactory;
+
+
   public void checkCommandLineVersion() {
     myChecker.checkExecutableAndNotifyIfNeeded();
   }
@@ -481,6 +490,9 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
       myChecker.checkExecutableAndNotifyIfNeeded();
     }
 
+    cmdClientFactory = new CmdClientFactory(this);
+    svnKitClientFactory = new SvnKitClientFactory(this);
+
     // do one time after project loaded
     StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() {
       @Override
@@ -911,24 +923,125 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
     return new File(file, pathToDirProps);
   }
 
+  /**
+   * 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 {
+      result = SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration.myUseAcceleration)
+               ? getInfoCommandLine(file, SVNRevision.UNDEFINED)
+               : getInfoSvnKit(file);
+    }
+    catch (SVNException e) {
+      handleInfoException(e);
+    }
+
+    return result;
+  }
+
+  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, pegRevision, revision);
+    } else {
+      return (manager != null ? createWCClient(manager) : createWCClient()).doInfo(url, pegRevision, revision);
+    }
+  }
+
+  public SVNInfo getInfo(@NotNull SVNURL url, SVNRevision revision) throws SVNException {
+    return getInfo(url, SVNRevision.UNDEFINED, 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, SVNRevision.UNDEFINED) : runInfoCommand(ioFile);
     }
     catch (SVNException e) {
-      return null;
+      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);
+    }
+
+    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 {
+    SVNInfo info = getInfoSvnKit(ioFile, SVNRevision.UNDEFINED);
+    if (info == null || info.getRepositoryRootURL() == null) {
+      info = getInfoSvnKit(ioFile, SVNRevision.HEAD);
+    }
+    return info;
+  }
+
+  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, revision);
+  }
+
+  private SvnWcClientI createInfoClient() {
+    return new SvnCommandLineInfoClient(myProject);
+  }
+
+  public WorkingCopyFormat getWorkingCopyFormat(@NotNull File ioFile) {
+    RootUrlInfo rootInfo = getSvnFileUrlMapping().getWcRootForFilePath(ioFile);
+    WorkingCopyFormat format = rootInfo != null ? rootInfo.getFormat() : WorkingCopyFormat.UNKNOWN;
+
+    if (WorkingCopyFormat.UNKNOWN.equals(format)) {
+      format = SvnFormatSelector.findRootAndGetFormat(ioFile);
+    }
+
+    return format;
   }
 
   public void refreshSSLProperty() {
@@ -1245,4 +1358,27 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
     }
     return myCheckoutProvider;
   }
+
+  /**
+   * 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
+   */
+  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) {
+    WorkingCopyFormat format = getWorkingCopyFormat(file);
+
+    return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) ? cmdClientFactory : getFactory();
+  }
 }
index 36e0b08c5a86c9553e40172fe16c08eb7d14c9d3..ca97edb1c228b956012aae543bcfd93ba7d3eb24 100644 (file)
@@ -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;
 
index d40f947a71ee0288855a38e6e914b92e75f13bdb..c007541816c5b68e5bfb9a4439a8e243023ec3ab 100644 (file)
  */
 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;
index 06c255b6ed38e8ecd04c5a6fe38a9fb6420a8ad8..7558a483fcd7d84cea1feb4f6023e89b18732604 100644 (file)
@@ -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<VirtualFile> additionallyDirty = new HashSet<VirtualFile>();
             final FileStatusManager fileStatusManager = FileStatusManager.getInstance(project);
             for (VirtualFile item : items) {
@@ -84,13 +80,13 @@ public class AddAction extends BasicAction {
                 }
               }
             }
-            Collection<SVNException> exceptions =
-              SvnCheckinEnvironment.scheduleUnversionedFilesForAddition(wcClient, Arrays.asList(items), true);
+            Collection<VcsException> exceptions =
+              SvnCheckinEnvironment.scheduleUnversionedFilesForAddition(activeVcs, Arrays.asList(items), true);
             additionallyDirty.addAll(Arrays.asList(items));
             markDirty(project, additionallyDirty);
             if (!exceptions.isEmpty()) {
               final Collection<String> messages = new ArrayList<String>(exceptions.size());
-              for (SVNException exception : exceptions) {
+              for (VcsException exception : exceptions) {
                 messages.add(exception.getMessage());
               }
               throw new VcsException(messages);
index 87b36970228b73898829a7f419f466252324ae44..d65c6d3c9c20599e941dfb2bdda3bfd11c078351 100644 (file)
@@ -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<String> collectResolvablePaths(final SvnVcs vcs, VirtualFile[] files) {
     final Collection<String> target = new TreeSet<String>();
-    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;
index 4c582d01557d920e6e362a0e36b8c7ff81d6da7d..3130dc948c130549ccc718f6cc693e002223350a 100644 (file)
@@ -27,12 +27,13 @@ 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.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;
@@ -57,38 +58,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();
+        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);
+          }
+          if (mergeCase) {
+            // this is merge case
+            oldFile = info.getConflictNewFile();
+            newFile = info.getConflictOldFile();
             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());
           }
-        }
-        catch (SVNException e) {
-          throw new VcsException(e);
+          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 +96,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 +111,17 @@ public class SvnMergeProvider implements MergeProvider {
     return data;
   }
 
-  private ByteArrayOutputStream getBaseRevisionContents(SVNWCClient client, VirtualFile file) {
+  private ByteArrayOutputStream getBaseRevisionContents(@NotNull SvnVcs vcs, @NotNull VirtualFile file) {
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
     try {
-      client.doGetFileContents(new File(file.getPath()), SVNRevision.UNDEFINED, SVNRevision.BASE, true, bos);
+      byte[] contents = SvnUtil.getFileContents(vcs, SvnTarget.fromFile(new File(file.getPath())), 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 +136,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();
@@ -152,17 +154,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, false, 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/add/AddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/AddClient.java
new file mode 100644 (file)
index 0000000..718a56d
--- /dev/null
@@ -0,0 +1,23 @@
+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;
+
+/**
+ * @author Konstantin Kolosovsky.
+ */
+public interface AddClient extends SvnClient {
+
+  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
new file mode 100644 (file)
index 0000000..c786671
--- /dev/null
@@ -0,0 +1,69 @@
+package org.jetbrains.idea.svn.add;
+
+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.tmatesoft.svn.core.SVNDepth;
+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 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,
+                  @Nullable SVNDepth depth,
+                  boolean makeParents,
+                  boolean includeIgnored,
+                  boolean force,
+                  @Nullable ISVNEventHandler handler) throws VcsException {
+    List<String> parameters = prepareParameters(file, depth, makeParents, includeIgnored, force);
+
+    // 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<String> prepareParameters(File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) {
+    List<String> parameters = new ArrayList<String>();
+
+    CommandUtil.put(parameters, file);
+    CommandUtil.put(parameters, depth);
+    CommandUtil.put(parameters, makeParents, "--parents");
+    CommandUtil.put(parameters, includeIgnored, "--no-ignore");
+    CommandUtil.put(parameters, force, "--force");
+
+    return parameters;
+  }
+
+  private static class AddStatusConvertor implements Convertor<Matcher, SVNEvent> {
+    @Override
+    public SVNEvent convert(Matcher o) {
+      SVNStatusType contentStatus = CommandUtil.getStatusType(o.group(1));
+      String path = o.group(3);
+
+      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/add/SvnKitAddClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/add/SvnKitAddClient.java
new file mode 100644 (file)
index 0000000..d6250c7
--- /dev/null
@@ -0,0 +1,39 @@
+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;
+
+/**
+ * @author Konstantin Kolosovsky.
+ */
+public class SvnKitAddClient extends BaseSvnClient implements AddClient {
+
+  @Override
+  public void add(@NotNull File file,
+                  @Nullable SVNDepth depth,
+                  boolean makeParents,
+                  boolean includeIgnored,
+                  boolean force,
+                  @Nullable ISVNEventHandler handler) throws VcsException {
+    try {
+      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/annotate/AnnotateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/AnnotateClient.java
new file mode 100644 (file)
index 0000000..df30cfd
--- /dev/null
@@ -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 (file)
index 0000000..d29d40e
--- /dev/null
@@ -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<String> parameters = new ArrayList<String>();
+    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<LineEntry> 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;
+  }
+}
index d0885c8a293e453cc2b01716f6e9721ef2bcc862..cd43da7c4d20dbbf289b90fa133477d860c8c190 100644 (file)
@@ -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, SvnTarget.fromFile(ioFile), 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();
@@ -99,16 +100,13 @@ 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;
           }
           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();
@@ -124,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<SVNRevision> 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) {
@@ -137,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<SvnChangeList,ChangeBrowserSettings> provider = myVcs.getCommittedChangesProvider();
-            try {
-              final Pair<SvnChangeList, FilePath> 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;
+          }
         }
       }
     };
@@ -177,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<SvnChangeList,ChangeBrowserSettings> provider = myVcs.getCommittedChangesProvider();
+      try {
+        final Pair<SvnChangeList, FilePath> 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();
@@ -214,8 +232,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());
     }
@@ -225,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, 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);
     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;
   }
 
@@ -370,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,
@@ -395,7 +409,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
       myRevisionPoints = new LinkedList<SVNRevision>();
     }
 
-    public void go() throws SVNException {
+    public void go() throws VcsException {
       final int maxAnnotateRevisions = SvnConfiguration.getInstance(myVcs.getProject()).getMaxAnnotateRevisions();
       boolean longHistory = true;
       if (maxAnnotateRevisions == -1) {
@@ -437,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) {
@@ -464,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 (file)
index 0000000..315178c
--- /dev/null
@@ -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/BaseSvnClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java
new file mode 100644 (file)
index 0000000..54401cf
--- /dev/null
@@ -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 (file)
index 0000000..b851216
--- /dev/null
@@ -0,0 +1,99 @@
+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.content.ContentClient;
+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;
+
+/**
+ * @author Konstantin Kolosovsky.
+ */
+public abstract class ClientFactory {
+
+  @NotNull
+  protected SvnVcs myVcs;
+
+  protected AddClient addClient;
+  protected AnnotateClient annotateClient;
+  protected ContentClient contentClient;
+  protected HistoryClient historyClient;
+  protected RevertClient revertClient;
+  protected DeleteClient deleteClient;
+  protected SvnStatusClientI statusClient;
+  protected CopyMoveClient copyMoveClient;
+  protected ConflictClient conflictClient;
+  protected PropertyClient propertyClient;
+
+  protected ClientFactory(@NotNull SvnVcs vcs) {
+    myVcs = vcs;
+    setup();
+  }
+
+  protected abstract void setup();
+
+  @NotNull
+  public AddClient createAddClient() {
+    return prepare(addClient);
+  }
+
+  @NotNull
+  public AnnotateClient createAnnotateClient() {
+    return prepare(annotateClient);
+  }
+
+  @NotNull
+  public ContentClient createContentClient() {
+    return prepare(contentClient);
+  }
+
+  @NotNull
+  public HistoryClient createHistoryClient() {
+    return prepare(historyClient);
+  }
+
+  @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
+  public DeleteClient createDeleteClient() {
+    return prepare(deleteClient);
+  }
+
+  @NotNull
+  public CopyMoveClient createCopyMoveClient() {
+    return prepare(copyMoveClient);
+  }
+
+  @NotNull
+  public ConflictClient createConflictClient() {
+    return prepare(conflictClient);
+  }
+
+  @NotNull
+  public PropertyClient createPropertyClient() {
+    return prepare(propertyClient);
+  }
+
+  @NotNull
+  protected <T extends SvnClient> 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
new file mode 100644 (file)
index 0000000..ca4088b
--- /dev/null
@@ -0,0 +1,38 @@
+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.content.CmdContentClient;
+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;
+
+/**
+ * @author Konstantin Kolosovsky.
+ */
+public class CmdClientFactory extends ClientFactory {
+
+  public CmdClientFactory(@NotNull SvnVcs vcs) {
+    super(vcs);
+  }
+
+  @Override
+  protected void setup() {
+    addClient = new CmdAddClient();
+    annotateClient = new CmdAnnotateClient();
+    contentClient = new CmdContentClient();
+    historyClient = new CmdHistoryClient();
+    revertClient = new CmdRevertClient();
+    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/FileStatusResultParser.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/FileStatusResultParser.java
new file mode 100644 (file)
index 0000000..fc202c2
--- /dev/null
@@ -0,0 +1,68 @@
+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<Matcher, SVNEvent> myConvertor;
+
+  public FileStatusResultParser(@NotNull Pattern linePattern,
+                                @Nullable ISVNEventHandler handler,
+                                @NotNull Convertor<Matcher, SVNEvent> convertor) {
+    myLinePattern = linePattern;
+    this.handler = handler;
+    myConvertor = convertor;
+  }
+
+  public void parse(@NotNull String output) throws VcsException {
+    if (StringUtil.isEmpty(output)) {
+      return;
+    }
+
+    for (String line : StringUtil.splitByLines(output)) {
+      onLine(line);
+    }
+  }
+
+  public void onLine(@NotNull String line) throws VcsException {
+    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 {
+    if (handler != null) {
+      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/api/SvnClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnClient.java
new file mode 100644 (file)
index 0000000..90124f1
--- /dev/null
@@ -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 (file)
index 0000000..7e19518
--- /dev/null
@@ -0,0 +1,38 @@
+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.content.SvnKitContentClient;
+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;
+
+/**
+ * @author Konstantin Kolosovsky.
+ */
+public class SvnKitClientFactory extends ClientFactory {
+
+  public SvnKitClientFactory(@NotNull SvnVcs vcs) {
+    super(vcs);
+  }
+
+  @Override
+  protected void setup() {
+    addClient = new SvnKitAddClient();
+    annotateClient = new SvnKitAnnotateClient();
+    contentClient = new SvnKitContentClient();
+    historyClient = new SvnKitHistoryClient();
+    revertClient = new SvnKitRevertClient();
+    deleteClient = new SvnKitDeleteClient();
+    copyMoveClient = new SvnKitCopyMoveClient();
+    conflictClient = new SvnKitConflictClient();
+    propertyClient = new SvnKitPropertyClient();
+    statusClient = new SvnkitSvnStatusClient(myVcs.createStatusClient());
+  }
+}
index 021568aac806b575a4c5106a0fcdd134e4221b06..2b779fd0de701240b8a3eb7f8cd11f25d8f6ab97 100644 (file)
@@ -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;
index 28e74e7c395e0e474063d0849318181ae9c8ff66..483bfda7cfd386c60070397aeca530a48cc1ab86 100644 (file)
@@ -223,9 +223,8 @@ public class SvnBranchConfigurationNew {
     private BranchRootSearcher(final SvnVcs vcs, final VirtualFile root) throws SVNException {
       myRoot = root;
       myBranchesUnder = new HashMap<String, String>();
-      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 {
index 3bd8256e7b02b3e3985fad2d7b8e66c0701bd9a0..5ac6b967777e62eaa3d35ad3035f87376e5c156e 100644 (file)
@@ -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;
index 995646f50d45770efccf23c955f5bf3844f06daf..f765595745b38a69f69338bb80878cc54c9c319c 100644 (file)
@@ -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;
@@ -77,6 +78,20 @@ 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) {
+    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
   public boolean acceptSSLServerCertificate(final File file, final String realm) {
     final File base = getExistingParent(file);
@@ -354,7 +369,9 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall
                                     }, new ThrowableRunnable<SVNException>() {
                                       @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);
                                       }
                                     }
       );
index 433e4063e02c000e001c309b2efb88a89d8eacae..c7d2d4b41bf23a01a96f5161beedb21e94e9821d 100644 (file)
@@ -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.*;
 
@@ -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);
@@ -256,14 +256,25 @@ 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<String[], SVNURL>() {
+        @Override
+        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;
+        }
+      });
       client.setAuthenticationCallback(authenticationCallback);
       client.setHandler(new IdeaCommitHandler(ProgressManager.getInstance().getProgressIndicator()));
       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();
     }
@@ -348,25 +359,19 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
   private List<File> getCommitables(List<File> 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 +379,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<File> collectPaths(final List<Change> changes) {
     // case sensitive..
     ArrayList<File> result = new ArrayList<File>();
@@ -418,15 +445,14 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
 
   public List<VcsException> scheduleMissingFileForDeletion(List<FilePath> filePaths) {
     List<VcsException> exceptions = new ArrayList<VcsException>();
-    final SVNWCClient wcClient = mySvnVcs.createWCClient();
-
     List<File> 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);
       }
     }
 
@@ -434,30 +460,22 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
   }
 
   public List<VcsException> scheduleUnversionedFilesForAddition(List<VirtualFile> files) {
-    final List<VcsException> result = new ArrayList<VcsException>();
-    final SVNWCClient wcClient = mySvnVcs.createWCClient();
-
-    final List<SVNException> exceptionList = scheduleUnversionedFilesForAddition(wcClient, files);
-    for (SVNException svnException : exceptionList) {
-      result.add(new VcsException(svnException));
-    }
-    return result;
+    return scheduleUnversionedFilesForAddition(mySvnVcs, files);
   }
 
-  public static List<SVNException> scheduleUnversionedFilesForAddition(SVNWCClient wcClient, List<VirtualFile> files) {
-    return scheduleUnversionedFilesForAddition(wcClient, files, false);
+  public static List<VcsException> scheduleUnversionedFilesForAddition(@NotNull SvnVcs vcs, List<VirtualFile> files) {
+    return scheduleUnversionedFilesForAddition(vcs, files, false);
   }
 
-  public static List<SVNException> scheduleUnversionedFilesForAddition(SVNWCClient wcClient, List<VirtualFile> files, final boolean recursive) {
-    List<SVNException> exceptions = new ArrayList<SVNException>();
-
+  public static List<VcsException> scheduleUnversionedFilesForAddition(@NotNull SvnVcs vcs, List<VirtualFile> 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() + ")"));
@@ -472,12 +490,18 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
           if (pi.isCanceled()) throw new SVNCancelException();
         }
       }
-    });
+    };
+
+    List<VcsException> exceptions = new ArrayList<VcsException>();
+
     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);
       }
     }
similarity index 87%
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 bdc9c2deb03c4fbdce8d2808f99bbfcf5a334d6b..1944749f360860a07ed29c5b14e81395f8c253a4 100644 (file)
  * 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;
+import org.tmatesoft.svn.core.auth.SVNAuthentication;
 
 import java.io.File;
 import java.io.IOException;
@@ -50,6 +52,17 @@ 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);
+
   /**
    * @return config directory if TMP was created
    */
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 (file)
index 0000000..737d8a8
--- /dev/null
@@ -0,0 +1,218 @@
+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.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;
+
+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(@NotNull SvnCommandName name,
+                                         @NotNull SvnVcs vcs,
+                                         @Nullable File base,
+                                         @Nullable SVNURL url,
+                                         List<String> parameters)
+    throws SVNException {
+    String exe = resolveExePath();
+    base = resolveBaseDirectory(base, exe);
+    url = resolveRepositoryUrl(vcs, url);
+
+    try {
+      return SvnLineCommand
+        .runWithAuthenticationAttempt(exe, base, url, name, new SvnCommitRunner.CommandListener(null),
+                                      new IdeaSvnkitBasedAuthenticationCallback(vcs), ArrayUtil.toStringArray(parameters));
+    }
+    catch (SvnBindException 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()
+    return runSimple(SvnCommandName.empty, vcs, base, url, new ArrayList<String>(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<String> parameters, boolean condition, @NotNull String value) {
+    if (condition) {
+      parameters.add(value);
+    }
+  }
+
+  public static void put(@NotNull List<String> parameters, @NotNull File path) {
+    parameters.add(path.getAbsolutePath());
+  }
+
+  public static void put(@NotNull List<String> parameters, @NotNull File path, @Nullable SVNRevision pegRevision) {
+    put(parameters, path.getAbsolutePath(), pegRevision);
+  }
+
+  public static void put(@NotNull List<String> parameters, @NotNull String path, @Nullable SVNRevision pegRevision) {
+    StringBuilder builder = new StringBuilder(path);
+
+    if (pegRevision != null && !SVNRevision.UNDEFINED.equals(pegRevision) && !SVNRevision.WORKING.equals(pegRevision) &&
+        pegRevision.getNumber() > 0) {
+      builder.append("@");
+      builder.append(pegRevision);
+    }
+
+    parameters.add(builder.toString());
+  }
+
+  public static void put(@NotNull List<String> parameters, @NotNull File... paths) {
+    for (File path : paths) {
+      put(parameters, path);
+    }
+  }
+
+  public static void put(@NotNull List<String> parameters, @Nullable SVNDepth depth) {
+    if (depth != null && !SVNDepth.UNKNOWN.equals(depth)) {
+      parameters.add("--depth");
+      parameters.add(depth.getName());
+    }
+  }
+
+  public static void put(@NotNull List<String> 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<String> 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.
+   * // TODO: Should be replaced with non-static analogue.
+   *
+   * @param vcs
+   * @param name
+   * @param parameters
+   * @param parser
+   * @throws VcsException
+   */
+  public static SvnCommand execute(@NotNull SvnVcs vcs,
+                                   @NotNull SvnCommandName name,
+                                   @NotNull List<String> parameters,
+                                   @Nullable FileStatusResultParser parser)
+    throws VcsException {
+    String exe = resolveExePath();
+    File base = resolveBaseDirectory(null, exe);
+    SVNURL url = resolveRepositoryUrl(vcs, null);
+
+    SvnLineCommand command = SvnLineCommand.runWithAuthenticationAttempt(
+      exe, base, url, name, new SvnCommitRunner.CommandListener(null),
+      new IdeaSvnkitBasedAuthenticationCallback(vcs),
+      ArrayUtil.toStringArray(parameters));
+
+    if (parser != null) {
+      parser.parse(command.getOutput());
+    }
+
+    return command;
+  }
+
+  /**
+   * 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;
+  }
+}
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 7f3bcf3bf4a5d47f6543ac03ab5eba1c2f49adbe..d74884073863a70238415819aa0a2185b7fb234e 100644 (file)
@@ -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;
 
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 46609e40532c5ba0eda69737b4b4d21587b8a1e7..87dc212d034132c95da328d75d33921cbd65a74d 100644 (file)
@@ -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/src/org/jetbrains/idea/svn/commandLine/SvnBindClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindClient.java
new file mode 100644 (file)
index 0000000..8f14cb2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.jetbrains.idea.svn.commandLine;
+
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.util.containers.Convertor;
+import org.tmatesoft.svn.core.SVNURL;
+
+import java.util.Map;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Irina.Chernushina
+ * Date: 2/5/13
+ * Time: 3:08 PM
+ */
+public class SvnBindClient {
+  private final String myExecutablePath;
+  private CommitEventHandler myHandler;
+  private AuthenticationCallback myAuthenticationCallback;
+  private Convertor<String[], SVNURL> myUrlProvider;
+
+  public SvnBindClient(String path, Convertor<String[], SVNURL> urlProvider) {
+    myExecutablePath = path;
+    myUrlProvider = urlProvider;
+  }
+
+  public long commit(String[] path, String message, boolean recurse, boolean noUnlock) throws VcsException {
+    return commit(path, message, recurse? 3 : 0, noUnlock, false, null, null);
+  }
+
+  public long commit(String[] path,
+                     String message,
+                     int depth,
+                     boolean noUnlock,
+                     boolean keepChangelist,
+                     String[] changelists,
+                     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 VcsException("Wrong committed revision number: " + commit);
+    }
+    return commit;
+  }
+
+  public void setHandler(CommitEventHandler handler) {
+    myHandler = handler;
+  }
+
+  public void setAuthenticationCallback(AuthenticationCallback authenticationCallback) {
+    myAuthenticationCallback = authenticationCallback;
+  }
+}
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 8957843e911c36bae35829db297034dcbaa5184a..524b928eae920ab1c761eaf337c79883584fd2fc 100644 (file)
  * 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<String> messages) {
-    super(messages);
-  }
 }
similarity index 73%
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 1fec6b3bf86500cbaa9df8e3dc2d6a4fbbbf8f87..7d663bae65b5f062fe922c24de6a67e0447f5f35 100644 (file)
@@ -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;
@@ -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<DateFormat> ourFormats = new ArrayList<DateFormat>();
 
   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");
-  }
 }
similarity index 81%
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
index d6df6bae947e403ec10075f267c87e206b39c62a..9e355e56f4d671e57b84d5e716c8204b82fbef97 100644 (file)
@@ -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;
@@ -45,13 +47,13 @@ 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;
 
   private final EventDispatcher<ProcessEventListener> 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 +61,34 @@ 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();
+    }
+  }
+
+  /**
+   * Indicates if process was destroyed "manually" by command execution logic.
+   *
+   * @return
+   */
+  public boolean isManuallyDestroyed() {
+    return myIsDestroyed;
   }
 
   public void start() {
@@ -112,10 +133,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
@@ -186,6 +213,18 @@ public abstract class SvnCommand {
     }
   }
 
+  public String getCommandText() {
+    synchronized (myLock) {
+      return myCommandLine.getCommandLineString();
+    }
+  }
+
+  public String getExePath() {
+    synchronized (myLock) {
+      return myCommandLine.getExePath();
+    }
+  }
+
   /**
    * check that process is not started yet
    *
@@ -226,4 +265,8 @@ public abstract class SvnCommand {
   protected File getWorkingDirectory() {
     return myWorkingDirectory;
   }
+
+  public SvnCommandName getCommandName() {
+    return myCommandName;
+  }
 }
index 0d2f4d00bd39c25fff02c09132229244824ed538..47b6b5234396f1fae5ed23b47e5ff77e5e4b3c18 100644 (file)
  */
 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.Consumer;
-import org.jetbrains.idea.svn.SvnBindUtil;
+import org.jetbrains.idea.svn.SvnApplicationSettings;
 import org.jetbrains.idea.svn.SvnVcs;
 import org.jetbrains.idea.svn.portable.SvnExceptionWrapper;
 import org.jetbrains.idea.svn.portable.SvnkitSvnWcClient;
@@ -36,7 +37,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 +48,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;
   }
@@ -74,22 +80,56 @@ 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);
+  }
+
+  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<String> parameters = new ArrayList<String>();
+
+    fillParameters(path, pegRevision, revision, depth, parameters);
+    command.addParameters(parameters);
+    SvnCommandLineStatusClient.changelistsToCommand(changeLists, command);
 
-    if (depth != null) {
-      command.addParameters("--depth", depth.getName());
+    parseResult(handler, base, execute(command));
+  }
+
+  private String execute(SvnSimpleCommand command) throws SVNException {
+    try {
+      return command.run();
     }
-    if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) {
-      command.addParameters("-r", revision.toString());
+    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")) {
+        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() + "</info>";
+        } else {
+          throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_WORKING_COPY, e), e);
+        }
+      }
+      throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
     }
-    command.addParameters("--xml");
-    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());
+  }
+
+  private void parseResult(final ISVNInfoHandler handler, File base, String result) throws SVNException {
+    if (StringUtil.isEmpty(result)) {
+      return;
     }
 
     final SvnInfoHandler[] infoHandler = new SvnInfoHandler[1];
@@ -106,38 +146,34 @@ 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) {
+      LOG.info("info output " + result);
       throw (SVNException) e.getCause();
     } catch (IOException e) {
-      throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
+      LOG.info("info output " + result);
+      throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
     }
     catch (ParserConfigurationException e) {
-      throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
+      LOG.info("info output " + result);
+      throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
     }
     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);
+      LOG.info("info output " + result);
+      throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
     }
   }
 
+  private void fillParameters(String path, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, List<String> parameters) {
+    CommandUtil.put(parameters, depth);
+    CommandUtil.put(parameters, revision);
+    CommandUtil.put(parameters, path, pegRevision);
+    parameters.add("--xml");
+  }
+
   @Override
   public void doInfo(SVNURL url, SVNRevision pegRevision, SVNRevision revision, boolean recursive, ISVNInfoHandler handler)
     throws SVNException {
@@ -147,7 +183,14 @@ 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<String> parameters = new ArrayList<String>();
+
+    fillParameters(path, pegRevision, revision, depth, parameters);
+    File base = new File(SvnApplicationSettings.getInstance().getCommandLinePath());
+    String result = CommandUtil.runSimple(SvnCommandName.info, SvnVcs.getInstance(myProject), base, url, parameters).getOutput();
+
+    parseResult(handler, base, result);
   }
 
   @Override
index a1a31536c8a9edea4fb092452f6f25053e9c1a64..c1429be699af4c2a20ca169cfc12b8a5414ee53a 100644 (file)
  */
 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.idea.svn.SvnBindUtil;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.idea.svn.SvnUtil;
+import org.jetbrains.idea.svn.SvnVcs;
 import org.jetbrains.idea.svn.portable.PortableStatus;
 import org.jetbrains.idea.svn.portable.SvnExceptionWrapper;
 import org.jetbrains.idea.svn.portable.SvnStatusClientI;
@@ -48,6 +50,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;
 
@@ -102,47 +106,84 @@ 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;
+  }
+
+  private String execute(SvnSimpleCommand command, File base) throws SVNException {
+    String result = CommandUtil.runSimple(command, SvnVcs.getInstance(myProject), base, null).getOutput();
 
-    final SvnStatusHandler[] svnHandl = new SvnStatusHandler[1];
-    svnHandl[0] = createStatusHandler(revision, handler, base, infoBase, svnHandl);
+    if (StringUtil.isEmptyOrSpaces(result)) {
+      throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL, "Status request returned nothing for command: " +
+                                                                             command.myCommandLine.getCommandLineString()));
+    }
+
+    return result;
+  }
+
+  private void parseResult(final File path,
+                           SVNRevision revision,
+                           ISVNStatusHandler handler,
+                           File base,
+                           SVNInfo infoBase,
+                           SvnSimpleCommand command, String result) throws SVNException {
+
+    if (StringUtil.isEmpty(result)) {
+      return;
+    }
 
     try {
-      final String result = command.run();
-      if (StringUtil.isEmptyOrSpaces(result)) {
-        throw new VcsException("Status request returned nothing for command: " + command.myCommandLine.getCommandLineString());
-      }
+      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)) {
-          throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY));
+      if (!svnHandl[0].isAnythingReported()) {
+        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
+          // <status>
+          // <target path="1.txt"></target>
+          // </status>
+          // so it does not contain any <entry> element and current parsing logic returns null
+
+          PortableStatus status = new PortableStatus();
+          status.setPath(path.getAbsolutePath());
+          status.setContentsStatus(SVNStatusType.STATUS_NORMAL);
+          status.setInfoGetter(new Getter<SVNInfo>() {
+            @Override
+            public SVNInfo get() {
+              return createInfoGetter(null).convert(path);
+            }
+          });
+          handler.handleStatus(status);
         }
       }
     }
     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);
-    }
-    catch (VcsException e) {
-      throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
+      throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
     }
-    return 0;
   }
 
-  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());
     }
@@ -171,7 +212,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<File, SVNInfo>() {
+    return new SvnStatusHandler(callback, base, createInfoGetter(revision));
+  }
+
+  private Convertor<File, SVNInfo> createInfoGetter(final SVNRevision revision) {
+    return new Convertor<File, SVNInfo>() {
       @Override
       public SVNInfo convert(File o) {
         try {
@@ -181,7 +226,7 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI {
           throw new SvnExceptionWrapper(e);
         }
       }
-    });
+    };
   }
 
   public static SvnStatusHandler.ExternalDataCallback createStatusCallback(final ISVNStatusHandler handler,
index c0e9c8e79fa207f3cf1ff640debdcc6c80f82268..e0834c2f116f9853b3070d3e353934013962daca 100644 (file)
@@ -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.*;
@@ -49,9 +48,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;
   }
 
@@ -88,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<String> parameters = new ArrayList<String>();
-    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<String> parameters = prepareParameters(paths, revision, depth, allowUnversionedObstructions, depthIsSticky, makeParents);
 
     final AtomicReference<SVNException> excRef = new AtomicReference<SVNException>();
     final ISVNEventHandler handler = getEventHandler();
@@ -166,7 +137,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));
     }
@@ -180,6 +151,29 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient {
     return updatedToRevision.get();
   }
 
+  private List<String> prepareParameters(File[] paths,
+                                         SVNRevision revision,
+                                         SVNDepth depth,
+                                         boolean allowUnversionedObstructions,
+                                         boolean depthIsSticky, boolean makeParents) {
+    List<String> parameters = new ArrayList<String>();
+
+    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;
similarity index 75%
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
index 58c2ff2ab308b496ed9fe7b6df7926faafbb521d..c19ea283bbd19a2a7b49f674e382ef838e524677 100644 (file)
@@ -22,13 +22,25 @@ 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),
   st("st", false),
   up("up", true),
   ci("commit", true),
-  cleanup("cleanup", true);
-  
+  cleanup("cleanup", true),
+  cat("cat", false),
+  add("add", true),
+  log("log", false),
+  revert("revert", true),
+  delete("delete", true),
+  copy("copy", true),
+  move("move", true),
+  resolve("resolve", true),
+  propget("propget", false),
+  blame("blame", false);
+
   private final String myName;
   private final boolean myWriteable;
 
similarity index 86%
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 525d675303fc4fba07bdfd0a1f2bdeb0a2dfc38f..83f6ec156cf1c5e14d4a6a5f26b612b2d11c8430 100644 (file)
  * 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;
 import java.util.*;
@@ -42,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) {
@@ -57,7 +54,7 @@ public class SvnCommitRunner {
                      boolean noUnlock,
                      boolean keepChangelist,
                      String[] changelists,
-                     Map revpropTable) throws ClientException {
+                     Map revpropTable, Convertor<String[], SVNURL> urlProvider) throws VcsException {
     if (paths.length == 0) return Revision.SVN_INVALID_REVNUM;
 
     final List<String> parameters = new ArrayList<String>();
@@ -84,19 +81,14 @@ public class SvnCommitRunner {
     Arrays.sort(paths);
     parameters.addAll(Arrays.asList(paths));
 
-    try {
-      SvnLineCommand.runWithAuthenticationAttempt(myExePath, new File(paths[0]), 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();
   }
 
-  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;
@@ -106,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;
       }
     }
 
index 022130e4a9f628bc442a910594100cc16b7d85df..d8dbb6c19f67a8988b2269e1a4ce2fc6e065c450 100644 (file)
@@ -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;
@@ -49,7 +50,7 @@ public class SvnInfoHandler extends DefaultHandler {
   public SvnInfoHandler(File base, final Consumer<SVNInfo> infoConsumer) {
     myBase = base;
     myInfoConsumer = infoConsumer;
-    myPending = new SvnInfoStructure();
+    myPending = createPending();
     myElementsMap = new HashMap<String, Getter<ElementHandlerBase>>();
     fillElements();
     myParseStack = new ArrayList<ElementHandlerBase>();
@@ -70,7 +71,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
@@ -90,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;
@@ -115,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());
@@ -252,6 +269,24 @@ public class SvnInfoHandler extends DefaultHandler {
         return new Url();
       }
     });
+    myElementsMap.put("relative-url", new Getter<ElementHandlerBase>() {
+      @Override
+      public ElementHandlerBase get() {
+        return new RelativeUrl();
+      }
+    });
+    myElementsMap.put("lock", new Getter<ElementHandlerBase>() {
+      @Override
+      public ElementHandlerBase get() {
+        return new Lock();
+      }
+    });
+    myElementsMap.put("created", new Getter<ElementHandlerBase>() {
+      @Override
+      public ElementHandlerBase get() {
+        return new Date();
+      }
+    });
     myElementsMap.put("uuid", new Getter<ElementHandlerBase>() {
       @Override
       public ElementHandlerBase get() {
@@ -270,6 +305,18 @@ public class SvnInfoHandler extends DefaultHandler {
         return new WcInfo();
       }
     });
+    myElementsMap.put("moved-to", new Getter<ElementHandlerBase>() {
+      @Override
+      public ElementHandlerBase get() {
+        return new MovedPath();
+      }
+    });
+    myElementsMap.put("moved-from", new Getter<ElementHandlerBase>() {
+      @Override
+      public ElementHandlerBase get() {
+        return new MovedPath();
+      }
+    });
     myElementsMap.put("wcroot-abspath", new Getter<ElementHandlerBase>() {
       @Override
       public ElementHandlerBase get() {
@@ -295,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();
@@ -382,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();
     }
   }
 
@@ -397,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();
     }
   }
 
@@ -412,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
@@ -498,6 +550,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[]{});
@@ -617,7 +688,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
@@ -698,11 +769,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;
     }
 
@@ -763,12 +857,22 @@ public class SvnInfoHandler extends DefaultHandler {
   private abstract static class ElementHandlerBase {
     private final Set<String> myAwaitedChildren;
     private final Set<String> myAwaitedChildrenMultiple;
+    private ElementHandlerBase parent;
 
     ElementHandlerBase(String[] awaitedChildren, String[] awaitedChildrenMultiple) {
       myAwaitedChildren = new HashSet<String>(Arrays.asList(awaitedChildren));
       myAwaitedChildrenMultiple = new HashSet<String>(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 {
index 0292b7d936149a9bc798cd91a0751e5f9749e1af..1aa5248c193910951db1d66f0528c8ab7bde1f99 100644 (file)
@@ -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;
similarity index 66%
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 5821d7a5fb189ab6e086e3faed8b317af8618154..a34e5cf2f4069605c1453b40c6405c51c3915c76 100644 (file)
@@ -23,20 +23,30 @@ 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;
 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.jetbrains.idea.svn.SvnUtil;
+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;
 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.
@@ -47,11 +57,21 @@ import java.util.concurrent.atomic.AtomicReference;
  * 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";
   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";
+
+  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 '(.*)'");
 
   // kept for exact text
   //public static final String CLIENT_CERTIFICATE_FILENAME = "Client certificate filename:";
@@ -66,6 +86,7 @@ public class SvnLineCommand extends SvnCommand {
   private final EventDispatcher<LineProcessEventListener> myLineListeners;
   private final AtomicReference<Integer> myExitCode;
   private final StringBuffer myErr;
+  private final StringBuffer myStdOut;
 
   public SvnLineCommand(File workingDirectory, @NotNull SvnCommandName commandName, @NotNull @NonNls String exePath) {
     this(workingDirectory, commandName, exePath, null);
@@ -76,6 +97,7 @@ public class SvnLineCommand extends SvnCommand {
     myLineListeners = EventDispatcher.create(LineProcessEventListener.class);
     myExitCode = new AtomicReference<Integer>();
     myErr = new StringBuffer();
+    myStdOut = new StringBuffer();
   }
 
   @Override
@@ -89,13 +111,14 @@ public class SvnLineCommand extends SvnCommand {
     }
   }
 
-  public static void runWithAuthenticationAttempt(final String exePath,
-                                                  final File firstFile,
-                                                  SvnCommandName commandName,
-                                                  final LineCommandListener listener,
-                                                  @Nullable AuthenticationCallback authenticationCallback,
-                                                  final String... parameters) throws SvnBindException {
-    File base = firstFile.isDirectory() ? firstFile : firstFile.getParentFile();
+  public static SvnLineCommand runWithAuthenticationAttempt(final String exePath,
+                                                            final File firstFile,
+                                                            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);
 
     listener.baseDirectory(base);
@@ -114,13 +137,14 @@ 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);
+              cleanup(exePath, command, base);
               if (callback.getCredentials(errText)) {
                 if (authenticationCallback.getSpecialConfigDir() != null) {
                   configDir = authenticationCallback.getSpecialConfigDir();
                 }
+                parameters = updateParameters(callback, parameters);
                 continue;
               }
             }
@@ -131,7 +155,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) {
@@ -140,6 +164,13 @@ public class SvnLineCommand extends SvnCommand {
     }
   }
 
+  private static String[] updateParameters(AuthCallbackCase callback, String[] parameters) {
+    List<String> p = new ArrayList<String>(Arrays.asList(parameters));
+
+    callback.updateParameters(p);
+    return ArrayUtil.toStringArray(p);
+  }
+
   private static void writeIdeaConfig2SubversionConfig(@NotNull AuthenticationCallback authenticationCallback, @NotNull File base) throws SvnBindException {
     if (authenticationCallback.haveDataForTmpConfig()) {
       try {
@@ -158,7 +189,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 +202,85 @@ 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);
+    }
+    // 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);
+    }
+    // https one-way protocol untrusted server certificate
+    if (errText.contains(UNTRUSTED_SERVER_CERTIFICATE)) {
+      return new CertificateCallbackCase(callback, base);
+    }
+    // https two-way protocol invalid client certificate
+    if (errText.contains(ACCESS_TO_PREFIX) && errText.contains(FORBIDDEN_STATUS)) {
+      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 {
+    protected SVNAuthentication myAuthentication;
+    protected 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),
+                                                                     getType());
+
+      return myAuthentication != null;
+    }
+
+    public String getType() {
+      return ISVNAuthenticationManager.PASSWORD;
+    }
+
+    @Override
+    public void updateParameters(List<String> 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) {
+      Matcher matcher = UNABLE_TO_CONNECT_TO_URL_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.parseURIEncoded(urlValue);
+      }
+      catch (SVNException e) {
+        return null;
+      }
+    }
+  }
+
   private static class ProxyCallback extends AuthCallbackCase {
     protected ProxyCallback(AuthenticationCallback callback, File base) {
       super(callback, base);
@@ -192,7 +299,8 @@ 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);
@@ -212,13 +320,16 @@ public class SvnLineCommand extends SvnCommand {
   }
 
   private static class CertificateCallbackCase extends AuthCallbackCase {
+    private boolean accepted;
+
     private CertificateCallbackCase(AuthenticationCallback callback, File base) {
       super(callback, base);
     }
 
     @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);
@@ -229,11 +340,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<String> 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<String> 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 {
@@ -247,17 +395,23 @@ public class SvnLineCommand extends SvnCommand {
     }
 
     abstract boolean getCredentials(final String errText) throws SvnBindException;
+
+    public void updateParameters(List<String> parameters) {
+    }
   }
 
-  private static void cleanup(String exePath, SvnCommandName commandName, File base) throws SvnBindException {
-    File wcRoot = SvnBindUtil.getWcRoot(base);
-    if (wcRoot == null) throw new SvnBindException("Can not find working copy root for: " + base.getPath());
+  private static void cleanup(String exePath, SvnCommand command, File base) throws SvnBindException {
+    // 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());
+      }
 
-    //cleanup -> check command type
-    if (commandName.isWriteable()) {
-      final SvnSimpleCommand command = new SvnSimpleCommand(wcRoot, SvnCommandName.cleanup, exePath);
+      final SvnSimpleCommand cleanupCommand = new SvnSimpleCommand(wcRoot, SvnCommandName.cleanup, exePath);
       try {
-        command.run();
+        cleanupCommand.run();
       }
       catch (VcsException e) {
         throw new SvnBindException(e);
@@ -320,6 +474,10 @@ public class SvnLineCommand extends SvnCommand {
     command.addLineListener(new LineProcessEventListener() {
       @Override
       public void onLineAvailable(String line, Key outputType) {
+        if (ProcessOutputTypes.STDOUT.equals(outputType)) {
+          command.myStdOut.append(line);
+        }
+
         if (SvnCommand.LOG.isDebugEnabled()) {
           SvnCommand.LOG.debug("==> " + line);
         }
similarity index 97%
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
index 75c43befb6cbd256ad0afa1cafce7d7ee0d3cf59..a088da0334a3145ca3c6b8f77bb494ffc3c6f892 100644 (file)
@@ -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())
index 6536646374bd3a0821c75a8445cd6e5d0ae108ee..8700c363f46010ec360ce1b19f4c759c0a6435d2 100644 (file)
@@ -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)) {
@@ -103,9 +105,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 +142,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/conflict/CmdConflictClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/conflict/CmdConflictClient.java
new file mode 100644 (file)
index 0000000..79614a2
--- /dev/null
@@ -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<String> parameters = new ArrayList<String>();
+
+    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 (file)
index 0000000..812fdef
--- /dev/null
@@ -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 (file)
index 0000000..33ee0f8
--- /dev/null
@@ -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);
+    }
+  }
+}
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 (file)
index 0000000..c822fe0
--- /dev/null
@@ -0,0 +1,39 @@
+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<String> parameters = new ArrayList<String>();
+    CommandUtil.put(parameters, target.getPathOrUrlString(), pegRevision);
+    CommandUtil.put(parameters, revision);
+
+    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 (file)
index 0000000..3654d09
--- /dev/null
@@ -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 (file)
index 0000000..0a0e585
--- /dev/null
@@ -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 (file)
index 0000000..d591697
--- /dev/null
@@ -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/copy/CmdCopyMoveClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/copy/CmdCopyMoveClient.java
new file mode 100644 (file)
index 0000000..eceef14
--- /dev/null
@@ -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<String> parameters = new ArrayList<String>();
+
+    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 (file)
index 0000000..ec48107
--- /dev/null
@@ -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 (file)
index 0000000..ea84bc6
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..5fc26ac
--- /dev/null
@@ -0,0 +1,29 @@
+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<String> parameters = new ArrayList<String>();
+
+    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);
+  }
+}
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 (file)
index 0000000..23a1cf9
--- /dev/null
@@ -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 (file)
index 0000000..c97cfd2
--- /dev/null
@@ -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 (SVN