/*
* Copyright 2003-2015 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 jetbrains.mps.ide.vfs;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.util.io.StreamUtil;
import com.intellij.openapi.vfs.SafeWriteRequestor;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import jetbrains.mps.ide.platform.watching.FileSystemListenersContainer;
import jetbrains.mps.util.FileUtil;
import jetbrains.mps.vfs.CachingContext;
import jetbrains.mps.vfs.CachingFile;
import jetbrains.mps.vfs.CachingFileSystem;
import jetbrains.mps.vfs.FileSystem;
import jetbrains.mps.vfs.FileSystemListener;
import jetbrains.mps.vfs.IFile;
import jetbrains.mps.vfs.DefaultCachingContext;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Evgeny Gerashchenko
*/
public class IdeaFileSystem extends IdeaFSComponent implements SafeWriteRequestor {
private static final Logger LOG = LogManager.getLogger(IdeaFileSystem.class);
private FileSystemListenersContainer myListeners = new FileSystemListenersContainer();
public IdeaFileSystem() {
}
@Override
public void refresh(@NotNull CachingContext context, Collection<CachingFile> files) {
Set<VirtualFile> virtualFiles = files.stream().map(file -> ((IdeaFile) file).getVirtualFile()).filter(Objects::nonNull).collect(Collectors.toSet());
virtualFiles.forEach(VirtualFile::getChildren); // to enforce refresh for this file
RefreshQueue.getInstance().refresh(!context.isSynchronous(), context.isRecursive(), null, virtualFiles);
}
@NotNull
@Override
public IdeaFile getFile(@NotNull String path) {
return new IdeaFile(this, path);
}
@Override
public void addListener(@NotNull FileSystemListener listener) {
myListeners.addListener(listener);
}
@Override
public void removeListener(@NotNull FileSystemListener listener) {
myListeners.removeListener(listener);
}
public FileSystemListenersContainer getListenersContainer() {
return myListeners;
}
@Override
public boolean isFileIgnored(@NotNull String name) {
return FileTypeManager.getInstance().isFileIgnored(name);
}
@Override
public void scheduleUpdateForWrittenFiles(Iterable<IFile> writtenFiles) {
final List<IFile> newFiles = new ArrayList<>();
final List<IFile> updatedFiles = new ArrayList<>();
for (IFile file : writtenFiles) {
if (file.exists()) {
updatedFiles.add(file);
} else {
newFiles.add(file);
}
}
ApplicationManager.getApplication().invokeLater(new IdeaWriteAction(() -> {
// Recreate files using VFS
for (IFile file : newFiles) {
OutputStream out = null;
try {
// No need to close InputStream: it will be closed by loadFromStream()
byte[] content = StreamUtil.loadFromStream(new FileInputStream(file.getPath()));
out = file.openOutputStream();
out.write(content);
} catch (IOException e) {
LOG.error(null, e);
} finally {
FileUtil.closeFileSafe(out);
}
}
// Refresh added files
Set<CachingFile> ideaFiles = updatedFiles.stream()
.filter(file -> file instanceof IdeaFile)
.map(file -> ((IdeaFile) file)).collect(Collectors.toSet());
refresh(new DefaultCachingContext(true, false), ideaFiles);
})
);
}
@Override
public boolean runWriteTransaction(@NotNull Runnable r) {
final IdeaWriteAction action = new IdeaWriteAction(r);
ApplicationManager.getApplication().invokeAndWait(action, ModalityState.defaultModalityState());
return action.getFailure() == null;
}
private static class IdeaWriteAction implements Runnable {
private final Runnable myDelegate;
private Exception myException;
public IdeaWriteAction(@NotNull Runnable delegate) {
myDelegate = delegate;
}
@Override
public void run() {
try {
ApplicationManager.getApplication().runWriteAction(myDelegate);
} catch (Exception ex) {
LOG.error(ex.getMessage(), ex);
myException = ex;
}
}
public Exception getFailure() {
return myException;
}
}
@NotNull
@Override
public String getComponentName() {
return "IdeaFileSystemProvider";
}
}