[patch]: implement smart base root preselection and additional check that selected changes located under base dir path

This commit is contained in:
Nadya Zabrodina
2016-06-06 21:16:53 +03:00
committed by Nadya Zabrodina
parent a2e903caa1
commit 2af7100164
5 changed files with 63 additions and 0 deletions
@@ -46,6 +46,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.ChangesUtil;
import com.intellij.openapi.vcs.changes.patch.CreatePatchConfigurationPanel;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy;
@@ -455,6 +456,7 @@ public abstract class HistoryDialog<T extends HistoryDialogModel> extends FrameW
CreatePatchConfigurationPanel p = new CreatePatchConfigurationPanel(myProject);
p.setFileName(getDefaultPatchFile());
p.setCommonParentPath(ChangesUtil.findCommonAncestor(myModel.getChanges()));
if (!showAsDialog(p)) return;
myModel.createPatch(p.getFileName(), p.getBaseDirName(), p.isReversePatch());
@@ -212,6 +212,15 @@ public class FileUtil extends FileUtilRt {
return result;
}
@Nullable
public static File findAncestor(@NotNull File f1, @NotNull File f2) {
File ancestor = f1;
while (ancestor != null && !isAncestor(ancestor, f2, false)) {
ancestor = ancestor.getParentFile();
}
return ancestor;
}
@Nullable
public static File getParentFile(@NotNull File file) {
return FileUtilRt.getParentFile(file);
@@ -32,6 +32,7 @@ import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.Navigatable;
import com.intellij.util.NullableFunction;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -466,4 +467,33 @@ public class ChangesUtil {
public static String getDefaultChangeListName() {
return VcsBundle.message("changes.default.changelist.name");
}
/**
* Find common ancestor for changes (included both before and after files)
*/
@Nullable
public static File findCommonAncestor(@NotNull Collection<Change> changes) {
File ancestor = null;
for (Change change : changes) {
File currentChangeAncestor = getCommonBeforeAfterAncestor(change);
if (currentChangeAncestor == null) return null;
if (ancestor == null) {
ancestor = currentChangeAncestor;
}
else {
ancestor = FileUtil.findAncestor(ancestor, currentChangeAncestor);
if (ancestor == null) return null;
}
}
return ancestor;
}
@Nullable
private static File getCommonBeforeAfterAncestor(@NotNull Change change) {
FilePath before = getBeforePath(change);
FilePath after = getAfterPath(change);
return before == null
? ObjectUtils.assertNotNull(after).getIOFile()
: after == null ? before.getIOFile() : FileUtil.findAncestor(before.getIOFile(), after.getIOFile());
}
}
@@ -33,13 +33,16 @@ import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.VcsApplicationSettings;
import com.intellij.openapi.vcs.VcsBundle;
import com.intellij.openapi.vcs.VcsConfiguration;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager;
import com.intellij.openapi.vcs.changes.ui.SessionDialog;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.WaitForProgressToShow;
import com.intellij.vcsUtil.VcsUtil;
import org.jdom.Element;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
@@ -50,6 +53,7 @@ import javax.swing.*;
import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public class CreatePatchCommitExecutor extends LocalCommitExecutor implements ProjectComponent, JDOMExternalizable {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.patch.CreatePatchCommitExecutor");
@@ -136,6 +140,15 @@ public class CreatePatchCommitExecutor extends LocalCommitExecutor implements Pr
}
}
myPanel.setFileName(ShelveChangesManager.suggestPatchName(myProject, commitMessage, new File(PATCH_PATH), null));
File commonAncestor = ChangesUtil.findCommonAncestor(changes);
myPanel.setCommonParentPath(commonAncestor);
Set<AbstractVcs> affectedVcses = ChangesUtil.getAffectedVcses(changes, myProject);
if (affectedVcses.size() == 1 && commonAncestor != null) {
VirtualFile vcsRoot = VcsUtil.getVcsRootFor(myProject, VcsUtil.getFilePath(commonAncestor));
if (vcsRoot != null) {
myPanel.selectBasePath(vcsRoot.getPath());
}
}
myPanel.setReversePatch(false);
JComponent panel = myPanel.getPanel();
@@ -61,6 +61,7 @@ public class CreatePatchConfigurationPanel {
private ComboBox<Charset> myEncoding;
private JLabel myWarningLabel;
private final Project myProject;
@Nullable private File myCommonParentPath;
public CreatePatchConfigurationPanel(@NotNull final Project project) {
myProject = project;
@@ -124,6 +125,10 @@ public class CreatePatchConfigurationPanel {
.getPanel();
}
public void setCommonParentPath(@Nullable File commonParentPath) {
myCommonParentPath = commonParentPath;
}
private void checkExist() {
myWarningLabel.setText(new File(getFileName()).exists() ? "File with the same name already exists" : "");
}
@@ -163,6 +168,10 @@ public class CreatePatchConfigurationPanel {
if (StringUtil.isEmptyOrSpaces(baseDirName)) return new ValidationInfo("Base path can't be empty!", myBasePathField);
File baseFile = new File(baseDirName);
if (!baseFile.exists()) return new ValidationInfo("Base dir doesn't exist", myBasePathField);
if (myCommonParentPath != null && !FileUtil.isAncestor(baseFile, myCommonParentPath, false)) {
return new ValidationInfo(String.format("Base path doesn't contain all selected changes (use %s)", myCommonParentPath.getPath()),
myBasePathField);
}
return null;
}