2 * Copyright 2000-2005 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
.update
;
18 import com
.intellij
.openapi
.application
.ApplicationManager
;
19 import com
.intellij
.openapi
.options
.Configurable
;
20 import com
.intellij
.openapi
.progress
.ProcessCanceledException
;
21 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
22 import com
.intellij
.openapi
.ui
.Messages
;
23 import com
.intellij
.openapi
.util
.Ref
;
24 import com
.intellij
.openapi
.util
.io
.FileUtil
;
25 import com
.intellij
.openapi
.vcs
.*;
26 import com
.intellij
.openapi
.vcs
.changes
.VcsDirtyScopeManager
;
27 import com
.intellij
.openapi
.vcs
.history
.VcsRevisionNumber
;
28 import com
.intellij
.openapi
.vcs
.update
.*;
29 import com
.intellij
.openapi
.vfs
.LocalFileSystem
;
30 import com
.intellij
.openapi
.vfs
.ReadonlyStatusHandler
;
31 import com
.intellij
.openapi
.vfs
.VirtualFile
;
32 import com
.intellij
.openapi
.vfs
.newvfs
.RefreshQueue
;
33 import com
.intellij
.openapi
.vfs
.newvfs
.RefreshSession
;
34 import org
.jetbrains
.annotations
.NonNls
;
35 import org
.jetbrains
.annotations
.NotNull
;
36 import org
.jetbrains
.annotations
.Nullable
;
37 import org
.jetbrains
.idea
.svn
.SvnBundle
;
38 import org
.jetbrains
.idea
.svn
.SvnUtil
;
39 import org
.jetbrains
.idea
.svn
.SvnVcs
;
40 import org
.jetbrains
.idea
.svn
.actions
.SvnMergeProvider
;
41 import org
.tmatesoft
.svn
.core
.wc
.ISVNEventHandler
;
46 public abstract class AbstractSvnUpdateIntegrateEnvironment
implements UpdateEnvironment
{
47 protected final SvnVcs myVcs
;
48 private final ProjectLevelVcsManager myVcsManager
;
49 @NonNls public static final String REPLACED_ID
= "replaced";
50 @NonNls public static final String EXTERNAL_ID
= "external";
52 protected AbstractSvnUpdateIntegrateEnvironment(final SvnVcs vcs
) {
54 myVcsManager
= ProjectLevelVcsManager
.getInstance(vcs
.getProject());
57 public void fillGroups(UpdatedFiles updatedFiles
) {
58 updatedFiles
.registerGroup(new FileGroup(VcsBundle
.message("update.group.name.merged.with.property.conflicts"),
59 VcsBundle
.message("status.group.name.will.be.merged.with.property.conflicts"), false,
60 FileGroup
.MERGED_WITH_PROPERTY_CONFLICT_ID
, false));
61 updatedFiles
.registerGroup(new FileGroup(VcsBundle
.message("update.group.name.merged.with.tree.conflicts"),
62 VcsBundle
.message("status.group.name.will.be.merged.with.tree.conflicts"), false,
63 SvnUpdateGroups
.MERGED_WITH_TREE_CONFLICT
, false));
67 public UpdateSession
updateDirectories(@NotNull final FilePath
[] contentRoots
,
68 final UpdatedFiles updatedFiles
,
69 final ProgressIndicator progressIndicator
, @NotNull final Ref
<SequentialUpdatesContext
> context
)
70 throws ProcessCanceledException
{
72 final ArrayList
<VcsException
> exceptions
= new ArrayList
<VcsException
>();
73 UpdateEventHandler eventHandler
= new UpdateEventHandler(myVcs
, progressIndicator
);
74 eventHandler
.setUpdatedFiles(updatedFiles
);
76 boolean totalUpdate
= true;
77 AbstractUpdateIntegrateCrawler crawler
= createCrawler(eventHandler
, totalUpdate
, exceptions
, updatedFiles
);
79 Collection
<File
> updatedRoots
= new HashSet
<File
>();
80 for (FilePath contentRoot
: contentRoots
) {
81 if (progressIndicator
!= null && progressIndicator
.isCanceled()) {
82 throw new ProcessCanceledException();
84 Collection
<File
> roots
= SvnUtil
.crawlWCRoots(contentRoot
.getIOFile(), crawler
, progressIndicator
);
85 updatedRoots
.addAll(roots
);
87 if (updatedRoots
.isEmpty()) {
88 ApplicationManager
.getApplication().invokeLater(new Runnable() {
90 Messages
.showErrorDialog(myVcs
.getProject(), SvnBundle
.message("message.text.update.no.directories.found"),
91 SvnBundle
.message("messate.text.update.error"));
94 return new UpdateSessionAdapter(Collections
.<VcsException
>emptyList(), true);
97 return new MyUpdateSessionAdapter(contentRoots
, updatedFiles
, exceptions
);
100 private class MyUpdateSessionAdapter
extends UpdateSessionAdapter
{
101 private final FilePath
[] myContentRoots
;
102 private final UpdatedFiles myUpdatedFiles
;
103 private final VcsDirtyScopeManager myDirtyScopeManager
;
104 private final List
<MyConflictWorker
> myGroupWorkers
;
106 private MyUpdateSessionAdapter(@NotNull final FilePath
[] contentRoots
, final UpdatedFiles updatedFiles
, final List
<VcsException
> exceptions
) {
107 super(exceptions
, false);
108 myContentRoots
= contentRoots
;
109 myUpdatedFiles
= updatedFiles
;
110 myDirtyScopeManager
= VcsDirtyScopeManager
.getInstance(myVcs
.getProject());
113 myGroupWorkers
= Arrays
.asList(new MyTextConflictWorker(), new MyConflictWorker(FileGroup
.MERGED_WITH_PROPERTY_CONFLICT_ID
) {
114 protected List
<VirtualFile
> merge() {
117 }, new MyConflictWorker(SvnUpdateGroups
.MERGED_WITH_TREE_CONFLICT
) {
118 protected List
<VirtualFile
> merge() {
123 myGroupWorkers
= Collections
.emptyList();
127 // update switched/ignored status of directories
128 private void dirtyRoots() {
129 final Collection
<VirtualFile
> vfColl
= new ArrayList
<VirtualFile
>(myContentRoots
.length
);
130 for (FilePath contentRoot
: myContentRoots
) {
131 final VirtualFile vf
= contentRoot
.getVirtualFile();
136 myDirtyScopeManager
.filesDirty(vfColl
, null);
139 public void onRefreshFilesCompleted() {
142 for (MyConflictWorker groupWorker
: myGroupWorkers
) {
143 groupWorker
.execute();
147 private class MyTextConflictWorker
extends MyConflictWorker
{
148 private MyTextConflictWorker() {
149 super(FileGroup
.MERGED_WITH_CONFLICT_ID
);
152 protected List
<VirtualFile
> merge() {
153 final List
<VirtualFile
> writeable
= prepareWriteable(myFiles
);
154 final AbstractVcsHelper vcsHelper
= AbstractVcsHelper
.getInstance(myVcs
.getProject());
155 return vcsHelper
.showMergeDialog(writeable
, new SvnMergeProvider(myVcs
.getProject()));
159 private abstract class MyConflictWorker
{
160 private final String groupId
;
161 protected final List
<VirtualFile
> myFiles
;
162 private LocalFileSystem myLfs
;
163 private final ProjectLevelVcsManager myPlVcsManager
;
165 protected MyConflictWorker(final String groupId
) {
166 this.groupId
= groupId
;
167 myFiles
= new ArrayList
<VirtualFile
>();
168 myLfs
= LocalFileSystem
.getInstance();
169 myPlVcsManager
= ProjectLevelVcsManager
.getInstance(myVcs
.getProject());
173 protected List
<VirtualFile
> prepareWriteable(final Collection
<VirtualFile
> files
) {
174 final List
<VirtualFile
> writeable
= new ArrayList
<VirtualFile
>();
175 for (VirtualFile vf
: files
) {
176 if (myVcs
.equals(myPlVcsManager
.getVcsFor(vf
))) {
180 final ReadonlyStatusHandler
.OperationStatus operationStatus
=
181 ReadonlyStatusHandler
.getInstance(myVcs
.getProject()).ensureFilesWritable(writeable
);
182 writeable
.removeAll(Arrays
.asList(operationStatus
.getReadonlyFiles()));
188 protected abstract List
<VirtualFile
> merge();
190 public void execute() {
191 fillAndRefreshFiles();
192 if (! myFiles
.isEmpty()) {
193 final List
<VirtualFile
> merged
= merge();
194 if (merged
!= null && (! merged
.isEmpty())) {
195 moveToMergedGroup(merged
);
198 myDirtyScopeManager
.filesDirty(merged
, null);
203 protected void moveToMergedGroup(final List
<VirtualFile
> merged
) {
204 final FileGroup conflictedGroup
= myUpdatedFiles
.getGroupById(groupId
);
205 FileGroup mergedGroup
= myUpdatedFiles
.getGroupById(FileGroup
.MERGED_ID
);
206 for (VirtualFile mergedFile
: merged
) {
207 final String path
= FileUtil
.toSystemDependentName(mergedFile
.getPresentableUrl());
208 final VcsRevisionNumber revision
= conflictedGroup
.getRevision(myVcsManager
, path
);
209 conflictedGroup
.remove(path
);
210 if (revision
!= null) {
211 mergedGroup
.add(path
, myVcs
, revision
);
214 mergedGroup
.add(path
);
219 protected void fillAndRefreshFiles() {
220 final FileGroup conflictedGroup
= myUpdatedFiles
.getGroupById(groupId
);
221 final Collection
<String
> conflictedFiles
= conflictedGroup
.getFiles();
222 final Collection
<VirtualFile
> parents
= new ArrayList
<VirtualFile
>();
224 if ((conflictedFiles
!= null) && (! conflictedFiles
.isEmpty())) {
225 for (final String conflictedFile
: conflictedFiles
) {
226 final File file
= new File(conflictedFile
);
227 VirtualFile vf
= myLfs
.findFileByIoFile(file
);
229 vf
= myLfs
.refreshAndFindFileByIoFile(file
);
233 final VirtualFile parent
= vf
.getParent();
234 if (parent
!= null) {
241 if (! myFiles
.isEmpty()) {
242 final RefreshQueue refreshQueue
= RefreshQueue
.getInstance();
243 final RefreshSession session
= refreshQueue
.createSession(true, true, null);
244 session
.addAllFiles(parents
);
247 myDirtyScopeManager
.filesDirty(myFiles
, null);
251 public String
getGroupId() {
257 protected boolean isDryRun() {
261 protected abstract AbstractUpdateIntegrateCrawler
createCrawler(ISVNEventHandler eventHandler
,
263 ArrayList
<VcsException
> exceptions
, UpdatedFiles updatedFiles
);
266 public abstract Configurable
createConfigurable(Collection
<FilePath
> collection
);