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
.*;
51 name
= "SvnBranchConfigurationManager",
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
) {
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
>();
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() {
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;
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
) {
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() {
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
) {
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 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
) {
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();
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());
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();
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);
300 private String
serializeUrl(final String url
, final Ref
<Boolean
> withUserInfo
) {
301 if (Boolean
.FALSE
.equals(withUserInfo
.get())) {
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
) {
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
) {
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
) {