mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-77857 Git fetch with --prune
Detect which refs were deleted and display a minor notification about them.
This commit is contained in:
@@ -21,6 +21,9 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import static com.intellij.openapi.util.text.StringUtil.join;
|
||||
import static com.intellij.openapi.util.text.StringUtil.pluralize;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
@@ -28,6 +31,7 @@ public final class GitFetchResult {
|
||||
|
||||
private final Type myType;
|
||||
private Collection<Exception> myErrors = new ArrayList<Exception>();
|
||||
private Collection<String> myPrunedRefs = new ArrayList<String>();
|
||||
|
||||
public enum Type {
|
||||
SUCCESS,
|
||||
@@ -83,4 +87,21 @@ public final class GitFetchResult {
|
||||
return myErrors;
|
||||
}
|
||||
|
||||
public void addPruneInfo(@NotNull Collection<String> prunedRefs) {
|
||||
myPrunedRefs.addAll(prunedRefs);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<String> getPrunedRefs() {
|
||||
return myPrunedRefs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getAdditionalInfo() {
|
||||
if (!myPrunedRefs.isEmpty()) {
|
||||
return "Pruned obsolete remote " + pluralize("reference", myPrunedRefs.size()) + ": " + join(myPrunedRefs, ",");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,9 +19,12 @@ import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.NotificationManager;
|
||||
import git4idea.commands.*;
|
||||
import git4idea.jgit.GitHttpAdapter;
|
||||
import git4idea.repo.GitRemote;
|
||||
@@ -33,7 +36,11 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
@@ -62,7 +69,8 @@ public class GitFetcher {
|
||||
GitRepository repository = myRepositoryManager.getRepositoryForRoot(root);
|
||||
assert repository != null : "Repository can't be null for " + root + "\n" + myRepositoryManager;
|
||||
|
||||
GitFetchResult result = GitFetchResult.success();
|
||||
// TODO need to have a fair compound result here
|
||||
GitFetchResult fetchResult = GitFetchResult.success();
|
||||
for (GitRemote remote : repository.getRemotes()) {
|
||||
String url = remote.getFirstUrl();
|
||||
if (url == null) {
|
||||
@@ -70,32 +78,38 @@ public class GitFetcher {
|
||||
}
|
||||
if (GitHttpAdapter.shouldUseJGit(url)) {
|
||||
GitFetchResult res = GitHttpAdapter.fetch(repository, remote, url);
|
||||
myErrors.addAll(res.getErrors());
|
||||
if (!res.isSuccess()) {
|
||||
result = res;
|
||||
res.addPruneInfo(fetchResult.getPrunedRefs());
|
||||
fetchResult = res;
|
||||
myErrors.addAll(fetchResult.getErrors());
|
||||
if (!fetchResult.isSuccess()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
GitFetchResult fetchResult = fetchNatively(root, remote);
|
||||
GitFetchResult res = fetchNatively(root, remote);
|
||||
res.addPruneInfo(fetchResult.getPrunedRefs());
|
||||
fetchResult = res;
|
||||
if (!fetchResult.isSuccess()) {
|
||||
result = fetchResult;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repository.update(GitRepository.TrackedTopic.BRANCHES);
|
||||
return result;
|
||||
return fetchResult;
|
||||
}
|
||||
|
||||
private GitFetchResult fetchNatively(@NotNull VirtualFile root, @NotNull GitRemote remote) {
|
||||
final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(myProject, root, GitCommand.FETCH);
|
||||
h.addParameters("--prune");
|
||||
h.addParameters(remote.getName());
|
||||
final GitTask fetchTask = new GitTask(myProject, h, "Fetching...");
|
||||
fetchTask.setProgressIndicator(myProgressIndicator);
|
||||
fetchTask.setProgressAnalyzer(new GitStandardProgressAnalyzer());
|
||||
|
||||
GitFetchPruneDetector pruneDetector = new GitFetchPruneDetector();
|
||||
h.addLineListener(pruneDetector);
|
||||
|
||||
final AtomicReference<GitFetchResult> result = new AtomicReference<GitFetchResult>();
|
||||
fetchTask.execute(true, false, new GitTaskResultHandlerAdapter() {
|
||||
@Override
|
||||
@@ -120,6 +134,8 @@ public class GitFetcher {
|
||||
result.set(GitFetchResult.error(myErrors));
|
||||
}
|
||||
});
|
||||
|
||||
result.get().addPruneInfo(pruneDetector.getPrunedRefs());
|
||||
return result.get();
|
||||
}
|
||||
|
||||
@@ -132,9 +148,9 @@ public class GitFetcher {
|
||||
@NotNull GitFetchResult result,
|
||||
@Nullable String errorNotificationTitle, @NotNull Collection<? extends Exception> errors) {
|
||||
if (result.isSuccess()) {
|
||||
GitVcs.NOTIFICATION_GROUP_ID.createNotification("Fetched successfully", NotificationType.INFORMATION).notify(project);
|
||||
GitVcs.NOTIFICATION_GROUP_ID.createNotification("Fetched successfully" + result.getAdditionalInfo(), NotificationType.INFORMATION).notify(project);
|
||||
} else if (result.isCancelled()) {
|
||||
GitVcs.NOTIFICATION_GROUP_ID.createNotification("Fetch cancelled by user", NotificationType.WARNING).notify(project);
|
||||
GitVcs.NOTIFICATION_GROUP_ID.createNotification("Fetch cancelled by user" + result.getAdditionalInfo(), NotificationType.WARNING).notify(project);
|
||||
} else if (result.isNotAuthorized()) {
|
||||
String title;
|
||||
String description;
|
||||
@@ -145,11 +161,12 @@ public class GitFetcher {
|
||||
title = "Fetch failed";
|
||||
description = "Couldn't authorize";
|
||||
}
|
||||
description += result.getAdditionalInfo();
|
||||
GitUIUtil.notifyMessage(project, title, description, NotificationType.ERROR, true, null);
|
||||
} else {
|
||||
GitVcs instance = GitVcs.getInstance(project);
|
||||
if (instance != null && instance.getExecutableValidator().isExecutableValid()) {
|
||||
GitUIUtil.notifyMessage(project, "Fetch failed", null, NotificationType.ERROR, true, errors);
|
||||
GitUIUtil.notifyMessage(project, "Fetch failed", result.getAdditionalInfo(), NotificationType.ERROR, true, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,8 +182,10 @@ public class GitFetcher {
|
||||
* @return true if all fetches were successful, false if at least one fetch failed.
|
||||
*/
|
||||
public boolean fetchRootsAndNotify(@NotNull Collection<VirtualFile> roots, @Nullable String errorNotificationTitle, boolean notifySuccess) {
|
||||
Map<VirtualFile, String> additionalInfo = new HashMap<VirtualFile, String>();
|
||||
for (VirtualFile root : roots) {
|
||||
GitFetchResult result = fetch(root);
|
||||
additionalInfo.put(root, result.getAdditionalInfo());
|
||||
if (!result.isSuccess()) {
|
||||
displayFetchResult(myProject, result, errorNotificationTitle, getErrors());
|
||||
return false;
|
||||
@@ -175,6 +194,50 @@ public class GitFetcher {
|
||||
if (notifySuccess) {
|
||||
GitUIUtil.notifySuccess(myProject, "", "Fetched successfully");
|
||||
}
|
||||
|
||||
String addInfo = makeAdditionalInfoByRoot(additionalInfo);
|
||||
if (!StringUtil.isEmptyOrSpaces(addInfo)) {
|
||||
NotificationManager.getInstance(myProject).notify(GitVcs.MINOR_NOTIFICATION, "Fetch details", addInfo, NotificationType.INFORMATION);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String makeAdditionalInfoByRoot(@NotNull Map<VirtualFile, String> additionalInfo) {
|
||||
if (additionalInfo.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder info = new StringBuilder();
|
||||
if (myRepositoryManager.moreThanOneRoot()) {
|
||||
for (Map.Entry<VirtualFile, String> entry : additionalInfo.entrySet()) {
|
||||
info.append(entry.getValue()).append(" in ").append(GitUIUtil.getShortRepositoryName(myProject, entry.getKey()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
info.append(additionalInfo.values().iterator().next());
|
||||
}
|
||||
return info.toString();
|
||||
}
|
||||
|
||||
private static class GitFetchPruneDetector extends GitLineHandlerAdapter {
|
||||
|
||||
private static final Pattern PRUNE_PATTERN = Pattern.compile("\\s*x\\s*\\[deleted\\].*->\\s*(\\S*)");
|
||||
|
||||
@NotNull private final Collection<String> myPrunedRefs = new ArrayList<String>();
|
||||
|
||||
@Override
|
||||
public void onLineAvailable(String line, Key outputType) {
|
||||
// x [deleted] (none) -> origin/frmari
|
||||
Matcher matcher = PRUNE_PATTERN.matcher(line);
|
||||
if (matcher.matches()) {
|
||||
myPrunedRefs.add(matcher.group(1));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<String> getPrunedRefs() {
|
||||
return myPrunedRefs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user