blob: 3ce3c986c8aebda73262a1baf51af4fa73c7cd6d [file] [log] [blame]
/*
* Copyright 2000-2009 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.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.info.Info;
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 java.io.File;
import java.util.*;
public class SvnBranchConfigurationNew {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew");
private String myTrunkUrl;
// need public for serialization
public Map<String, InfoStorage<List<SvnBranchItem>>> myBranchMap;
private boolean myUserinfoInUrl;
public SvnBranchConfigurationNew() {
myTrunkUrl = "";
myBranchMap = new HashMap<String, InfoStorage<List<SvnBranchItem>>>();
}
public boolean isUserinfoInUrl() {
return myUserinfoInUrl;
}
public void setUserinfoInUrl(final boolean userinfoInUrl) {
myUserinfoInUrl = userinfoInUrl;
}
public void setTrunkUrl(final String trunkUrl) {
myTrunkUrl = trunkUrl;
}
public String getTrunkUrl() {
return myTrunkUrl;
}
public List<String> getBranchUrls() {
final ArrayList<String> result = new ArrayList<String>(myBranchMap.keySet());
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(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.");
return;
}
myBranchMap.put(branchParentName, 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.");
return;
}
current.accept(items);
}
public Map<String, InfoStorage<List<SvnBranchItem>>> getBranchMap() {
return myBranchMap;
}
public List<SvnBranchItem> getBranches(String url) {
url = ensureEndSlash(url);
return myBranchMap.get(url).getValue();
}
public SvnBranchConfigurationNew copy() {
SvnBranchConfigurationNew result = new SvnBranchConfigurationNew();
result.myUserinfoInUrl = myUserinfoInUrl;
result.myTrunkUrl = myTrunkUrl;
result.myBranchMap = new HashMap<String, InfoStorage<List<SvnBranchItem>>>();
for (Map.Entry<String, InfoStorage<List<SvnBranchItem>>> entry : myBranchMap.entrySet()) {
final InfoStorage<List<SvnBranchItem>> infoStorage = entry.getValue();
result.myBranchMap.put(entry.getKey(), new InfoStorage<List<SvnBranchItem>>(
new ArrayList<SvnBranchItem>(infoStorage.getValue()), infoStorage.getInfoReliability()));
}
return result;
}
@Nullable
public String getBaseUrl(String url) {
if (myTrunkUrl != null) {
if (SVNPathUtil.isAncestor(myTrunkUrl, url)) {
return cutEndSlash(myTrunkUrl);
}
}
for(String branchUrl: myBranchMap.keySet()) {
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;
}
@Nullable
public String getBaseName(String url) {
String baseUrl = getBaseUrl(url);
if (baseUrl == null) {
return null;
}
int lastSlash = baseUrl.lastIndexOf("/");
return lastSlash == -1 ? baseUrl : baseUrl.substring(lastSlash + 1);
}
@Nullable
public String getRelativeUrl(String url) {
String baseUrl = getBaseUrl(url);
return baseUrl == null ? null : url.substring(baseUrl.length());
}
@Nullable
public SVNURL getWorkingBranch(final SVNURL someUrl) throws SVNException {
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 {
final BranchSearcher branchSearcher = new BranchSearcher(url);
for (String group : myBranchMap.keySet()) {
if (branchSearcher.accept(group)) {
return group;
}
}
return null;
}
private void iterateUrls(final UrlListener listener) throws SVNException {
if (listener.accept(myTrunkUrl)) {
return;
}
for (String branchUrl : myBranchMap.keySet()) {
// use more exact comparison first (paths longer)
final List<SvnBranchItem> children = myBranchMap.get(branchUrl).getValue();
for (SvnBranchItem child : children) {
if (listener.accept(child.getUrl())) {
return;
}
}
/*if (listener.accept(branchUrl)) {
return;
}*/
}
}
// 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 {
final BranchRootSearcher searcher = new BranchRootSearcher(SvnVcs.getInstance(project), root);
iterateUrls(searcher);
return searcher.getBranchesUnder();
} catch (SVNException e) {
return null;
}
}
public void removeBranch(String url) {
url = ensureEndSlash(url);
myBranchMap.remove(url);
}
private static class BranchRootSearcher implements UrlListener {
private final VirtualFile myRoot;
private final SVNURL myRootUrl;
// url path to file path
private final Map<String, String> myBranchesUnder;
private BranchRootSearcher(final SvnVcs vcs, final VirtualFile root) throws SVNException {
myRoot = root;
myBranchesUnder = new HashMap<String, String>();
final Info info = vcs.getInfo(myRoot.getPath());
myRootUrl = info != null ? info.getURL() : null;
}
public boolean accept(final String url) throws SVNException {
if (myRootUrl != null) {
final File baseDir = new File(myRoot.getPath());
final String baseUrl = myRootUrl.getPath();
final SVNURL branchUrl = SVNURL.parseURIEncoded(url);
if (myRootUrl.equals(SVNURLUtil.getCommonURLAncestor(myRootUrl, branchUrl))) {
final File file = SvnUtil.fileFromUrl(baseDir, baseUrl, branchUrl.getPath());
myBranchesUnder.put(url, file.getAbsolutePath());
}
}
return false; // iterate everything
}
public Map<String, String> getBranchesUnder() {
return myBranchesUnder;
}
}
private interface UrlListener {
boolean accept(final String url) throws SVNException;
}
// todo not checked
private static class BranchSearcher implements UrlListener {
private final SVNURL mySomeUrl;
private SVNURL myResult;
private BranchSearcher(final SVNURL someUrl) {
mySomeUrl = someUrl;
}
public boolean accept(final String url) throws SVNException {
myResult = urlIsParent(url, mySomeUrl);
return myResult != null;
}
public SVNURL getResult() {
return myResult;
}
}
@Nullable
private static SVNURL urlIsParent(final String parentCandidate, final SVNURL child) throws SVNException {
final SVNURL parentUrl = SVNURL.parseURIEncoded(parentCandidate);
if(parentUrl.equals(SVNURLUtil.getCommonURLAncestor(parentUrl, child))) {
return parentUrl;
}
return null;
}
}