[vcs]: implement favourite-branches serialization

* add git realization
This commit is contained in:
Nadya Zabrodina
2017-01-11 16:45:33 +03:00
parent e1b2d4454b
commit 9bc60ea17f
6 changed files with 252 additions and 33 deletions
@@ -0,0 +1,66 @@
/*
* Copyright 2000-2016 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 com.intellij.dvcs.branch;
import com.intellij.dvcs.repo.Repository;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.annotations.MapAnnotation;
import com.intellij.util.xmlb.annotations.Property;
import com.intellij.util.xmlb.annotations.Tag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import static com.intellij.dvcs.branch.DvcsBranchUtil.find;
import static com.intellij.util.containers.ContainerUtil.newArrayList;
@Tag("branch-storage")
public class BranchStorage {
@Property(surroundWithTag = false)
@MapAnnotation(keyAttributeName = "type")
@NotNull public Map<String, List<DvcsBranchInfo>> myBranches = ContainerUtil.newHashMap();
public BranchStorage() {
}
public boolean contains(@NotNull String typeName, @Nullable Repository repository, @NotNull String branchName) {
List<DvcsBranchInfo> branches = myBranches.get(typeName);
return branches != null && find(branches, repository, branchName) != null;
}
public void add(@NotNull String typeName, @Nullable Repository repository,
@NotNull String branchName) {
if (contains(typeName, repository, branchName)) return;
List<DvcsBranchInfo> branchInfos = myBranches.computeIfAbsent(typeName, name -> newArrayList());
branchInfos.add(new DvcsBranchInfo(DvcsBranchUtil.getPathFor(repository), branchName));
}
public void remove(@NotNull String typeName, @Nullable Repository repository,
@NotNull String branchName) {
List<DvcsBranchInfo> branches = myBranches.get(typeName);
DvcsBranchInfo toDelete = find(branches, repository, branchName);
if (toDelete != null) {
branches.remove(toDelete);
if (branches.isEmpty()) {
myBranches.remove(typeName);
}
}
}
}
@@ -0,0 +1,40 @@
package com.intellij.dvcs.branch;
import com.intellij.util.xmlb.annotations.Attribute;
import com.intellij.util.xmlb.annotations.Tag;
import java.util.Objects;
@Tag("branch-info")
public class DvcsBranchInfo {
@Attribute(value = "repo") public final String repoPath;
@Attribute(value = "source") public final String sourceName;
@SuppressWarnings("unused")
public DvcsBranchInfo() {
this("", "");
}
public DvcsBranchInfo(String repositoryPath, String source) {
repoPath = repositoryPath;
sourceName = source;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DvcsBranchInfo info = (DvcsBranchInfo)o;
if (repoPath != null ? !repoPath.equals(info.repoPath) : info.repoPath != null) return false;
if (sourceName != null ? !sourceName.equals(info.sourceName) : info.sourceName != null) return false;
return true;
}
@Override
public int hashCode() {
return Objects.hash(repoPath, sourceName);
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2000-2016 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 com.intellij.dvcs.branch;
import com.intellij.dvcs.repo.Repository;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public class DvcsBranchUtil {
@Nullable
public static <T extends DvcsBranchInfo> T find(@Nullable final Collection<T> branches,
@Nullable Repository repository,
@NotNull String sourceBranch) {
if (branches == null) return null;
return ContainerUtil.find(branches, targetInfo -> repoAndSourceAreEqual(repository, sourceBranch, targetInfo));
}
private static boolean repoAndSourceAreEqual(@Nullable Repository repository,
@NotNull String sourceBranch,
@NotNull DvcsBranchInfo targetInfo) {
return getPathFor(repository).equals(targetInfo.repoPath) && StringUtil.equals(targetInfo.sourceName, sourceBranch);
}
@NotNull
public static String getPathFor(@Nullable Repository repository) {
return repository == null ? "" : repository.getRoot().getPath();
}
}
@@ -0,0 +1,21 @@
/*
* Copyright 2000-2016 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 git4idea.branch;
public enum GitBranchType {
GIT_LOCAL, GIT_REMOTE
}
@@ -15,7 +15,10 @@
*/
package git4idea.config;
import com.intellij.dvcs.branch.BranchStorage;
import com.intellij.dvcs.branch.DvcsBranchInfo;
import com.intellij.dvcs.branch.DvcsSyncSettings;
import com.intellij.dvcs.repo.Repository;
import com.intellij.lifecycle.PeriodicalTasksCloser;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
@@ -30,16 +33,18 @@ import com.intellij.util.xmlb.annotations.Attribute;
import com.intellij.util.xmlb.annotations.Tag;
import git4idea.GitRemoteBranch;
import git4idea.GitUtil;
import git4idea.branch.GitBranchType;
import git4idea.push.GitPushTagMode;
import git4idea.repo.GitRemote;
import git4idea.repo.GitRepository;
import git4idea.reset.GitResetMode;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.dvcs.branch.DvcsBranchUtil.find;
/**
* Git VCS settings
*/
@@ -83,6 +88,9 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
@AbstractCollection(surroundWithTag = false)
@Tag("push-targets")
public List<PushTargetInfo> PUSH_TARGETS = ContainerUtil.newArrayList();
@Tag("favourite-branches")
public BranchStorage FAVOURITE_BRANCHES = new BranchStorage();
}
public GitVcsSettings(GitVcsApplicationSettings appSettings) {
@@ -265,50 +273,37 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
@Nullable
public GitRemoteBranch getPushTarget(@NotNull GitRepository repository, @NotNull String sourceBranch) {
Iterator<PushTargetInfo> iterator = myState.PUSH_TARGETS.iterator();
PushTargetInfo targetInfo = find(iterator, repository, sourceBranch);
if (targetInfo == null) {
return null;
}
PushTargetInfo targetInfo = find(myState.PUSH_TARGETS, repository, sourceBranch);
if (targetInfo == null) return null;
GitRemote remote = GitUtil.findRemoteByName(repository, targetInfo.targetRemoteName);
if (remote == null) {
return null;
}
if (remote == null) return null;
return GitUtil.findOrCreateRemoteBranch(repository, remote, targetInfo.targetBranchName);
}
public void setPushTarget(@NotNull GitRepository repository, @NotNull String sourceBranch,
@NotNull String targetRemote, @NotNull String targetBranch) {
String repositoryPath = repository.getRoot().getPath();
List<PushTargetInfo> targets = new ArrayList<>(myState.PUSH_TARGETS);
Iterator<PushTargetInfo> iterator = targets.iterator();
PushTargetInfo existingInfo = find(iterator, repository, sourceBranch);
PushTargetInfo existingInfo = find(myState.PUSH_TARGETS, repository, sourceBranch);
if (existingInfo != null) {
iterator.remove();
myState.PUSH_TARGETS.remove(existingInfo);
}
PushTargetInfo newInfo = new PushTargetInfo(repositoryPath, sourceBranch, targetRemote, targetBranch);
targets.add(newInfo);
myState.PUSH_TARGETS = targets;
myState.PUSH_TARGETS.add(new PushTargetInfo(repositoryPath, sourceBranch, targetRemote, targetBranch));
}
@Nullable
@Contract(pure = false)
private static PushTargetInfo find(@NotNull Iterator<PushTargetInfo> iterator,
@NotNull GitRepository repository,
@NotNull String sourceBranch) {
while (iterator.hasNext()) {
PushTargetInfo targetInfo = iterator.next();
if (targetInfo.repoPath.equals(repository.getRoot().getPath()) && targetInfo.sourceName.equals(sourceBranch)) {
return targetInfo;
}
}
return null;
public void addToFavourites(@NotNull GitBranchType type, @Nullable GitRepository repository, @NotNull String branchName) {
myState.FAVOURITE_BRANCHES.add(type.toString(), repository, branchName);
}
public void removeFromFavourites(@NotNull GitBranchType type, @Nullable GitRepository repository, @NotNull String branchName) {
myState.FAVOURITE_BRANCHES.remove(type.toString(), repository, branchName);
}
public boolean isFavourite(@NotNull GitBranchType type, @Nullable Repository repository, @NotNull String branchName) {
return myState.FAVOURITE_BRANCHES.contains(type.toString(), repository, branchName);
}
@Tag("push-target-info")
private static class PushTargetInfo {
@Attribute(value = "repo") public String repoPath;
@Attribute(value = "source") public String sourceName;
private static class PushTargetInfo extends DvcsBranchInfo {
@Attribute(value = "target-remote") public String targetRemoteName;
@Attribute(value = "target-branch") public String targetBranchName;
@@ -318,10 +313,28 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
}
PushTargetInfo(@NotNull String repositoryPath, @NotNull String source, @NotNull String targetRemote, @NotNull String targetBranch) {
repoPath = repositoryPath;
sourceName = source;
super(repositoryPath, source);
targetRemoteName = targetRemote;
targetBranchName = targetBranch;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
PushTargetInfo info = (PushTargetInfo)o;
if (targetRemoteName != null ? !targetRemoteName.equals(info.targetRemoteName) : info.targetRemoteName != null) return false;
if (targetBranchName != null ? !targetBranchName.equals(info.targetBranchName) : info.targetBranchName != null) return false;
return true;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), targetRemoteName,targetBranchName);
}
}
}
@@ -29,6 +29,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.util.containers.ContainerUtil;
import git4idea.branch.GitBranchUtil;
import git4idea.branch.GitBrancher;
import git4idea.config.GitVcsSettings;
import git4idea.repo.GitRepository;
import git4idea.validators.GitNewBranchNameValidator;
import org.jetbrains.annotations.NotNull;
@@ -41,6 +42,8 @@ import java.util.stream.Collectors;
import static com.intellij.dvcs.branch.DvcsBranchPopup.MyMoreIndex.MAX_BRANCH_NUM;
import static com.intellij.dvcs.ui.BranchActionGroupPopup.addMoreActionIfNeeded;
import static git4idea.GitStatisticsCollectorKt.reportUsage;
import static git4idea.branch.GitBranchType.GIT_LOCAL;
import static git4idea.branch.GitBranchType.GIT_REMOTE;
class GitBranchPopupActions {
@@ -142,6 +145,7 @@ class GitBranchPopupActions {
static class LocalBranchActions extends BranchActionGroup implements PopupElementWithAdditionalInfo {
private final Project myProject;
private final GitVcsSettings myGitVcsSettings;
private final List<GitRepository> myRepositories;
private final String myBranchName;
@NotNull private final GitRepository mySelectedRepository;
@@ -152,7 +156,9 @@ class GitBranchPopupActions {
myRepositories = repositories;
myBranchName = branchName;
mySelectedRepository = selectedRepository;
myGitVcsSettings = GitVcsSettings.getInstance(project);
getTemplatePresentation().setText(calcBranchText(), false); // no mnemonics
setFavourite(myGitVcsSettings.isFavourite(GIT_LOCAL, repositories.size() > 1 ? null : mySelectedRepository, myBranchName));
}
@NotNull
@@ -191,6 +197,17 @@ class GitBranchPopupActions {
return new GitMultiRootBranchConfig(myRepositories).getTrackedBranch(myBranchName);
}
@Override
public void toggle() {
super.toggle();
if (isFavourite()) {
myGitVcsSettings.addToFavourites(GIT_LOCAL, myRepositories.size() > 1 ? null : mySelectedRepository, myBranchName);
}
else {
myGitVcsSettings.removeFromFavourites(GIT_LOCAL, myRepositories.size() > 1 ? null : mySelectedRepository, myBranchName);
}
}
static class CheckoutAction extends DumbAwareAction {
private final Project myProject;
private final List<GitRepository> myRepositories;
@@ -288,17 +305,32 @@ class GitBranchPopupActions {
static class RemoteBranchActions extends BranchActionGroup {
private final Project myProject;
private final GitVcsSettings myGitVcsSettings;
private final List<GitRepository> myRepositories;
private final String myBranchName;
@NotNull private final GitRepository mySelectedRepository;
RemoteBranchActions(@NotNull Project project, @NotNull List<GitRepository> repositories, @NotNull String branchName,
@NotNull GitRepository selectedRepository) {
myProject = project;
myRepositories = repositories;
myBranchName = branchName;
mySelectedRepository = selectedRepository;
myGitVcsSettings = GitVcsSettings.getInstance(project);
getTemplatePresentation().setText(myBranchName, false); // no mnemonics
setFavourite(myGitVcsSettings.isFavourite(GIT_REMOTE, repositories.size() > 1 ? null : mySelectedRepository, myBranchName));
}
@Override
public void toggle() {
super.toggle();
if (isFavourite()) {
myGitVcsSettings.addToFavourites(GIT_REMOTE, myRepositories.size() > 1 ? null : mySelectedRepository, myBranchName);
}
else {
myGitVcsSettings.removeFromFavourites(GIT_REMOTE, myRepositories.size() > 1 ? null : mySelectedRepository, myBranchName);
}
}
@NotNull