SVN 1.7: path to Svn executable - into settings
authorirengrig <Irina.Chernushina@jetbrains.com>
Tue, 31 Jan 2012 12:22:15 +0000 (16:22 +0400)
committerirengrig <Irina.Chernushina@jetbrains.com>
Tue, 31 Jan 2012 12:22:15 +0000 (16:22 +0400)
ExecutableValidator: allow to reset error description during validation (there could be different reasons why executable is not valid)

platform/platform-impl/src/com/intellij/execution/ExecutableValidator.java
plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnConfigurable.form
plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnConfigurable.java
plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnVcs17.java
plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnCommand.java
plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnExecutableChecker.java [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnSimpleCommand.java

index 62e6e308c27edc925d1029d84d36624c82c2fa54..8c278e84cff6e0f96bfe455c99c8dc34b9ff6c5d 100644 (file)
@@ -44,9 +44,9 @@ public abstract class ExecutableValidator {
   private final NotificationGroup myNotificationGroup = new NotificationGroup(NOTIFICATION_ID, NotificationDisplayType.TOOL_WINDOW, true,
                                                                               ToolWindowId.VCS);
 
-  private final Project myProject;
+  protected final Project myProject;
   private final String myNotificationErrorTitle;
-  private final String myNotificationErrorDescription;
+  private String myNotificationErrorDescription;
 
   /**
    * Configures notification and dialog by setting text messages and titles specific to the whoever uses the validator.
@@ -91,6 +91,10 @@ public abstract class ExecutableValidator {
     }
   }
 
+  public void setNotificationErrorDescription(String notificationErrorDescription) {
+    myNotificationErrorDescription = notificationErrorDescription;
+  }
+
   /**
    * Shows a notification about not configured executable with a link to the Settings to fix it.
    * Expires the notification if user fixes the path from the opened Settings dialog.
index bb7a896d1f51a1b3c1ed5799ced35276d1f110f7..30006a8529d11cf93b74ec77d45130205b41a296 100644 (file)
               <text value="with command line client"/>
             </properties>
           </component>
+          <component id="44a8" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myCommandLineClient">
+            <constraints>
+              <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+          </component>
         </children>
       </grid>
     </children>
index f7e988ac7e6cd99817ec97011ff29748d9e7c67b..086a730d6c9c6ce75707041a009141ac46d93e61 100644 (file)
@@ -27,6 +27,7 @@ import com.intellij.openapi.options.ConfigurationException;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.Messages;
 import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.openapi.util.Comparing;
 import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileManager;
@@ -73,6 +74,7 @@ public class SvnConfigurable implements Configurable {
   private JRadioButton myNoAcceleration;
   private JLabel myJavaHLInfo;
   private JRadioButton myWithCommandLineClient;
+  private TextFieldWithBrowseButton myCommandLineClient;
 
   @NonNls private static final String HELP_ID = "project.propSubversion";
 
@@ -96,6 +98,8 @@ public class SvnConfigurable implements Configurable {
         }
       }
     });
+    myCommandLineClient.addBrowseFolderListener("Subversion", "Select path to Subversion executable (1.7+)", project,
+                                       FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor());
 
     myClearAuthButton.addActionListener(new ActionListener(){
       public void actionPerformed(final ActionEvent e) {
@@ -221,6 +225,8 @@ public class SvnConfigurable implements Configurable {
     if (configuration.mySSHReadTimeout/1000 != ((SpinnerNumberModel) mySSHReadTimeout.getModel()).getNumber().longValue()) {
       return true;
     }
+    final SvnApplicationSettings17 applicationSettings17 = SvnApplicationSettings17.getInstance();
+    if (! Comparing.equal(applicationSettings17.getCommandLinePath(), myCommandLineClient.getText().trim())) return true;
     return !configuration.getConfigurationDirectory().equals(myConfigurationDirectoryText.getText().trim());
   }
   
@@ -261,8 +267,9 @@ public class SvnConfigurable implements Configurable {
     configuration.setConfigurationDirectory(myConfigurationDirectoryText.getText());
     configuration.setUseDefaultConfiguation(myUseDefaultCheckBox.isSelected());
     configuration.setIsUseDefaultProxy(myUseCommonProxy.isSelected());
+    final SvnVcs17 vcs17 = SvnVcs17.getInstance(myProject);
     if ((! configuration.DETECT_NESTED_COPIES) && (configuration.DETECT_NESTED_COPIES != myDetectNestedWorkingCopiesCheckBox.isSelected())) {
-      SvnVcs17.getInstance(myProject).invokeRefreshSvnRoots(true);
+      vcs17.invokeRefreshSvnRoots(true);
     }
     configuration.DETECT_NESTED_COPIES = myDetectNestedWorkingCopiesCheckBox.isSelected();
     configuration.CHECK_NESTED_FOR_QUICK_MERGE = myCheckNestedInQuickMerge.isSelected();
@@ -277,6 +284,10 @@ public class SvnConfigurable implements Configurable {
     configuration.mySSHConnectionTimeout = ((SpinnerNumberModel) mySSHConnectionTimeout.getModel()).getNumber().longValue() * 1000;
     configuration.mySSHReadTimeout = ((SpinnerNumberModel) mySSHReadTimeout.getModel()).getNumber().longValue() * 1000;
     configuration.myUseAcceleration = acceleration();
+
+    final SvnApplicationSettings17 applicationSettings17 = SvnApplicationSettings17.getInstance();
+    applicationSettings17.setCommandLinePath(myCommandLineClient.getText().trim());
+    vcs17.checkCommandLineVersion();
   }
 
   public void reset() {
@@ -310,6 +321,8 @@ public class SvnConfigurable implements Configurable {
     mySSHConnectionTimeout.setValue(Long.valueOf(configuration.mySSHConnectionTimeout / 1000));
     mySSHReadTimeout.setValue(Long.valueOf(configuration.mySSHReadTimeout / 1000));
     setAcceleration(configuration.myUseAcceleration);
+    final SvnApplicationSettings17 applicationSettings17 = SvnApplicationSettings17.getInstance();
+    myCommandLineClient.setText(applicationSettings17.getCommandLinePath());
   }
 
   public void disposeUIResources() {
index fb9e5d05ca04d0235c319ed2adae641c6d744f0d..0d070d3436a2c17981b6ec0cbf61b63f514a9193 100644 (file)
@@ -66,6 +66,7 @@ import org.jetbrains.idea.svn17.actions.ShowPropertiesDiffWithLocalAction;
 import org.jetbrains.idea.svn17.actions.SvnMergeProvider;
 import org.jetbrains.idea.svn17.annotate.SvnAnnotationProvider;
 import org.jetbrains.idea.svn17.checkin.SvnCheckinEnvironment17;
+import org.jetbrains.idea.svn17.commandLine.SvnExecutableChecker;
 import org.jetbrains.idea.svn17.dialogs.SvnBranchPointsCalculator;
 import org.jetbrains.idea.svn17.dialogs.SvnFormatWorker;
 import org.jetbrains.idea.svn17.dialogs.WCInfo;
@@ -157,6 +158,11 @@ public class SvnVcs17 extends AbstractVcs<CommittedChangeList> {
   private final SvnLoadedBrachesStorage17 myLoadedBranchesStorage;
 
   public static final String SVNKIT_HTTP_SSL_PROTOCOLS = "svnkit.http.sslProtocols";
+  private final SvnExecutableChecker myChecker;
+
+  public void checkCommandLineVersion() {
+    myChecker.checkExecutableAndNotifyIfNeeded();
+  }
 
   static {
     SVNJNAUtil.setJNAEnabled(true);
@@ -238,6 +244,7 @@ public class SvnVcs17 extends AbstractVcs<CommittedChangeList> {
 
     // remove used some time before old notification group ids
     correctNotificationIds();
+    myChecker = new SvnExecutableChecker(myProject);
   }
 
   private void correctNotificationIds() {
@@ -410,8 +417,11 @@ public class SvnVcs17 extends AbstractVcs<CommittedChangeList> {
       }
     }
 
-    if (SvnConfiguration17.UseAcceleration.javaHL.equals(SvnConfiguration17.getInstance(myProject).myUseAcceleration)) {
+    final SvnConfiguration17.UseAcceleration accelerationType = SvnConfiguration17.getInstance(myProject).myUseAcceleration;
+    if (SvnConfiguration17.UseAcceleration.javaHL.equals(accelerationType)) {
       CheckJavaHL.runtimeCheck(myProject);
+    } else if (SvnConfiguration17.UseAcceleration.commandLine.equals(accelerationType) && ! ApplicationManager.getApplication().isHeadlessEnvironment()) {
+      myChecker.checkExecutableAndNotifyIfNeeded();
     }
 
     // do one time after project loaded
index 444946aa4fd3bdab654d2da2288e3fb4262f2b67..340c17dd5830930059858e5de400ec59b86c0656 100644 (file)
@@ -26,6 +26,7 @@ import com.intellij.util.Processor;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.idea.svn17.SvnApplicationSettings17;
+import org.jetbrains.idea.svn17.SvnVcs17;
 
 import java.io.File;
 import java.io.OutputStream;
@@ -72,9 +73,14 @@ public abstract class SvnCommand {
 
       try {
         myProcess = startProcess();
-        startHandlingStreams();
+        if (myProcess != null) {
+          startHandlingStreams();
+        } else {
+          SvnVcs17.getInstance(myProject).checkCommandLineVersion();
+          myListeners.getMulticaster().startFailed(null);
+        }
       } catch (Throwable t) {
-        // todo check executable
+        SvnVcs17.getInstance(myProject).checkCommandLineVersion();
         myListeners.getMulticaster().startFailed(t);
       }
     }
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnExecutableChecker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnExecutableChecker.java
new file mode 100644 (file)
index 0000000..6f8b290
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.idea.svn17.commandLine;
+
+import com.intellij.execution.ExecutableValidator;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.execution.process.CapturingProcessHandler;
+import com.intellij.execution.process.ProcessOutput;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.CharsetToolkit;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.idea.svn17.SvnApplicationSettings17;
+import org.jetbrains.idea.svn17.SvnVcs17;
+
+import java.text.MessageFormat;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Irina.Chernushina
+ * Date: 1/31/12
+ * Time: 3:02 PM
+ */
+public class SvnExecutableChecker extends ExecutableValidator {
+  private final static String ourPath = "Probably the path to Subversion executable is wrong.";
+  private static final String ourVersion = "Subversion command line client version is too old ({0}).";
+  
+  public SvnExecutableChecker(Project project) {
+    super(project, "Can't use Subversion command line client", ourPath);
+  }
+
+  @Override
+  protected String getCurrentExecutable() {
+    return SvnApplicationSettings17.getInstance().getCommandLinePath();
+  }
+
+  @NotNull
+  @Override
+  protected Configurable getConfigurable() {
+    return SvnVcs17.getInstance(myProject).getConfigurable();
+  }
+
+  @Override
+  protected boolean isExecutableValid(String executable) {
+    setNotificationErrorDescription(ourPath);
+    try {
+      GeneralCommandLine commandLine = new GeneralCommandLine();
+      commandLine.setExePath(executable);
+      commandLine.addParameter("--version");
+      commandLine.addParameter("--quiet");
+      CapturingProcessHandler handler = new CapturingProcessHandler(commandLine.createProcess(), CharsetToolkit.getDefaultSystemCharset());
+      ProcessOutput result = handler.runProcess(30 * 1000);
+      if (! result.isTimeout() && (result.getExitCode() == 0) && result.getStderr().isEmpty()) {
+        final String stdout = result.getStdout().trim();
+        final String[] parts = stdout.split("\\.");
+        if (parts.length < 3 || ! "1".equals(parts[0])) {
+          setNotificationErrorDescription(MessageFormat.format(ourVersion, stdout));
+          return false;
+        }
+        try {
+          final int second = Integer.parseInt(parts[1]);
+          if (second >= 7) return true;
+        } catch (NumberFormatException e) {
+          //
+        }
+        setNotificationErrorDescription(MessageFormat.format(ourVersion, stdout));
+        return false;
+      } else {
+        return false;
+      }
+    } catch (Throwable e) {
+      return false;
+    }
+  }
+}
index b9a70bb732b4dd786801a0cb791e93b4fe968104..3ae3af1997eba8f8c7ddda231e422bf5d0083573 100644 (file)
@@ -95,7 +95,9 @@ public class SvnSimpleCommand extends SvnTextCommand {
       }
     });
     start();
-    waitFor();
+    if (myProcess != null) {
+      waitFor();
+    }
     if (ex[0] != null) {
       throw ex[0];
     }