diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgExecutableValidator.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgExecutableValidator.java index 03bf71e1504b..c9d5ee7c8f2b 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgExecutableValidator.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgExecutableValidator.java @@ -39,7 +39,7 @@ public class HgExecutableValidator extends ExecutableValidator { @Override public boolean isExecutableValid(String executable) { - return new HgVersionCommand().isValid(executable); + return new HgVersionCommand().isValid(executable, myVcs.getGlobalSettings().isRunViaBash()); } @Override diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgGlobalSettings.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgGlobalSettings.java index 341369d9c53d..6c73c9dca1cc 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgGlobalSettings.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgGlobalSettings.java @@ -13,7 +13,6 @@ package org.zmlx.hg4idea; import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.util.containers.HashMap; @@ -29,18 +28,32 @@ import java.util.Map; name = "HgGlobalSettings", storages = @Storage(id = "HgGlobalSettings", file = "$APP_CONFIG$/vcs.xml") ) -public class HgGlobalSettings implements PersistentStateComponent { +public class HgGlobalSettings implements PersistentStateComponent { private static final String HG = HgVcs.HG_EXECUTABLE_FILE_NAME; private static final int FIVE_MINUTES = 300; - private String hgExecutable = HG; + private String myHgExecutable = HG; // visited URL -> list of logins for this URL. Passwords are remembered in the PasswordSafe. private Map> myRememberedUrls = new HashMap>(); + private boolean myRunViaBash; - public static HgGlobalSettings getInstance() { - return ServiceManager.getService(HgGlobalSettings.class); + public static class State { + public String hgExecutable; + public boolean runViaBash; + } + + public State getState() { + State s = new State(); + s.hgExecutable = myHgExecutable; + s.runViaBash = myRunViaBash; + return s; + } + + public void loadState(State state) { + myHgExecutable = state.hgExecutable; + myRunViaBash = state.runViaBash; } /** @@ -77,31 +90,31 @@ public class HgGlobalSettings implements PersistentStateComponent { + private final HgGlobalSettings myAppSettings; private boolean myCheckIncoming = true; private boolean myCheckOutgoing = true; + public HgProjectSettings(HgGlobalSettings appSettings) { + myAppSettings = appSettings; + } + public static class State { public boolean myCheckIncoming = true; public boolean myCheckOutgoing = true; @@ -59,19 +64,27 @@ public class HgProjectSettings implements PersistentStateComponent commandLine, String dir, Charset charset) throws ShellCommandException, InterruptedException { if (commandLine == null || commandLine.isEmpty()) { throw new IllegalArgumentException("commandLine is empty"); } + + if (myRunViaBash) { + // run via bash -cl => need to escape bash special symbols + // '-l' makes bash execute as a login shell thus reading .bash_profile + String hgCommand = StringUtil.join(commandLine, " "); + hgCommand = StringUtil.escapeStringCharacters(hgCommand.length(), hgCommand, "\b\t\n\f\r|>$\"'&", false, false, new StringBuilder()).toString(); // we don't escape backslash, because we want special unicode characters (\u0017 for hg log) + commandLine = new ArrayList(3); + commandLine.add("bash"); + commandLine.add("-cl"); + commandLine.add(hgCommand); + } + StringWriter out = new StringWriter(); StringWriter err = new StringWriter(); try { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.form b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.form index 081bfbf896ce..a251f8fb50f3 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.form +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.form @@ -1,6 +1,6 @@
- + @@ -80,9 +80,17 @@ - + + + + + + + + + diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.java index 6d314b56f224..b5b7e745a5e9 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.java @@ -34,6 +34,7 @@ public class HgConfigurationProjectPanel { private JRadioButton myAutoRadioButton; private JRadioButton mySelectRadioButton; private TextFieldWithBrowseButton myPathSelector; + private JCheckBox myRunHgAsBashCheckBox; public HgConfigurationProjectPanel(HgProjectSettings projectSettings) { myProjectSettings = projectSettings; @@ -53,12 +54,14 @@ public class HgConfigurationProjectPanel { ? !myPathSelector.getText().equals(myProjectSettings.getHgExecutable()) : myAutoRadioButton.isSelected() != myProjectSettings.isAutodetectHg(); return executableModified || myCheckIncomingCbx.isSelected() != myProjectSettings.isCheckIncoming() - || myCheckOutgoingCbx.isSelected() != myProjectSettings.isCheckOutgoing(); + || myCheckOutgoingCbx.isSelected() != myProjectSettings.isCheckOutgoing() + || myRunHgAsBashCheckBox.isSelected() != myProjectSettings.isRunViaBash(); } public void saveSettings() { myProjectSettings.setCheckIncoming(myCheckIncomingCbx.isSelected()); myProjectSettings.setCheckOutgoing(myCheckOutgoingCbx.isSelected()); + myProjectSettings.setRunViaBash(myRunHgAsBashCheckBox.isSelected()); if (myAutoRadioButton.isSelected()) { myProjectSettings.enableAutodetectHg(); @@ -70,6 +73,7 @@ public class HgConfigurationProjectPanel { public void loadSettings() { myCheckIncomingCbx.setSelected(myProjectSettings.isCheckIncoming()); myCheckOutgoingCbx.setSelected(myProjectSettings.isCheckOutgoing()); + myRunHgAsBashCheckBox.setSelected(myProjectSettings.isRunViaBash()); boolean isAutodetectHg = myProjectSettings.isAutodetectHg(); myAutoRadioButton.setSelected(isAutodetectHg); @@ -94,7 +98,7 @@ public class HgConfigurationProjectPanel { hgExecutable = myPathSelector.getText(); } HgVersionCommand command = new HgVersionCommand(); - if (!command.isValid(hgExecutable)) { + if (!command.isValid(hgExecutable, myRunHgAsBashCheckBox.isSelected())) { throw new ConfigurationException( HgVcsMessages.message("hg4idea.configuration.executable.error", hgExecutable) ); @@ -102,7 +106,7 @@ public class HgConfigurationProjectPanel { } private void createUIComponents() { - myPathSelector = new HgSetExecutablePathPanel(); + myPathSelector = new HgSetExecutablePathPanel(myProjectSettings); } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgSetExecutablePathPanel.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgSetExecutablePathPanel.java index 7594a7c86244..356becd98291 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgSetExecutablePathPanel.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgSetExecutablePathPanel.java @@ -4,6 +4,7 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.vfs.VirtualFile; +import org.zmlx.hg4idea.HgProjectSettings; import org.zmlx.hg4idea.HgVcsMessages; import org.zmlx.hg4idea.command.HgVersionCommand; @@ -19,12 +20,12 @@ class HgSetExecutablePathPanel extends TextFieldWithBrowseButton { private final Set myOkListeners = new HashSet(); - HgSetExecutablePathPanel() { + HgSetExecutablePathPanel(final HgProjectSettings projectSettings) { FileChooserDescriptor descriptor = new FileChooserDescriptor(true, false, false, false, false, false) { public void validateSelectedFiles(VirtualFile[] files) throws Exception { HgVersionCommand command = new HgVersionCommand(); String path = files[0].getPath(); - if (!command.isValid(path)) { + if (!command.isValid(path, projectSettings.isRunViaBash())) { throw new ConfigurationException(HgVcsMessages.message("hg4idea.configuration.executable.error", path)); } for (ActionListener okListener : myOkListeners) {