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.
16 package org
.jetbrains
.idea
.svn
.mergeinfo
;
18 import com
.intellij
.openapi
.application
.ApplicationManager
;
19 import com
.intellij
.openapi
.components
.ServiceManager
;
20 import com
.intellij
.openapi
.diagnostic
.Logger
;
21 import com
.intellij
.openapi
.project
.Project
;
22 import com
.intellij
.util
.Consumer
;
23 import com
.intellij
.util
.containers
.SoftHashMap
;
24 import com
.intellij
.util
.messages
.Topic
;
25 import org
.jetbrains
.annotations
.Nullable
;
26 import org
.jetbrains
.idea
.svn
.SvnVcs
;
27 import org
.jetbrains
.idea
.svn
.dialogs
.WCInfoWithBranches
;
28 import org
.jetbrains
.idea
.svn
.dialogs
.WCPaths
;
29 import org
.jetbrains
.idea
.svn
.history
.FirstInBranch
;
30 import org
.jetbrains
.idea
.svn
.history
.SvnChangeList
;
31 import org
.tmatesoft
.svn
.core
.internal
.wc
.DefaultSVNOptions
;
32 import org
.tmatesoft
.svn
.core
.wc
.SVNWCClient
;
36 public class SvnMergeInfoCache
{
37 private final static Logger LOG
= Logger
.getInstance("#org.jetbrains.idea.svn.mergeinfo.SvnMergeInfoCache");
39 private final Project myProject
;
40 private final MyState myState
;
41 private final SVNWCClient myClient
;
43 public static Topic
<SvnMergeInfoCacheListener
> SVN_MERGE_INFO_CACHE
= new Topic
<SvnMergeInfoCacheListener
>("SVN_MERGE_INFO_CACHE",
44 SvnMergeInfoCacheListener
.class);
46 private SvnMergeInfoCache(final Project project
) {
48 myState
= new MyState();
49 final SvnVcs vcs
= SvnVcs
.getInstance(myProject
);
50 myClient
= vcs
.createWCClient();
51 myClient
.setOptions(new DefaultSVNOptions() {
53 public byte[] getNativeEOL() {
54 return new byte[]{'\n'};
59 public static SvnMergeInfoCache
getInstance(final Project project
) {
60 return ServiceManager
.getService(project
, SvnMergeInfoCache
.class);
63 public void clear(final WCPaths info
, final String branchPath
) {
64 final String currentUrl
= info
.getRootUrl();
66 final MyCurrentUrlData rootMapping
= myState
.getCurrentUrlMapping().get(currentUrl
);
67 if (rootMapping
!= null) {
68 final BranchInfo branchInfo
= rootMapping
.getBranchInfo(branchPath
);
69 if (branchInfo
!= null) {
76 public MergeinfoCached
getCachedState(final WCPaths info
, final String branchPath
) {
77 final String currentUrl
= info
.getRootUrl();
79 MyCurrentUrlData rootMapping
= myState
.getCurrentUrlMapping().get(currentUrl
);
80 if (rootMapping
!= null) {
81 final BranchInfo branchInfo
= rootMapping
.getBranchInfo(branchPath
);
82 if (branchInfo
!= null) {
83 return branchInfo
.getCached();
89 // only refresh might have changed; for branches/roots change, another method is used
90 public MergeCheckResult
getState(final WCInfoWithBranches info
, final SvnChangeList list
, final WCInfoWithBranches
.Branch selectedBranch
) {
91 return getState(info
, list
, selectedBranch
, null);
94 // only refresh might have changed; for branches/roots change, another method is used
95 public MergeCheckResult
getState(final WCInfoWithBranches info
, final SvnChangeList list
, final WCInfoWithBranches
.Branch selectedBranch
,
96 final String branchPath
) {
97 final String currentUrl
= info
.getRootUrl();
98 final String branchUrl
= selectedBranch
.getUrl();
100 MyCurrentUrlData rootMapping
= myState
.getCurrentUrlMapping().get(currentUrl
);
101 BranchInfo branchInfo
= null;
102 if (rootMapping
== null) {
103 rootMapping
= new MyCurrentUrlData();
104 myState
.getCurrentUrlMapping().put(currentUrl
, rootMapping
);
106 branchInfo
= rootMapping
.getBranchInfo(branchPath
);
108 if (branchInfo
== null) {
109 branchInfo
= new BranchInfo(SvnVcs
.getInstance(myProject
), info
.getRepoUrl(), branchUrl
, currentUrl
, info
.getTrunkRoot(), myClient
);
110 rootMapping
.addBranchInfo(branchPath
, branchInfo
);
113 return branchInfo
.checkList(list
, branchPath
);
116 public boolean isMixedRevisions(final WCInfoWithBranches info
, final String branchPath
) {
117 final String currentUrl
= info
.getRootUrl();
118 final MyCurrentUrlData rootMapping
= myState
.getCurrentUrlMapping().get(currentUrl
);
119 if (rootMapping
!= null) {
120 final BranchInfo branchInfo
= rootMapping
.getBranchInfo(branchPath
);
121 if (branchInfo
!= null) {
122 return branchInfo
.isMixedRevisionsFound();
128 private static class MyState
{
129 private Map
<String
, MyCurrentUrlData
> myCurrentUrlMapping
;
132 myCurrentUrlMapping
= new HashMap
<String
, MyCurrentUrlData
>();
135 public Map
<String
, MyCurrentUrlData
> getCurrentUrlMapping() {
136 return myCurrentUrlMapping
;
139 public void setCurrentUrlMapping(final Map
<String
, MyCurrentUrlData
> currentUrlMapping
) {
140 myCurrentUrlMapping
= currentUrlMapping
;
144 public static enum MergeCheckResult
{
149 NOT_EXISTS_PARTLY_MERGED
;
151 public static MergeCheckResult
getInstance(final boolean merged
) {
152 // not exists assumed to be already checked
160 static class CopyRevison
{
161 private final String myPath
;
162 private volatile long myRevision
;
164 CopyRevison(final SvnVcs vcs
, final String path
, final String repositoryRoot
, final String branchUrl
, final String trunkUrl
) {
168 ApplicationManager
.getApplication().executeOnPooledThread(new FirstInBranch(vcs
, repositoryRoot
, branchUrl
, trunkUrl
,
169 new Consumer
<Long
>() {
170 public void consume(final Long aLong
) {
172 if (myRevision
!= -1) {
173 ApplicationManager
.getApplication().invokeLater(new Runnable() {
175 if (vcs
.getProject().isDisposed()) return;
176 vcs
.getProject().getMessageBus().syncPublisher(SVN_MERGE_INFO_CACHE
).copyRevisionUpdated();
184 public String
getPath() {
188 public long getRevision() {
193 private static class MyCurrentUrlData
{
194 private final Map
<String
, BranchInfo
> myBranchInfo
;
196 private MyCurrentUrlData() {
197 myBranchInfo
= new SoftHashMap
<String
, BranchInfo
>();
200 public BranchInfo
getBranchInfo(final String branchUrl
) {
201 return myBranchInfo
.get(branchUrl
);
204 public void addBranchInfo(final String branchUrl
, final BranchInfo branchInfo
) {
205 myBranchInfo
.put(branchUrl
, branchInfo
);
209 public interface SvnMergeInfoCacheListener
{
210 void copyRevisionUpdated();