IDEA-68072 "Subversion -> Compare with branch..." not working when selecting trunk

+ ask credentials if needed when "Refresh branches"
+ do not store concrete branches info in other.xml, store only mappings
+ store concrete branches in /system
+ order branches mapping for serialization
This commit is contained in:
irengrig
2011-08-24 19:43:56 +04:00
parent 8d1e1865ee
commit 815d83ccd6
13 changed files with 306 additions and 140 deletions
+2
View File
@@ -122,6 +122,8 @@
serviceImplementation="org.jetbrains.idea.svn.history.LoadedRevisionsCache"/>
<projectService serviceInterface="org.jetbrains.idea.svn.mergeinfo.SvnMergeInfoCache"
serviceImplementation="org.jetbrains.idea.svn.mergeinfo.SvnMergeInfoCache"/>
<projectService serviceInterface="org.jetbrains.idea.svn.SvnLoadedBrachesStorage"
serviceImplementation="org.jetbrains.idea.svn.SvnLoadedBrachesStorage"/>
<applicationService serviceInterface="org.jetbrains.idea.svn.SvnBranchMapperManager"
serviceImplementation="org.jetbrains.idea.svn.SvnBranchMapperManager"/>
<applicationService serviceInterface="org.jetbrains.idea.svn.dialogs.browserCache.SvnRepositoryCache"
@@ -60,10 +60,12 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnBranchConfigurationManager");
private final Project myProject;
private final ProjectLevelVcsManager myVcsManager;
private final SvnLoadedBrachesStorage myStorage;
public SvnBranchConfigurationManager(final Project project, final ProjectLevelVcsManager vcsManager) {
public SvnBranchConfigurationManager(final Project project, final ProjectLevelVcsManager vcsManager, final SvnLoadedBrachesStorage storage) {
myProject = project;
myVcsManager = vcsManager;
myStorage = storage;
myBunch = new NewRootBunch(project);
}
@@ -72,7 +74,7 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
}
public static class ConfigurationBean {
public Map<String, SvnBranchConfiguration> myConfigurationMap = new HashMap<String, SvnBranchConfiguration>();
public Map<String, SvnBranchConfiguration> myConfigurationMap = new TreeMap<String, SvnBranchConfiguration>();
/**
* version of "support SVN in IDEA". for features tracking. should grow
*/
@@ -122,7 +124,6 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
for (String origKey : origMap.keySet()) {
map.put(origKey, origMap.get(origKey).getValue());
}
configuration.setBranchMap(map);
result.myConfigurationMap.put(key, helper.prepareForSerialization(configuration));
}
result.mySupportsUserInfoFilter = true;
@@ -159,7 +160,7 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
// check if cancel had been put
if (! vcs.isVcsBackgroundOperationsAllowed(myRoot)) return;
if (myAll || (! oldUrls.contains(newBranchUrl))) {
new NewRootBunch.BranchesLoadRunnable(myProject, myBunch, newBranchUrl, InfoReliability.defaultValues, myRoot, null).run();
new NewRootBunch.BranchesLoadRunnable(myProject, myBunch, newBranchUrl, InfoReliability.defaultValues, myRoot, null, true).run();
}
}
}
@@ -193,13 +194,14 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
final SvnBranchConfigurationNew newConfig = new SvnBranchConfigurationNew();
newConfig.setTrunkUrl(configToConvert.getTrunkUrl());
newConfig.setUserinfoInUrl(configToConvert.isUserinfoInUrl());
final Map<String, List<SvnBranchItem>> oldMap = configToConvert.getBranchMap();
for (String branchUrl : configToConvert.getBranchUrls()) {
List<SvnBranchItem> items = oldMap.get(branchUrl);
items = ((items == null) || (items.isEmpty())) ? new ArrayList<SvnBranchItem>() : items;
whatToInit.add(new Pair<VirtualFile, SvnBranchConfigurationNew>(root, newConfig));
newConfig.addBranches(branchUrl, new InfoStorage<List<SvnBranchItem>>(items,
(items.isEmpty()) ? InfoReliability.defaultValues : InfoReliability.setByUser));
List<SvnBranchItem> stored = getStored(branchUrl);
if (stored != null && ! stored.isEmpty()) {
newConfig.addBranches(branchUrl, new InfoStorage<List<SvnBranchItem>>(stored, InfoReliability.setByUser));
} else {
whatToInit.add(new Pair<VirtualFile, SvnBranchConfigurationNew>(root, newConfig));
newConfig.addBranches(branchUrl, new InfoStorage<List<SvnBranchItem>>(new ArrayList<SvnBranchItem>(), InfoReliability.empty));
}
}
myBunch.updateForRoot(root, new InfoStorage<SvnBranchConfigurationNew>(newConfig, InfoReliability.setByUser), null);
@@ -227,6 +229,14 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
myConfigurationBean = object;
}
private List<SvnBranchItem> getStored(String branchUrl) {
Collection<SvnBranchItem> collection = myStorage.get(branchUrl);
if (collection == null) return null;
final List<SvnBranchItem> items = new ArrayList<SvnBranchItem>(collection);
Collections.sort(items);
return items;
}
private static class UrlSerializationHelper {
private final SvnVcs myVcs;
@@ -248,24 +258,9 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
newBranchesList.add(serializeUrl(s, withUserInfo));
}
final Map<String, List<SvnBranchItem>> map = configuration.getBranchMap();
final Map<String, List<SvnBranchItem>> newMap = new HashMap<String, List<SvnBranchItem>>(map.size(), 1.0f);
for (Map.Entry<String, List<SvnBranchItem>> entry : map.entrySet()) {
final List<SvnBranchItem> items = entry.getValue();
if (items != null) {
final List<SvnBranchItem> newItems = new ArrayList<SvnBranchItem>();
for (SvnBranchItem item : items) {
newItems.add(new SvnBranchItem(serializeUrl(item.getUrl(), withUserInfo), new java.util.Date(item.getCreationDateMillis()),
item.getRevision()));
}
newMap.put(serializeUrl(entry.getKey(), withUserInfo), newItems);
}
}
final SvnBranchConfiguration result = new SvnBranchConfiguration();
result.setTrunkUrl(trunkUrl);
result.setBranchUrls(newBranchesList);
result.setBranchMap(newMap);
result.setUserinfoInUrl(withUserInfo.isNull() ? false : withUserInfo.get());
return result;
}
@@ -286,24 +281,9 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
newBranchesList.add(deserializeUrl(s, userInfo));
}
final Map<String, List<SvnBranchItem>> map = configuration.getBranchMap();
final Map<String, List<SvnBranchItem>> newMap = new HashMap<String, List<SvnBranchItem>>(map.size(), 1.0f);
for (Map.Entry<String, List<SvnBranchItem>> entry : map.entrySet()) {
final List<SvnBranchItem> items = entry.getValue();
if (items != null) {
final List<SvnBranchItem> newItems = new ArrayList<SvnBranchItem>();
for (SvnBranchItem item : items) {
newItems.add(new SvnBranchItem(deserializeUrl(item.getUrl(), userInfo), new java.util.Date(item.getCreationDateMillis()),
item.getRevision()));
}
newMap.put(deserializeUrl(entry.getKey(), userInfo), newItems);
}
}
final SvnBranchConfiguration result = new SvnBranchConfiguration();
result.setTrunkUrl(newTrunkUrl);
result.setBranchUrls(newBranchesList);
result.setBranchMap(newMap);
result.setUserinfoInUrl(userInfo != null && userInfo.length() > 0);
return result;
}
@@ -28,6 +28,9 @@ import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
import java.io.File;
import java.util.*;
/**
* Holds what working copies we have for URLs
*/
@State(
name = "SvnBranchMapperManager",
storages = {
@@ -433,7 +433,7 @@ compare.with.branch.diff.title=Compare with Branch
compare.with.branch.error.title=Compare with Branch
compare.with.branch.popup.title=Compare with Branch
getting.branch.configuration.error=Error retrieving branch configuration: {0}
compare.with.branch.location.error=Couldn''t find repository location for file ''{0}'' under branch ''{1}''
compare.with.branch.location.error=Couldn''t find repository location for file ''{0}'' under branch ''{1}''\nPlease check your branch configuration.
compare.with.branch.list.error=Error Loading Branches
create.branch.invalid.revision.error=Invalid revision ''{0}''
create.branch.no.working.copy.error=No working copy found at {0}
@@ -0,0 +1,153 @@
/*
* Copyright 2000-2011 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 org.jetbrains.idea.svn;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.persistent.SmallMapSerializer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.EnumeratorStringDescriptor;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.branchConfig.InfoReliability;
import org.jetbrains.idea.svn.branchConfig.InfoStorage;
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
import org.jetbrains.idea.svn.integrate.SvnBranchItem;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* Created by IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 8/24/11
* Time: 1:21 PM
*/
public class SvnLoadedBrachesStorage {
private final Object myLock;
private SmallMapSerializer<String, Map<String, Collection<SvnBranchItem>>> myState;
private final File myFile;
private final Project myProject;
public SvnLoadedBrachesStorage(final Project project) {
myProject = project;
final File vcsFile = new File(PathManager.getSystemPath(), "vcs");
File file = new File(vcsFile, "svn_branches");
file.mkdirs();
myFile = new File(file, project.getLocationHash());
myLock = new Object();
}
@Nullable
public Collection<SvnBranchItem> get(final String url) {
synchronized (myLock) {
if (myState == null) return null;
Map<String, Collection<SvnBranchItem>> map = myState.get("");
return map == null ? null : map.get(SvnBranchConfigurationNew.ensureEndSlash(url));
}
}
public void put(final String url, final Collection<SvnBranchItem> items) {
synchronized (myLock) {
if (myState == null) return;
Map<String, Collection<SvnBranchItem>> map = myState.get("");
if (map == null) {
map = new HashMap<String, Collection<SvnBranchItem>>();
myState.put("", map);
}
map.put(url, items);
}
}
public void activate() {
synchronized (myLock) {
myState = new SmallMapSerializer<String, Map<String, Collection<SvnBranchItem>>>(myFile, new EnumeratorStringDescriptor(), createExternalizer());
}
}
public void deactivate() {
SvnBranchConfigurationManager manager = SvnBranchConfigurationManager.getInstance(myProject);
Map<VirtualFile,SvnBranchConfigurationNew> mapCopy = manager.getSvnBranchConfigManager().getMapCopy();
for (Map.Entry<VirtualFile, SvnBranchConfigurationNew> entry : mapCopy.entrySet()) {
Map<String,InfoStorage<List<SvnBranchItem>>> branchMap = entry.getValue().getBranchMap();
for (Map.Entry<String, InfoStorage<List<SvnBranchItem>>> storageEntry : branchMap.entrySet()) {
put(storageEntry.getKey(), storageEntry.getValue().getValue());
}
}
synchronized (myLock) {
myState.force();
myState = null;
}
}
private DataExternalizer<Map<String, Collection<SvnBranchItem>>> createExternalizer() {
return new DataExternalizer<Map<String, Collection<SvnBranchItem>>>() {
@Override
public void save(DataOutput out, Map<String, Collection<SvnBranchItem>> value) throws IOException {
out.writeInt(value.size());
ArrayList<String> keys = new ArrayList<String>(value.keySet());
Collections.sort(keys);
for (String key : keys) {
out.writeUTF(key);
List<SvnBranchItem> list = new ArrayList<SvnBranchItem>(value.get(key));
Collections.sort(list, SerializationComparator.getInstance());
out.writeInt(list.size());
for (SvnBranchItem item : list) {
out.writeUTF(item.getUrl());
out.writeLong(item.getCreationDateMillis());
out.writeLong(item.getRevision());
}
}
}
@Override
public Map<String, Collection<SvnBranchItem>> read(DataInput in) throws IOException {
final HashMap<String, Collection<SvnBranchItem>> map = new HashMap<String, Collection<SvnBranchItem>>();
int mapSize = in.readInt();
for (int i = 0; i < mapSize; i++) {
final String key = in.readUTF();
final int size = in.readInt();
final ArrayList<SvnBranchItem> list = new ArrayList<SvnBranchItem>(size);
for (int j = 0; j < size; j++) {
String url = in.readUTF();
long creation = in.readLong();
long revision = in.readLong();
list.add(new SvnBranchItem(url, new Date(creation), revision));
}
map.put(key, list);
}
return map;
}
};
}
private static class SerializationComparator implements Comparator<SvnBranchItem> {
private final static SerializationComparator ourInstance = new SerializationComparator();
public static SerializationComparator getInstance() {
return ourInstance;
}
@Override
public int compare(SvnBranchItem o1, SvnBranchItem o2) {
return o1.getUrl().compareToIgnoreCase(o2.getUrl());
}
}
}
@@ -0,0 +1,26 @@
/*
* Copyright 2000-2011 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 org.jetbrains.idea.svn;
/**
* Created by IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 8/24/11
* Time: 1:07 PM
* To change this template use File | Settings | File Templates.
*/
public class SvnLoadedBranches {
}
@@ -151,6 +151,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
private final RootsToWorkingCopies myRootsToWorkingCopies;
private final SvnAuthenticationNotifier myAuthNotifier;
private static RareLogger.LogFilter[] ourLogFilters;
private final SvnLoadedBrachesStorage myLoadedBranchesStorage;
static {
SVNJNAUtil.setJNAEnabled(true);
@@ -180,8 +181,10 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
return Boolean.valueOf(System.getProperty(systemParameterName));
}
public SvnVcs(final Project project, MessageBus bus, SvnConfiguration svnConfiguration) {
public SvnVcs(final Project project, MessageBus bus, SvnConfiguration svnConfiguration, final ChangeListManager changeListManager,
final VcsDirtyScopeManager vcsDirtyScopeManager, final SvnLoadedBrachesStorage storage) {
super(project, VCS_NAME);
myLoadedBranchesStorage = storage;
LOG.debug("ct");
myRootsToWorkingCopies = new RootsToWorkingCopies(myProject);
myConfiguration = svnConfiguration;
@@ -417,6 +420,8 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
});
vcsManager.addVcsListener(myRootsToWorkingCopies);
myLoadedBranchesStorage.activate();
}
private static void initLogFilters() {
@@ -500,6 +505,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
mySvnBranchPointsCalculator.deactivate();
mySvnBranchPointsCalculator = null;
myWorkingCopiesContent.deactivate();
myLoadedBranchesStorage.deactivate();
}
public VcsShowConfirmationOption getAddConfirmation() {
@@ -15,6 +15,7 @@
*/
package org.jetbrains.idea.svn.actions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
@@ -27,11 +28,14 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.components.JBList;
import com.intellij.util.Consumer;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.continuation.ModalityIgnorantBackgroundableTask;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.*;
import org.jetbrains.idea.svn.branchConfig.InfoReliability;
import org.jetbrains.idea.svn.branchConfig.NewRootBunch;
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigManager;
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
import org.jetbrains.idea.svn.dialogs.BranchConfigurationDialog;
@@ -181,52 +185,40 @@ public class SelectBranchPopup {
});
}
else {
showBranchPopup(selectedValue, true);
showBranchPopup(selectedValue);
}
return FINAL_CHOICE;
}
@Nullable
private List<SvnBranchItem> loadBranches(final String selectedBranchesHolder, final boolean cached) {
if (cached) {
return myConfiguration.getBranches(selectedBranchesHolder);
}
final List<SvnBranchItem> result = new ArrayList<SvnBranchItem>();
private void loadBranches(final String selectedBranchesHolder, final Runnable runnable) {
final ProgressManager pm = ProgressManager.getInstance();
final boolean wasCanceled = ! pm.runProcessWithProgressSynchronously(new Runnable() {
public void run() {
final ProgressIndicator pi = pm.getProgressIndicator();
final Semaphore s = new Semaphore();
s.down();
final Ref<Boolean> completedRef = new Ref<Boolean>();
final SvnBranchConfigManager manager = SvnBranchConfigurationManager.getInstance(myProject).getSvnBranchConfigManager();
manager.reloadBranches(myVcsRoot, selectedBranchesHolder, new Consumer<List<SvnBranchItem>>() {
public void consume(final List<SvnBranchItem> svnBranchItems) {
result.addAll(svnBranchItems);
completedRef.set(true);
s.up();
}
});
while (true) {
s.waitFor(500);
if (Boolean.TRUE.equals(completedRef.get())) break;
pi.checkCanceled();
}
pm.run(new ModalityIgnorantBackgroundableTask(myProject, SvnBundle.message("compare.with.branch.progress.loading.branches")) {
@Override
protected void doInAwtIfFail(Exception e) {
runnable.run();
}
}, SvnBundle.message("compare.with.branch.progress.loading.branches"), true, myProject);
@Override
protected void doInAwtIfCancel() {
runnable.run();
}
if (wasCanceled) {
return myConfiguration.getBranches(selectedBranchesHolder);
} else {
return result;
}
@Override
protected void doInAwtIfSuccess() {
runnable.run();
}
@Override
protected void runImpl(@NotNull ProgressIndicator indicator) {
final SvnBranchConfigManager manager = SvnBranchConfigurationManager.getInstance(myProject).getSvnBranchConfigManager();
new NewRootBunch.BranchesLoadRunnable(myProject, manager, selectedBranchesHolder, InfoReliability.setByUser, myVcsRoot, null, false).run();
}
});
}
private void showBranchPopup(final String selectedValue, final boolean cached) {
List<SvnBranchItem> branches = loadBranches(selectedValue, cached);
private void showBranchPopup(final String selectedValue) {
List<SvnBranchItem> branches = myConfiguration.getBranches(selectedValue);
if (branches == null) {
return;
}
@@ -247,7 +239,12 @@ public class SelectBranchPopup {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
showBranchPopup(selectedValue, false);
loadBranches(selectedValue, new Runnable() {
@Override
public void run() {
showBranchPopup(selectedValue);
}
});
}
});
return;
@@ -18,6 +18,7 @@ package org.jetbrains.idea.svn.branchConfig;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import org.jetbrains.idea.svn.SvnConfiguration;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.integrate.SvnBranchItem;
import org.tmatesoft.svn.core.ISVNDirEntryHandler;
import org.tmatesoft.svn.core.SVNDirEntry;
@@ -37,11 +38,12 @@ public class BranchesLoader {
private BranchesLoader() {
}
public static List<SvnBranchItem> loadBranches(final Project project, final String url) throws SVNException {
public static List<SvnBranchItem> loadBranches(final Project project, final String url, boolean passive) throws SVNException {
final List<SvnBranchItem> result = new LinkedList<SvnBranchItem>();
final SvnConfiguration configuration = SvnConfiguration.getInstance(project);
final ISVNAuthenticationManager passiveManager = configuration.getPassiveAuthenticationManager();
final ISVNAuthenticationManager passiveManager = passive ? configuration.getPassiveAuthenticationManager() : configuration.getInteractiveManager(
SvnVcs.getInstance(project));
final SVNLogClient logClient = new SVNLogClient(passiveManager, configuration.getOptions(project));
final SVNURL branchesUrl = SVNURL.parseURIEncoded(url);
@@ -32,7 +32,6 @@ import org.jetbrains.idea.svn.integrate.SvnBranchItem;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -95,7 +94,7 @@ public class NewRootBunch implements SvnBranchConfigManager {
public void reloadBranches(@NotNull final VirtualFile root, @NotNull final String branchParentUrl,
final Consumer<List<SvnBranchItem>> callback) {
ApplicationManager.getApplication().executeOnPooledThread(new BranchesLoadRunnable(myProject, this, branchParentUrl,
InfoReliability.setByUser, root, callback));
InfoReliability.setByUser, root, callback, true));
}
@Nullable
@@ -125,7 +124,7 @@ public class NewRootBunch implements SvnBranchConfigManager {
public void consume(List<SvnBranchItem> svnBranchItems) {
runnable.run();
}
}).run();
}, true).run();
}
}
catch (SVNException e) {
@@ -142,21 +141,28 @@ public class NewRootBunch implements SvnBranchConfigManager {
private final Consumer<List<SvnBranchItem>> myCallback;
private final String myUrl;
private final InfoReliability myInfoReliability;
private boolean myPassive;
public BranchesLoadRunnable(final Project project, final SvnBranchConfigManager bunch, final String url, final InfoReliability infoReliability,
final VirtualFile root, @Nullable final Consumer<List<SvnBranchItem>> callback) {
public BranchesLoadRunnable(final Project project,
final SvnBranchConfigManager bunch,
final String url,
final InfoReliability infoReliability,
final VirtualFile root,
@Nullable final Consumer<List<SvnBranchItem>> callback,
boolean passive) {
myProject = project;
myBunch = bunch;
myUrl = url;
myInfoReliability = infoReliability;
myRoot = root;
myCallback = callback;
myPassive = passive;
}
public void run() {
boolean callbackCalled = false;
try {
final List<SvnBranchItem> items = BranchesLoader.loadBranches(myProject, myUrl);
final List<SvnBranchItem> items = BranchesLoader.loadBranches(myProject, myUrl, myPassive);
myBunch.updateBranches(myRoot, myUrl, new InfoStorage<List<SvnBranchItem>>(items, myInfoReliability));
if (myCallback != null) {
myCallback.consume(items);
@@ -171,7 +177,7 @@ public class NewRootBunch implements SvnBranchConfigManager {
} finally {
// callback must be called by contract
if (myCallback != null && (! callbackCalled)) {
myCallback.consume(Collections.<SvnBranchItem>emptyList());
myCallback.consume(null);
}
}
}
@@ -193,7 +199,8 @@ public class NewRootBunch implements SvnBranchConfigManager {
if (result != null) {
final Application application = ApplicationManager.getApplication();
for (String url : result.getBranchUrls()) {
application.executeOnPooledThread(new BranchesLoadRunnable(myProject, myBunch, url, InfoReliability.defaultValues, myRoot, null));
application.executeOnPooledThread(new BranchesLoadRunnable(myProject, myBunch, url, InfoReliability.defaultValues, myRoot, null,
true));
}
myBunch.updateForRoot(myRoot, new InfoStorage<SvnBranchConfigurationNew>(result, InfoReliability.defaultValues), null);
}
@@ -38,7 +38,7 @@ public interface SvnBranchConfigManager {
SvnBranchConfigurationNew getConfig(@NotNull VirtualFile root);
void reloadBranches(@NotNull VirtualFile root, @NotNull String branchParentUrl,
Consumer<List<SvnBranchItem>> callback);
Consumer<List<SvnBranchItem>> callback);
@Nullable
@CalledInBackground
SVNURL getWorkingBranchWithReload(final SVNURL svnurl, final VirtualFile root);
@@ -17,13 +17,16 @@ package org.jetbrains.idea.svn.branchConfig;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.ObjectsConvertor;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.Convertor;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.integrate.SvnBranchItem;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
import org.tmatesoft.svn.core.wc.SVNInfo;
import org.tmatesoft.svn.core.wc.SVNRevision;
@@ -62,11 +65,18 @@ public class SvnBranchConfigurationNew {
public List<String> getBranchUrls() {
final ArrayList<String> result = new ArrayList<String>(myBranchMap.keySet());
Collections.sort(result);
return result;
final List<String> cutList = ObjectsConvertor.convert(result, new Convertor<String, String>() {
@Override
public String convert(String s) {
return cutEndSlash(s);
}
});
Collections.sort(cutList);
return cutList;
}
public void addBranches(final String branchParentName, final InfoStorage<List<SvnBranchItem>> items) {
public void addBranches(String branchParentName, final InfoStorage<List<SvnBranchItem>> items) {
branchParentName = ensureEndSlash(branchParentName);
InfoStorage<List<SvnBranchItem>> current = myBranchMap.get(branchParentName);
if (current != null) {
LOG.info("Branches list not added for : '" + branchParentName + "; this branch parent URL is already present.");
@@ -75,7 +85,16 @@ public class SvnBranchConfigurationNew {
myBranchMap.put(branchParentName, items);
}
public void updateBranch(final String branchParentName, final InfoStorage<List<SvnBranchItem>> items) {
public static String ensureEndSlash(String name) {
return name.trim().endsWith("/") ? name : name + "/";
}
private static String cutEndSlash(String name) {
return name.endsWith("/") && name.length() > 0 ? name.substring(0, name.length() - 1) : name;
}
public void updateBranch(String branchParentName, final InfoStorage<List<SvnBranchItem>> items) {
branchParentName = ensureEndSlash(branchParentName);
final InfoStorage<List<SvnBranchItem>> current = myBranchMap.get(branchParentName);
if (current == null) {
LOG.info("Branches list not updated for : '" + branchParentName + "; since config has changed.");
@@ -89,21 +108,10 @@ public class SvnBranchConfigurationNew {
}
public List<SvnBranchItem> getBranches(String url) {
url = ensureEndSlash(url);
return myBranchMap.get(url).getValue();
}
/*public SvnBranchConfiguration createFromVcsRootBranches() {
final SvnBranchConfiguration result = new SvnBranchConfiguration();
result.setTrunkUrl(myTrunkUrl);
final Map<String, List<SvnBranchItem>> branchMap = result.getBranchMap();
for (String key : myBranchMap.keySet()) {
result.setTrunkUrl(key);
final List<SvnBranchItem> list = myBranchMap.get(key).getT();
branchMap.put(key, list);
}
return result;
}*/
public SvnBranchConfigurationNew copy() {
SvnBranchConfigurationNew result = new SvnBranchConfigurationNew();
result.myUserinfoInUrl = myUserinfoInUrl;
@@ -119,16 +127,16 @@ public class SvnBranchConfigurationNew {
@Nullable
public String getBaseUrl(String url) {
if ((myTrunkUrl != null) && url.startsWith(myTrunkUrl)) {
return myTrunkUrl;
if (myTrunkUrl != null) {
if (SVNPathUtil.isAncestor(myTrunkUrl, url)) {
return cutEndSlash(myTrunkUrl);
}
}
for(String branchUrl: myBranchMap.keySet()) {
if (url.startsWith(branchUrl)) {
int pos = url.indexOf('/', branchUrl.length()+1);
if (pos >= 0) {
return url.substring(0, pos);
}
return branchUrl;
if (SVNPathUtil.isAncestor(branchUrl, url)) {
String relativePath = SVNPathUtil.getRelativePath(branchUrl, url);
int secondSlash = relativePath.indexOf("/");
return cutEndSlash(branchUrl + (secondSlash == -1 ? relativePath : relativePath.substring(0, secondSlash)));
}
}
return null;
@@ -140,27 +148,8 @@ public class SvnBranchConfigurationNew {
if (baseUrl == null) {
return null;
}
if (myBranchMap.isEmpty()) {
return baseUrl;
}
int commonPrefixLength = getCommonPrefixLength(url, myTrunkUrl);
for (String branchUrl : myBranchMap.keySet()) {
commonPrefixLength = Math.min(commonPrefixLength, getCommonPrefixLength(url, branchUrl));
if (commonPrefixLength <= 0) {
return baseUrl;
}
}
return baseUrl.substring(commonPrefixLength);
}
private static int getCommonPrefixLength(final String s1, final String s2) {
final int minLength = Math.min(s1.length(), s2.length());
for(int i=0; i< minLength; i++) {
if (s1.charAt(i) != s2.charAt(i)) {
return i;
}
}
return minLength;
int lastSlash = baseUrl.lastIndexOf("/");
return lastSlash == -1 ? baseUrl : baseUrl.substring(lastSlash + 1);
}
@Nullable
@@ -171,12 +160,11 @@ public class SvnBranchConfigurationNew {
@Nullable
public SVNURL getWorkingBranch(final SVNURL someUrl) throws SVNException {
final BranchSearcher branchSearcher = new BranchSearcher(someUrl);
iterateUrls(branchSearcher);
return branchSearcher.getResult();
String baseUrl = getBaseUrl(someUrl.toString());
return baseUrl == null ? null : SVNURL.parseURIEncoded(baseUrl);
}
// todo not checked
// todo +-
@Nullable
public String getGroupToLoadToReachUrl(final SVNURL url) throws SVNException {
@@ -209,6 +197,7 @@ public class SvnBranchConfigurationNew {
}
}
// to retrieve mappings between existing in the project working copies and their URLs
@Nullable
public Map<String,String> getUrl2FileMappings(final Project project, final VirtualFile root) {
try {
@@ -220,7 +209,8 @@ public class SvnBranchConfigurationNew {
}
}
public void removeBranch(final String url) {
public void removeBranch(String url) {
url = ensureEndSlash(url);
myBranchMap.remove(url);
}
@@ -261,6 +251,7 @@ public class SvnBranchConfigurationNew {
boolean accept(final String url) throws SVNException;
}
// todo not checked
private static class BranchSearcher implements UrlListener {
private final SVNURL mySomeUrl;
private SVNURL myResult;
@@ -24,7 +24,6 @@ import com.intellij.util.NullableFunction;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnBranchConfiguration;
import org.jetbrains.idea.svn.SvnBranchMapperManager;
import org.jetbrains.idea.svn.SvnBundle;
import org.jetbrains.idea.svn.SvnUtil;