blob: b26e49e033eb762036291f9b229af135ee530a1b [file] [log] [blame]
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.cvsSupport2.changeBrowser;
import com.intellij.cvsSupport2.connections.CvsEnvironment;
import com.intellij.cvsSupport2.history.CvsRevisionNumber;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import org.netbeans.lib.cvsclient.command.log.Revision;
import org.netbeans.lib.cvsclient.command.log.SymbolicName;
import java.util.*;
public class CvsChangeListsBuilder {
@NonNls private static final String INITIALLY_ADDED_ON_BRANCH = "was initially added on branch";
private static class ChangeListKey extends Trinity<String, String, String> {
public ChangeListKey(final String branch, final String author, final String message) {
super(branch, author, message);
}
}
private final Map<ChangeListKey, List<CvsChangeList>> myCache = new HashMap<ChangeListKey, List<CvsChangeList>>();
private long myLastNumber = 0;
private final String myRootPath;
private final CvsEnvironment myEnvironment;
private final Project myProject;
private final VirtualFile myRootFile;
public CvsChangeListsBuilder(final String rootPath, final CvsEnvironment environment, final Project project, final VirtualFile rootFile) {
myRootPath = rootPath;
myEnvironment = environment;
myProject = project;
myRootFile = rootFile;
}
public List<CvsChangeList> getVersions() {
final ArrayList<CvsChangeList> result = new ArrayList<CvsChangeList>();
for (List<CvsChangeList> versions : myCache.values()) {
result.addAll(versions);
}
return result;
}
public CvsChangeList addRevision(RevisionWrapper revisionWrapper) {
final Revision revision = revisionWrapper.getRevision();
final CvsChangeList version = findOrCreateVersionFor(revision.getMessage(),
revisionWrapper.getTime(),
revision.getAuthor(),
revisionWrapper.getBranch(),
revisionWrapper.getFile());
version.addFileRevision(revisionWrapper);
return version;
}
private CvsChangeList findOrCreateVersionFor(final String message, final long date, final String author,
final String branch, final String path) {
final ChangeListKey key = new ChangeListKey(branch, author, message);
final List<CvsChangeList> versions = myCache.get(key);
if (versions != null) {
for (int i = versions.size() - 1; i >= 0; i--) {
final CvsChangeList version = versions.get(i);
if (version.containsDate(date) && !version.containsFile(path)) {
return version;
}
}
}
final CvsChangeList result =
new CvsChangeList(myProject, myEnvironment, myRootFile, myLastNumber, message, date, author, myRootPath);
myLastNumber += 1;
if (!myCache.containsKey(key)) {
myCache.put(key, new ArrayList<CvsChangeList>());
}
myCache.get(key).add(result);
return result;
}
@Nullable
public List<RevisionWrapper> revisionWrappersFromLog(final LogInformationWrapper log) {
final String file = log.getFile();
if (!CvsChangeList.isAncestor(myRootPath, file)) {
return null;
}
final List<RevisionWrapper> result = new ArrayList<RevisionWrapper>();
for (Revision revision : log.getRevisions()) {
if (revision != null) {
if (revision.getState().equals(CvsChangeList.DEAD_STATE) &&
revision.getMessage().contains(INITIALLY_ADDED_ON_BRANCH)) {
// ignore dead revision (otherwise it'll get stuck in incoming changes forever - it's considered a deletion and
// the file is never actually deleted)
continue;
}
final String branchName = getBranchName(revision, log.getSymbolicNames());
result.add(new RevisionWrapper(file, revision, branchName));
}
}
return result;
}
public void add(LogInformationWrapper log) {
final List<RevisionWrapper> wrappers = revisionWrappersFromLog(log);
if (wrappers == null) {
return;
}
for (RevisionWrapper wrapper : wrappers) {
addRevision(wrapper);
}
}
@Nullable
private static String getBranchName(final Revision revision, final List<SymbolicName> symbolicNames) {
final CvsRevisionNumber number = new CvsRevisionNumber(revision.getNumber().trim());
final int[] subRevisions = number.getSubRevisions();
String branchNumberString = null;
if (subRevisions != null && subRevisions.length >= 4) {
final int branchRevNumber = subRevisions [subRevisions.length-2];
final CvsRevisionNumber branchNumber = number.removeTailVersions(2).addTailVersions(0, branchRevNumber);
branchNumberString = branchNumber.asString();
}
if (branchNumberString == null) {
final String branches = revision.getBranches();
if (branches != null && branches.length() > 0) {
final String[] branchNames = branches.split(";");
final CvsRevisionNumber revisionNumber = new CvsRevisionNumber(branchNames [0].trim());
final int[] branchSubRevisions = revisionNumber.getSubRevisions();
assert branchSubRevisions != null;
final int rev = branchSubRevisions [branchSubRevisions.length-1];
final CvsRevisionNumber branchNumber = revisionNumber.removeTailVersions(1).addTailVersions(0, rev);
branchNumberString = branchNumber.asString();
}
}
if (branchNumberString != null) {
for(SymbolicName name: symbolicNames) {
if (name.getRevision().equals(branchNumberString)) {
return name.getName();
}
}
}
return null;
}
}