3fe68b23dc23e7a52b68fffcd4dfd164447c38d3
[fedora-idea.git] / plugins / cvs / cvs-plugin / src / com / intellij / cvsSupport2 / changeBrowser / CvsCommittedChangesProvider.java
blob3fe68b23dc23e7a52b68fffcd4dfd164447c38d3
1 /*
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 com.intellij.cvsSupport2.changeBrowser;
18 import com.intellij.CvsBundle;
19 import com.intellij.cvsSupport2.CvsUtil;
20 import com.intellij.cvsSupport2.application.CvsEntriesManager;
21 import com.intellij.cvsSupport2.connections.CvsEnvironment;
22 import com.intellij.cvsSupport2.cvsExecution.CvsOperationExecutor;
23 import com.intellij.cvsSupport2.cvsExecution.CvsOperationExecutorCallback;
24 import com.intellij.cvsSupport2.cvshandlers.CommandCvsHandler;
25 import com.intellij.cvsSupport2.history.CvsRevisionNumber;
26 import com.intellij.openapi.application.ApplicationManager;
27 import com.intellij.openapi.cvsIntegration.CvsResult;
28 import com.intellij.openapi.diagnostic.Logger;
29 import com.intellij.openapi.progress.ProcessCanceledException;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.util.Comparing;
32 import com.intellij.openapi.util.Computable;
33 import com.intellij.openapi.vcs.*;
34 import com.intellij.openapi.vcs.changes.ChangesUtil;
35 import com.intellij.openapi.vcs.changes.committed.*;
36 import com.intellij.openapi.vcs.history.VcsRevisionNumber;
37 import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
38 import com.intellij.openapi.vcs.versionBrowser.ChangesBrowserSettingsEditor;
39 import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
40 import com.intellij.openapi.vfs.VirtualFile;
41 import com.intellij.util.AsynchConsumer;
42 import com.intellij.util.Consumer;
43 import org.jetbrains.annotations.NonNls;
44 import org.jetbrains.annotations.NotNull;
45 import org.jetbrains.annotations.Nullable;
46 import org.netbeans.lib.cvsclient.admin.Entry;
48 import java.io.DataInput;
49 import java.io.DataOutput;
50 import java.io.IOException;
51 import java.util.*;
53 /**
54 * @author yole
56 public class CvsCommittedChangesProvider implements CachingCommittedChangesProvider<CvsChangeList, ChangeBrowserSettings> {
57 private static final Logger LOG = Logger.getInstance("#com.intellij.cvsSupport2.changeBrowser.CvsCommittedChangesProvider");
59 private final Project myProject;
60 private final MyZipper myZipper;
62 @NonNls private static final String INVALID_OPTION_S = "invalid option -- S";
64 public CvsCommittedChangesProvider(Project project) {
65 myProject = project;
66 myZipper = new MyZipper();
69 public ChangeBrowserSettings createDefaultSettings() {
70 return new ChangeBrowserSettings();
73 public ChangesBrowserSettingsEditor<ChangeBrowserSettings> createFilterUI(final boolean showDateFilter) {
74 return new CvsVersionFilterComponent(showDateFilter);
77 public VcsCommittedListsZipper getZipper() {
78 return myZipper;
81 private class MyZipper extends VcsCommittedListsZipperAdapter {
82 private MyZipper() {
83 super(new GroupCreator() {
84 public Object createKey(final RepositoryLocation location) {
85 final CvsRepositoryLocation cvsLocation = (CvsRepositoryLocation) location;
86 return cvsLocation.getEnvironment().getRepository();
89 public RepositoryLocationGroup createGroup(final Object key, final Collection<RepositoryLocation> locations) {
90 final RepositoryLocationGroup group = new RepositoryLocationGroup((String) key);
91 for (RepositoryLocation location : locations) {
92 group.add(location);
94 return group;
96 });
99 @Override
100 public long getNumber(final CommittedChangeList list) {
101 return list.getCommitDate().getTime();
105 @Nullable
106 public CvsRepositoryLocation getLocationFor(final FilePath root) {
107 if (!CvsUtil.fileIsUnderCvs(root.getIOFile())) {
108 return null;
110 final VirtualFile rootDir = root.isDirectory() ? root.getVirtualFile() : root.getVirtualFileParent();
111 final String module = CvsUtil.getModuleName(root);
112 final CvsEnvironment connectionSettings = CvsEntriesManager.getInstance().getCvsConnectionSettingsFor(rootDir);
113 return new CvsRepositoryLocation(root.getVirtualFile(), connectionSettings, module);
116 public RepositoryLocation getLocationFor(final FilePath root, final String repositoryPath) {
117 return getLocationFor(root);
120 public ChangeListColumn[] getColumns() {
121 return new ChangeListColumn[] { ChangeListColumn.DATE, ChangeListColumn.NAME, ChangeListColumn.DESCRIPTION, BRANCH_COLUMN };
124 @Nullable
125 public VcsCommittedViewAuxiliary createActions(final DecoratorManager manager, final RepositoryLocation location) {
126 return null;
129 public int getUnlimitedCountValue() {
130 return 0;
133 public List<CvsChangeList> getCommittedChanges(ChangeBrowserSettings settings, RepositoryLocation location, final int maxCount) throws VcsException {
134 CvsRepositoryLocation cvsLocation = (CvsRepositoryLocation) location;
135 return loadCommittedChanges(settings, cvsLocation.getModuleName(), cvsLocation.getEnvironment(), cvsLocation.getRootFile());
138 public void loadCommittedChanges(ChangeBrowserSettings settings,
139 RepositoryLocation location,
140 int maxCount,
141 final AsynchConsumer<CommittedChangeList> consumer)
142 throws VcsException {
143 try {
144 CvsRepositoryLocation cvsLocation = (CvsRepositoryLocation) location;
145 final String module = cvsLocation.getModuleName();
146 final CvsEnvironment connectionSettings = cvsLocation.getEnvironment();
147 if (connectionSettings.isOffline()) {
148 return;
150 final CvsChangeListsBuilder builder = new CvsChangeListsBuilder(module, connectionSettings, myProject, cvsLocation.getRootFile());
151 Date dateTo = settings.getDateBeforeFilter();
152 Date dateFrom = settings.getDateAfterFilter();
153 if (dateFrom == null) {
154 final Calendar calendar = Calendar.getInstance();
155 calendar.set(1970, 2, 2);
156 dateFrom = calendar.getTime();
158 final ChangeBrowserSettings.Filter filter = settings.createFilter();
159 final CvsResult executionResult = runRLogOperation(connectionSettings, module, dateFrom, dateTo, new Consumer<LogInformationWrapper>() {
160 public void consume(LogInformationWrapper wrapper) {
161 final RevisionWrapper revisionWrapper = builder.revisionWrapperFromLog(wrapper);
162 final CvsChangeList changeList = builder.addRevision(revisionWrapper);
163 if (filter.accepts(changeList)) {
164 consumer.consume(changeList);
169 if (executionResult.isCanceled()) {
170 throw new ProcessCanceledException();
172 else if (!executionResult.hasNoErrors()) {
173 throw executionResult.composeError();
176 finally {
177 consumer.finished();
181 private List<CvsChangeList> loadCommittedChanges(final ChangeBrowserSettings settings,
182 final String module,
183 final CvsEnvironment connectionSettings,
184 final VirtualFile rootFile) throws VcsException {
185 if (connectionSettings.isOffline()) {
186 return Collections.emptyList();
188 final CvsChangeListsBuilder builder = new CvsChangeListsBuilder(module, connectionSettings, myProject, rootFile);
189 Date dateTo = settings.getDateBeforeFilter();
190 Date dateFrom = settings.getDateAfterFilter();
191 if (dateFrom == null) {
192 final Calendar calendar = Calendar.getInstance();
193 calendar.set(1970, 2, 2);
194 dateFrom = calendar.getTime();
196 final List<LogInformationWrapper> log = new ArrayList<LogInformationWrapper>();
197 final CvsResult executionResult = runRLogOperation(connectionSettings, module, dateFrom, dateTo, log);
199 if (executionResult.isCanceled()) {
200 throw new ProcessCanceledException();
202 else if (!executionResult.hasNoErrors()) {
203 throw executionResult.composeError();
205 else {
206 builder.addLogs(log);
207 final List<CvsChangeList> versions = builder.getVersions();
208 settings.filterChanges(versions);
209 return versions;
213 private CvsResult runRLogOperation(final CvsEnvironment settings,
214 final String module,
215 final Date dateFrom,
216 final Date dateTo,
217 final Consumer<LogInformationWrapper> consumer) {
218 final CvsResult executionResult = runRLogOperationImpl(settings, module, dateFrom, dateTo, consumer);
220 for (VcsException error : executionResult.getErrors()) {
221 for (String message : error.getMessages()) {
222 if (message.indexOf(INVALID_OPTION_S) >= 0) {
223 LoadHistoryOperation.doesNotSuppressEmptyHeaders(settings);
224 // try only once
225 return runRLogOperationImpl(settings, module, dateFrom, dateTo, consumer);
229 return executionResult;
232 private CvsResult runRLogOperationImpl(final CvsEnvironment settings,
233 final String module,
234 final Date dateFrom,
235 final Date dateTo,
236 final Consumer<LogInformationWrapper> consumer) {
237 LoadHistoryOperation operation = new LoadHistoryOperation(settings, module, dateFrom, dateTo, null) {
238 @Override
239 protected void wrapperAdded(final LogInformationWrapper wrapper) {
240 consumer.consume(wrapper);
244 CvsOperationExecutor executor = new CvsOperationExecutor(myProject);
245 executor.performActionSync(new CommandCvsHandler(CvsBundle.message("browse.changes.load.history.progress.title"), operation),
246 CvsOperationExecutorCallback.EMPTY);
248 return executor.getResult();
251 private CvsResult runRLogOperation(final CvsEnvironment settings,
252 final String module,
253 final Date dateFrom,
254 final Date dateTo,
255 final List<LogInformationWrapper> log) {
256 LoadHistoryOperation operation = new LoadHistoryOperation(settings, module, dateFrom, dateTo, log);
258 CvsOperationExecutor executor = new CvsOperationExecutor(myProject);
259 executor.performActionSync(new CommandCvsHandler(CvsBundle.message("browse.changes.load.history.progress.title"), operation),
260 CvsOperationExecutorCallback.EMPTY);
262 final CvsResult executionResult = executor.getResult();
264 for (VcsException error : executionResult.getErrors()) {
265 for (String message : error.getMessages()) {
266 if (message.indexOf(INVALID_OPTION_S) >= 0) {
267 LoadHistoryOperation.doesNotSuppressEmptyHeaders(settings);
268 log.clear();
269 return runRLogOperation(settings, module, dateFrom, dateTo, log);
274 return executionResult;
277 public int getFormatVersion() {
278 return 2;
281 public void writeChangeList(final DataOutput stream, final CvsChangeList list) throws IOException {
282 list.writeToStream(stream);
285 public CvsChangeList readChangeList(final RepositoryLocation location, final DataInput stream) throws IOException {
286 CvsRepositoryLocation cvsLocation = (CvsRepositoryLocation) location;
287 return new CvsChangeList(myProject, cvsLocation.getEnvironment(), cvsLocation.getRootFile(), stream);
290 public boolean isMaxCountSupported() {
291 return false;
294 public Collection<FilePath> getIncomingFiles(final RepositoryLocation location) {
295 return null;
298 public boolean refreshCacheByNumber() {
299 return false;
302 public String getChangelistTitle() {
303 return null;
306 public boolean isChangeLocallyAvailable(final FilePath filePath, @Nullable VcsRevisionNumber localRevision, VcsRevisionNumber changeRevision,
307 final CvsChangeList changeList) {
308 if (localRevision instanceof CvsRevisionNumber && changeRevision instanceof CvsRevisionNumber) {
309 final CvsRevisionNumber cvsLocalRevision = (CvsRevisionNumber)localRevision;
310 final CvsRevisionNumber cvsChangeRevision = (CvsRevisionNumber)changeRevision;
311 final int[] localSubRevisions = cvsLocalRevision.getSubRevisions();
312 final int[] changeSubRevisions = cvsChangeRevision.getSubRevisions();
313 if (localSubRevisions != null && changeSubRevisions != null) {
314 if (localSubRevisions.length != changeSubRevisions.length) {
315 // local is trunk, change is branch / vice versa
316 return true;
318 for(int i=2; i<localSubRevisions.length; i += 2) {
319 if (localSubRevisions [i] != changeSubRevisions [i]) {
320 // local is one branch, change is a different branch
321 return true;
327 return isDifferentBranch(filePath, changeList) || (localRevision != null && localRevision.compareTo(changeRevision) >= 0);
330 private static boolean isDifferentBranch(final FilePath filePath, final CvsChangeList changeList) {
331 String localTag;
332 final CvsEntriesManager cvsEntriesManager = CvsEntriesManager.getInstance();
333 final VirtualFile parent = filePath.getVirtualFileParent();
334 if (parent != null) {
335 Entry entry = cvsEntriesManager.getEntryFor(parent, filePath.getName());
336 if (entry != null) {
337 localTag = entry.getStickyTag();
339 else {
340 localTag = getDirectoryTag(parent);
343 else {
344 final VirtualFile validParent = ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile>() {
345 @Nullable
346 public VirtualFile compute() {
347 return ChangesUtil.findValidParent(filePath);
350 if (validParent == null) return false;
351 localTag = getDirectoryTag(validParent);
353 final String remoteTag = changeList.getBranch();
354 if (!Comparing.equal(localTag, remoteTag)) {
355 LOG.info(filePath + ": local tag " + localTag + ", remote tag " + remoteTag);
356 return true;
358 return false;
361 @Nullable
362 private static String getDirectoryTag(@NotNull final VirtualFile parent) {
363 final String dirTag = CvsEntriesManager.getInstance().getCvsInfoFor(parent).getStickyTag();
364 if (dirTag == null || !CvsUtil.isNonDateTag(dirTag)) return null;
365 return dirTag.substring(1);
368 public boolean refreshIncomingWithCommitted() {
369 return true;
372 private final ChangeListColumn<CvsChangeList> BRANCH_COLUMN = new ChangeListColumn<CvsChangeList>() {
373 public String getTitle() {
374 return CvsBundle.message("changelist.column.branch");
377 public Object getValue(final CvsChangeList changeList) {
378 final String branch = changeList.getBranch();
379 return branch == null ? "HEAD" : branch;