SVN auth
[fedora-idea.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / SvnBranchConfigurationManager.java
blob1464e569816e04372ce9b9c76ee8fb49919f9715
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.
17 package org.jetbrains.idea.svn;
19 import com.intellij.openapi.application.Application;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.components.PersistentStateComponent;
22 import com.intellij.openapi.components.ServiceManager;
23 import com.intellij.openapi.components.State;
24 import com.intellij.openapi.components.Storage;
25 import com.intellij.openapi.diagnostic.Logger;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.util.Pair;
28 import com.intellij.openapi.util.Ref;
29 import com.intellij.openapi.vcs.ProjectLevelVcsManager;
30 import com.intellij.openapi.vcs.VcsException;
31 import com.intellij.openapi.vcs.changes.committed.VcsConfigurationChangeListener;
32 import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
33 import com.intellij.openapi.vcs.impl.VcsInitObject;
34 import com.intellij.openapi.vfs.LocalFileSystem;
35 import com.intellij.openapi.vfs.VirtualFile;
36 import com.intellij.util.PairConsumer;
37 import com.intellij.util.messages.MessageBus;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
40 import org.jetbrains.idea.svn.branchConfig.*;
41 import org.jetbrains.idea.svn.integrate.SvnBranchItem;
42 import org.tmatesoft.svn.core.*;
44 import java.io.File;
45 import java.util.*;
47 /**
48 * @author yole
50 @State(
51 name = "SvnBranchConfigurationManager",
52 storages = {
53 @Storage(
54 id ="other",
55 file = "$PROJECT_FILE$"
58 public class SvnBranchConfigurationManager implements PersistentStateComponent<SvnBranchConfigurationManager.ConfigurationBean> {
59 private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnBranchConfigurationManager");
60 private final Project myProject;
61 private final ProjectLevelVcsManager myVcsManager;
63 public SvnBranchConfigurationManager(final Project project, final ProjectLevelVcsManager vcsManager) {
64 myProject = project;
65 myVcsManager = vcsManager;
66 myBunch = new NewRootBunch(project);
69 public static SvnBranchConfigurationManager getInstance(final Project project) {
70 return ServiceManager.getService(project, SvnBranchConfigurationManager.class);
73 public static class ConfigurationBean {
74 public Map<String, SvnBranchConfiguration> myConfigurationMap = new HashMap<String, SvnBranchConfiguration>();
75 /**
76 * version of "support SVN in IDEA". for features tracking. should grow
78 public Long myVersion;
79 public boolean mySupportsUserInfoFilter;
82 public Long getSupportValue() {
83 return myConfigurationBean.myVersion;
86 private ConfigurationBean myConfigurationBean = new ConfigurationBean();
87 private final SvnBranchConfigManager myBunch;
89 public SvnBranchConfigurationNew get(@NotNull final VirtualFile vcsRoot) throws VcsException {
90 return myBunch.getConfig(vcsRoot);
93 public SvnBranchConfigManager getSvnBranchConfigManager() {
94 return myBunch;
97 public void setConfiguration(final VirtualFile vcsRoot, final SvnBranchConfigurationNew configuration) {
98 myBunch.updateForRoot(vcsRoot, new InfoStorage<SvnBranchConfigurationNew>(configuration, InfoReliability.setByUser),
99 new BranchesPreloader(myProject, myBunch, vcsRoot));
101 SvnBranchMapperManager.getInstance().notifyBranchesChanged(myProject, vcsRoot, configuration);
103 final MessageBus messageBus = myProject.getMessageBus();
104 messageBus.syncPublisher(VcsConfigurationChangeListener.BRANCHES_CHANGED).execute(myProject, vcsRoot);
107 public ConfigurationBean getState() {
108 final ConfigurationBean result = new ConfigurationBean();
109 result.myVersion = myConfigurationBean.myVersion;
110 final UrlSerializationHelper helper = new UrlSerializationHelper(SvnVcs.getInstance(myProject));
112 for (VirtualFile root : myBunch.getMapCopy().keySet()) {
113 final String key = root.getPath();
114 final SvnBranchConfigurationNew configOrig = myBunch.getConfig(root);
115 final SvnBranchConfiguration configuration = new SvnBranchConfiguration();
116 configuration.setTrunkUrl(configOrig.getTrunkUrl());
117 configuration.setUserinfoInUrl(configOrig.isUserinfoInUrl());
118 configuration.setBranchUrls(configOrig.getBranchUrls());
119 final HashMap<String, List<SvnBranchItem>> map = new HashMap<String, List<SvnBranchItem>>();
120 final Map<String, InfoStorage<List<SvnBranchItem>>> origMap = configOrig.getBranchMap();
121 for (String origKey : origMap.keySet()) {
122 map.put(origKey, origMap.get(origKey).getValue());
124 configuration.setBranchMap(map);
125 result.myConfigurationMap.put(key, helper.prepareForSerialization(configuration));
127 result.mySupportsUserInfoFilter = true;
128 return result;
131 private static class BranchesPreloader implements PairConsumer<SvnBranchConfigurationNew, SvnBranchConfigurationNew> {
132 private final Project myProject;
133 private final VirtualFile myRoot;
134 private final SvnBranchConfigManager myBunch;
135 private boolean myAll;
137 public BranchesPreloader(Project project, @NotNull final SvnBranchConfigManager bunch, VirtualFile root) {
138 myBunch = bunch;
139 myProject = project;
140 myRoot = root;
143 public void consume(final SvnBranchConfigurationNew prev, final SvnBranchConfigurationNew next) {
144 final Set<String> oldUrls = (prev == null) ? Collections.<String>emptySet() : new HashSet<String>(prev.getBranchUrls());
145 final Application application = ApplicationManager.getApplication();
146 application.executeOnPooledThread(new Runnable() {
147 public void run() {
148 final SvnVcs vcs = SvnVcs.getInstance(myProject);
149 final RootsToWorkingCopies rootsToWorkingCopies = vcs.getRootsToWorkingCopies();
150 final WorkingCopy wcRoot = rootsToWorkingCopies.getWcRoot(myRoot);
151 if (wcRoot == null) return;
153 final boolean validated = SvnAuthenticationNotifier.passiveValidation(myProject, wcRoot.getUrl(), false, null, null);
154 if (! validated) return;
156 for (String newBranchUrl : next.getBranchUrls()) {
157 if (myAll || (! oldUrls.contains(newBranchUrl))) {
158 new NewRootBunch.BranchesLoadRunnable(myProject, myBunch, newBranchUrl, InfoReliability.defaultValues, myRoot, null).run();
165 public void setAll(boolean all) {
166 myAll = all;
170 public void loadState(final ConfigurationBean object) {
171 final UrlSerializationHelper helper = new UrlSerializationHelper(SvnVcs.getInstance(myProject));
172 final Map<String, SvnBranchConfiguration> map = object.myConfigurationMap;
173 final Map<String, SvnBranchConfiguration> newMap = new HashMap<String, SvnBranchConfiguration>(map.size(), 1);
174 final LocalFileSystem lfs = LocalFileSystem.getInstance();
176 final Set<Pair<VirtualFile, SvnBranchConfigurationNew>> whatToInit = new HashSet<Pair<VirtualFile, SvnBranchConfigurationNew>>();
177 for (Map.Entry<String, SvnBranchConfiguration> entry : map.entrySet()) {
178 final SvnBranchConfiguration configuration = entry.getValue();
179 final VirtualFile root = lfs.refreshAndFindFileByIoFile(new File(entry.getKey()));
180 if (root == null) {
181 LOG.info("root not found: " + entry.getKey());
182 continue;
185 final SvnBranchConfiguration configToConvert;
186 if ((! myConfigurationBean.mySupportsUserInfoFilter) || configuration.isUserinfoInUrl()) {
187 configToConvert = helper.afterDeserialization(entry.getKey(), configuration);
188 } else {
189 configToConvert = configuration;
191 final SvnBranchConfigurationNew newConfig = new SvnBranchConfigurationNew();
192 newConfig.setTrunkUrl(configToConvert.getTrunkUrl());
193 newConfig.setUserinfoInUrl(configToConvert.isUserinfoInUrl());
194 final Map<String, List<SvnBranchItem>> oldMap = configToConvert.getBranchMap();
195 for (String branchUrl : configToConvert.getBranchUrls()) {
196 List<SvnBranchItem> items = oldMap.get(branchUrl);
197 items = ((items == null) || (items.isEmpty())) ? new ArrayList<SvnBranchItem>() : items;
198 whatToInit.add(new Pair<VirtualFile, SvnBranchConfigurationNew>(root, newConfig));
199 newConfig.addBranches(branchUrl, new InfoStorage<List<SvnBranchItem>>(items,
200 (items.isEmpty()) ? InfoReliability.defaultValues : InfoReliability.setByUser));
203 myBunch.updateForRoot(root, new InfoStorage<SvnBranchConfigurationNew>(newConfig, InfoReliability.setByUser), null);
205 ((ProjectLevelVcsManagerImpl) myVcsManager).addInitializationRequest(VcsInitObject.BRANCHES, new Runnable() {
206 public void run() {
207 for (Pair<VirtualFile, SvnBranchConfigurationNew> pair : whatToInit) {
208 final BranchesPreloader branchesPreloader = new BranchesPreloader(myProject, myBunch, pair.getFirst());
209 branchesPreloader.setAll(true);
210 branchesPreloader.consume(null, pair.getSecond());
214 object.myConfigurationMap.clear();
215 object.myConfigurationMap.putAll(newMap);
216 myConfigurationBean = object;
219 private static class UrlSerializationHelper {
220 private final SvnVcs myVcs;
222 private UrlSerializationHelper(final SvnVcs vcs) {
223 myVcs = vcs;
226 public SvnBranchConfiguration prepareForSerialization(final SvnBranchConfiguration configuration) {
227 final Ref<Boolean> withUserInfo = new Ref<Boolean>();
228 final String trunkUrl = serializeUrl(configuration.getTrunkUrl(), withUserInfo);
230 if (Boolean.FALSE.equals(withUserInfo.get())) {
231 return configuration;
234 final List<String> branches = configuration.getBranchUrls();
235 final List<String> newBranchesList = new ArrayList<String>(branches.size());
236 for (String s : branches) {
237 newBranchesList.add(serializeUrl(s, withUserInfo));
240 final Map<String, List<SvnBranchItem>> map = configuration.getBranchMap();
241 final Map<String, List<SvnBranchItem>> newMap = new HashMap<String, List<SvnBranchItem>>(map.size(), 1.0f);
242 for (Map.Entry<String, List<SvnBranchItem>> entry : map.entrySet()) {
243 final List<SvnBranchItem> items = entry.getValue();
244 if (items != null) {
245 final List<SvnBranchItem> newItems = new ArrayList<SvnBranchItem>();
246 for (SvnBranchItem item : items) {
247 newItems.add(new SvnBranchItem(serializeUrl(item.getUrl(), withUserInfo), new java.util.Date(item.getCreationDateMillis()),
248 item.getRevision()));
250 newMap.put(serializeUrl(entry.getKey(), withUserInfo), newItems);
254 final SvnBranchConfiguration result = new SvnBranchConfiguration();
255 result.setTrunkUrl(trunkUrl);
256 result.setBranchUrls(newBranchesList);
257 result.setBranchMap(newMap);
258 result.setUserinfoInUrl(withUserInfo.isNull() ? false : withUserInfo.get());
259 return result;
262 public SvnBranchConfiguration afterDeserialization(final String path, final SvnBranchConfiguration configuration) {
263 if (! configuration.isUserinfoInUrl()) {
264 return configuration;
266 final String userInfo = getUserInfo(path);
267 if (userInfo == null) {
268 return configuration;
271 final String newTrunkUrl = deserializeUrl(configuration.getTrunkUrl(), userInfo);
272 final List<String> branches = configuration.getBranchUrls();
273 final List<String> newBranchesList = new ArrayList<String>(branches.size());
274 for (String s : branches) {
275 newBranchesList.add(deserializeUrl(s, userInfo));
278 final Map<String, List<SvnBranchItem>> map = configuration.getBranchMap();
279 final Map<String, List<SvnBranchItem>> newMap = new HashMap<String, List<SvnBranchItem>>(map.size(), 1.0f);
280 for (Map.Entry<String, List<SvnBranchItem>> entry : map.entrySet()) {
281 final List<SvnBranchItem> items = entry.getValue();
282 if (items != null) {
283 final List<SvnBranchItem> newItems = new ArrayList<SvnBranchItem>();
284 for (SvnBranchItem item : items) {
285 newItems.add(new SvnBranchItem(deserializeUrl(item.getUrl(), userInfo), new java.util.Date(item.getCreationDateMillis()),
286 item.getRevision()));
288 newMap.put(deserializeUrl(entry.getKey(), userInfo), newItems);
292 final SvnBranchConfiguration result = new SvnBranchConfiguration();
293 result.setTrunkUrl(newTrunkUrl);
294 result.setBranchUrls(newBranchesList);
295 result.setBranchMap(newMap);
296 result.setUserinfoInUrl(userInfo != null && userInfo.length() > 0);
297 return result;
300 private String serializeUrl(final String url, final Ref<Boolean> withUserInfo) {
301 if (Boolean.FALSE.equals(withUserInfo.get())) {
302 return url;
304 try {
305 final SVNURL svnurl = SVNURL.parseURIEncoded(url);
306 if (withUserInfo.isNull()) {
307 final String userInfo = svnurl.getUserInfo();
308 withUserInfo.set((userInfo != null) && (userInfo.length() > 0));
310 if (withUserInfo.get()) {
311 return SVNURL.create(svnurl.getProtocol(), null, svnurl.getHost(), svnurl.getPort(), svnurl.getURIEncodedPath(), true).toString();
314 catch (SVNException e) {
317 return url;
320 @Nullable
321 private String getUserInfo(final String path) {
322 final SVNURL svnurl = myVcs.getSvnFileUrlMapping().getUrlForFile(new File(path));
323 return svnurl != null ? svnurl.getUserInfo() : null;
326 private String deserializeUrl(final String url, final String userInfo) {
327 try {
328 final SVNURL svnurl = SVNURL.parseURIEncoded(url);
329 return SVNURL.create(svnurl.getProtocol(), userInfo, svnurl.getHost(), svnurl.getPort(), svnurl.getURIEncodedPath(), true).toString();
330 } catch (SVNException e) {
331 return url;