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
;
52 name
= "SvnBranchConfigurationManager",
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
) {
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
>();
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() {
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;
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
) {
144 public void consume(final SvnBranchConfigurationNew prev
, final SvnBranchConfigurationNew next
) {
145 final Application application
= ApplicationManager
.getApplication();
146 application
.executeOnPooledThread(new Runnable() {
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
) {
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()));
181 LOG
.info("root not found: " + entry
.getKey());
185 final SvnBranchConfiguration configToConvert
;
186 if ((! myConfigurationBean
.mySupportsUserInfoFilter
) || configuration
.isUserinfoInUrl()) {
187 configToConvert
= helper
.afterDeserialization(entry
.getKey(), configuration
);
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() {
207 ApplicationManager
.getApplication().executeOnPooledThread(new Runnable() {
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
) {
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();
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());
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();
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);
304 private String
serializeUrl(final String url
, final Ref
<Boolean
> withUserInfo
) {
305 if (Boolean
.FALSE
.equals(withUserInfo
.get())) {
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
) {
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
) {
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
) {