package jetbrains.mps.build.util; /*Generated by MPS */ import jetbrains.mps.generator.template.TemplateQueryContext; import org.jetbrains.mps.openapi.model.SNode; import java.util.List; import jetbrains.mps.baseLanguage.tuples.runtime.Tuples; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.ArrayList; import jetbrains.mps.internal.collections.runtime.SetSequence; import java.util.HashSet; import jetbrains.mps.build.behavior.BuildProject__BehaviorDescriptor; import jetbrains.mps.internal.collections.runtime.ISelector; import jetbrains.mps.baseLanguage.tuples.runtime.MultiTuple; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPropertyOperations; import java.util.Set; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations; import jetbrains.mps.internal.collections.runtime.IWhereFilter; import org.jetbrains.mps.openapi.model.SModel; import org.jetbrains.mps.openapi.module.SModule; public class ProjectDependency { private final TemplateQueryContext myGenContext; private final SNode myProject; private final List<Tuples._2<SNode, String>> myDependency = ListSequence.fromList(new ArrayList<Tuples._2<SNode, String>>()); private final Context myContext; public ProjectDependency(TemplateQueryContext genContext, SNode project) { myGenContext = genContext; myProject = project; myContext = Context.defaultContext(myGenContext); } public ProjectDependency collectDependencies() { List<SNode> dependencies = ListSequence.fromList(new ArrayList<SNode>()); dfs(myProject, dependencies, SetSequence.fromSet(new HashSet<SNode>())); String basePath = BuildProject__BehaviorDescriptor.getBasePath_id4jjtc7WZOyG.invoke(myProject, myContext); if ((basePath == null || basePath.length() == 0)) { return this; } final RelativePathHelper helper = new RelativePathHelper(basePath); ListSequence.fromList(myDependency).addSequence(ListSequence.fromList(dependencies).select(new ISelector<SNode, Tuples._2<SNode, String>>() { public Tuples._2<SNode, String> select(SNode it) { return MultiTuple.<SNode,String>from(SLinkOperations.getTarget(it, MetaAdapterFactory.getReferenceLink(0x798100da4f0a421aL, 0xb99171f8c50ce5d2L, 0x454b730dd908c220L, 0x4df58c6f18f84a24L, "script")), calculatePath(it, helper)); } })); return this; } public List<Tuples._2<SNode, String>> getDependencies() { return myDependency; } private String calculatePath(SNode node, RelativePathHelper helper) { SNode script = SLinkOperations.getTarget(node, MetaAdapterFactory.getReferenceLink(0x798100da4f0a421aL, 0xb99171f8c50ce5d2L, 0x454b730dd908c220L, 0x4df58c6f18f84a24L, "script")); String filePath = BuildProject__BehaviorDescriptor.getScriptsPath_id4ahc858UcHk.invoke(script, myContext); if (filePath == null) { myGenContext.showErrorMessage(script, "no script path for required script " + SPropertyOperations.getString(script, MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name"))); return "."; } try { String relative = helper.makeRelative(filePath); if ((relative == null || relative.length() == 0)) { return BuildProject__BehaviorDescriptor.getOutputFileName_id4gSHdTptyu0.invoke(script); } if (!(relative.endsWith("/"))) { relative += "/"; } return relative + BuildProject__BehaviorDescriptor.getOutputFileName_id4gSHdTptyu0.invoke(script); } catch (RelativePathHelper.PathException ex) { myGenContext.showErrorMessage(node, "cannot calculate relative path: " + ex.getMessage()); return "????"; } } private void dfs(SNode project, List<SNode> result, Set<SNode> visited) { SetSequence.fromSet(visited).addElement(project); for (SNode dependency : Sequence.fromIterable(getLocalDependencies(project))) { if (SetSequence.fromSet(visited).contains(SLinkOperations.getTarget(dependency, MetaAdapterFactory.getReferenceLink(0x798100da4f0a421aL, 0xb99171f8c50ce5d2L, 0x454b730dd908c220L, 0x4df58c6f18f84a24L, "script")))) { continue; } dfs(SLinkOperations.getTarget(dependency, MetaAdapterFactory.getReferenceLink(0x798100da4f0a421aL, 0xb99171f8c50ce5d2L, 0x454b730dd908c220L, 0x4df58c6f18f84a24L, "script")), result, visited); ListSequence.fromList(result).addElement(dependency); } } private Iterable<SNode> getLocalDependencies(SNode project) { return Sequence.fromIterable(SNodeOperations.ofConcept(SLinkOperations.getChildren(project, MetaAdapterFactory.getContainmentLink(0x798100da4f0a421aL, 0xb99171f8c50ce5d2L, 0x4df58c6f18f84a13L, 0x4df58c6f18f84a25L, "dependencies")), MetaAdapterFactory.getConcept(0x798100da4f0a421aL, 0xb99171f8c50ce5d2L, 0x454b730dd908c220L, "jetbrains.mps.build.structure.BuildProjectDependency"))).where(new IWhereFilter<SNode>() { public boolean accept(SNode it) { return (SLinkOperations.getTarget(it, MetaAdapterFactory.getContainmentLink(0x798100da4f0a421aL, 0xb99171f8c50ce5d2L, 0x454b730dd908c220L, 0x395055ca96617d32L, "artifacts")) == null) && isProjectLocal(it); } }); } /** * Tell whether dependency points to a BP inside local MPS project, so that one * could expect generated build scripts present here, and invoke them as part of myProject build. * * XXX I got doubts why whole MPS project is treated as a scope. On one hand, we might have * scope limited to the model/module of myProject (and take anything else as 'external' dependency), * OTOH, with absence of project module deployment story, it's not clear whether scenario of * two dependant build solutions inside single MPS project won't get broken. * According to BuildProject.isPackaged(), any BuildProject from non-packaged module is ok, * as well as any BuildProject from transient module, provided we're inside generation (always true * for this particular class). This assumption doesn't seem to work well with * checkpoint models of deployed build solutions, as they might get copied into transients, * depending on Generator runtime implementation, which is constantly changing. */ private boolean isProjectLocal(SNode dep) { SModel targetScriptModel = SNodeOperations.getModel(SLinkOperations.getTarget(dep, MetaAdapterFactory.getReferenceLink(0x798100da4f0a421aL, 0xb99171f8c50ce5d2L, 0x454b730dd908c220L, 0x4df58c6f18f84a24L, "script"))); if (targetScriptModel == null || SNodeOperations.getModel(myProject) == null) { // "local" doesn't make sense unless there's location (i.e. my BP's model) to check againts return false; } if (targetScriptModel == SNodeOperations.getModel(myProject)) { // XXX what if we introduce per-root transformation, when one root (BuildProject) comes from transient model, while // target comes from source? Guess, would need to rely on module.isPackaged check below return true; } SModule targetScriptModule = targetScriptModel.getModule(); if (targetScriptModule == SNodeOperations.getModel(myProject).getModule()) { return true; } // FIXME add an option Module.isPackaged (to access it like node.model.module.isPackaged) return !(targetScriptModule.isPackaged()); } }