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.vcs.ObjectsConvertor;
21 import com.intellij.openapi.vfs.VirtualFile;
22 import com.intellij.util.containers.Convertor;
23 import org.jetbrains.annotations.Nullable;
24 import org.jetbrains.idea.svn.SvnUtil;
25 import org.jetbrains.idea.svn.SvnVcs;
26 import org.jetbrains.idea.svn.info.Info;
27 import org.tmatesoft.svn.core.SVNException;
28 import org.tmatesoft.svn.core.SVNURL;
29 import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
30 import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
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() {
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() {
63 public List<String> getBranchUrls() {
64 final ArrayList<String> result = new ArrayList<String>(myBranchMap.keySet());
65 final List<String> cutList = ObjectsConvertor.convert(result, new Convertor<String, String>() {
67 public String convert(String s) {
68 return cutEndSlash(s);
71 Collections.sort(cutList);
75 public void addBranches(String branchParentName, final InfoStorage<List<SvnBranchItem>> items) {
76 branchParentName = ensureEndSlash(branchParentName);
77 InfoStorage<List<SvnBranchItem>> current = myBranchMap.get(branchParentName);
78 if (current != null) {
79 LOG.info("Branches list not added for : '" + branchParentName + "; this branch parent URL is already present.");
82 myBranchMap.put(branchParentName, items);
85 public static String ensureEndSlash(String name) {
86 return name.trim().endsWith("/") ? name : name + "/";
89 private static String cutEndSlash(String name) {
90 return name.endsWith("/") && name.length() > 0 ? name.substring(0, name.length() - 1) : name;
93 public void updateBranch(String branchParentName, final InfoStorage<List<SvnBranchItem>> items) {
94 branchParentName = ensureEndSlash(branchParentName);
95 final InfoStorage<List<SvnBranchItem>> current = myBranchMap.get(branchParentName);
96 if (current == null) {
97 LOG.info("Branches list not updated for : '" + branchParentName + "; since config has changed.");
100 current.accept(items);
103 public Map<String, InfoStorage<List<SvnBranchItem>>> getBranchMap() {
107 public List<SvnBranchItem> getBranches(String url) {
108 url = ensureEndSlash(url);
109 return myBranchMap.get(url).getValue();
112 public SvnBranchConfigurationNew copy() {
113 SvnBranchConfigurationNew result = new SvnBranchConfigurationNew();
114 result.myUserinfoInUrl = myUserinfoInUrl;
115 result.myTrunkUrl = myTrunkUrl;
116 result.myBranchMap = new HashMap<String, InfoStorage<List<SvnBranchItem>>>();
117 for (Map.Entry<String, InfoStorage<List<SvnBranchItem>>> entry : myBranchMap.entrySet()) {
118 final InfoStorage<List<SvnBranchItem>> infoStorage = entry.getValue();
119 result.myBranchMap.put(entry.getKey(), new InfoStorage<List<SvnBranchItem>>(
120 new ArrayList<SvnBranchItem>(infoStorage.getValue()), infoStorage.getInfoReliability()));
126 public String getBaseUrl(String url) {
127 if (myTrunkUrl != null) {
128 if (SVNPathUtil.isAncestor(myTrunkUrl, url)) {
129 return cutEndSlash(myTrunkUrl);
132 for(String branchUrl: myBranchMap.keySet()) {
133 if (SVNPathUtil.isAncestor(branchUrl, url)) {
134 String relativePath = SVNPathUtil.getRelativePath(branchUrl, url);
135 int secondSlash = relativePath.indexOf("/");
136 return cutEndSlash(branchUrl + (secondSlash == -1 ? relativePath : relativePath.substring(0, secondSlash)));
143 public String getBaseName(String url) {
144 String baseUrl = getBaseUrl(url);
145 if (baseUrl == null) {
148 int lastSlash = baseUrl.lastIndexOf("/");
149 return lastSlash == -1 ? baseUrl : baseUrl.substring(lastSlash + 1);
153 public String getRelativeUrl(String url) {
154 String baseUrl = getBaseUrl(url);
155 return baseUrl == null ? null : url.substring(baseUrl.length());
159 public SVNURL getWorkingBranch(final SVNURL someUrl) throws SVNException {
160 String baseUrl = getBaseUrl(someUrl.toString());
161 return baseUrl == null ? null : SVNURL.parseURIEncoded(baseUrl);
167 public String getGroupToLoadToReachUrl(final SVNURL url) throws SVNException {
168 final BranchSearcher branchSearcher = new BranchSearcher(url);
169 for (String group : myBranchMap.keySet()) {
170 if (branchSearcher.accept(group)) {
177 private void iterateUrls(final UrlListener listener) throws SVNException {
178 if (listener.accept(myTrunkUrl)) {
182 for (String branchUrl : myBranchMap.keySet()) {
183 // use more exact comparison first (paths longer)
184 final List<SvnBranchItem> children = myBranchMap.get(branchUrl).getValue();
185 for (SvnBranchItem child : children) {
186 if (listener.accept(child.getUrl())) {
191 /*if (listener.accept(branchUrl)) {
197 // to retrieve mappings between existing in the project working copies and their URLs
199 public Map<String,String> getUrl2FileMappings(final Project project, final VirtualFile root) {
201 final BranchRootSearcher searcher = new BranchRootSearcher(SvnVcs.getInstance(project), root);
202 iterateUrls(searcher);
203 return searcher.getBranchesUnder();
204 } catch (SVNException e) {
209 public void removeBranch(String url) {
210 url = ensureEndSlash(url);
211 myBranchMap.remove(url);
214 private static class BranchRootSearcher implements UrlListener {
215 private final VirtualFile myRoot;
216 private final SVNURL myRootUrl;
217 // url path to file path
218 private final Map<String, String> myBranchesUnder;
220 private BranchRootSearcher(final SvnVcs vcs, final VirtualFile root) throws SVNException {
222 myBranchesUnder = new HashMap<String, String>();
223 final Info info = vcs.getInfo(myRoot.getPath());
224 myRootUrl = info != null ? info.getURL() : null;
227 public boolean accept(final String url) throws SVNException {
228 if (myRootUrl != null) {
229 final File baseDir = new File(myRoot.getPath());
230 final String baseUrl = myRootUrl.getPath();
232 final SVNURL branchUrl = SVNURL.parseURIEncoded(url);
233 if (myRootUrl.equals(SVNURLUtil.getCommonURLAncestor(myRootUrl, branchUrl))) {
234 final File file = SvnUtil.fileFromUrl(baseDir, baseUrl, branchUrl.getPath());
235 myBranchesUnder.put(url, file.getAbsolutePath());
238 return false; // iterate everything
241 public Map<String, String> getBranchesUnder() {
242 return myBranchesUnder;
246 private interface UrlListener {
247 boolean accept(final String url) throws SVNException;
251 private static class BranchSearcher implements UrlListener {
252 private final SVNURL mySomeUrl;
253 private SVNURL myResult;
255 private BranchSearcher(final SVNURL someUrl) {
259 public boolean accept(final String url) throws SVNException {
260 myResult = urlIsParent(url, mySomeUrl);
261 return myResult != null;
264 public SVNURL getResult() {
270 private static SVNURL urlIsParent(final String parentCandidate, final SVNURL child) throws SVNException {
271 final SVNURL parentUrl = SVNURL.parseURIEncoded(parentCandidate);
272 if(parentUrl.equals(SVNURLUtil.getCommonURLAncestor(parentUrl, child))) {