IDEADEV-41714 ("Collecting Information on Changes" hangs entire GUI) r=yole
[fedora-idea.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / branchConfig / SvnBranchConfigurationNew.java
blob1d8a3b812101a7d4df3df21e501fa28a0d1c069d
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.jetbrains.idea.svn.branchConfig;
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.vfs.VirtualFile;
21 import org.jetbrains.annotations.Nullable;
22 import org.jetbrains.idea.svn.SvnUtil;
23 import org.jetbrains.idea.svn.SvnVcs;
24 import org.jetbrains.idea.svn.integrate.SvnBranchItem;
25 import org.tmatesoft.svn.core.SVNException;
26 import org.tmatesoft.svn.core.SVNURL;
27 import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
28 import org.tmatesoft.svn.core.wc.SVNInfo;
29 import org.tmatesoft.svn.core.wc.SVNRevision;
30 import org.tmatesoft.svn.core.wc.SVNWCClient;
32 import java.io.File;
33 import java.util.*;
35 public class SvnBranchConfigurationNew {
36 private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew");
37 private String myTrunkUrl;
38 // need public for serialization
39 public Map<String, InfoStorage<List<SvnBranchItem>>> myBranchMap;
40 private boolean myUserinfoInUrl;
42 public SvnBranchConfigurationNew() {
43 myTrunkUrl = "";
44 myBranchMap = new HashMap<String, InfoStorage<List<SvnBranchItem>>>();
47 public boolean isUserinfoInUrl() {
48 return myUserinfoInUrl;
51 public void setUserinfoInUrl(final boolean userinfoInUrl) {
52 myUserinfoInUrl = userinfoInUrl;
55 public void setTrunkUrl(final String trunkUrl) {
56 myTrunkUrl = trunkUrl;
59 public String getTrunkUrl() {
60 return myTrunkUrl;
63 public List<String> getBranchUrls() {
64 final ArrayList<String> result = new ArrayList<String>(myBranchMap.keySet());
65 Collections.sort(result);
66 return result;
69 public void addBranches(final String branchParentName, final InfoStorage<List<SvnBranchItem>> items) {
70 InfoStorage<List<SvnBranchItem>> current = myBranchMap.get(branchParentName);
71 if (current != null) {
72 LOG.info("Branches list not added for : '" + branchParentName + "; this branch parent URL is already present.");
73 return;
75 myBranchMap.put(branchParentName, items);
78 public void updateBranch(final String branchParentName, final InfoStorage<List<SvnBranchItem>> items) {
79 final InfoStorage<List<SvnBranchItem>> current = myBranchMap.get(branchParentName);
80 if (current == null) {
81 LOG.info("Branches list not updated for : '" + branchParentName + "; since config has changed.");
82 return;
84 current.accept(items, null);
87 public Map<String, InfoStorage<List<SvnBranchItem>>> getBranchMap() {
88 return myBranchMap;
91 public List<SvnBranchItem> getBranches(String url) {
92 return myBranchMap.get(url).getValue();
95 /*public SvnBranchConfiguration createFromVcsRootBranches() {
96 final SvnBranchConfiguration result = new SvnBranchConfiguration();
97 result.setTrunkUrl(myTrunkUrl);
98 final Map<String, List<SvnBranchItem>> branchMap = result.getBranchMap();
99 for (String key : myBranchMap.keySet()) {
100 result.setTrunkUrl(key);
101 final List<SvnBranchItem> list = myBranchMap.get(key).getT();
102 branchMap.put(key, list);
104 return result;
107 public SvnBranchConfigurationNew copy() {
108 SvnBranchConfigurationNew result = new SvnBranchConfigurationNew();
109 result.myUserinfoInUrl = myUserinfoInUrl;
110 result.myTrunkUrl = myTrunkUrl;
111 result.myBranchMap = new HashMap<String, InfoStorage<List<SvnBranchItem>>>();
112 for (Map.Entry<String, InfoStorage<List<SvnBranchItem>>> entry : myBranchMap.entrySet()) {
113 final InfoStorage<List<SvnBranchItem>> infoStorage = entry.getValue();
114 result.myBranchMap.put(entry.getKey(), new InfoStorage<List<SvnBranchItem>>(
115 new ArrayList<SvnBranchItem>(infoStorage.getValue()), infoStorage.getInfoReliability()));
117 return result;
120 @Nullable
121 public String getBaseUrl(String url) {
122 if ((myTrunkUrl != null) && url.startsWith(myTrunkUrl)) {
123 return myTrunkUrl;
125 for(String branchUrl: myBranchMap.keySet()) {
126 if (url.startsWith(branchUrl)) {
127 int pos = url.indexOf('/', branchUrl.length()+1);
128 if (pos >= 0) {
129 return url.substring(0, pos);
131 return branchUrl;
134 return null;
137 @Nullable
138 public String getBaseName(String url) {
139 String baseUrl = getBaseUrl(url);
140 if (baseUrl == null) {
141 return null;
143 if (myBranchMap.isEmpty()) {
144 return baseUrl;
146 int commonPrefixLength = getCommonPrefixLength(url, myTrunkUrl);
147 for (String branchUrl : myBranchMap.keySet()) {
148 commonPrefixLength = Math.min(commonPrefixLength, getCommonPrefixLength(url, branchUrl));
149 if (commonPrefixLength <= 0) {
150 return baseUrl;
153 return baseUrl.substring(commonPrefixLength);
156 private static int getCommonPrefixLength(final String s1, final String s2) {
157 final int minLength = Math.min(s1.length(), s2.length());
158 for(int i=0; i< minLength; i++) {
159 if (s1.charAt(i) != s2.charAt(i)) {
160 return i;
163 return minLength;
166 @Nullable
167 public String getRelativeUrl(String url) {
168 String baseUrl = getBaseUrl(url);
169 return baseUrl == null ? null : url.substring(baseUrl.length());
172 @Nullable
173 public SVNURL getWorkingBranch(final SVNURL someUrl) throws SVNException {
174 final BranchSearcher branchSearcher = new BranchSearcher(someUrl);
175 iterateUrls(branchSearcher);
177 return branchSearcher.getResult();
180 private void iterateUrls(final UrlListener listener) throws SVNException {
181 if (listener.accept(myTrunkUrl)) {
182 return;
185 for (String branchUrl : myBranchMap.keySet()) {
186 // use more exact comparison first (paths longer)
187 final List<SvnBranchItem> children = myBranchMap.get(branchUrl).getValue();
188 for (SvnBranchItem child : children) {
189 if (listener.accept(child.getUrl())) {
190 return;
194 if (listener.accept(branchUrl)) {
195 return;
200 @Nullable
201 public Map<String,String> getUrl2FileMappings(final Project project, final VirtualFile root) {
202 try {
203 final BranchRootSearcher searcher = new BranchRootSearcher(SvnVcs.getInstance(project), root);
204 iterateUrls(searcher);
205 return searcher.getBranchesUnder();
206 } catch (SVNException e) {
207 return null;
211 public void removeBranch(final String url) {
212 myBranchMap.remove(url);
215 private static class BranchRootSearcher implements UrlListener {
216 private final VirtualFile myRoot;
217 private final SVNURL myRootUrl;
218 // url path to file path
219 private final Map<String, String> myBranchesUnder;
221 private BranchRootSearcher(final SvnVcs vcs, final VirtualFile root) throws SVNException {
222 myRoot = root;
223 myBranchesUnder = new HashMap<String, String>();
224 final SVNWCClient client = vcs.createWCClient();
225 final SVNInfo info = client.doInfo(new File(myRoot.getPath()), SVNRevision.WORKING);
226 myRootUrl = info.getURL();
229 public boolean accept(final String url) throws SVNException {
230 if (myRootUrl != null) {
231 final File baseDir = new File(myRoot.getPath());
232 final String baseUrl = myRootUrl.getPath();
234 final SVNURL branchUrl = SVNURL.parseURIEncoded(url);
235 if (myRootUrl.equals(SVNURLUtil.getCommonURLAncestor(myRootUrl, branchUrl))) {
236 final File file = SvnUtil.fileFromUrl(baseDir, baseUrl, branchUrl.getPath());
237 myBranchesUnder.put(url, file.getAbsolutePath());
240 return false; // iterate everything
243 public Map<String, String> getBranchesUnder() {
244 return myBranchesUnder;
248 private interface UrlListener {
249 boolean accept(final String url) throws SVNException;
252 private static class BranchSearcher implements UrlListener {
253 private final SVNURL mySomeUrl;
254 private SVNURL myResult;
256 private BranchSearcher(final SVNURL someUrl) {
257 mySomeUrl = someUrl;
260 public boolean accept(final String url) throws SVNException {
261 myResult = urlIsParent(url, mySomeUrl);
262 return myResult != null;
265 public SVNURL getResult() {
266 return myResult;
270 @Nullable
271 private static SVNURL urlIsParent(final String parentCandidate, final SVNURL child) throws SVNException {
272 final SVNURL parentUrl = SVNURL.parseURIEncoded(parentCandidate);
273 if(parentUrl.equals(SVNURLUtil.getCommonURLAncestor(parentUrl, child))) {
274 return parentUrl;
276 return null;