package jetbrains.mps.build.workflow.generator.util; /*Generated by MPS */ import org.jetbrains.mps.openapi.model.SNode; import java.util.Map; import java.util.HashMap; import jetbrains.mps.generator.template.TemplateQueryContext; import java.util.Set; import java.util.HashSet; import jetbrains.mps.internal.collections.runtime.ListSequence; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import jetbrains.mps.internal.collections.runtime.IWhereFilter; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations; import jetbrains.mps.build.workflow.util.XmlSignature; import java.util.List; import java.util.ArrayList; import jetbrains.mps.internal.collections.runtime.ISelector; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPropertyOperations; import jetbrains.mps.make.dependencies.graph.Graph; import jetbrains.mps.make.dependencies.graph.Graphs; import java.util.Collections; import java.util.Comparator; import org.jetbrains.mps.openapi.model.SModel; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModelOperations; import java.util.LinkedHashSet; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.smodel.CopyUtil; import jetbrains.mps.make.dependencies.graph.IVertex; public class CycleHelper { private final SNode project; private final Map<SNode, CycleHelper.Module> map = new HashMap<SNode, CycleHelper.Module>(); private final TemplateQueryContext genContext; public CycleHelper(SNode project, TemplateQueryContext genContext) { this.project = project; this.genContext = genContext; } public void optimizeDependencies(SNode m) { final Set<String> seenDependencies = new HashSet<String>(); ListSequence.fromList(SLinkOperations.getChildren(m, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x41fde5e4adce38c8L, "dependencies"))).removeWhere(new IWhereFilter<SNode>() { public boolean accept(SNode dep) { if (!(SNodeOperations.isInstanceOf(dep, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x5c3f3e2c1cede077L, "jetbrains.mps.build.workflow.structure.BwfJavaClassPath")))) { return false; } SNode cp = SLinkOperations.getTarget(SNodeOperations.cast(dep, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x5c3f3e2c1cede077L, "jetbrains.mps.build.workflow.structure.BwfJavaClassPath")), MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x5c3f3e2c1cede077L, 0x6e014d63c0847621L, "classpath")); XmlSignature s = new XmlSignature().add(cp); String id = (s.hasErrors() ? "dep." + cp.getNodeId().toString() : s.getResult()); return !(seenDependencies.add(id)); } }); } public void processCycles() { List<SNode> modules = new ArrayList<SNode>(); ListSequence.fromList(modules).addSequence(ListSequence.fromList(SLinkOperations.getChildren(project, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x2670d5989d5a6271L, 0x2670d5989d5ace60L, "parts"))).where(new IWhereFilter<SNode>() { public boolean accept(SNode it) { return SNodeOperations.isInstanceOf(it, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, "jetbrains.mps.build.workflow.structure.BwfJavaModule")); } }).select(new ISelector<SNode, SNode>() { public SNode select(SNode it) { return SNodeOperations.cast(it, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, "jetbrains.mps.build.workflow.structure.BwfJavaModule")); } })); for (SNode m : ListSequence.fromList(modules)) { optimizeDependencies(m); } for (SNode jm : modules) { CycleHelper.Module module = new CycleHelper.Module(jm); map.put(jm, module); if (isEmptyString(SPropertyOperations.getString(jm, MetaAdapterFactory.getProperty(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x667edfe4171f2fb7L, "outputFolder")))) { genContext.showErrorMessage(jm, "empty output path"); } else if (SPropertyOperations.getString(jm, MetaAdapterFactory.getProperty(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x667edfe4171f2fb7L, "outputFolder")).endsWith("/") || SPropertyOperations.getString(jm, MetaAdapterFactory.getProperty(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x667edfe4171f2fb7L, "outputFolder")).endsWith("\\")) { genContext.showErrorMessage(jm, "output path shouldn't end with slash"); } } Graph<CycleHelper.Module> graph = new Graph(); for (CycleHelper.Module module : map.values()) { graph.add(module); } List<List<CycleHelper.Module>> cycles = Graphs.findStronglyConnectedComponents(graph); Collections.reverse(cycles); List<SNode> cyclesToName = new ArrayList<SNode>(); for (List<CycleHelper.Module> cycle : cycles) { if (cycle.size() < 2) { continue; } final Set<SNode> cycleModules = new HashSet<SNode>(); for (CycleHelper.Module m : cycle) { cycleModules.add(m.getModule()); } Collections.sort(cycle, new Comparator<CycleHelper.Module>() { public int compare(CycleHelper.Module m1, CycleHelper.Module m2) { return new Integer(SNodeOperations.getIndexInParent(m1.getModule())).compareTo(SNodeOperations.getIndexInParent(m2.getModule())); } }); SNode first = cycle.get(0).getModule(); SModel model = SNodeOperations.getModel(first); SNode cycleX = SModelOperations.createNewNode(model, null, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, "jetbrains.mps.build.workflow.structure.BwfJavaModule")); cyclesToName.add(cycleX); SNodeOperations.insertPrevSiblingChild(first, cycleX); SPropertyOperations.set(cycleX, MetaAdapterFactory.getProperty(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0xcdff0e1a96ccbeeL, "noWarnings"), "" + (true)); // build cycle sources & dependencies; trying to avoid duplication (which is not critical) Set<String> seenSources = new HashSet<String>(); List<SNode> sources = new ArrayList<SNode>(); Set<String> seenDependencies = new HashSet<String>(); List<SNode> deps = new ArrayList<SNode>(); Set<SNode> seenModules = new LinkedHashSet<SNode>(); Set<SNode> seenLibraries = new LinkedHashSet<SNode>(); Set<SNode> taskDependency = new LinkedHashSet<SNode>(); int heapSize = 0; for (CycleHelper.Module m : cycle) { SNode module = m.getModule(); heapSize = Math.max(heapSize, SPropertyOperations.getInteger(module, MetaAdapterFactory.getProperty(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0xcdff0e1a96ccbe3L, "heapSize"))); ListSequence.fromList(SLinkOperations.getChildren(module, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x41fde5e4adce38c8L, "dependencies"))).removeWhere(new IWhereFilter<SNode>() { public boolean accept(SNode it) { return SNodeOperations.isInstanceOf(it, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, "jetbrains.mps.build.workflow.structure.BwfJavaModuleReference")) && cycleModules.contains(SLinkOperations.getTarget(SNodeOperations.cast(it, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, "jetbrains.mps.build.workflow.structure.BwfJavaModuleReference")), MetaAdapterFactory.getReferenceLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, 0x41fde5e4adce38c5L, "target"))); } }); for (SNode dep : SLinkOperations.getChildren(module, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x41fde5e4adce38c8L, "dependencies"))) { if (SNodeOperations.isInstanceOf(dep, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, "jetbrains.mps.build.workflow.structure.BwfJavaModuleReference"))) { seenModules.add(SLinkOperations.getTarget(SNodeOperations.cast(dep, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, "jetbrains.mps.build.workflow.structure.BwfJavaModuleReference")), MetaAdapterFactory.getReferenceLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, 0x41fde5e4adce38c5L, "target"))); } else if (SNodeOperations.isInstanceOf(dep, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x2021cfb4db759cbL, "jetbrains.mps.build.workflow.structure.BwfJavaLibraryReference"))) { seenLibraries.add(SLinkOperations.getTarget(SNodeOperations.cast(dep, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x2021cfb4db759cbL, "jetbrains.mps.build.workflow.structure.BwfJavaLibraryReference")), MetaAdapterFactory.getReferenceLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x2021cfb4db759cbL, 0x2021cfb4db759ccL, "target"))); } else if (SNodeOperations.isInstanceOf(dep, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x5c3f3e2c1cede077L, "jetbrains.mps.build.workflow.structure.BwfJavaClassPath"))) { SNode cp = SLinkOperations.getTarget(SNodeOperations.cast(dep, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x5c3f3e2c1cede077L, "jetbrains.mps.build.workflow.structure.BwfJavaClassPath")), MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x5c3f3e2c1cede077L, 0x6e014d63c0847621L, "classpath")); XmlSignature s = new XmlSignature().add(cp); String id = (s.hasErrors() ? "dep." + cp.getNodeId().toString() : s.getResult()); if (seenDependencies.add(id)) { deps.add(cp); } } else { genContext.showErrorMessage(dep, "unexpected dependency type"); } } for (SNode task : ListSequence.fromList(SLinkOperations.getChildren(module, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x5a7e1dc16b102462L, "taskDeps"))).select(new ISelector<SNode, SNode>() { public SNode select(SNode it) { return SLinkOperations.getTarget(it, MetaAdapterFactory.getReferenceLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x2670d5989d5ace56L, 0x2670d5989d5ace57L, "target")); } })) { if ((task != null)) { taskDependency.add(task); } } SNode mref = SModelOperations.createNewNode(model, null, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, "jetbrains.mps.build.workflow.structure.BwfJavaModuleReference")); SLinkOperations.setTarget(mref, MetaAdapterFactory.getReferenceLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, 0x41fde5e4adce38c5L, "target"), cycleX); ListSequence.fromList(SLinkOperations.getChildren(module, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x41fde5e4adce38c8L, "dependencies"))).addElement(mref); for (SNode n : ListSequence.fromList(SLinkOperations.getChildren(SLinkOperations.getTarget(module, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x6e014d63c07ebd25L, "sources")), MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x6e014d63c07ebd1bL, 0x6e014d63c07ebd1cL, "elements")))) { XmlSignature s = new XmlSignature().add(n); String id = (s.hasErrors() ? "path." + n.getNodeId().toString() : s.getResult()); if (seenSources.add(id)) { sources.add(n); } } } SPropertyOperations.set(cycleX, MetaAdapterFactory.getProperty(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0xcdff0e1a96ccbe3L, "heapSize"), "" + (heapSize)); SLinkOperations.setNewChild(cycleX, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x6e014d63c07ebd25L, "sources"), MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x6e014d63c07ebd1bL, "jetbrains.mps.build.workflow.structure.BwfFileSet")); ListSequence.fromList(SLinkOperations.getChildren(SLinkOperations.getTarget(cycleX, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x6e014d63c07ebd25L, "sources")), MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x6e014d63c07ebd1bL, 0x6e014d63c07ebd1cL, "elements"))).addSequence(Sequence.fromIterable(((Iterable<SNode>) sources)).select(new ISelector<SNode, SNode>() { public SNode select(SNode it) { return CopyUtil.copy(it); } })); for (SNode dep : deps) { SNode cp = SModelOperations.createNewNode(model, null, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x5c3f3e2c1cede077L, "jetbrains.mps.build.workflow.structure.BwfJavaClassPath")); SLinkOperations.setTarget(cp, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x5c3f3e2c1cede077L, 0x6e014d63c0847621L, "classpath"), CopyUtil.copy(dep)); ListSequence.fromList(SLinkOperations.getChildren(cycleX, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x41fde5e4adce38c8L, "dependencies"))).addElement(cp); } for (SNode jl : seenLibraries) { SNode mref = SModelOperations.createNewNode(model, null, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x2021cfb4db759cbL, "jetbrains.mps.build.workflow.structure.BwfJavaLibraryReference")); SLinkOperations.setTarget(mref, MetaAdapterFactory.getReferenceLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x2021cfb4db759cbL, 0x2021cfb4db759ccL, "target"), jl); ListSequence.fromList(SLinkOperations.getChildren(cycleX, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x41fde5e4adce38c8L, "dependencies"))).addElement(mref); } for (SNode jm : seenModules) { SNode mref = SModelOperations.createNewNode(model, null, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, "jetbrains.mps.build.workflow.structure.BwfJavaModuleReference")); SLinkOperations.setTarget(mref, MetaAdapterFactory.getReferenceLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, 0x41fde5e4adce38c5L, "target"), jm); ListSequence.fromList(SLinkOperations.getChildren(cycleX, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x41fde5e4adce38c8L, "dependencies"))).addElement(mref); } for (SNode task : taskDependency) { SNode dependency = SModelOperations.createNewNode(model, null, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x2670d5989d5ace56L, "jetbrains.mps.build.workflow.structure.BwfTaskDependency")); SLinkOperations.setTarget(dependency, MetaAdapterFactory.getReferenceLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x2670d5989d5ace56L, 0x2670d5989d5ace57L, "target"), task); ListSequence.fromList(SLinkOperations.getChildren(cycleX, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x5a7e1dc16b102462L, "taskDeps"))).addElement(dependency); } } int cycleCounter = 0; Collections.sort(cyclesToName, new Comparator<SNode>() { public int compare(SNode n1, SNode n2) { return new Integer(SNodeOperations.getIndexInParent(n1)).compareTo(SNodeOperations.getIndexInParent(n2)); } }); for (SNode cycleX : cyclesToName) { SPropertyOperations.set(cycleX, MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name"), "java.modules.cycle." + ++cycleCounter); SPropertyOperations.set(cycleX, MetaAdapterFactory.getProperty(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x667edfe4171f2fb7L, "outputFolder"), SPropertyOperations.getString(project, MetaAdapterFactory.getProperty(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x2670d5989d5a6271L, 0x667edfe41720f53eL, "temporaryFolder")) + "/" + SPropertyOperations.getString(cycleX, MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name"))); } } public class Module implements IVertex { private final SNode module; private Set<CycleHelper.Module> targets; public Module(SNode module) { this.module = module; } public Set<? extends IVertex> getNexts() { if (targets == null) { if (ListSequence.fromList(SLinkOperations.getChildren(module, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x41fde5e4adce38c8L, "dependencies"))).isEmpty()) { targets = Collections.emptySet(); } else { targets = new HashSet<CycleHelper.Module>(); for (SNode ref : ListSequence.fromList(SLinkOperations.getChildren(module, MetaAdapterFactory.getContainmentLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38bbL, 0x41fde5e4adce38c8L, "dependencies"))).where(new IWhereFilter<SNode>() { public boolean accept(SNode it) { return SNodeOperations.isInstanceOf(it, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, "jetbrains.mps.build.workflow.structure.BwfJavaModuleReference")); } })) { CycleHelper.Module tm = map.get(SLinkOperations.getTarget(SNodeOperations.cast(ref, MetaAdapterFactory.getConcept(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, "jetbrains.mps.build.workflow.structure.BwfJavaModuleReference")), MetaAdapterFactory.getReferenceLink(0x698a8d22a10447a0L, 0xba8d10e3ec237f13L, 0x41fde5e4adce38c4L, 0x41fde5e4adce38c5L, "target"))); if (tm == null) { genContext.showErrorMessage(ref, "internal problem: unsatisfied local dependency"); } else { targets.add(tm); } } } } return targets; } public SNode getModule() { return module; } } private static boolean isEmptyString(String str) { return str == null || str.length() == 0; } }