SVN 1.6 support. svnkit: 1-3-0-beta3, patched for IDEA
[fedora-idea.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / update / AbstractSvnUpdateIntegrateEnvironment.java
blob91831259a2ec6b57819d3a823d725c3fec5a6c39
1 /*
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;
43 import java.io.File;
44 import java.util.*;
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) {
53 myVcs = 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));
66 @NotNull
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() {
89 public void run() {
90 Messages.showErrorDialog(myVcs.getProject(), SvnBundle.message("message.text.update.no.directories.found"),
91 SvnBundle.message("messate.text.update.error"));
93 });
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());
112 if (! isDryRun()) {
113 myGroupWorkers = Arrays.asList(new MyTextConflictWorker(), new MyConflictWorker(FileGroup.MERGED_WITH_PROPERTY_CONFLICT_ID) {
114 protected List<VirtualFile> merge() {
115 return null;
117 }, new MyConflictWorker(SvnUpdateGroups.MERGED_WITH_TREE_CONFLICT) {
118 protected List<VirtualFile> merge() {
119 return null;
122 } else {
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();
132 if (vf != null) {
133 vfColl.add(vf);
136 myDirtyScopeManager.filesDirty(vfColl, null);
139 public void onRefreshFilesCompleted() {
140 dirtyRoots();
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());
172 // for reuse
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))) {
177 writeable.add(vf);
180 final ReadonlyStatusHandler.OperationStatus operationStatus =
181 ReadonlyStatusHandler.getInstance(myVcs.getProject()).ensureFilesWritable(writeable);
182 writeable.removeAll(Arrays.asList(operationStatus.getReadonlyFiles()));
184 return writeable;
187 @Nullable
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);
197 // do we need this
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);
213 else {
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);
228 if (vf == null) {
229 vf = myLfs.refreshAndFindFileByIoFile(file);
231 if (vf != null) {
232 myFiles.add(vf);
233 final VirtualFile parent = vf.getParent();
234 if (parent != null) {
235 parents.add(parent);
241 if (! myFiles.isEmpty()) {
242 final RefreshQueue refreshQueue = RefreshQueue.getInstance();
243 final RefreshSession session = refreshQueue.createSession(true, true, null);
244 session.addAllFiles(parents);
245 session.launch();
247 myDirtyScopeManager.filesDirty(myFiles, null);
251 public String getGroupId() {
252 return groupId;
257 protected boolean isDryRun() {
258 return false;
261 protected abstract AbstractUpdateIntegrateCrawler createCrawler(ISVNEventHandler eventHandler,
262 boolean totalUpdate,
263 ArrayList<VcsException> exceptions, UpdatedFiles updatedFiles);
265 @Nullable
266 public abstract Configurable createConfigurable(Collection<FilePath> collection);