SVN: load branches on start inside one short; will produce ordered authorization...
[fedora-idea.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / SvnBranchConfigurationManager.java
blobbfdf5dc7322634e831d5e4f151caf74dc34e8c68
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.SVNException;
43 import org.tmatesoft.svn.core.SVNURL;
45 import java.io.File;
46 import java.util.*;
48 /**
49 * @author yole
51 @State(
52 name = "SvnBranchConfigurationManager",
53 storages = {
54 @Storage(
55 id ="other",
56 file = "$PROJECT_FILE$"
59 public class SvnBranchConfigurationManager implements PersistentStateComponent<SvnBranchConfigurationManager.ConfigurationBean> {
60 private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnBranchConfigurationManager");
61 private final Project myProject;
62 private final ProjectLevelVcsManager myVcsManager;
64 public SvnBranchConfigurationManager(final Project project, final ProjectLevelVcsManager vcsManager) {
65 myProject = project;
66 myVcsManager = vcsManager;
67 myBunch = new NewRootBunch(project);
70 public static SvnBranchConfigurationManager getInstance(final Project project) {
71 return ServiceManager.getService(project, SvnBranchConfigurationManager.class);
74 public static class ConfigurationBean {
75 public Map<String, SvnBranchConfiguration> myConfigurationMap = new HashMap<String, SvnBranchConfiguration>();
76 /**
77 * version of "support SVN in IDEA". for features tracking. should grow
79 public Long myVersion;
80 public boolean mySupportsUserInfoFilter;
83 public Long getSupportValue() {
84 return myConfigurationBean.myVersion;
87 private ConfigurationBean myConfigurationBean = new ConfigurationBean();
88 private final SvnBranchConfigManager myBunch;
90 public SvnBranchConfigurationNew get(@NotNull final VirtualFile vcsRoot) throws VcsException {
91 return myBunch.getConfig(vcsRoot);
94 public SvnBranchConfigManager getSvnBranchConfigManager() {
95 return myBunch;
98 public void setConfiguration(final VirtualFile vcsRoot, final SvnBranchConfigurationNew configuration) {
99 myBunch.updateForRoot(vcsRoot, new InfoStorage<SvnBranchConfigurationNew>(configuration, InfoReliability.setByUser),
100 new BranchesPreloader(myProject, myBunch, vcsRoot));
102 SvnBranchMapperManager.getInstance().notifyBranchesChanged(myProject, vcsRoot, configuration);
104 final MessageBus messageBus = myProject.getMessageBus();
105 messageBus.syncPublisher(VcsConfigurationChangeListener.BRANCHES_CHANGED).execute(myProject, vcsRoot);
108 public ConfigurationBean getState() {
109 final ConfigurationBean result = new ConfigurationBean();
110 result.myVersion = myConfigurationBean.myVersion;
111 final UrlSerializationHelper helper = new UrlSerializationHelper(SvnVcs.getInstance(myProject));
113 for (VirtualFile root : myBunch.getMapCopy().keySet()) {
114 final String key = root.getPath();
115 final SvnBranchConfigurationNew configOrig = myBunch.getConfig(root);
116 final SvnBranchConfiguration configuration = new SvnBranchConfiguration();
117 configuration.setTrunkUrl(configOrig.getTrunkUrl());
118 configuration.setUserinfoInUrl(configOrig.isUserinfoInUrl());
119 configuration.setBranchUrls(configOrig.getBranchUrls());
120 final HashMap<String, List<SvnBranchItem>> map = new HashMap<String, List<SvnBranchItem>>();
121 final Map<String, InfoStorage<List<SvnBranchItem>>> origMap = configOrig.getBranchMap();
122 for (String origKey : origMap.keySet()) {
123 map.put(origKey, origMap.get(origKey).getValue());
125 configuration.setBranchMap(map);
126 result.myConfigurationMap.put(key, helper.prepareForSerialization(configuration));
128 result.mySupportsUserInfoFilter = true;
129 return result;
132 private static class BranchesPreloader implements PairConsumer<SvnBranchConfigurationNew, SvnBranchConfigurationNew> {
133 private final Project myProject;
134 private final VirtualFile myRoot;
135 private final SvnBranchConfigManager myBunch;
136 private boolean myAll;
138 public BranchesPreloader(Project project, @NotNull final SvnBranchConfigManager bunch, VirtualFile root) {
139 myBunch = bunch;
140 myProject = project;
141 myRoot = root;
144 public void consume(final SvnBranchConfigurationNew prev, final SvnBranchConfigurationNew next) {
145 final Application application = ApplicationManager.getApplication();
146 application.executeOnPooledThread(new Runnable() {
147 public void run() {
148 loadImpl(prev, next);
153 protected void loadImpl(final SvnBranchConfigurationNew prev, final SvnBranchConfigurationNew next) {
154 final Set<String> oldUrls = (prev == null) ? Collections.<String>emptySet() : new HashSet<String>(prev.getBranchUrls());
155 final SvnVcs vcs = SvnVcs.getInstance(myProject);
156 if (! vcs.isVcsBackgroundOperationsAllowed(myRoot)) return;
158 for (String newBranchUrl : next.getBranchUrls()) {
159 if (myAll || (! oldUrls.contains(newBranchUrl))) {
160 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 ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
208 public void run() {
209 for (Pair<VirtualFile, SvnBranchConfigurationNew> pair : whatToInit) {
210 final BranchesPreloader branchesPreloader = new BranchesPreloader(myProject, myBunch, pair.getFirst());
211 branchesPreloader.setAll(true);
212 branchesPreloader.loadImpl(null, pair.getSecond());
218 object.myConfigurationMap.clear();
219 object.myConfigurationMap.putAll(newMap);
220 myConfigurationBean = object;
223 private static class UrlSerializationHelper {
224 private final SvnVcs myVcs;
226 private UrlSerializationHelper(final SvnVcs vcs) {
227 myVcs = vcs;
230 public SvnBranchConfiguration prepareForSerialization(final SvnBranchConfiguration configuration) {
231 final Ref<Boolean> withUserInfo = new Ref<Boolean>();
232 final String trunkUrl = serializeUrl(configuration.getTrunkUrl(), withUserInfo);
234 if (Boolean.FALSE.equals(withUserInfo.get())) {
235 return configuration;
238 final List<String> branches = configuration.getBranchUrls();
239 final List<String> newBranchesList = new ArrayList<String>(branches.size());
240 for (String s : branches) {
241 newBranchesList.add(serializeUrl(s, withUserInfo));
244 final Map<String, List<SvnBranchItem>> map = configuration.getBranchMap();
245 final Map<String, List<SvnBranchItem>> newMap = new HashMap<String, List<SvnBranchItem>>(map.size(), 1.0f);
246 for (Map.Entry<String, List<SvnBranchItem>> entry : map.entrySet()) {
247 final List<SvnBranchItem> items = entry.getValue();
248 if (items != null) {
249 final List<SvnBranchItem> newItems = new ArrayList<SvnBranchItem>();
250 for (SvnBranchItem item : items) {
251 newItems.add(new SvnBranchItem(serializeUrl(item.getUrl(), withUserInfo), new java.util.Date(item.getCreationDateMillis()),
252 item.getRevision()));
254 newMap.put(serializeUrl(entry.getKey(), withUserInfo), newItems);
258 final SvnBranchConfiguration result = new SvnBranchConfiguration();
259 result.setTrunkUrl(trunkUrl);
260 result.setBranchUrls(newBranchesList);
261 result.setBranchMap(newMap);
262 result.setUserinfoInUrl(withUserInfo.isNull() ? false : withUserInfo.get());
263 return result;
266 public SvnBranchConfiguration afterDeserialization(final String path, final SvnBranchConfiguration configuration) {
267 if (! configuration.isUserinfoInUrl()) {
268 return configuration;
270 final String userInfo = getUserInfo(path);
271 if (userInfo == null) {
272 return configuration;
275 final String newTrunkUrl = deserializeUrl(configuration.getTrunkUrl(), userInfo);
276 final List<String> branches = configuration.getBranchUrls();
277 final List<String> newBranchesList = new ArrayList<String>(branches.size());
278 for (String s : branches) {
279 newBranchesList.add(deserializeUrl(s, userInfo));
282 final Map<String, List<SvnBranchItem>> map = configuration.getBranchMap();
283 final Map<String, List<SvnBranchItem>> newMap = new HashMap<String, List<SvnBranchItem>>(map.size(), 1.0f);
284 for (Map.Entry<String, List<SvnBranchItem>> entry : map.entrySet()) {
285 final List<SvnBranchItem> items = entry.getValue();
286 if (items != null) {
287 final List<SvnBranchItem> newItems = new ArrayList<SvnBranchItem>();
288 for (SvnBranchItem item : items) {
289 newItems.add(new SvnBranchItem(deserializeUrl(item.getUrl(), userInfo), new java.util.Date(item.getCreationDateMillis()),
290 item.getRevision()));
292 newMap.put(deserializeUrl(entry.getKey(), userInfo), newItems);
296 final SvnBranchConfiguration result = new SvnBranchConfiguration();
297 result.setTrunkUrl(newTrunkUrl);
298 result.setBranchUrls(newBranchesList);
299 result.setBranchMap(newMap);
300 result.setUserinfoInUrl(userInfo != null && userInfo.length() > 0);
301 return result;
304 private String serializeUrl(final String url, final Ref<Boolean> withUserInfo) {
305 if (Boolean.FALSE.equals(withUserInfo.get())) {
306 return url;
308 try {
309 final SVNURL svnurl = SVNURL.parseURIEncoded(url);
310 if (withUserInfo.isNull()) {
311 final String userInfo = svnurl.getUserInfo();
312 withUserInfo.set((userInfo != null) && (userInfo.length() > 0));
314 if (withUserInfo.get()) {
315 return SVNURL.create(svnurl.getProtocol(), null, svnurl.getHost(), svnurl.getPort(), svnurl.getURIEncodedPath(), true).toString();
318 catch (SVNException e) {
321 return url;
324 @Nullable
325 private String getUserInfo(final String path) {
326 final SVNURL svnurl = myVcs.getSvnFileUrlMapping().getUrlForFile(new File(path));
327 return svnurl != null ? svnurl.getUserInfo() : null;
330 private String deserializeUrl(final String url, final String userInfo) {
331 try {
332 final SVNURL svnurl = SVNURL.parseURIEncoded(url);
333 return SVNURL.create(svnurl.getProtocol(), userInfo, svnurl.getHost(), svnurl.getPort(), svnurl.getURIEncodedPath(), true).toString();
334 } catch (SVNException e) {
335 return url;