private static Graph<PluginId> createPluginIdGraph( final Map<PluginId, IdeaPluginDescriptorImpl> idToDescriptorMap) { final List<PluginId> ids = new ArrayList<PluginId>(idToDescriptorMap.keySet()); // this magic ensures that the dependent plugins always follow their dependencies in // lexicographic order // needed to make sure that extensions are always in the same order Collections.sort( ids, new Comparator<PluginId>() { @Override public int compare(PluginId o1, PluginId o2) { return o2.getIdString().compareTo(o1.getIdString()); } }); return GraphGenerator.create( CachingSemiGraph.create( new GraphGenerator.SemiGraph<PluginId>() { @Override public Collection<PluginId> getNodes() { return ids; } @Override public Iterator<PluginId> getIn(PluginId pluginId) { final IdeaPluginDescriptor descriptor = idToDescriptorMap.get(pluginId); ArrayList<PluginId> plugins = new ArrayList<PluginId>(); for (PluginId dependentPluginId : descriptor.getDependentPluginIds()) { // check for missing optional dependency if (idToDescriptorMap.containsKey(dependentPluginId)) { plugins.add(dependentPluginId); } } return plugins.iterator(); } })); }
@Nullable private static Pair<List<String>, Boolean> keysOrder(final ResourceBundle resourceBundle) { final boolean[] isAlphaSorted = new boolean[] {true}; final Graph<String> generator = GraphGenerator.generate( CachingSemiGraph.cache( new InboundSemiGraph<String>() { @Override public Collection<String> getNodes() { final Set<String> nodes = new LinkedHashSet<>(); for (PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { for (IProperty property : propertiesFile.getProperties()) { final String key = property.getKey(); if (key != null) { nodes.add(key); } } } return nodes; } @Override public Iterator<String> getIn(String n) { final Collection<String> siblings = new LinkedHashSet<>(); for (PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { for (IProperty property : propertiesFile.findPropertiesByKey(n)) { PsiElement sibling = property.getPsiElement().getNextSibling(); while (sibling instanceof PsiWhiteSpace || sibling instanceof PsiComment) { sibling = sibling.getNextSibling(); } if (sibling instanceof IProperty) { final String key = ((IProperty) sibling).getKey(); if (key != null) { if (isAlphaSorted[0] && String.CASE_INSENSITIVE_ORDER.compare(n, key) > 0) { isAlphaSorted[0] = false; } siblings.add(key); } } } } return siblings.iterator(); } })); DFSTBuilder<String> dfstBuilder = new DFSTBuilder<>(generator); final boolean acyclic = dfstBuilder.isAcyclic(); if (acyclic) { if (isAlphaSorted[0]) { final List<String> sortedNodes = new ArrayList<>(generator.getNodes()); Collections.sort(sortedNodes, String.CASE_INSENSITIVE_ORDER); return Pair.create(sortedNodes, true); } else { final List<String> dfsNodes = dfstBuilder.getSortedNodes(); Collections.reverse(dfsNodes); return Pair.create(dfsNodes, false); } } else { return null; } }