IDEA-144811 Allow designating project-level git executable override

This commit is contained in:
Ivan Semenov
2017-11-10 14:15:58 +03:00
parent ff70388bab
commit 54b5cce0db
6 changed files with 100 additions and 29 deletions
@@ -22,3 +22,5 @@ push.force.confirmation.text = You''re going to force push{0}. It may overwrite
sync.setting=Execute branch operations on all roots
sync.setting.description=If selected, you would be able to checkout, compare, delete and create new branches in all {0} \
roots with a single action. It will also affect behavior of the push dialog.
executable.path.project.override=Set this path only for current project
@@ -580,3 +580,8 @@ paths.affected.in.revision=Paths Affected in Revision {0}
refresh.failed.message=Refresh failed: {0}
file.status.name.up.to.date.immediate.children=Have immediate changed children
file.status.name.up.to.date.recursive.children=Have changed descendants
executable.project.override.reset.title=Project Executable
executable.project.override.reset.message=Path to executable configured for this project can be set as the global path for all projects or reverted to the current global executable
executable.project.override.reset.globalize=Set as Global
executable.project.override.reset.revert=Revert
+1 -1
View File
@@ -151,7 +151,7 @@ public class GitVcs extends AbstractVcs<CommittedChangeList> {
myRollbackEnvironment = gitRollbackEnvironment;
myGitExecutableManager = gitExecutableManager;
myRevSelector = new GitRevisionSelector();
myConfigurable = new GitVcsConfigurable(myProject, gitProjectSettings, sharedSettings);
myConfigurable = new GitVcsConfigurable(gitSettings, myProject, gitProjectSettings, sharedSettings);
myUpdateEnvironment = new GitUpdateEnvironment(myProject, gitProjectSettings);
myCommittedChangeListProvider = new GitCommittedChangeListProvider(myProject);
myOutgoingChangesProvider = new GitOutgoingChangesProvider(myProject);
@@ -8,7 +8,7 @@
<properties/>
<border type="none"/>
<children>
<grid id="c9e6b" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="c9e6b" layout-manager="GridLayoutManager" row-count="4" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="7" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -30,7 +30,7 @@
</component>
<component id="5a909" class="javax.swing.JLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="2" 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>
<labelFor value="f5de9"/>
@@ -40,7 +40,7 @@
<grid id="97c7d" 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="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -66,7 +66,7 @@
<properties/>
<border type="none"/>
<children>
<component id="25af7" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myGitField">
<component id="25af7" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myGitField" custom-create="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
@@ -84,6 +84,15 @@
</component>
</children>
</grid>
<component id="76ca7" class="com.intellij.ui.components.JBCheckBox" binding="myProjectGitPathCheckBox">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<enabled value="true"/>
<text resource-bundle="com/intellij/dvcs/ui/DvcsBundle" key="executable.path.project.override"/>
</properties>
</component>
</children>
</grid>
<vspacer id="4c83d">
@@ -28,11 +28,14 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsBundle;
import com.intellij.ui.EnumComboBoxModel;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBTextField;
import com.intellij.ui.components.fields.ExpandableTextField;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.execution.ParametersListUtil;
import com.intellij.util.ui.UIUtil;
@@ -40,6 +43,7 @@ import git4idea.GitVcs;
import git4idea.i18n.GitBundle;
import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.ActionEvent;
@@ -47,6 +51,7 @@ import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.List;
import java.util.Objects;
/**
* Git VCS configuration panel
@@ -56,12 +61,14 @@ public class GitVcsPanel implements ConfigurableUi<GitVcsConfigurable.GitVcsSett
private static final String IDEA_SSH = GitBundle.getString("git.vcs.config.ssh.mode.idea"); // IDEA ssh value
private static final String NATIVE_SSH = GitBundle.getString("git.vcs.config.ssh.mode.native"); // Native SSH value
private final GitVcsApplicationSettings myAppSettings;
private final GitVcs myVcs;
@NotNull private final Project myProject;
private String myDetectedGitPath;
private String myApplicationGitPath;
private JButton myTestButton; // Test git executable
private JComponent myRootPanel;
private TextFieldWithBrowseButton myGitField;
private JBCheckBox myProjectGitPathCheckBox;
private JComboBox mySSHExecutableComboBox; // Type of SSH executable to use
private JCheckBox myAutoUpdateIfPushRejected;
private JBCheckBox mySyncControl;
@@ -74,20 +81,16 @@ public class GitVcsPanel implements ConfigurableUi<GitVcsConfigurable.GitVcsSett
private JComboBox myUpdateMethodComboBox;
public GitVcsPanel(@NotNull Project project) {
myVcs = GitVcs.getInstance(project);
myAppSettings = GitVcsApplicationSettings.getInstance();
myProject = project;
mySSHExecutableComboBox.addItem(IDEA_SSH);
mySSHExecutableComboBox.addItem(NATIVE_SSH);
mySSHExecutableComboBox.setSelectedItem(IDEA_SSH);
mySSHExecutableComboBox
.setToolTipText(GitBundle.message("git.vcs.config.ssh.mode.tooltip", ApplicationNamesInfo.getInstance().getFullProductName()));
myTestButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
testConnection();
}
});
myTestButton.addActionListener(e -> testExecutable());
myGitField.addBrowseFolderListener(GitBundle.getString("find.git.title"), GitBundle.getString("find.git.description"), project,
FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor());
myProjectGitPathCheckBox.addActionListener(e -> handleProjectOverrideStateChanged());
if (!project.isDefault()) {
final GitRepositoryManager repositoryManager = GitRepositoryManager.getInstance(project);
mySyncControl.setVisible(repositoryManager != null && repositoryManager.moreThanOneRoot());
@@ -106,22 +109,16 @@ public class GitVcsPanel implements ConfigurableUi<GitVcsConfigurable.GitVcsSett
});
}
/**
* Test availability of the connection
*/
private void testConnection() {
final String executable = getCurrentExecutablePath();
if (myAppSettings != null) {
myAppSettings.setPathToGit(executable);
}
private void testExecutable() {
GitVersion version;
String executable = ObjectUtils.notNull(getCurrentExecutablePath(), myDetectedGitPath);
try {
version = ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable<GitVersion, Exception>() {
@Override
public GitVersion compute() throws Exception {
return GitVersion.identifyVersion(executable);
}
}, "Testing Git Executable...", true, myVcs.getProject());
}, "Testing Git Executable...", true, myProject);
}
catch (ProcessCanceledException pce) {
return;
@@ -144,8 +141,30 @@ public class GitVcsPanel implements ConfigurableUi<GitVcsConfigurable.GitVcsSett
}
}
private void handleProjectOverrideStateChanged() {
if (!myProjectGitPathCheckBox.isSelected()
&& !Objects.equals(getCurrentExecutablePath(), myApplicationGitPath)) {
switch (Messages.showYesNoCancelDialog(myRootPanel,
VcsBundle.getString("executable.project.override.reset.message"),
VcsBundle.getString("executable.project.override.reset.title"),
VcsBundle.getString("executable.project.override.reset.globalize"),
VcsBundle.getString("executable.project.override.reset.revert"),
Messages.CANCEL_BUTTON,
null)) {
case Messages.NO:
myGitField.setText(myApplicationGitPath);
break;
case Messages.CANCEL:
myProjectGitPathCheckBox.setSelected(true);
break;
}
}
}
@Nullable
private String getCurrentExecutablePath() {
return myGitField.getText().trim();
return StringUtil.nullize(myGitField.getText().trim());
}
@NotNull
@@ -160,7 +179,12 @@ public class GitVcsPanel implements ConfigurableUi<GitVcsConfigurable.GitVcsSett
GitVcsSettings projectSettings = settings.getProjectSettings();
GitSharedSettings sharedSettings = settings.getSharedSettings();
myGitField.setText(applicationSettings.getPathToGit());
myApplicationGitPath = applicationSettings.getSavedPathToGit();
String projectSettingsPathToGit = projectSettings.getPathToGit();
myGitField.setText(ObjectUtils.coalesce(projectSettingsPathToGit, myApplicationGitPath));
myDetectedGitPath = GitExecutableManager.getInstance().getDetectedExecutable();
((JBTextField)myGitField.getTextField()).getEmptyText().setText("Auto-detected: " + myDetectedGitPath);
myProjectGitPathCheckBox.setSelected(projectSettingsPathToGit != null);
mySSHExecutableComboBox.setSelectedItem(projectSettings.isIdeaSsh() ? IDEA_SSH : NATIVE_SSH);
myAutoUpdateIfPushRejected.setSelected(projectSettings.autoUpdateIfPushRejected());
mySyncControl.setSelected(projectSettings.getSyncSetting() == DvcsSyncSettings.Value.SYNC);
@@ -178,7 +202,7 @@ public class GitVcsPanel implements ConfigurableUi<GitVcsConfigurable.GitVcsSett
GitVcsSettings projectSettings = settings.getProjectSettings();
GitSharedSettings sharedSettings = settings.getSharedSettings();
return !applicationSettings.getPathToGit().equals(getCurrentExecutablePath()) ||
return isGitPathModified(applicationSettings, projectSettings) ||
(projectSettings.isIdeaSsh() != IDEA_SSH.equals(mySSHExecutableComboBox.getSelectedItem())) ||
!projectSettings.autoUpdateIfPushRejected() == myAutoUpdateIfPushRejected.isSelected() ||
((projectSettings.getSyncSetting() == DvcsSyncSettings.Value.SYNC) != mySyncControl.isSelected() ||
@@ -191,26 +215,45 @@ public class GitVcsPanel implements ConfigurableUi<GitVcsConfigurable.GitVcsSett
ContainerUtil.sorted(getProtectedBranchesPatterns())));
}
private boolean isGitPathModified(@NotNull GitVcsApplicationSettings applicationSettings, @NotNull GitVcsSettings projectSettings) {
return myProjectGitPathCheckBox.isSelected()
? !Objects.equals(getCurrentExecutablePath(), projectSettings.getPathToGit())
: !Objects.equals(getCurrentExecutablePath(), applicationSettings.getSavedPathToGit())
|| projectSettings.getPathToGit() != null;
}
@Override
public void apply(@NotNull GitVcsConfigurable.GitVcsSettingsHolder settings) {
GitVcsApplicationSettings applicationSettings = settings.getApplicationSettings();
GitVcsSettings projectSettings = settings.getProjectSettings();
GitSharedSettings sharedSettings = settings.getSharedSettings();
applicationSettings.setPathToGit(getCurrentExecutablePath());
myVcs.checkVersion();
if (myProjectGitPathCheckBox.isSelected()) {
projectSettings.setPathToGit(getCurrentExecutablePath());
}
else {
myApplicationGitPath = getCurrentExecutablePath();
applicationSettings.setPathToGit(getCurrentExecutablePath());
projectSettings.setPathToGit(null);
}
applicationSettings.setIdeaSsh(IDEA_SSH.equals(mySSHExecutableComboBox.getSelectedItem()) ?
GitVcsApplicationSettings.SshExecutable.IDEA_SSH :
GitVcsApplicationSettings.SshExecutable.NATIVE_SSH);
projectSettings.setAutoUpdateIfPushRejected(myAutoUpdateIfPushRejected.isSelected());
projectSettings.setAutoUpdateIfPushRejected(myAutoUpdateIfPushRejected.isSelected());
projectSettings.setSyncSetting(mySyncControl.isSelected() ? DvcsSyncSettings.Value.SYNC : DvcsSyncSettings.Value.DONT_SYNC);
projectSettings.setAutoCommitOnCherryPick(myAutoCommitOnCherryPick.isSelected());
projectSettings.setWarnAboutCrlf(myWarnAboutCrlf.isSelected());
projectSettings.setWarnAboutDetachedHead(myWarnAboutDetachedHead.isSelected());
projectSettings.setForcePushAllowed(myEnableForcePush.isSelected());
projectSettings.setUpdateType((UpdateMethod)myUpdateMethodComboBox.getSelectedItem());
sharedSettings.setForcePushProhibitedPatters(getProtectedBranchesPatterns());
ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> GitVcs.getInstance(myProject).checkVersion(),
"Testing Git Executable...", true, null,
myRootPanel);
}
@NotNull
@@ -219,6 +262,7 @@ public class GitVcsPanel implements ConfigurableUi<GitVcsConfigurable.GitVcsSett
}
private void createUIComponents() {
myGitField = new TextFieldWithBrowseButton(new JBTextField());
myProtectedBranchesField = new ExpandableTextField(ParametersListUtil.COLON_LINE_PARSER, ParametersListUtil.COLON_LINE_JOINER);
myUpdateMethodComboBox = new ComboBox(new EnumComboBoxModel<>(UpdateMethod.class));
myUpdateMethodComboBox.setRenderer(new ListCellRendererWrapper<UpdateMethod>() {
@@ -60,6 +60,8 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
}
public static class State {
public String PATH_TO_GIT = null;
// The previously entered authors of the commit (up to {@value #PREVIOUS_COMMIT_AUTHORS_LIMIT})
public List<String> PREVIOUS_COMMIT_AUTHORS = new ArrayList<>();
public GitVcsApplicationSettings.SshExecutable SSH_EXECUTABLE = GitVcsApplicationSettings.SshExecutable.IDEA_SSH;
@@ -146,6 +148,15 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
myState = state;
}
@Nullable
public String getPathToGit() {
return myState.PATH_TO_GIT;
}
public void setPathToGit(@Nullable String pathToGit) {
myState.PATH_TO_GIT = pathToGit;
}
public boolean autoUpdateIfPushRejected() {
return myState.PUSH_AUTO_UPDATE;
}