diff --git a/plugins/svn4idea/src/META-INF/plugin.xml b/plugins/svn4idea/src/META-INF/plugin.xml index 27cc78249ba1..91272191afc3 100644 --- a/plugins/svn4idea/src/META-INF/plugin.xml +++ b/plugins/svn4idea/src/META-INF/plugin.xml @@ -122,6 +122,8 @@ serviceImplementation="org.jetbrains.idea.svn.history.LoadedRevisionsCache"/> + myConfigurationMap = new HashMap(); + public Map myConfigurationMap = new TreeMap(); /** * version of "support SVN in IDEA". for features tracking. should grow */ @@ -122,7 +124,6 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent> oldMap = configToConvert.getBranchMap(); for (String branchUrl : configToConvert.getBranchUrls()) { - List items = oldMap.get(branchUrl); - items = ((items == null) || (items.isEmpty())) ? new ArrayList() : items; - whatToInit.add(new Pair(root, newConfig)); - newConfig.addBranches(branchUrl, new InfoStorage>(items, - (items.isEmpty()) ? InfoReliability.defaultValues : InfoReliability.setByUser)); + List stored = getStored(branchUrl); + if (stored != null && ! stored.isEmpty()) { + newConfig.addBranches(branchUrl, new InfoStorage>(stored, InfoReliability.setByUser)); + } else { + whatToInit.add(new Pair(root, newConfig)); + newConfig.addBranches(branchUrl, new InfoStorage>(new ArrayList(), InfoReliability.empty)); + } } myBunch.updateForRoot(root, new InfoStorage(newConfig, InfoReliability.setByUser), null); @@ -227,6 +229,14 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent getStored(String branchUrl) { + Collection collection = myStorage.get(branchUrl); + if (collection == null) return null; + final List items = new ArrayList(collection); + Collections.sort(items); + return items; + } + private static class UrlSerializationHelper { private final SvnVcs myVcs; @@ -248,24 +258,9 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent> map = configuration.getBranchMap(); - final Map> newMap = new HashMap>(map.size(), 1.0f); - for (Map.Entry> entry : map.entrySet()) { - final List items = entry.getValue(); - if (items != null) { - final List newItems = new ArrayList(); - 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> map = configuration.getBranchMap(); - final Map> newMap = new HashMap>(map.size(), 1.0f); - for (Map.Entry> entry : map.entrySet()) { - final List items = entry.getValue(); - if (items != null) { - final List newItems = new ArrayList(); - 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; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBranchMapperManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBranchMapperManager.java index f099c99adaa4..32fe9c01b47f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBranchMapperManager.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBranchMapperManager.java @@ -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 = { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties index cdc41173293c..bb03dc312d59 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties @@ -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} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBrachesStorage.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBrachesStorage.java new file mode 100644 index 000000000000..803485242e0a --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBrachesStorage.java @@ -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>> 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 get(final String url) { + synchronized (myLock) { + if (myState == null) return null; + Map> map = myState.get(""); + return map == null ? null : map.get(SvnBranchConfigurationNew.ensureEndSlash(url)); + } + } + + public void put(final String url, final Collection items) { + synchronized (myLock) { + if (myState == null) return; + Map> map = myState.get(""); + if (map == null) { + map = new HashMap>(); + myState.put("", map); + } + map.put(url, items); + } + } + + public void activate() { + synchronized (myLock) { + myState = new SmallMapSerializer>>(myFile, new EnumeratorStringDescriptor(), createExternalizer()); + } + } + + + public void deactivate() { + SvnBranchConfigurationManager manager = SvnBranchConfigurationManager.getInstance(myProject); + Map mapCopy = manager.getSvnBranchConfigManager().getMapCopy(); + for (Map.Entry entry : mapCopy.entrySet()) { + Map>> branchMap = entry.getValue().getBranchMap(); + for (Map.Entry>> storageEntry : branchMap.entrySet()) { + put(storageEntry.getKey(), storageEntry.getValue().getValue()); + } + } + synchronized (myLock) { + myState.force(); + myState = null; + } + } + + private DataExternalizer>> createExternalizer() { + return new DataExternalizer>>() { + @Override + public void save(DataOutput out, Map> value) throws IOException { + out.writeInt(value.size()); + ArrayList keys = new ArrayList(value.keySet()); + Collections.sort(keys); + for (String key : keys) { + out.writeUTF(key); + List list = new ArrayList(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> read(DataInput in) throws IOException { + final HashMap> map = new HashMap>(); + int mapSize = in.readInt(); + for (int i = 0; i < mapSize; i++) { + final String key = in.readUTF(); + final int size = in.readInt(); + final ArrayList list = new ArrayList(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 { + 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()); + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBranches.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBranches.java new file mode 100644 index 000000000000..0dc10aed38e0 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBranches.java @@ -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 { +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index 192acd88a4cd..29d1bbecf1c6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -151,6 +151,7 @@ public class SvnVcs extends AbstractVcs { 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 { 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 { }); vcsManager.addVcsListener(myRootsToWorkingCopies); + + myLoadedBranchesStorage.activate(); } private static void initLogFilters() { @@ -500,6 +505,7 @@ public class SvnVcs extends AbstractVcs { mySvnBranchPointsCalculator.deactivate(); mySvnBranchPointsCalculator = null; myWorkingCopiesContent.deactivate(); + myLoadedBranchesStorage.deactivate(); } public VcsShowConfirmationOption getAddConfirmation() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SelectBranchPopup.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SelectBranchPopup.java index be1fe87edb7f..89bef1959558 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SelectBranchPopup.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SelectBranchPopup.java @@ -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 loadBranches(final String selectedBranchesHolder, final boolean cached) { - if (cached) { - return myConfiguration.getBranches(selectedBranchesHolder); - } - - final List result = new ArrayList(); + 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 completedRef = new Ref(); - final SvnBranchConfigManager manager = SvnBranchConfigurationManager.getInstance(myProject).getSvnBranchConfigManager(); - manager.reloadBranches(myVcsRoot, selectedBranchesHolder, new Consumer>() { - public void consume(final List 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 branches = loadBranches(selectedValue, cached); + private void showBranchPopup(final String selectedValue) { + List 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; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java index f490696921ca..2980c68438d7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java @@ -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 loadBranches(final Project project, final String url) throws SVNException { + public static List loadBranches(final Project project, final String url, boolean passive) throws SVNException { final List result = new LinkedList(); 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); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/NewRootBunch.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/NewRootBunch.java index 6c25d9bf9631..d1d26914f564 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/NewRootBunch.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/NewRootBunch.java @@ -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> 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 svnBranchItems) { runnable.run(); } - }).run(); + }, true).run(); } } catch (SVNException e) { @@ -142,21 +141,28 @@ public class NewRootBunch implements SvnBranchConfigManager { private final Consumer> 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> callback) { + public BranchesLoadRunnable(final Project project, + final SvnBranchConfigManager bunch, + final String url, + final InfoReliability infoReliability, + final VirtualFile root, + @Nullable final Consumer> 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 items = BranchesLoader.loadBranches(myProject, myUrl); + final List items = BranchesLoader.loadBranches(myProject, myUrl, myPassive); myBunch.updateBranches(myRoot, myUrl, new InfoStorage>(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.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(result, InfoReliability.defaultValues), null); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigManager.java index 0cc323a6dc97..0a47a7771171 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigManager.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigManager.java @@ -38,7 +38,7 @@ public interface SvnBranchConfigManager { SvnBranchConfigurationNew getConfig(@NotNull VirtualFile root); void reloadBranches(@NotNull VirtualFile root, @NotNull String branchParentUrl, - Consumer> callback); + Consumer> callback); @Nullable @CalledInBackground SVNURL getWorkingBranchWithReload(final SVNURL svnurl, final VirtualFile root); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java index 4221ab362b18..e37f0ed286a3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java @@ -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 getBranchUrls() { final ArrayList result = new ArrayList(myBranchMap.keySet()); - Collections.sort(result); - return result; + final List cutList = ObjectsConvertor.convert(result, new Convertor() { + @Override + public String convert(String s) { + return cutEndSlash(s); + } + }); + Collections.sort(cutList); + return cutList; } - public void addBranches(final String branchParentName, final InfoStorage> items) { + public void addBranches(String branchParentName, final InfoStorage> items) { + branchParentName = ensureEndSlash(branchParentName); InfoStorage> 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> 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> items) { + branchParentName = ensureEndSlash(branchParentName); final InfoStorage> 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 getBranches(String url) { + url = ensureEndSlash(url); return myBranchMap.get(url).getValue(); } - /*public SvnBranchConfiguration createFromVcsRootBranches() { - final SvnBranchConfiguration result = new SvnBranchConfiguration(); - result.setTrunkUrl(myTrunkUrl); - final Map> branchMap = result.getBranchMap(); - for (String key : myBranchMap.keySet()) { - result.setTrunkUrl(key); - final List 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 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; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnMergeInfoRootPanelManual.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnMergeInfoRootPanelManual.java index 088382e605ac..c6ed3c59a5c7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnMergeInfoRootPanelManual.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnMergeInfoRootPanelManual.java @@ -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;