[vcs] Refactor FilePathImpl to make it less mutable and make the data flow more predictable

1. Don't store myVirtualFile reference which could be modified at any time by refresh() and hardRefresh().
   Instead store just path + isDirectory.
   Make getVirtualFile() query LFS.findFileByPath: it should be fast enough.
   (If it doesn't in some case,  the problem is most probably in the calling code which shouldn't try to convert FilePath to VirtualFile so many times).
   Make hardRefresh call LFS.refreshAndFindFileByPath: this will affect any further getVirtualFile invocation.
   Make refresh do nothing: its work is done in getVirtualFile now.
   Deprecate both methods.

2. Get rid of the virtualParent: it tried to solve some problem with deleted files,
   but if there were no parent as well, the problem would still exist.
   It is also no more compliant with current getVirtualFile() strategy.
   Deprecate VcsContextFactory creation by parent + name, since there seems no point in it anymore.

3. Don't store the File, store just the path, make it canonical on FilePathImpl creation.

4. Make equals & hashCode use the system hashing strategy.

5. Remove all constructors but one.
   But keep various utility methods (some of which are handy),
   which take the path from the provided object (VirtualFile, File, parent VirtualFile, etc).
This commit is contained in:
Kirill Likhodedov
2015-05-28 15:16:50 +03:00
parent bfe900af95
commit 7b1f4f056a
33 changed files with 178 additions and 311 deletions
@@ -73,7 +73,6 @@ public class FileAwareDocumentContent extends DocumentContentImpl {
@NotNull
private Builder init(@NotNull FilePath path) {
path.refresh();
myHighlightFile = path.getVirtualFile();
myFileType = path.getFileType();
myCharset = path.getCharset(myProject);
@@ -100,10 +100,17 @@ public interface VcsContextFactory {
* @param name the name of the file.
* @return the FilePath instance.
*/
FilePath createFilePathOn(VirtualFile parent, String name);
@NotNull
FilePath createFilePathOn(@NotNull VirtualFile parent, @NotNull String name);
@NotNull
FilePath createFilePath(@NotNull VirtualFile parent, @NotNull String fileName, boolean isDirectory);
LocalChangeList createLocalChangeList(Project project, @NotNull final String name);
@NotNull
FilePath createFilePath(@NotNull String path, boolean isDirectory);
class SERVICE {
private SERVICE() {
}
@@ -161,15 +161,13 @@ public class ChangesUtil {
for (Change change : changes) {
final ContentRevision afterRevision = change.getAfterRevision();
if (afterRevision != null) {
VirtualFile file = afterRevision.getFile().getVirtualFile();
FilePath filePath = afterRevision.getFile();
VirtualFile file = filePath.getVirtualFile();
if (file == null || !file.isValid()) {
file = LocalFileSystem.getInstance().refreshAndFindFileByPath(filePath.getPath());
}
if (file != null && file.isValid()) {
files.add(file);
} else {
afterRevision.getFile().hardRefresh();
file = afterRevision.getFile().getVirtualFile();
if (file != null && file.isValid()) {
files.add(file);
}
}
}
}
@@ -39,16 +39,13 @@ public class CurrentContentRevision implements ContentRevision {
@Nullable
public String getContent() {
VirtualFile vFile = getVirtualFile();
final VirtualFile vFile = getVirtualFile();
if (vFile == null) {
myFile.refresh();
vFile = getVirtualFile();
if (vFile == null) return null;
return null;
}
final VirtualFile finalVFile = vFile;
final Document doc = ApplicationManager.getApplication().runReadAction(new Computable<Document>() {
public Document compute() {
return FileDocumentManager.getInstance().getDocument(finalVFile);
return FileDocumentManager.getInstance().getDocument(vFile);
}});
if (doc == null) return null;
return doc.getText();
@@ -323,8 +323,8 @@ public class VcsUtil {
return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file);
}
public static FilePath getFilePath(String path, boolean isDirectory) {
return getFilePath(new File(path), isDirectory);
public static FilePath getFilePath(@NotNull String path, boolean isDirectory) {
return VcsContextFactory.SERVICE.getInstance().createFilePath(path, isDirectory);
}
public static FilePath getFilePathOnNonLocal(String path, boolean isDirectory) {
@@ -339,6 +339,16 @@ public class VcsUtil {
return VcsContextFactory.SERVICE.getInstance().createFilePathOnDeleted(new File(path), isDirectory);
}
@NotNull
public static FilePath getFilePath(@NotNull VirtualFile parent, @NotNull String name) {
return VcsContextFactory.SERVICE.getInstance().createFilePathOn(parent, name);
}
@NotNull
public static FilePath getFilePath(@NotNull VirtualFile parent, @NotNull String fileName, boolean isDirectory) {
return VcsContextFactory.SERVICE.getInstance().createFilePath(parent, fileName, isDirectory);
}
/**
* Shows message in the status bar.
*
@@ -73,7 +73,7 @@ public interface FilePath {
* @return the character set of the file
*/
@NotNull
Charset getCharset(Project project);
Charset getCharset(@Nullable Project project);
/**
* @return the type of the file
@@ -81,8 +81,17 @@ public interface FilePath {
@NotNull
FileType getFileType();
/**
* @deprecated to remove in IDEA 16.
* Use {@code com.intellij.openapi.vfs.VfsUtil#findFileByPath} or {@code com.intellij.openapi.vfs.LocalFileSystem#findFileByPath} instead.
*/
@Deprecated
void refresh();
/**
* @deprecated to remove in IDEA 16. Use {@code com.intellij.openapi.vfs.LocalFileSystem#refreshAndFindFileByPath} instead.
*/
@Deprecated
void hardRefresh();
@NotNull
@@ -208,7 +208,7 @@ public class PathsVerifier<BinaryType extends FilePatch> {
return false;
}
addPatch(myPatch, beforeFile);
final FilePathImpl filePath = new FilePathImpl(beforeFile.getParent(), beforeFile.getName(), beforeFile.isDirectory());
FilePath filePath = VcsUtil.getFilePath(beforeFile.getParent(), beforeFile.getName(), beforeFile.isDirectory());
if (myPatch.isDeletedFile() || myPatch.getAfterName() == null) {
myDeletedPaths.add(filePath);
}
@@ -477,7 +477,7 @@ public class PathsVerifier<BinaryType extends FilePatch> {
public void doMoveIfNeeded(final VirtualFile file) throws IOException {
final MovedFileData movedFile = myMovedFiles.get(file);
if (movedFile != null) {
myBeforePaths.add(new FilePathImpl(file.getParent(), file.getName(), file.isDirectory()));
myBeforePaths.add(VcsUtil.getFilePath(file));
ApplicationManager.getApplication().runWriteAction(new ThrowableComputable<VirtualFile, IOException>() {
@Override
public VirtualFile compute() throws IOException {
@@ -22,6 +22,7 @@ import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.SortByVcsRoots;
import com.intellij.openapi.vcs.checkin.CheckinEnvironment;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.FilePathByPathComparator;
@@ -154,9 +155,6 @@ public class TriggerAdditionOrDeletion {
}
private void processAddition(SortByVcsRoots<FilePath> sortByVcsRoots) {
for (FilePath filePath : myExisting) {
filePath.hardRefresh();
}
final MultiMap<VcsRoot, FilePath> map = sortByVcsRoots.sort(myExisting);
myPreparedAddition = new MultiMap<VcsRoot, FilePath>();
for (VcsRoot vcsRoot : map.keySet()) {
@@ -243,11 +241,10 @@ public class TriggerAdditionOrDeletion {
while (current != null) {
VirtualFile vf = current.getVirtualFile();
if (vf == null) {
current.hardRefresh();
vf = current.getVirtualFile();
if (vf == null) {
return;
}
vf = LocalFileSystem.getInstance().refreshAndFindFileByPath(current.getPath());
}
if (vf == null) {
return;
}
if (! VfsUtil.isAncestor(myRoot, vf, true)) return;
@@ -20,14 +20,13 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.encoding.EncodingProjectManager;
import com.intellij.util.PathUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -36,202 +35,110 @@ import java.io.File;
import java.nio.charset.Charset;
public class FilePathImpl implements FilePath {
private VirtualFile myVirtualFile;
private VirtualFile myVirtualParent;
private final String myName;
@NotNull private final File myFile;
private boolean myIsDirectory;
@NotNull private final String myPath;
private final boolean myIsDirectory;
private FilePathImpl(VirtualFile virtualParent,
@NotNull String name,
final boolean isDirectory,
VirtualFile child,
final boolean forDeleted) {
this(fileFromVirtual(virtualParent, child, name), isDirectory);
myVirtualParent = virtualParent;
if (!forDeleted) {
if (child == null) {
refresh();
}
else {
myVirtualFile = child;
}
}
}
private static File fileFromVirtual(VirtualFile virtualParent, final VirtualFile child, String name) {
assert virtualParent != null || child != null;
if (virtualParent != null) {
return new File(virtualParent.getPath(), name);
}
return new File(child.getPath());
}
@Heavy
public FilePathImpl(@NotNull VirtualFile virtualParent, String name, final boolean isDirectory) {
this(virtualParent, name, isDirectory, null, false);
}
@Heavy
private FilePathImpl(@NotNull VirtualFile virtualParent, String name, final boolean isDirectory, final boolean forDeleted) {
this(virtualParent, name, isDirectory, null, forDeleted);
}
public FilePathImpl(@NotNull File file, final boolean isDirectory) {
myFile = file;
myName = file.getName();
public FilePathImpl(@NotNull String path, boolean isDirectory) {
myPath = FileUtil.toCanonicalPath(path);
myIsDirectory = isDirectory;
}
public FilePathImpl(@NotNull VirtualFile virtualFile) {
this(virtualFile.getParent(), virtualFile.getName(), virtualFile.isDirectory(), virtualFile, false);
}
public FilePath createChild(final String subPath, final boolean isDirectory) {
@NotNull
public FilePath createChild(@NotNull String subPath, boolean isDirectory) {
if (StringUtil.isEmptyOrSpaces(subPath)) return this;
if (getVirtualFile() != null && subPath.indexOf('/') == -1 && subPath.indexOf('\\') == -1) {
return new FilePathImpl(getVirtualFile(), subPath, isDirectory, true);
}
else {
return new FilePathImpl(new File(getIOFile(), subPath), isDirectory);
}
}
public int hashCode() {
return StringUtil.stringHashCodeInsensitive(myFile.getPath());
return new FilePathImpl(myPath + File.separator + subPath, isDirectory);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof FilePath)) {
return false;
}
else {
if (! isSpecialName(myName) && ! isSpecialName(((FilePath)o).getName()) &&
! Comparing.equal(myName, ((FilePath)o).getName())) return false;
return myFile.equals(((FilePath)o).getIOFile());
}
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FilePathImpl path = (FilePathImpl)o;
if (myIsDirectory != path.myIsDirectory) return false;
if (!FileUtil.PATH_HASHING_STRATEGY.equals(myPath, path.myPath)) return false;
return true;
}
private static boolean isSpecialName(final String name) {
return ".".equals(name) || "..".equals(name);
@Override
public int hashCode() {
int result = FileUtil.PATH_HASHING_STRATEGY.computeHashCode(myPath);
result = 31 * result + (myIsDirectory ? 1 : 0);
return result;
}
@Override
public void refresh() {
if (myVirtualParent == null) {
myVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(myFile);
}
else {
myVirtualFile = myVirtualParent.findChild(myName);
}
}
@Override
public void hardRefresh() {
if (myVirtualFile == null || ! myVirtualFile.isValid()) {
myVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(myFile);
}
LocalFileSystem.getInstance().refreshAndFindFileByPath(myPath);
}
@NotNull
@Override
public String getPath() {
final VirtualFile virtualFile = myVirtualFile;
if (virtualFile != null && virtualFile.isValid()) {
return virtualFile.getPath();
}
else {
return myFile.getPath();
}
return myPath;
}
@Override
public boolean isDirectory() {
if (myVirtualFile == null) {
return myIsDirectory;
}
else {
return myVirtualFile.isDirectory();
}
return myIsDirectory;
}
@Override
public boolean isUnder(FilePath parent, boolean strict) {
if (myVirtualFile != null) {
final VirtualFile parentFile = parent.getVirtualFile();
if (parentFile != null) {
return VfsUtilCore.isAncestor(parentFile, myVirtualFile, strict);
}
}
return FileUtil.isAncestor(parent.getIOFile(), getIOFile(), strict);
public boolean isUnder(@NotNull FilePath parent, boolean strict) {
return FileUtil.isAncestor(parent.getPath(), getPath(), strict);
}
@Override
@Nullable
public FilePath getParentPath() {
if (myVirtualParent != null && myVirtualParent.isValid() && myVirtualParent.getParent() != null) {
return new FilePathImpl(myVirtualParent);
}
// can't use File.getParentPath() because the path may not correspond to an actual file on disk,
// and adding a drive letter would not be appropriate (IDEADEV-7405)
// path containing exactly one separator is assumed to be root path
final String path = myFile.getPath();
int pos = path.lastIndexOf(File.separatorChar);
if (pos < 0 || pos == path.indexOf(File.separatorChar)) {
return null;
}
return new FilePathImpl(new File(path.substring(0, pos)), true);
String parent = PathUtil.getParentPath(myPath);
return parent.isEmpty() ? null : new FilePathImpl(parent, true);
}
@Override
@Nullable
public VirtualFile getVirtualFile() {
if (myVirtualFile != null && !myVirtualFile.isValid()) {
myVirtualFile = null;
}
return myVirtualFile;
return LocalFileSystem.getInstance().findFileByPath(myPath);
}
@Override
@Nullable
public VirtualFile getVirtualFileParent() {
if (myVirtualParent != null && !myVirtualParent.isValid()) {
myVirtualParent = null;
}
return myVirtualParent;
FilePath parent = getParentPath();
return parent != null ? parent.getVirtualFile() : null;
}
@Override
@NotNull
public File getIOFile() {
return myFile;
return new File(myPath);
}
@NotNull
@Override
public String getName() {
return myName;
return PathUtil.getFileName(myPath);
}
@Override
public String getPresentableUrl() {
if (myVirtualFile == null || !myVirtualFile.isValid()) {
return myFile.getAbsolutePath();
}
else {
return myVirtualFile.getPresentableUrl();
}
return FileUtil.toSystemDependentName(myPath);
}
@Override
@Nullable
public Document getDocument() {
if (myVirtualFile == null || myVirtualFile.getFileType().isBinary()) {
VirtualFile file = getVirtualFile();
if (file == null || file.getFileType().isBinary()) {
return null;
}
return FileDocumentManager.getInstance().getDocument(myVirtualFile);
return FileDocumentManager.getInstance().getDocument(file);
}
@Override
@@ -242,20 +149,15 @@ public class FilePathImpl implements FilePath {
@Override
@NotNull
public Charset getCharset(Project project) {
// try to find existing virtual file
VirtualFile existing = myVirtualFile != null && myVirtualFile.isValid() ? myVirtualFile : null;
if (existing == null) {
LocalFileSystem lfs = LocalFileSystem.getInstance();
for (File f = myFile; f != null; f = f.getParentFile()) {
existing = lfs.findFileByIoFile(f);
if (existing != null && existing.isValid()) {
break;
}
}
public Charset getCharset(@Nullable Project project) {
VirtualFile file = getVirtualFile();
String path = myPath;
while ((file == null || !file.isValid()) && !path.isEmpty()) {
path = PathUtil.getParentPath(path);
file = LocalFileSystem.getInstance().findFileByPath(path);
}
if (existing != null) {
return existing.getCharset();
if (file != null) {
return file.getCharset();
}
EncodingManager e = project == null ? EncodingManager.getInstance() : EncodingProjectManager.getInstance(project);
return e.getDefaultCharset();
@@ -264,67 +166,15 @@ public class FilePathImpl implements FilePath {
@Override
@NotNull
public FileType getFileType() {
return myVirtualFile != null ? myVirtualFile.getFileType() : FileTypeManager.getInstance().getFileTypeByFileName(myFile.getName());
}
public static FilePathImpl create(File selectedFile) {
return create(selectedFile, false);
}
public static FilePathImpl create(File selectedFile, boolean isDirectory) {
if (selectedFile == null) {
return null;
}
LocalFileSystem lfs = LocalFileSystem.getInstance();
VirtualFile virtualFile = lfs.findFileByIoFile(selectedFile);
if (virtualFile != null) {
return new FilePathImpl(virtualFile);
}
return createForDeletedFile(selectedFile, isDirectory);
}
public static FilePathImpl createForDeletedFile(final File selectedFile, final boolean isDirectory) {
LocalFileSystem lfs = LocalFileSystem.getInstance();
File parentFile = selectedFile.getParentFile();
if (parentFile == null) {
return new FilePathImpl(selectedFile, isDirectory);
}
VirtualFile virtualFileParent = lfs.findFileByIoFile(parentFile);
if (virtualFileParent != null) {
return new FilePathImpl(virtualFileParent, selectedFile.getName(), isDirectory, true);
}
else {
return new FilePathImpl(selectedFile, isDirectory);
}
}
public static FilePath createOn(String s) {
File ioFile = new File(s);
final LocalFileSystem localFileSystem = LocalFileSystem.getInstance();
VirtualFile virtualFile = localFileSystem.findFileByIoFile(ioFile);
if (virtualFile != null) {
return new FilePathImpl(virtualFile);
}
else {
VirtualFile virtualFileParent = localFileSystem.findFileByIoFile(ioFile.getParentFile());
if (virtualFileParent != null) {
return new FilePathImpl(virtualFileParent, ioFile.getName(), false);
}
else {
return null;
}
}
VirtualFile file = getVirtualFile();
FileTypeManager manager = FileTypeManager.getInstance();
return file != null ? manager.getFileTypeByFile(file) : manager.getFileTypeByFileName(getName());
}
@Override
@NonNls
public String toString() {
return "FilePath[" + myFile.getName() + "] (" + myFile.getParent() + ")";
return myPath + (myIsDirectory ? "/" : "");
}
@Override
@@ -46,7 +46,6 @@ import com.intellij.util.containers.CacheOneStepIterator;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
@@ -147,10 +146,9 @@ class ShowDiffFromAnnotation extends AnAction implements LineNumberListener {
private static int findSelfInList(List<Change> changes, final FilePath filePath) {
int idx = -1;
final File ioFile = filePath.getIOFile();
for (int i = 0; i < changes.size(); i++) {
final Change change = changes.get(i);
if ((change.getAfterRevision() != null) && (change.getAfterRevision().getFile().getIOFile().equals(ioFile))) {
if ((change.getAfterRevision() != null) && (change.getAfterRevision().getFile().equals(filePath))) {
idx = i;
break;
}
@@ -158,7 +156,7 @@ class ShowDiffFromAnnotation extends AnAction implements LineNumberListener {
if (idx >= 0) return idx;
idx = 0;
// try to use name only
final String name = ioFile.getName();
final String name = filePath.getName();
for (int i = 0; i < changes.size(); i++) {
final Change change = changes.get(i);
if ((change.getAfterRevision() != null) && (change.getAfterRevision().getFile().getName().equals(name))) {
@@ -85,7 +85,7 @@ public class TabbedShowHistoryAction extends AbstractVcsAction {
if (parentIoFile == null) continue;
final VirtualFile parent = LocalFileSystem.getInstance().findFileByIoFile(parentIoFile);
if (parent != null) {
final FilePathImpl child = new FilePathImpl(parent, file.getName(), false);
FilePath child = VcsUtil.getFilePath(parent, file.getName());
if (result != null) return null;
result = child;
}
@@ -35,6 +35,7 @@ import com.intellij.openapi.vcs.changes.actions.ShowDiffAction;
import com.intellij.openapi.vcs.ex.Range;
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager;
import com.intellij.openapi.vcs.impl.LineStatusTrackerManagerI;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.BeforeAfter;
import com.intellij.util.containers.SLRUMap;
@@ -69,7 +70,7 @@ public class FragmentedDiffRequestFromChange {
}
public PreparedFragmentedContent getRanges(Change change) throws VcsException {
final FilePath filePath = ChangesUtil.getFilePath(change);
FilePath filePath = ChangesUtil.getFilePath(change);
final RangesCalculator calculator = new RangesCalculator();
calculator.execute(change, filePath, myRangesCache, LineStatusTrackerManager.getInstance(myProject));
@@ -83,8 +84,7 @@ public class FragmentedDiffRequestFromChange {
FragmentedContent fragmentedContent = new FragmentedContent(calculator.getOldDocument(), calculator.getDocument(), ranges, change);
VirtualFile file = filePath.getVirtualFile();
if (file == null) {
filePath.hardRefresh();
file = filePath.getVirtualFile();
file = LocalFileSystem.getInstance().refreshAndFindFileByPath(filePath.getPath());
}
return new PreparedFragmentedContent(myProject, fragmentedContent,
filePath.getName(), filePath.getFileType(),
@@ -34,7 +34,6 @@ import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -133,9 +132,9 @@ public class VcsDirtyScopeVfsListener implements ApplicationComponent, BulkFileL
if (event instanceof VFileDeleteEvent) {
if (!file.isInLocalFileSystem()) { continue; }
dirtyFilesAndDirs.add(file, true);
dirtyFilesAndDirs.add(file);
} else if (event instanceof VFileMoveEvent || event instanceof VFilePropertyChangeEvent) {
dirtyFilesAndDirs.add(file, true);
dirtyFilesAndDirs.add(file);
}
}
// and notify VCSDirtyScopeManager
@@ -157,17 +156,17 @@ public class VcsDirtyScopeVfsListener implements ApplicationComponent, BulkFileL
if (event instanceof VFileContentChangeEvent || event instanceof VFileCopyEvent || event instanceof VFileCreateEvent ||
event instanceof VFileMoveEvent) {
dirtyFilesAndDirs.add(file, false);
dirtyFilesAndDirs.add(file);
} else if (event instanceof VFilePropertyChangeEvent) {
final VFilePropertyChangeEvent pce = (VFilePropertyChangeEvent) event;
if (pce.getPropertyName().equals(VirtualFile.PROP_NAME)) {
// if a file was renamed, then the file is dirty and its parent directory is dirty too;
// if a directory was renamed, all its children are recursively dirty, the parent dir is also dirty but not recursively.
dirtyFilesAndDirs.add(file, false); // the file is dirty recursively
dirtyFilesAndDirs.addToFiles(file.getParent(), false); // directory is dirty alone. if parent is null - is checked in the method
dirtyFilesAndDirs.add(file); // the file is dirty recursively
dirtyFilesAndDirs.addToFiles(file.getParent()); // directory is dirty alone. if parent is null - is checked in the method
} else {
dirtyFilesAndDirs.addToFiles(file, false);
dirtyFilesAndDirs.addToFiles(file);
}
}
}
@@ -204,13 +203,10 @@ public class VcsDirtyScopeVfsListener implements ApplicationComponent, BulkFileL
* @param file file which path is to be added.
* @param addToFiles If true, then add to dirty files even if it is a directory. Otherwise add to the proper set.
*/
private void add(VirtualFile file, boolean addToFiles, final boolean forDelete) {
private void add(VirtualFile file, boolean addToFiles) {
if (file == null) { return; }
final boolean isDirectory = file.isDirectory();
// need to create FilePath explicitly without referring to VirtualFile because the path of VirtualFile may change
FilePath path = forDelete ? VcsUtil.getFilePath(new File(file.getPath()), isDirectory) :
VcsUtil.getFilePath(file);
FilePath path = VcsUtil.getFilePath(file.getPath(), isDirectory);
final Collection<VcsDirtyScopeManager> managers = getManagers(file);
for (VcsDirtyScopeManager manager : managers) {
Couple<HashSet<FilePath>> filesAndDirs = map.get(manager);
@@ -230,16 +226,16 @@ public class VcsDirtyScopeVfsListener implements ApplicationComponent, BulkFileL
/**
* Adds files to the collection of files and directories - to the collection of directories (which are handled recursively).
*/
private void add(VirtualFile file, final boolean forDelete) {
add(file, false, forDelete);
private void add(VirtualFile file) {
add(file, false);
}
/**
* Adds to the collection of files. A file (even if it is a directory) is marked dirty alone (not recursively).
* Use this method, when you want directory not to be marked dirty recursively.
*/
private void addToFiles(VirtualFile file, final boolean forDelete) {
add(file, true, forDelete);
private void addToFiles(VirtualFile file) {
add(file, true);
}
private void markDirty(final Map<VcsDirtyScopeManager, Couple<HashSet<FilePath>>> outerMap) {
@@ -15,19 +15,14 @@
*/
package com.intellij.openapi.vcs.changes.actions;
import com.intellij.openapi.diff.DiffRequest;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangesUtil;
import com.intellij.openapi.vcs.changes.patch.ApplyPatchForBaseRevisionTexts;
import com.intellij.openapi.vcs.changes.patch.MergedDiffRequestPresentable;
import com.intellij.openapi.vcs.merge.MergeProvider;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.Convertor;
@@ -61,8 +56,7 @@ public class ChangeForDiffConvertor implements Convertor<Change, DiffRequestPres
final FilePath path = ChangesUtil.getFilePath(ch);
VirtualFile vf = path.getVirtualFile();
if (vf == null) {
path.hardRefresh();
vf = path.getVirtualFile();
vf = LocalFileSystem.getInstance().refreshAndFindFileByPath(path.getPath());
}
if (vf == null) return null;
@@ -45,6 +45,7 @@ import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.merge.MergeData;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
@@ -239,8 +240,7 @@ public class ChangeDiffRequestProducer implements DiffRequestProducer {
FilePath path = ChangesUtil.getFilePath(change);
VirtualFile file = path.getVirtualFile();
if (file == null) {
path.hardRefresh();
file = path.getVirtualFile();
file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path.getPath());
}
if (file == null) throw new DiffRequestProducerException("Can't show merge conflict - file not found");
@@ -967,7 +967,6 @@ public class ChangesCacheFile {
return new ProcessingResult(true, AFTER_DOES_NOT_MATTER_ALIEN_PATH);
}
localPath.refresh();
final VirtualFile file = localPath.getVirtualFile();
if (isDeletedFile(myDeletedFiles, afterRevision, myReplacedFiles)) {
debug("Found deleted file");
@@ -1016,7 +1015,6 @@ public class ChangesCacheFile {
debug("Skipping deleted file outside of incoming files: " + beforeRevision.getFile());
return new ProcessingResult(true, BEFORE_DOES_NOT_MATTER_OUTSIDE);
}
beforeRevision.getFile().refresh();
if (beforeRevision.getFile().getVirtualFile() == null || myCreatedFiles.contains(beforeRevision.getFile())) {
// if not deleted from vcs, mark as incoming, otherwise file already deleted
final boolean locallyDeleted = myClManager.isContainedInLocallyDeleted(beforeRevision.getFile());
@@ -24,10 +24,8 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.actions.VcsContextFactory;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.CurrentContentRevision;
@@ -164,8 +162,7 @@ public class FilePatchInProgress implements Strippable {
if (myNewContentRevision == null) {
myConflicts = null;
if (FilePatchStatus.ADDED.equals(myStatus)) {
final FilePath newFilePath = VcsContextFactory.SERVICE.getInstance().createFilePathOnNonLocal(myIoCurrentBase.getAbsolutePath(),
false);
final FilePath newFilePath = VcsUtil.getFilePathOnNonLocal(myIoCurrentBase.getAbsolutePath(), false);
final String content = myPatch.getNewFileText();
myNewContentRevision = new SimpleContentRevision(content, newFilePath, myPatch.getAfterVersionId());
} else {
@@ -78,7 +78,6 @@ public class ShelvedBinaryFile implements JDOMExternalizable {
final File baseDir = new File(project.getBaseDir().getPath());
if (BEFORE_PATH != null) {
final FilePath file = VcsUtil.getFilePath(new File(baseDir, BEFORE_PATH), false);
file.refresh();
before = new CurrentBinaryContentRevision(file) {
@NotNull
@Override
@@ -89,7 +88,6 @@ public class ShelvedBinaryFile implements JDOMExternalizable {
}
if (AFTER_PATH != null) {
final FilePath file = VcsUtil.getFilePath(new File(baseDir, AFTER_PATH), false);
file.refresh();
after = new ShelvedBinaryContentRevision(file, SHELVED_PATH);
}
return new Change(before, after);
@@ -943,7 +943,6 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton {
public void run() {
vp.refresh(false, true, new Runnable() {
public void run() {
myFilePath.refresh();
action.finish();
}
});
@@ -31,6 +31,7 @@ import com.intellij.openapi.vcs.impl.BackgroundableActionEnabledHandler;
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vcs.impl.VcsBackgroundableActions;
import com.intellij.openapi.vcs.impl.VcsBackgroundableComputable;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.vcsUtil.VcsUtil;
@@ -310,8 +311,10 @@ public class VcsHistoryProviderBackgroundableProxy {
if (VcsType.distributed.equals(myType)) {
final FilePath path = correctedFilePath != null ? correctedFilePath : filePath;
path.hardRefresh();
final VirtualFile virtualFile = path.getVirtualFile();
VirtualFile virtualFile = path.getVirtualFile();
if (virtualFile == null) {
virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(path.getPath());
}
if (virtualFile != null) {
final VcsRevisionNumber currentRevision = myDiffProvider.getCurrentRevision(virtualFile);
final List<VcsFileRevision> revisionList = cached.getRevisionList();
@@ -37,6 +37,7 @@ import com.intellij.openapi.vcs.ex.ProjectLevelVcsManagerEx;
import com.intellij.openapi.vcs.impl.projectlevelman.NewMappings;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -141,7 +142,7 @@ public class ModuleDefaultVcsRootPolicy extends DefaultVcsRootPolicy {
final Module[] modules = myModuleManager.getModules();
final StorageScheme storageScheme = ((ProjectEx) myProject).getStateStore().getStorageScheme();
if (StorageScheme.DIRECTORY_BASED.equals(storageScheme)) {
final FilePathImpl fp = new FilePathImpl(myBaseDir, Project.DIRECTORY_STORE_FOLDER, true);
FilePath fp = VcsUtil.getFilePath(myBaseDir, Project.DIRECTORY_STORE_FOLDER, true);
final AbstractVcs vcs = vcsGuess.getVcsForDirty(fp);
if (vcs != null) {
builder.addDirtyDirRecursively(new FilePathUnderVcs(fp, vcs));
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.vcs.update;
import com.intellij.diff.DiffDialogHints;
import com.intellij.history.ByteContent;
import com.intellij.history.Label;
import com.intellij.openapi.actionSystem.*;
@@ -23,9 +24,11 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.diff.DiffDialogHints;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffAction;
@@ -179,11 +182,7 @@ public class ShowUpdatedDiffAction extends AnAction implements DumbAware {
@NotNull
public FilePath getFile() {
final VirtualFile vf = myPointer.getFile();
if (vf != null) {
return VcsUtil.getFilePath(vf);
}
return VcsUtil.getFilePath(new File(myPointer.getPresentableUrl()), false);
return VcsUtil.getFilePath(myPointer.getPresentableUrl(), false);
}
@NotNull
@@ -45,11 +45,12 @@ public class VcsContextFactoryImpl implements VcsContextFactory {
}
public FilePath createFilePathOn(@NotNull final VirtualFile virtualFile) {
return new FilePathImpl(virtualFile);
return new FilePathImpl(virtualFile.getPath(), virtualFile.isDirectory());
}
public FilePath createFilePathOn(final File file) {
return FilePathImpl.create(file);
VirtualFile vf = LocalFileSystem.getInstance().findFileByIoFile(file);
return vf != null ? createFilePathOn(vf) : new FilePathImpl(file.getPath(), file.isDirectory());
}
public FilePath createFilePathOn(final File file, final NotNullFunction<File, Boolean> detector) {
@@ -61,7 +62,7 @@ public class VcsContextFactoryImpl implements VcsContextFactory {
}
public FilePath createFilePathOn(final File file, final boolean isDirectory) {
return FilePathImpl.create(file, isDirectory);
return new FilePathImpl(file.getPath(), isDirectory);
}
@NotNull
@@ -70,14 +71,27 @@ public class VcsContextFactoryImpl implements VcsContextFactory {
}
public FilePath createFilePathOnDeleted(final File file, final boolean isDirectory) {
return FilePathImpl.createForDeletedFile(file, isDirectory);
return createFilePathOn(file, isDirectory);
}
public FilePath createFilePathOn(final VirtualFile parent, final String name) {
return new FilePathImpl(parent, name, false);
@NotNull
public FilePath createFilePathOn(@NotNull final VirtualFile parent, @NotNull final String name) {
return createFilePath(parent, name, false);
}
@NotNull
@Override
public FilePath createFilePath(@NotNull VirtualFile parent, @NotNull String fileName, boolean isDirectory) {
return new FilePathImpl(parent.getPath() + "/" + fileName, isDirectory);
}
public LocalChangeList createLocalChangeList(Project project, @NotNull final String name) {
return LocalChangeListImpl.createEmptyChangeListImpl(project, name);
}
@NotNull
@Override
public FilePath createFilePath(@NotNull String path, boolean isDirectory) {
return new FilePathImpl(path, isDirectory);
}
}
@@ -17,7 +17,6 @@ package com.intellij.cvsSupport2;
import com.intellij.cvsSupport2.changeBrowser.CvsRepositoryLocation;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
/**
@@ -27,8 +26,8 @@ public class CvsFilePath extends FilePathImpl {
private final CvsRepositoryLocation myRepositoryLocation;
public CvsFilePath(@NotNull VirtualFile virtualFile, @NotNull CvsRepositoryLocation repositoryLocation) {
super(virtualFile);
public CvsFilePath(@NotNull String path, boolean isDirectory, @NotNull CvsRepositoryLocation repositoryLocation) {
super(path, isDirectory);
myRepositoryLocation = repositoryLocation;
}
@@ -175,7 +175,8 @@ public class BrowserPanel extends JPanel implements DataProvider, CvsTabbedWindo
final VcsHistoryProvider historyProvider = vcs.getVcsHistoryProvider();
final String moduleName = cvsElement.getElementPath();
final CvsRepositoryLocation location = new CvsRepositoryLocation(null, myCvsRootConfiguration, moduleName);
AbstractVcsHelper.getInstance(myProject).showFileHistory(historyProvider, new CvsFilePath(virtualFile, location), vcs, null);
CvsFilePath filePath = new CvsFilePath(virtualFile.getPath(), virtualFile.isDirectory(), location);
AbstractVcsHelper.getInstance(myProject).showFileHistory(historyProvider, filePath, vcs, null);
}
}
@@ -200,7 +200,7 @@ public class CvsChangeProvider implements ChangeProvider {
private void processFile(final VirtualFile dir, @Nullable VirtualFile file, Entry entry, final ChangelistBuilder builder,
final ProgressIndicator progress) throws VcsException {
final FilePath filePath = VcsContextFactory.SERVICE.getInstance().createFilePathOn(dir, entry.getFileName());
final FilePath filePath = VcsUtil.getFilePath(dir, entry.getFileName());
final FileStatus status = CvsStatusProvider.getStatus(file, entry);
final VcsRevisionNumber number = createRevisionNumber(entry.getRevision(), status);
processStatus(filePath, file, status, number, builder);
@@ -19,7 +19,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.Throwable2Computable;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.CurrentContentRevision;
@@ -171,7 +170,7 @@ public class GitContentRevision implements ContentRevision {
FilePath file = isDeleted ? VcsUtil.getFilePathForDeletedFile(absolutePath, false) : VcsUtil.getFilePath(absolutePath, false);
if (canBeDeleted && (! SystemInfo.isFileSystemCaseSensitive) && VcsFilePathUtil.caseDiffers(file.getPath(), absolutePath)) {
// as for deleted file
file = FilePathImpl.createForDeletedFile(new File(absolutePath), false);
file = VcsUtil.getFilePath(absolutePath, false);
}
return file;
}
@@ -301,7 +301,7 @@ public class SvnChangeProvider implements ChangeProvider {
FilePath path = changedFile.getFilePath();
return SvnContentRevision
.createBaseRevision(myVcs, forDeleted ? FilePathImpl.createForDeletedFile(status.getFile(), path.isDirectory()) : path,
.createBaseRevision(myVcs, forDeleted ? VcsUtil.getFilePath(status.getFile(), path.isDirectory()) : path,
status.getRevision());
}
@@ -21,7 +21,6 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.changes.*;
@@ -226,10 +225,11 @@ class SvnChangeProviderContext implements StatusReceiver {
myChangelistBuilder.processLocallyDeletedFile(new SvnLocallyDeletedChange(filePath, getState(status)));
}
else if (status.is(StatusType.STATUS_IGNORED)) {
if (filePath.getVirtualFile() == null) {
filePath.hardRefresh();
VirtualFile file = filePath.getVirtualFile();
if (file == null) {
file = LocalFileSystem.getInstance().refreshAndFindFileByPath(filePath.getPath());
}
if (filePath.getVirtualFile() == null) {
if (file == null) {
LOG.error("No virtual file for ignored file: " + filePath.getPresentableUrl() + ", isNonLocal: " + filePath.isNonLocal());
}
else if (!myVcs.isWcRoot(filePath)) {
@@ -28,6 +28,7 @@ import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Processor;
import com.intellij.vcsUtil.VcsUtil;
@@ -206,9 +207,8 @@ public class SvnRecursiveStatusWalker {
final Processor<File> checkDirProcessor = new Processor<File>() {
@Override
public boolean process(File file) {
final FilePath path = VcsUtil.getFilePath(file, true);
path.hardRefresh();
VirtualFile vf = path.getVirtualFile();
FilePath path = VcsUtil.getFilePath(file, true);
VirtualFile vf = VfsUtil.findFileByIoFile(file, true);
if (vf != null && isIgnoredIdeaLevel(vf)) {
lastIgnored.set(file);
myReceiver.processIgnored(vf);
@@ -33,6 +33,7 @@ import com.intellij.openapi.vcs.VcsKey;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.MarkerVcsContentRevision;
import com.intellij.openapi.vcs.impl.ContentRevisionCache;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -65,7 +66,9 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC
@Nullable
public String getContent() throws VcsException {
try {
myFilePath.hardRefresh();
if (myFilePath.getVirtualFile() == null) {
LocalFileSystem.getInstance().refreshAndFindFileByPath(myFilePath.getPath());
}
return ContentRevisionCache.getOrLoadAsString(myVcs.getProject(), myFilePath, getRevisionNumber(), myVcs.getKeyInstanceMethod(),
ContentRevisionCache.UniqueType.REPOSITORY_CONTENT,
new Throwable2Computable<byte[], VcsException, IOException>() {
@@ -300,7 +300,7 @@ public class SvnIntegrateChangesTask extends Task.Backgroundable {
UpdateFilesHelper.iterateFileGroupFiles(myAccumulatedFiles.getUpdatedFiles(), new UpdateFilesHelper.Callback() {
public void onFile(final String filePath, final String groupId) {
result.add(FilePathImpl.create(new File(filePath)));
result.add(VcsUtil.getFilePath(new File(filePath)));
}
});
ContainerUtil.addIfNotNull(result, myMergeTarget);
@@ -316,7 +316,7 @@ public class SvnIntegrateChangesTask extends Task.Backgroundable {
} else {
UpdateFilesHelper.iterateFileGroupFiles(myAccumulatedFiles.getUpdatedFiles(), new UpdateFilesHelper.Callback() {
public void onFile(final String filePath, final String groupId) {
dirtyScope.addFile(FilePathImpl.create(new File(filePath)));
dirtyScope.addFile(VcsUtil.getFilePath(new File(filePath)));
}
});
}
@@ -28,7 +28,6 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.actions.VcsContextFactory;
import com.intellij.openapi.vcs.changes.AbstractRefreshablePanel;
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
import com.intellij.openapi.vcs.changes.Change;
@@ -40,6 +39,7 @@ import com.intellij.util.BeforeAfter;
import com.intellij.util.containers.Convertor;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.VcsBackgroundTask;
import com.intellij.vcsUtil.VcsUtil;
import gnu.trove.TLongArrayList;
import org.jetbrains.idea.svn.ConflictedSvnChange;
import org.jetbrains.idea.svn.SvnRevisionNumber;
@@ -476,8 +476,9 @@ public class TreeConflictRefreshablePanel extends AbstractRefreshablePanel {
myVcs = vcs;
myPeg = peg;
try {
myPath = VcsContextFactory.SERVICE.getInstance().createFilePathOnNonLocal(
version.getRepositoryRoot().appendPath(FileUtil.toSystemIndependentName(version.getPath()), true).toString(), version.isDirectory());
myPath = VcsUtil.getFilePathOnNonLocal(
version.getRepositoryRoot().appendPath(FileUtil.toSystemIndependentName(version.getPath()), true).toString(),
version.isDirectory());
}
catch (SVNException e) {
throw new VcsException(e);