package jetbrains.mps.lang.core.plugin;
/*Generated by MPS */
import java.util.Map;
import org.jetbrains.mps.openapi.module.SModule;
import org.jetbrains.mps.openapi.model.SModel;
import jetbrains.mps.make.resources.IResource;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import java.util.HashMap;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import jetbrains.mps.smodel.resources.MResource;
import jetbrains.mps.smodel.Language;
import jetbrains.mps.smodel.Generator;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.internal.collections.runtime.IWhereFilter;
import jetbrains.mps.generator.GenerationFacade;
import jetbrains.mps.make.delta.IDelta;
import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes;
import jetbrains.mps.vfs.IFile;
import jetbrains.mps.internal.make.runtime.util.FilesDelta;
import org.jetbrains.mps.openapi.module.SModuleFacet;
import jetbrains.mps.project.facets.GenerationTargetFacet;
public final class RetainedUtil {
private RetainedUtil() {
}
public static Map<SModule, Iterable<SModel>> collectModelsToRetain(Iterable<? extends IResource> input) {
Map<SModule, Iterable<SModel>> retainedModels = MapSequence.fromMap(new HashMap<SModule, Iterable<SModel>>());
Iterable<SModel> empty = ListSequence.fromList(new ArrayList<SModel>());
for (IResource it : input) {
MResource mres = ((MResource) it);
SModule module = mres.module();
MapSequence.fromMap(retainedModels).put(module, empty);
if (module instanceof Language) {
// FIXME is there still a reason to record models of language's generators? Isn't generator module come as a distinct resource?
// Perhaps, it doesn't hurt to supply more, OTOH is there any reason to? Modules are generated into distinct locations, why bother to mark
// unrelated locations as retained?
for (Generator gen : ((Language) module).getGenerators()) {
if (!(MapSequence.fromMap(retainedModels).containsKey(gen))) {
MapSequence.fromMap(retainedModels).put(gen, Sequence.fromIterable(generateableModels(gen)).toListSequence());
}
}
// fall-through
} else if (module instanceof Generator) {
Language slang = ((Generator) module).getSourceLanguage();
if (!(MapSequence.fromMap(retainedModels).containsKey(slang))) {
MapSequence.fromMap(retainedModels).put(slang, Sequence.fromIterable(generateableModels(slang)).toListSequence());
}
for (Generator gen : slang.getGenerators()) {
if (gen == module) {
continue;
}
if (!(MapSequence.fromMap(retainedModels).containsKey(gen))) {
MapSequence.fromMap(retainedModels).put(gen, Sequence.fromIterable(generateableModels(gen)).toListSequence());
}
}
// fall-through
}
Iterable<SModel> modelsToRetain = generateableModels(module);
MapSequence.fromMap(retainedModels).put(mres.module(), Sequence.fromIterable(modelsToRetain).subtract(Sequence.fromIterable(mres.models())).toListSequence());
}
return retainedModels;
}
private static Iterable<SModel> generateableModels(SModule module) {
return Sequence.fromIterable(((Iterable<SModel>) module.getModels())).where(new IWhereFilter<SModel>() {
public boolean accept(SModel it) {
return GenerationFacade.canGenerate(it);
}
});
}
public static Iterable<IDelta> retainedDeltas(final SModule module, Iterable<SModel> smd, _FunctionTypes._return_P1_E0<? extends IFile, ? super String> getFile) {
// builds deltas that mark output locations of specified models to persist generation (respective folders marked as 'kept')
assert Sequence.fromIterable(smd).all(new IWhereFilter<SModel>() {
public boolean accept(SModel it) {
return it.getModule() == module;
}
});
// XXX delta doesn't uilize IFile, it's merely an indication of a location. Perhaps, it should be caller responsibility
// to translate delta's IFile to proper location (make.pathToFile) and leave this class straighforward delta builder without
// knowledge of path translation?
// FIXME need make.pathToFile to take IFile instead of String, it's odd to go there and back
final Map<IFile, FilesDelta> dir2delta = MapSequence.fromMap(new HashMap<IFile, FilesDelta>());
for (SModuleFacet mf : module.getFacets()) {
if (mf instanceof GenerationTargetFacet) {
GenerationTargetFacet gtf = (GenerationTargetFacet) mf;
IFile[] outputLocations = new IFile[2];
for (SModel m : smd) {
outputLocations[0] = gtf.getOutputLocation(m);
outputLocations[1] = gtf.getOutputCacheLocation(m);
for (IFile f : outputLocations) {
if (f == null) {
continue;
}
IFile actualOutput = getFile.invoke(f.getPath());
// XXX I'm not sure FilesDelta(dir).kept(new IFile(".")) or FilesDelta(dir).kept(dir) would work correctly, hence the magic with parent
IFile parent = actualOutput.getParent();
FilesDelta fd = MapSequence.fromMap(dir2delta).get(parent);
if (fd == null) {
MapSequence.fromMap(dir2delta).put(parent, fd = new FilesDelta(parent));
}
fd.kept(actualOutput);
}
}
}
}
return Sequence.fromIterable(MapSequence.fromMap(dir2delta).values()).ofType(IDelta.class);
}
}