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
.progress
.ProcessCanceledException
;
27 import com
.intellij
.openapi
.project
.Project
;
28 import com
.intellij
.openapi
.util
.Pair
;
29 import com
.intellij
.openapi
.util
.Ref
;
30 import com
.intellij
.openapi
.vcs
.ProjectLevelVcsManager
;
31 import com
.intellij
.openapi
.vcs
.VcsException
;
32 import com
.intellij
.openapi
.vcs
.changes
.committed
.VcsConfigurationChangeListener
;
33 import com
.intellij
.openapi
.vcs
.impl
.ProjectLevelVcsManagerImpl
;
34 import com
.intellij
.openapi
.vcs
.impl
.VcsInitObject
;
35 import com
.intellij
.openapi
.vfs
.LocalFileSystem
;
36 import com
.intellij
.openapi
.vfs
.VirtualFile
;
37 import com
.intellij
.util
.PairConsumer
;
38 import com
.intellij
.util
.messages
.MessageBus
;
39 import org
.jetbrains
.annotations
.NotNull
;
40 import org
.jetbrains
.annotations
.Nullable
;
41 import org
.jetbrains
.idea
.svn
.branchConfig
.*;
42 import org
.jetbrains
.idea
.svn
.integrate
.SvnBranchItem
;
43 import org
.tmatesoft
.svn
.core
.SVNException
;
44 import org
.tmatesoft
.svn
.core
.SVNURL
;
53 name
= "SvnBranchConfigurationManager",
57 file
= "$PROJECT_FILE$"
60 public class SvnBranchConfigurationManager
implements PersistentStateComponent
<SvnBranchConfigurationManager
.ConfigurationBean
> {
61 private static final Logger LOG
= Logger
.getInstance("#org.jetbrains.idea.svn.SvnBranchConfigurationManager");
62 private final Project myProject
;
63 private final ProjectLevelVcsManager myVcsManager
;
65 public SvnBranchConfigurationManager(final Project project
, final ProjectLevelVcsManager vcsManager
) {
67 myVcsManager
= vcsManager
;
68 myBunch
= new NewRootBunch(project
);
71 public static SvnBranchConfigurationManager
getInstance(final Project project
) {
72 return ServiceManager
.getService(project
, SvnBranchConfigurationManager
.class);
75 public static class ConfigurationBean
{
76 public Map
<String
, SvnBranchConfiguration
> myConfigurationMap
= new HashMap
<String
, SvnBranchConfiguration
>();
78 * version of "support SVN in IDEA". for features tracking. should grow
80 public Long myVersion
;
81 public boolean mySupportsUserInfoFilter
;
84 public Long
getSupportValue() {
85 return myConfigurationBean
.myVersion
;
88 private ConfigurationBean myConfigurationBean
= new ConfigurationBean();
89 private final SvnBranchConfigManager myBunch
;
91 public SvnBranchConfigurationNew
get(@NotNull final VirtualFile vcsRoot
) throws VcsException
{
92 return myBunch
.getConfig(vcsRoot
);
95 public SvnBranchConfigManager
getSvnBranchConfigManager() {
99 public void setConfiguration(final VirtualFile vcsRoot
, final SvnBranchConfigurationNew configuration
) {
100 myBunch
.updateForRoot(vcsRoot
, new InfoStorage
<SvnBranchConfigurationNew
>(configuration
, InfoReliability
.setByUser
),
101 new BranchesPreloader(myProject
, myBunch
, vcsRoot
));
103 SvnBranchMapperManager
.getInstance().notifyBranchesChanged(myProject
, vcsRoot
, configuration
);
105 final MessageBus messageBus
= myProject
.getMessageBus();
106 messageBus
.syncPublisher(VcsConfigurationChangeListener
.BRANCHES_CHANGED
).execute(myProject
, vcsRoot
);
109 public ConfigurationBean
getState() {
110 final ConfigurationBean result
= new ConfigurationBean();
111 result
.myVersion
= myConfigurationBean
.myVersion
;
112 final UrlSerializationHelper helper
= new UrlSerializationHelper(SvnVcs
.getInstance(myProject
));
114 for (VirtualFile root
: myBunch
.getMapCopy().keySet()) {
115 final String key
= root
.getPath();
116 final SvnBranchConfigurationNew configOrig
= myBunch
.getConfig(root
);
117 final SvnBranchConfiguration configuration
= new SvnBranchConfiguration();
118 configuration
.setTrunkUrl(configOrig
.getTrunkUrl());
119 configuration
.setUserinfoInUrl(configOrig
.isUserinfoInUrl());
120 configuration
.setBranchUrls(configOrig
.getBranchUrls());
121 final HashMap
<String
, List
<SvnBranchItem
>> map
= new HashMap
<String
, List
<SvnBranchItem
>>();
122 final Map
<String
, InfoStorage
<List
<SvnBranchItem
>>> origMap
= configOrig
.getBranchMap();
123 for (String origKey
: origMap
.keySet()) {
124 map
.put(origKey
, origMap
.get(origKey
).getValue());
126 configuration
.setBranchMap(map
);
127 result
.myConfigurationMap
.put(key
, helper
.prepareForSerialization(configuration
));
129 result
.mySupportsUserInfoFilter
= true;
133 private static class BranchesPreloader
implements PairConsumer
<SvnBranchConfigurationNew
, SvnBranchConfigurationNew
> {
134 private final Project myProject
;
135 private final VirtualFile myRoot
;
136 private final SvnBranchConfigManager myBunch
;
137 private boolean myAll
;
139 public BranchesPreloader(Project project
, @NotNull final SvnBranchConfigManager bunch
, VirtualFile root
) {
145 public void consume(final SvnBranchConfigurationNew prev
, final SvnBranchConfigurationNew next
) {
146 final Application application
= ApplicationManager
.getApplication();
147 application
.executeOnPooledThread(new Runnable() {
149 loadImpl(prev
, next
);
154 protected void loadImpl(final SvnBranchConfigurationNew prev
, final SvnBranchConfigurationNew next
) {
155 final Set
<String
> oldUrls
= (prev
== null) ? Collections
.<String
>emptySet() : new HashSet
<String
>(prev
.getBranchUrls());
156 final SvnVcs vcs
= SvnVcs
.getInstance(myProject
);
157 if (! vcs
.isVcsBackgroundOperationsAllowed(myRoot
)) return;
159 for (String newBranchUrl
: next
.getBranchUrls()) {
160 if (myAll
|| (! oldUrls
.contains(newBranchUrl
))) {
161 new NewRootBunch
.BranchesLoadRunnable(myProject
, myBunch
, newBranchUrl
, InfoReliability
.defaultValues
, myRoot
, null).run();
166 public void setAll(boolean all
) {
171 public void loadState(final ConfigurationBean object
) {
172 final UrlSerializationHelper helper
= new UrlSerializationHelper(SvnVcs
.getInstance(myProject
));
173 final Map
<String
, SvnBranchConfiguration
> map
= object
.myConfigurationMap
;
174 final Map
<String
, SvnBranchConfiguration
> newMap
= new HashMap
<String
, SvnBranchConfiguration
>(map
.size(), 1);
175 final LocalFileSystem lfs
= LocalFileSystem
.getInstance();
177 final Set
<Pair
<VirtualFile
, SvnBranchConfigurationNew
>> whatToInit
= new HashSet
<Pair
<VirtualFile
, SvnBranchConfigurationNew
>>();
178 for (Map
.Entry
<String
, SvnBranchConfiguration
> entry
: map
.entrySet()) {
179 final SvnBranchConfiguration configuration
= entry
.getValue();
180 final VirtualFile root
= lfs
.refreshAndFindFileByIoFile(new File(entry
.getKey()));
182 LOG
.info("root not found: " + entry
.getKey());
186 final SvnBranchConfiguration configToConvert
;
187 if ((! myConfigurationBean
.mySupportsUserInfoFilter
) || configuration
.isUserinfoInUrl()) {
188 configToConvert
= helper
.afterDeserialization(entry
.getKey(), configuration
);
190 configToConvert
= configuration
;
192 final SvnBranchConfigurationNew newConfig
= new SvnBranchConfigurationNew();
193 newConfig
.setTrunkUrl(configToConvert
.getTrunkUrl());
194 newConfig
.setUserinfoInUrl(configToConvert
.isUserinfoInUrl());
195 final Map
<String
, List
<SvnBranchItem
>> oldMap
= configToConvert
.getBranchMap();
196 for (String branchUrl
: configToConvert
.getBranchUrls()) {
197 List
<SvnBranchItem
> items
= oldMap
.get(branchUrl
);
198 items
= ((items
== null) || (items
.isEmpty())) ?
new ArrayList
<SvnBranchItem
>() : items
;
199 whatToInit
.add(new Pair
<VirtualFile
, SvnBranchConfigurationNew
>(root
, newConfig
));
200 newConfig
.addBranches(branchUrl
, new InfoStorage
<List
<SvnBranchItem
>>(items
,
201 (items
.isEmpty()) ? InfoReliability
.defaultValues
: InfoReliability
.setByUser
));
204 myBunch
.updateForRoot(root
, new InfoStorage
<SvnBranchConfigurationNew
>(newConfig
, InfoReliability
.setByUser
), null);
206 ((ProjectLevelVcsManagerImpl
) myVcsManager
).addInitializationRequest(VcsInitObject
.BRANCHES
, new Runnable() {
208 ApplicationManager
.getApplication().executeOnPooledThread(new Runnable() {
211 for (Pair
<VirtualFile
, SvnBranchConfigurationNew
> pair
: whatToInit
) {
212 final BranchesPreloader branchesPreloader
= new BranchesPreloader(myProject
, myBunch
, pair
.getFirst());
213 branchesPreloader
.setAll(true);
214 branchesPreloader
.loadImpl(null, pair
.getSecond());
217 catch (ProcessCanceledException e
) {
224 object
.myConfigurationMap
.clear();
225 object
.myConfigurationMap
.putAll(newMap
);
226 myConfigurationBean
= object
;
229 private static class UrlSerializationHelper
{
230 private final SvnVcs myVcs
;
232 private UrlSerializationHelper(final SvnVcs vcs
) {
236 public SvnBranchConfiguration
prepareForSerialization(final SvnBranchConfiguration configuration
) {
237 final Ref
<Boolean
> withUserInfo
= new Ref
<Boolean
>();
238 final String trunkUrl
= serializeUrl(configuration
.getTrunkUrl(), withUserInfo
);
240 if (Boolean
.FALSE
.equals(withUserInfo
.get())) {
241 return configuration
;
244 final List
<String
> branches
= configuration
.getBranchUrls();
245 final List
<String
> newBranchesList
= new ArrayList
<String
>(branches
.size());
246 for (String s
: branches
) {
247 newBranchesList
.add(serializeUrl(s
, withUserInfo
));
250 final Map
<String
, List
<SvnBranchItem
>> map
= configuration
.getBranchMap();
251 final Map
<String
, List
<SvnBranchItem
>> newMap
= new HashMap
<String
, List
<SvnBranchItem
>>(map
.size(), 1.0f
);
252 for (Map
.Entry
<String
, List
<SvnBranchItem
>> entry
: map
.entrySet()) {
253 final List
<SvnBranchItem
> items
= entry
.getValue();
255 final List
<SvnBranchItem
> newItems
= new ArrayList
<SvnBranchItem
>();
256 for (SvnBranchItem item
: items
) {
257 newItems
.add(new SvnBranchItem(serializeUrl(item
.getUrl(), withUserInfo
), new java
.util
.Date(item
.getCreationDateMillis()),
258 item
.getRevision()));
260 newMap
.put(serializeUrl(entry
.getKey(), withUserInfo
), newItems
);
264 final SvnBranchConfiguration result
= new SvnBranchConfiguration();
265 result
.setTrunkUrl(trunkUrl
);
266 result
.setBranchUrls(newBranchesList
);
267 result
.setBranchMap(newMap
);
268 result
.setUserinfoInUrl(withUserInfo
.isNull() ?
false : withUserInfo
.get());
272 public SvnBranchConfiguration
afterDeserialization(final String path
, final SvnBranchConfiguration configuration
) {
273 if (! configuration
.isUserinfoInUrl()) {
274 return configuration
;
276 final String userInfo
= getUserInfo(path
);
277 if (userInfo
== null) {
278 return configuration
;
281 final String newTrunkUrl
= deserializeUrl(configuration
.getTrunkUrl(), userInfo
);
282 final List
<String
> branches
= configuration
.getBranchUrls();
283 final List
<String
> newBranchesList
= new ArrayList
<String
>(branches
.size());
284 for (String s
: branches
) {
285 newBranchesList
.add(deserializeUrl(s
, userInfo
));
288 final Map
<String
, List
<SvnBranchItem
>> map
= configuration
.getBranchMap();
289 final Map
<String
, List
<SvnBranchItem
>> newMap
= new HashMap
<String
, List
<SvnBranchItem
>>(map
.size(), 1.0f
);
290 for (Map
.Entry
<String
, List
<SvnBranchItem
>> entry
: map
.entrySet()) {
291 final List
<SvnBranchItem
> items
= entry
.getValue();
293 final List
<SvnBranchItem
> newItems
= new ArrayList
<SvnBranchItem
>();
294 for (SvnBranchItem item
: items
) {
295 newItems
.add(new SvnBranchItem(deserializeUrl(item
.getUrl(), userInfo
), new java
.util
.Date(item
.getCreationDateMillis()),
296 item
.getRevision()));
298 newMap
.put(deserializeUrl(entry
.getKey(), userInfo
), newItems
);
302 final SvnBranchConfiguration result
= new SvnBranchConfiguration();
303 result
.setTrunkUrl(newTrunkUrl
);
304 result
.setBranchUrls(newBranchesList
);
305 result
.setBranchMap(newMap
);
306 result
.setUserinfoInUrl(userInfo
!= null && userInfo
.length() > 0);
310 private String
serializeUrl(final String url
, final Ref
<Boolean
> withUserInfo
) {
311 if (Boolean
.FALSE
.equals(withUserInfo
.get())) {
315 final SVNURL svnurl
= SVNURL
.parseURIEncoded(url
);
316 if (withUserInfo
.isNull()) {
317 final String userInfo
= svnurl
.getUserInfo();
318 withUserInfo
.set((userInfo
!= null) && (userInfo
.length() > 0));
320 if (withUserInfo
.get()) {
321 return SVNURL
.create(svnurl
.getProtocol(), null, svnurl
.getHost(), svnurl
.getPort(), svnurl
.getURIEncodedPath(), true).toString();
324 catch (SVNException e
) {
331 private String
getUserInfo(final String path
) {
332 final SVNURL svnurl
= myVcs
.getSvnFileUrlMapping().getUrlForFile(new File(path
));
333 return svnurl
!= null ? svnurl
.getUserInfo() : null;
336 private String
deserializeUrl(final String url
, final String userInfo
) {
338 final SVNURL svnurl
= SVNURL
.parseURIEncoded(url
);
339 return SVNURL
.create(svnurl
.getProtocol(), userInfo
, svnurl
.getHost(), svnurl
.getPort(), svnurl
.getURIEncodedPath(), true).toString();
340 } catch (SVNException e
) {