VCS: change lists index refactoring (simplifying) + IDEADEV-31378 (NPE: ChangeListManagerImpl.getChange)

This commit is contained in:
Irina Chernushina
2008-10-18 22:53:06 +04:00
parent e2fbf497a4
commit f71d991030
7 changed files with 91 additions and 127 deletions
@@ -228,14 +228,14 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
myChangesViewManager.scheduleRefresh();
}
final ChangeListManagerGate gate = changeListWorker.createSelfGate();
// do actual requests about file statuses
final UpdatingChangeListBuilder builder = new UpdatingChangeListBuilder(changeListWorker, composite, new Getter<Boolean>() {
public Boolean get() {
return myUpdater.isStopped();
}
}, updateUnversionedFiles, myIgnoredIdeaLevel);
final ChangeListManagerGate gate = changeListWorker.createSelfGate();
}, updateUnversionedFiles, myIgnoredIdeaLevel, gate);
for (final VcsDirtyScope scope : scopes) {
final AbstractVcs vcs = scope.getVcs();
@@ -253,15 +253,15 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
synchronized (myDataLock) {
// do same modifications to change lists as was done during update + do delayed notifications
if (wasEverythingDirty) {
changeListWorker.notifyDoneProcessingChanges(myListeners);
}
myModifier.exitUpdate();
myModifier.apply(changeListWorker);
myModifier.clearQueue();
// update member from copy
myWorker.takeData(changeListWorker);
if (wasEverythingDirty) {
changeListWorker.notifyDoneProcessingChanges(myListeners);
}
if (updateUnversionedFiles) {
boolean statusChanged = !myComposite.equals(composite);
myComposite = composite;
@@ -524,9 +524,8 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
@Nullable
public Change getChange(VirtualFile file) {
synchronized (myDataLock) {
final String name = myWorker.getListName(file);
if (name != null) {
final LocalChangeList list = myWorker.getCopyByName(name);
final LocalChangeList list = myWorker.getListCopy(file);
if (list != null) {
for (Change change : list.getChanges()) {
final ContentRevision afterRevision = change.getAfterRevision();
if (afterRevision != null) {
@@ -552,9 +551,8 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
return null;
}
synchronized (myDataLock) {
final String name = myWorker.getListName(virtualFile);
if (name != null) {
final LocalChangeList list = myWorker.getCopyByName(name);
final LocalChangeList list = myWorker.getListCopy(virtualFile);
if (list != null) {
for (Change change : list.getChanges()) {
final ContentRevision afterRevision = change.getAfterRevision();
if (afterRevision != null && afterRevision.getFile().equals(file)) {
@@ -41,7 +41,6 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
LocalChangeList defaultList = null;
for (LocalChangeList changeList : worker.myMap.values()) {
final LocalChangeList copy = changeList.copy();
((LocalChangeListImpl) copy).setLocalListener(myIdx);
final String changeListName = copy.getName();
myMap.put(changeListName, copy);
@@ -102,24 +101,16 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
return list != null;
}
public void startProcessingChanges(@NotNull final String name, final VcsDirtyScope scope) {
final LocalChangeList changeList = myMap.get(name);
if (changeList != null) {
((LocalChangeListImpl) changeList).startProcessingChanges(myProject, scope);
}
}
public LocalChangeList addChangeList(@NotNull final String name, @Nullable final String description) {
return addChangeList(name, description, false);
}
public LocalChangeList addChangeList(@NotNull final String name, @Nullable final String description, final boolean inUpdate) {
LocalChangeList addChangeList(@NotNull final String name, @Nullable final String description, final boolean inUpdate) {
final boolean contains = myMap.containsKey(name);
LOG.assertTrue(! contains, "Attempt to create duplicate changelist " + name);
if (! contains) {
final LocalChangeListImpl newList = (LocalChangeListImpl) LocalChangeList.createEmptyChangeList(myProject, name);
newList.setLocalListener(myIdx);
if (description != null) {
newList.setComment(description);
}
@@ -137,6 +128,7 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
final LocalChangeList changeList = myMap.get(name);
if (changeList != null) {
((LocalChangeListImpl) changeList).addChange(change);
myIdx.changeAdded(change);
}
return changeList != null;
}
@@ -145,9 +137,13 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
assert myDefault != null;
for (LocalChangeList list : myMap.values()) {
if (list.isDefault()) continue;
if (((LocalChangeListImpl) list).processChange(change)) return;
if (((LocalChangeListImpl) list).processChange(change)) {
myIdx.changeAdded(change);
return;
}
}
((LocalChangeListImpl) myDefault).processChange(change);
myIdx.changeAdded(change);
}
public boolean removeChangeList(@NotNull String name) {
@@ -161,7 +157,6 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
final String listName = list.getName();
for (Change change : list.getChanges()) {
myIdx.changeRemoved(listName, change);
((LocalChangeListImpl) myDefault).addChange(change);
}
@@ -195,7 +190,6 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
((LocalChangeListImpl) list).setNameImpl(toName);
myMap.remove(fromName);
myMap.put(toName, list);
myIdx.renamed(toName, list.getChanges());
}
return list != null;
}
@@ -227,8 +221,12 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
}
public void notifyStartProcessingChanges(final VcsDirtyScope scope) {
final Collection<Change> oldChanges = new ArrayList<Change>();
for (LocalChangeList list : myMap.values()) {
((LocalChangeListImpl) list).startProcessingChanges(myProject, scope);
oldChanges.addAll(((LocalChangeListImpl) list).startProcessingChanges(myProject, scope));
}
for (Change change : oldChanges) {
myIdx.changeRemoved(change);
}
}
@@ -256,37 +254,38 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
return myDefault == null ? null : myDefault.getName();
}
public interface LocalListListener {
void changeAdded(final String listName, final Change change);
void changeRemoved(final String listName, final Change change);
}
public List<File> getAffectedPaths() {
return myIdx.getAffectedPaths();
}
@NotNull
public List<VirtualFile> getAffectedFiles() {
return myIdx.getAffectedFiles();
final List<VirtualFile> result = new ArrayList<VirtualFile>();
for (LocalChangeList list : myMap.values()) {
for (Change change : list.getChanges()) {
final ContentRevision before = change.getBeforeRevision();
final ContentRevision after = change.getAfterRevision();
if (before != null) {
result.add(before.getFile().getVirtualFile());
}
if (after != null) {
result.add(after.getFile().getVirtualFile());
}
}
}
return result;
}
// should be tested
public String getListName(@NotNull final VirtualFile file) {
final String listName = myIdx.getListName(file);
if (listName == null || ((listName != null) && myMap.containsKey(listName))) {
return listName;
}
LOG.info("Error: index does not coinside with change lists map. list name: " + listName + " for file: " + file.getPath());
public LocalChangeList getListCopy(@NotNull final VirtualFile file) {
for (LocalChangeList list : myMap.values()) {
for (Change change : list.getChanges()) {
if (change.getAfterRevision() != null &&
Comparing.equal(change.getAfterRevision().getFile().getVirtualFile(), file)) {
return listName;
return list.copy();
}
if (change.getBeforeRevision() != null &&
Comparing.equal(change.getBeforeRevision().getFile().getVirtualFile(), file)) {
return listName;
return list.copy();
}
}
}
@@ -377,4 +376,14 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
return list;
}
}
// used by methods related to user modifications
interface UserAccess {
}
// used only by UpdatingListBuilder to fill lists
interface BuilderAccess {
}
}
@@ -1,108 +1,77 @@
package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ChangeListsIndexes implements ChangeListWorker.LocalListListener {
private final Map<VirtualFile, String> myFileToListName;
private final Map<VirtualFile, FileStatus> myFileToStatus;
public class ChangeListsIndexes {
private final Map<String, FileStatus> myFileToStatus;
ChangeListsIndexes() {
myFileToListName = new HashMap<VirtualFile, String>();
myFileToStatus = new HashMap<VirtualFile, FileStatus>();
myFileToStatus = new HashMap<String, FileStatus>();
}
ChangeListsIndexes(final ChangeListsIndexes idx) {
myFileToListName = new HashMap<VirtualFile, String>(idx.myFileToListName);
myFileToStatus = new HashMap<VirtualFile, FileStatus>(idx.myFileToStatus);
myFileToStatus = new HashMap<String, FileStatus>(idx.myFileToStatus);
}
void add(final VirtualFile file, final String listName, final FileStatus status) {
myFileToListName.put(file, listName);
myFileToStatus.put(file, status);
void add(final FilePath file, final FileStatus status) {
myFileToStatus.put(file.getIOFile().getAbsolutePath(), status);
}
void remove(final VirtualFile file) {
myFileToListName.remove(file);
myFileToStatus.remove(file);
}
void move(final VirtualFile file, final String newListName) {
myFileToListName.put(file, newListName);
}
public String getListName(final VirtualFile file) {
return myFileToListName.get(file);
void remove(final FilePath file) {
myFileToStatus.remove(file.getIOFile().getAbsolutePath());
}
public FileStatus getStatus(final VirtualFile file) {
return myFileToStatus.get(file);
return myFileToStatus.get(new File(file.getPath()).getAbsolutePath());
}
void renamed(final String newName, final Collection<Change> changes) {
for (Change change : changes) {
addChangeToIdx(newName, change);
}
public void changeAdded(final Change change) {
addChangeToIdx(change);
}
public void changeAdded(final String listName, final Change change) {
addChangeToIdx(listName, change);
}
public void changeRemoved(final String listName, final Change change) {
public void changeRemoved(final Change change) {
final ContentRevision afterRevision = change.getAfterRevision();
final ContentRevision beforeRevision = change.getBeforeRevision();
if ((isInIdx(afterRevision, listName)) || isInIdx(beforeRevision, listName)) {
if (afterRevision != null) {
remove(afterRevision.getFile().getVirtualFile());
}
if (beforeRevision != null) {
remove(beforeRevision.getFile().getVirtualFile());
}
if (afterRevision != null) {
remove(afterRevision.getFile());
}
if (beforeRevision != null) {
remove(beforeRevision.getFile());
}
}
private boolean isInIdx(final ContentRevision revision, final String listName) {
if (revision != null) {
final VirtualFile vf = revision.getFile().getVirtualFile();
final String idxListName = myFileToListName.get(vf);
return Comparing.equal(idxListName, listName);
}
return false;
}
private void addChangeToIdx(final String listName, final Change change) {
private void addChangeToIdx(final Change change) {
final ContentRevision afterRevision = change.getAfterRevision();
if (afterRevision != null) {
add(afterRevision.getFile().getVirtualFile(), listName, change.getFileStatus());
add(afterRevision.getFile(), change.getFileStatus());
}
final ContentRevision beforeRevision = change.getBeforeRevision();
if (beforeRevision != null) {
if (afterRevision != null) {
if (! Comparing.equal(beforeRevision.getFile(), afterRevision.getFile())) {
add(beforeRevision.getFile().getVirtualFile(), listName, FileStatus.DELETED);
add(beforeRevision.getFile(), FileStatus.DELETED);
}
} else {
add(beforeRevision.getFile().getVirtualFile(), listName, change.getFileStatus());
add(beforeRevision.getFile(), change.getFileStatus());
}
}
}
public List<File> getAffectedPaths() {
final List<File> result = new ArrayList<File>(myFileToListName.size());
for (VirtualFile virtualFile : myFileToListName.keySet()) {
result.add(new File(virtualFile.getPath()));
final List<File> result = new ArrayList<File>(myFileToStatus.size());
for (String path : myFileToStatus.keySet()) {
result.add(new File(path));
}
return result;
}
@NotNull
public List<VirtualFile> getAffectedFiles() {
return new ArrayList<VirtualFile>(myFileToListName.keySet());
}
}
@@ -33,7 +33,6 @@ public class LocalChangeListImpl extends LocalChangeList {
private Collection<Change> myOutdatedChanges;
private boolean myIsInUpdate = false;
private ChangeHashSet myChangesBeforeUpdate;
private ChangeListWorker.LocalListListener myLocalListener;
public static LocalChangeListImpl createEmptyChangeListImpl(Project project, String name) {
return new LocalChangeListImpl(project, name);
@@ -120,9 +119,6 @@ public class LocalChangeListImpl extends LocalChangeList {
synchronized void addChange(Change change) {
if (!myIsInUpdate) myReadChangesCache = null;
myChanges.add(change);
if (myLocalListener != null) {
myLocalListener.changeAdded(myName, change);
}
}
synchronized Change removeChange(Change change) {
@@ -132,17 +128,15 @@ public class LocalChangeListImpl extends LocalChangeList {
if (! myIsInUpdate) {
myReadChangesCache = null;
}
if (myLocalListener != null) {
myLocalListener.changeRemoved(myName, localChange);
}
return localChange;
}
}
return null;
}
synchronized void startProcessingChanges(final Project project, @Nullable final VcsDirtyScope scope) {
synchronized Collection<Change> startProcessingChanges(final Project project, @Nullable final VcsDirtyScope scope) {
createReadChangesCache();
final Collection<Change> result = new ArrayList<Change>();
myChangesBeforeUpdate = new ChangeHashSet(myChanges);
myOutdatedChanges = new ArrayList<Change>();
final ExcludedFileIndex fileIndex = ExcludedFileIndex.getInstance(project);
@@ -151,9 +145,7 @@ public class LocalChangeListImpl extends LocalChangeList {
final ContentRevision after = oldBoy.getAfterRevision();
if (scope == null || before != null && scope.belongsTo(before.getFile()) || after != null && scope.belongsTo(after.getFile())
|| isIgnoredChange(oldBoy, fileIndex)) {
if (myLocalListener != null) {
myLocalListener.changeRemoved(myName, oldBoy);
}
result.add(oldBoy);
myIsInUpdate = true;
removeChange(oldBoy);
myOutdatedChanges.add(oldBoy);
@@ -162,6 +154,7 @@ public class LocalChangeListImpl extends LocalChangeList {
if (isDefault()) {
myIsInUpdate = true;
}
return result;
}
private static boolean isIgnoredChange(final Change change, final ExcludedFileIndex fileIndex) {
@@ -294,8 +287,4 @@ public class LocalChangeListImpl extends LocalChangeList {
return null;
}
}
void setLocalListener(final ChangeListWorker.LocalListListener localListener) {
myLocalListener = localListener;
}
}
@@ -25,7 +25,7 @@ public class Modifier implements ChangeListsWriteOperations {
}
public LocalChangeList addChangeList(@NotNull final String name, final String comment) {
final AddList command = new AddList(name, comment, myInsideUpdate);
final AddList command = new AddList(name, comment);
impl(command);
return command.getNewListCopy();
}
@@ -19,17 +19,19 @@ class UpdatingChangeListBuilder implements ChangelistBuilder {
private final boolean myUpdateUnversioned;
private final IgnoredFilesComponent myIgnoredFilesComponent;
private final ExcludedFileIndex myIndex;
private final ChangeListManagerGate myGate;
UpdatingChangeListBuilder(final ChangeListWorker changeListWorker,
final FileHolderComposite composite,
final Getter<Boolean> disposedGetter,
final boolean updateUnversioned,
final IgnoredFilesComponent ignoredFilesComponent) {
final IgnoredFilesComponent ignoredFilesComponent, final ChangeListManagerGate gate) {
myChangeListWorker = changeListWorker;
myComposite = composite;
myDisposedGetter = disposedGetter;
myUpdateUnversioned = updateUnversioned;
myIgnoredFilesComponent = ignoredFilesComponent;
myGate = gate;
myIndex = ExcludedFileIndex.getInstance(changeListWorker.getProject());
}
@@ -72,8 +74,7 @@ class UpdatingChangeListBuilder implements ChangelistBuilder {
if (changeListName != null) {
list = myChangeListWorker.getCopyByName(changeListName);
if (list == null) {
list = myChangeListWorker.addChangeList(changeListName, null, true);
myChangeListWorker.startProcessingChanges(list.getName(), myScope);
list = myGate.addChangeList(changeListName, null);
}
}
processChangeInList(change, list);
@@ -8,17 +8,15 @@ import com.intellij.util.EventDispatcher;
public class AddList implements ChangeListCommand {
private final String myName;
private final String myComment;
private final boolean myInsideUpdate;
private LocalChangeList myNewListCopy;
public AddList(final String name, final String comment, final boolean insideUpdate) {
public AddList(final String name, final String comment) {
myName = name;
myComment = comment;
myInsideUpdate = insideUpdate;
}
public void apply(final ChangeListWorker worker) {
myNewListCopy = worker.addChangeList(myName, myComment, myInsideUpdate);
myNewListCopy = worker.addChangeList(myName, myComment);
}
public void doNotify(final EventDispatcher<ChangeListListener> dispatcher) {