package jetbrains.mps.internal.make.runtime.util;
/*Generated by MPS */
import jetbrains.mps.vfs.IFile;
import java.util.Map;
import java.util.List;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import java.util.HashMap;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.internal.collections.runtime.ISelector;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import java.util.Queue;
import jetbrains.mps.internal.collections.runtime.QueueSequence;
import java.util.LinkedList;
import java.util.Arrays;
import jetbrains.mps.baseLanguage.tuples.runtime.Tuples;
import jetbrains.mps.baseLanguage.tuples.runtime.MultiTuple;
import org.jetbrains.mps.openapi.model.SModel;
import jetbrains.mps.generator.info.GeneratorPathsComponent;
import java.util.Set;
import jetbrains.mps.internal.collections.runtime.SetSequence;
import java.util.HashSet;
public class StaleFilesCollector {
private IFile rootDir;
private Map<IFile, List<IFile>> generatedChildren = MapSequence.fromMap(new HashMap<IFile, List<IFile>>());
public StaleFilesCollector(IFile rootDir) {
this.rootDir = rootDir;
}
private List<IFile> collectFilesToDelete(Iterable<IFile> filesToKeep) {
String[] pathsToKeep = Sequence.fromIterable(filesToKeep).select(new ISelector<IFile, String>() {
public String select(IFile f) {
return (f.isDirectory() ? DirUtil.normalizeAsDir(f.getPath()) : DirUtil.normalize(f.getPath()));
}
}).sort(new ISelector<String, String>() {
public String select(String p) {
return p;
}
}, true).toListSequence().toGenericArray(String.class);
List<IFile> filesToDelete = ListSequence.fromList(new ArrayList<IFile>());
Queue<IFile> dirQueue = QueueSequence.fromQueueAndArray(new LinkedList<IFile>(), rootDir);
while (QueueSequence.fromQueue(dirQueue).isNotEmpty()) {
IFile dir = QueueSequence.fromQueue(dirQueue).removeFirstElement();
String dirpath = DirUtil.normalizeAsDir(dir.getPath());
int diridx = Arrays.binarySearch(pathsToKeep, dirpath);
for (Tuples._2<IFile, String> fileAndPath : Sequence.fromIterable(getChildren(dir)).select(new ISelector<IFile, Tuples._2<IFile, String>>() {
public Tuples._2<IFile, String> select(IFile f) {
return MultiTuple.<IFile,String>from(f, DirUtil.normalize(f.getPath()));
}
}).sort(new ISelector<Tuples._2<IFile, String>, String>() {
public String select(Tuples._2<IFile, String> t) {
return t._1();
}
}, true)) {
if (fileAndPath._0().isDirectory()) {
int fidx = Arrays.binarySearch(pathsToKeep, DirUtil.normalizeAsDir(fileAndPath._1()));
fidx = (fidx < 0 ? -1 - fidx : fidx);
if (fidx >= pathsToKeep.length || !(DirUtil.startsWith(pathsToKeep[fidx], fileAndPath._1()))) {
ListSequence.fromList(filesToDelete).addElement(fileAndPath._0());
if (fidx >= pathsToKeep.length) {
break;
}
} else if (fidx < pathsToKeep.length) {
QueueSequence.fromQueue(dirQueue).addLastElement(fileAndPath._0());
}
} else {
int fidx = Arrays.binarySearch(pathsToKeep, fileAndPath._1());
if (fidx < 0 && diridx < 0) {
ListSequence.fromList(filesToDelete).addElement(fileAndPath._0());
}
}
}
}
return filesToDelete;
}
/**
* Read cached state of generated files, if any, assuming files were generated under rootDir.
*
* The code is intended to handle case when we generate into a root with foreign files we shall keep.
* Generally, all the files under rootDir might need deletion (except those explicitly written/kept).
* Files left after excluding those touched are additionally filtered through 'foreign' roots in a way
* that we consider only generated files under output root (intersect in getChildren).
*/
public void recordGeneratedChildren(SModel model) {
List<IFile> genChildren = GeneratorPathsComponent.getInstance().getGeneratedChildren(rootDir, model);
if (ListSequence.fromList(genChildren).isNotEmpty()) {
MapSequence.fromMap(generatedChildren).put(rootDir, ListSequence.fromListWithValues(new ArrayList<IFile>(), genChildren));
}
}
public void updateDelta(FilesDelta delta) {
final Set<IFile> filesToKeep = SetSequence.fromSet(new HashSet<IFile>());
delta.acceptVisitor(new FilesDelta.Visitor() {
@Override
public boolean acceptWritten(IFile file) {
SetSequence.fromSet(filesToKeep).addElement(file);
return true;
}
@Override
public boolean acceptKept(IFile file) {
SetSequence.fromSet(filesToKeep).addElement(file);
return true;
}
});
for (IFile f : collectFilesToDelete(filesToKeep)) {
delta.stale(f);
}
}
private Iterable<IFile> getChildren(IFile dir) {
Iterable<IFile> realChilren = (Iterable<IFile>) dir.getChildren();
if (GeneratorPathsComponent.getInstance().isForeign(dir)) {
List<IFile> genChildren = MapSequence.fromMap(generatedChildren).get(dir);
return ListSequence.fromList(genChildren).intersect(Sequence.fromIterable(realChilren));
}
return realChilren;
}
}