repository libraries: add option to exclude only some transitive dependencies (IDEA-193045)

This commit is contained in:
nik
2018-05-31 14:33:45 +03:00
parent e515496621
commit 735d40847b
24 changed files with 628 additions and 56 deletions
@@ -0,0 +1,27 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.aether;
import org.eclipse.aether.artifact.Artifact;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class ArtifactDependencyNode {
private final Artifact myArtifact;
private final List<ArtifactDependencyNode> myDependencies;
public ArtifactDependencyNode(@NotNull Artifact artifact, @NotNull List<ArtifactDependencyNode> dependencies) {
myArtifact = artifact;
myDependencies = dependencies;
}
@NotNull
public Artifact getArtifact() {
return myArtifact;
}
@NotNull
public List<ArtifactDependencyNode> getDependencies() {
return myDependencies;
}
}
@@ -10,6 +10,7 @@ import org.eclipse.aether.collection.CollectResult;
import org.eclipse.aether.collection.DependencyCollectionException;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.graph.DependencyVisitor;
import org.eclipse.aether.impl.DefaultServiceLocator;
@@ -151,16 +152,34 @@ public class ArtifactRepositoryManager {
);
}
public Collection<File> resolveDependency(String groupId, String artifactId, String version, boolean includeTransitiveDependencies) throws Exception {
public Collection<File> resolveDependency(String groupId, String artifactId, String version, boolean includeTransitiveDependencies,
List<String> excludedDependencies) throws Exception {
final List<File> files = new ArrayList<>();
for (Artifact artifact : resolveDependencyAsArtifact(groupId, artifactId, version, EnumSet.of(ArtifactKind.ARTIFACT), includeTransitiveDependencies)) {
for (Artifact artifact : resolveDependencyAsArtifact(groupId, artifactId, version, EnumSet.of(ArtifactKind.ARTIFACT), includeTransitiveDependencies,
excludedDependencies)) {
files.add(artifact.getFile());
}
return files;
}
@Nullable
public ArtifactDependencyNode collectDependencies(String groupId, String artifactId, String versionConstraint) throws Exception {
Set<VersionConstraint> constraints = Collections.singleton(asVersionConstraint(versionConstraint));
CollectRequest collectRequest = createCollectRequest(groupId, artifactId, constraints, EnumSet.of(ArtifactKind.ARTIFACT));
ArtifactDependencyTreeBuilder builder = new ArtifactDependencyTreeBuilder();
DependencyNode root = ourSystem.collectDependencies(mySession, collectRequest).getRoot();
if (root.getArtifact() == null && root.getChildren().size() == 1) {
root = root.getChildren().get(0);
}
root.accept(new TreeDependencyVisitor(new FilteringDependencyVisitor(builder, createScopeFilter())));
return builder.getRoot();
}
@NotNull
public Collection<Artifact> resolveDependencyAsArtifact(String groupId, String artifactId, String versionConstraint, Set<ArtifactKind> artifactKinds, boolean includeTransitiveDependencies) throws Exception {final List<Artifact> artifacts = new ArrayList<>();
public Collection<Artifact> resolveDependencyAsArtifact(String groupId, String artifactId, String versionConstraint,
Set<ArtifactKind> artifactKinds, boolean includeTransitiveDependencies,
List<String> excludedDependencies) throws Exception {
final List<Artifact> artifacts = new ArrayList<>();
final Set<VersionConstraint> constraints = Collections.singleton(asVersionConstraint(versionConstraint));
for (ArtifactKind kind : artifactKinds) {
// RepositorySystem.resolveDependencies() ignores classifiers, so we need to set classifiers explicitly for discovered dependencies.
@@ -172,9 +191,11 @@ public class ArtifactRepositoryManager {
mySession, createCollectRequest(groupId, artifactId, constraints, EnumSet.of(kind))
);
final ArtifactRequestBuilder builder = new ArtifactRequestBuilder(kind);
collectResult.getRoot().accept(new TreeDependencyVisitor(
new FilteringDependencyVisitor(builder, DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE, JavaScopes.RUNTIME))
));
DependencyFilter filter = createScopeFilter();
if (!excludedDependencies.isEmpty()) {
filter = DependencyFilterUtils.andFilter(filter, new ExcludeDependenciesFilter(excludedDependencies));
}
collectResult.getRoot().accept(new TreeDependencyVisitor(new FilteringDependencyVisitor(builder, filter)));
requests = builder.getRequests();
}
else {
@@ -220,6 +241,11 @@ public class ArtifactRepositoryManager {
return artifacts;
}
@NotNull
private static DependencyFilter createScopeFilter() {
return DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE, JavaScopes.RUNTIME);
}
public List<Version> getAvailableVersions(String groupId, String artifactId, String versionConstraint, final ArtifactKind artifactKind) throws Exception {
final VersionRangeResult result = ourSystem.resolveVersionRange(
mySession, createVersionRangeRequest(groupId, artifactId, asVersionConstraint(versionConstraint), artifactKind)
@@ -325,4 +351,60 @@ public class ArtifactRepositoryManager {
return myRequests;
}
}
private static class ExcludeDependenciesFilter implements DependencyFilter {
private final HashSet<String> myExcludedDependencies;
public ExcludeDependenciesFilter(List<String> excludedDependencies) {
myExcludedDependencies = new HashSet<>(excludedDependencies);
}
@Override
public boolean accept(DependencyNode node, List<DependencyNode> parents) {
Artifact artifact = node.getArtifact();
if (artifact != null && myExcludedDependencies.contains(artifact.getGroupId() + ":" + artifact.getArtifactId())) {
return false;
}
for (DependencyNode parent : parents) {
Artifact parentArtifact = parent.getArtifact();
if (parentArtifact != null && myExcludedDependencies.contains(parentArtifact.getGroupId() + ":" + parentArtifact.getArtifactId())) {
return false;
}
}
return true;
}
}
private static class ArtifactDependencyTreeBuilder implements DependencyVisitor {
private final List<List<ArtifactDependencyNode>> myCurrentChildren = new ArrayList<>();
public ArtifactDependencyTreeBuilder() {
myCurrentChildren.add(new ArrayList<>());
}
@Override
public boolean visitEnter(DependencyNode node) {
Artifact artifact = node.getArtifact();
if (artifact == null) return false;
myCurrentChildren.add(new ArrayList<>());
return true;
}
@Override
public boolean visitLeave(DependencyNode node) {
Artifact artifact = node.getArtifact();
if (artifact != null) {
List<ArtifactDependencyNode> last = myCurrentChildren.get(myCurrentChildren.size() - 1);
myCurrentChildren.remove(myCurrentChildren.size() - 1);
myCurrentChildren.get(myCurrentChildren.size() - 1).add(new ArtifactDependencyNode(artifact, last));
}
return true;
}
public ArtifactDependencyNode getRoot() {
List<ArtifactDependencyNode> rootNodes = myCurrentChildren.get(0);
return rootNodes.isEmpty() ? null : rootNodes.get(0);
}
}
}
@@ -18,9 +18,11 @@ package org.jetbrains.idea.maven.aether;
import com.intellij.testFramework.UsefulTestCase;
import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtil;
import org.eclipse.aether.artifact.Artifact;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
/**
* @author nik
@@ -36,17 +38,56 @@ public class ArtifactRepositoryManagerTest extends UsefulTestCase {
}
public void testResolveTransitively() throws Exception {
Collection<File> files = myRepositoryManager.resolveDependency("junit", "junit", "4.12", true);
assertSameElements(ContainerUtil.map(files, File::getName), "junit-4.12.jar", "hamcrest-core-1.3.jar");
Collection<File> files = myRepositoryManager.resolveDependency("junit", "junit", "4.12", true, Collections.emptyList());
assertFileNames(files, "junit-4.12.jar", "hamcrest-core-1.3.jar");
}
public void testResolveNonTransitively() throws Exception {
Collection<File> files = myRepositoryManager.resolveDependency("junit", "junit", "4.12", false);
assertSameElements(ContainerUtil.map(files, File::getName), "junit-4.12.jar");
Collection<File> files = myRepositoryManager.resolveDependency("junit", "junit", "4.12", false, Collections.emptyList());
assertFileNames(files, "junit-4.12.jar");
}
public void testExcludeDirectDependency() throws Exception {
Collection<File> all = myRepositoryManager.resolveDependency("junit", "junit", "4.12", true, Collections.singletonList("org.hamcrest:wrong"));
assertFileNames(all, "junit-4.12.jar", "hamcrest-core-1.3.jar");
Collection<File> excluded = myRepositoryManager.resolveDependency("junit", "junit", "4.12", true, Collections.singletonList("org.hamcrest:hamcrest-core"));
assertFileNames(excluded, "junit-4.12.jar");
}
public void testExcludeDependenciesTransitively() throws Exception {
Collection<File> all = myRepositoryManager.resolveDependency("org.apache.httpcomponents", "fluent-hc", "4.5.5", true, Collections.emptyList());
assertFileNames(all, "fluent-hc-4.5.5.jar", "httpclient-4.5.5.jar", "httpcore-4.4.9.jar", "commons-logging-1.2.jar", "commons-codec-1.10.jar");
Collection<File> excluded = myRepositoryManager.resolveDependency("org.apache.httpcomponents", "fluent-hc", "4.5.5", true, Collections.singletonList("org.apache.httpcomponents:httpclient"));
assertFileNames(excluded, "fluent-hc-4.5.5.jar", "commons-logging-1.2.jar");
}
public void testResolveRuntimeDependencies() throws Exception {
Collection<File> files = myRepositoryManager.resolveDependency("com.netflix.feign", "feign-jackson", "8.18.0", true);
Collection<File> files = myRepositoryManager.resolveDependency("com.netflix.feign", "feign-jackson", "8.18.0", true,
Collections.emptyList());
assertContainsElements(ContainerUtil.map(files, File::getName), "feign-core-8.18.0.jar");
}
public void testCollectDependencies() throws Exception {
ArtifactDependencyNode result = myRepositoryManager.collectDependencies("org.apache.httpcomponents", "fluent-hc", "4.5.5");
assertNotNull(result);
assertCoordinates(result.getArtifact(), "org.apache.httpcomponents", "fluent-hc", "4.5.5");
assertEquals(2, result.getDependencies().size());
ArtifactDependencyNode first = result.getDependencies().get(0);
ArtifactDependencyNode second = result.getDependencies().get(1);
assertCoordinates(first.getArtifact(), "org.apache.httpcomponents", "httpclient", "4.5.5");
assertCoordinates(second.getArtifact(), "commons-logging", "commons-logging", "1.2");
assertEquals(2, first.getDependencies().size());
assertCoordinates(first.getDependencies().get(0).getArtifact(), "org.apache.httpcomponents", "httpcore", "4.4.9");
assertCoordinates(first.getDependencies().get(1).getArtifact(), "commons-codec", "commons-codec", "1.10");
}
private static void assertCoordinates(Artifact artifact, String groupId, String artifactId, String version) {
assertEquals(groupId, artifact.getGroupId());
assertEquals(artifactId, artifact.getArtifactId());
assertEquals(version, artifact.getVersion());
}
private static void assertFileNames(Collection<File> files, String... expectedNames) {
assertSameElements(ContainerUtil.map(files, File::getName), expectedNames);
}
}
@@ -53,6 +53,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.concurrency.AsyncPromise;
import org.jetbrains.concurrency.Promise;
import org.jetbrains.idea.maven.aether.ArtifactDependencyNode;
import org.jetbrains.idea.maven.aether.ArtifactKind;
import org.jetbrains.idea.maven.aether.ArtifactRepositoryManager;
import org.jetbrains.idea.maven.aether.ProgressConsumer;
@@ -265,6 +266,27 @@ public class JarRepositoryManager {
return submitBackgroundJob(project, "Looking up available versions for " + libraryDescription.getDisplayName(), new VersionResolveJob(libraryDescription, repos));
}
@Nullable
public static ArtifactDependencyNode loadDependenciesTree(@NotNull RepositoryLibraryDescription description, @NotNull String version, Project project) {
List<RemoteRepositoryDescription> repositories = RemoteRepositoriesConfiguration.getInstance(project).getRepositories();
return submitModalJob(project, "Resolving Maven Dependencies", new AetherJob<ArtifactDependencyNode>(repositories) {
@Override
protected String getProgressText() {
return "Loading dependencies of " + description.getMavenCoordinates(version);
}
@Override
protected ArtifactDependencyNode perform(ProgressIndicator progress, ArtifactRepositoryManager manager) throws Exception {
return manager.collectDependencies(description.getGroupId(), description.getArtifactId(), version);
}
@Override
protected ArtifactDependencyNode getDefaultResult() {
return null;
}
});
}
private static void notifyArtifactsDownloaded(Project project, Collection<OrderRoot> roots) {
final StringBuilder sb = new StringBuilder();
final String title = "The following files were downloaded:";
@@ -533,7 +555,7 @@ public class JarRepositoryManager {
final String version = myDesc.getVersion();
try {
return manager.resolveDependencyAsArtifact(myDesc.getGroupId(), myDesc.getArtifactId(), version, myKinds,
myDesc.isIncludeTransitiveDependencies());
myDesc.isIncludeTransitiveDependencies(), myDesc.getExcludedDependencies());
}
catch (TransferCancelledException e) {
throw new ProcessCanceledException(e);
@@ -548,7 +570,7 @@ public class JarRepositoryManager {
}
try {
return manager.resolveDependencyAsArtifact(myDesc.getGroupId(), myDesc.getArtifactId(), resolvedVersion, myKinds,
myDesc.isIncludeTransitiveDependencies());
myDesc.isIncludeTransitiveDependencies(), myDesc.getExcludedDependencies());
}
catch (TransferCancelledException e1) {
throw new ProcessCanceledException(e1);
@@ -38,7 +38,8 @@ public class RepositoryLibrarySupportInModuleConfigurable extends FrameworkSuppo
public RepositoryLibrarySupportInModuleConfigurable(@Nullable Project project, @NotNull RepositoryLibraryDescription libraryDescription) {
this.libraryDescription = libraryDescription;
RepositoryLibraryProperties defaultProperties = libraryDescription.createDefaultProperties();
this.model = new RepositoryLibraryPropertiesModel(defaultProperties.getVersion(), false, false, defaultProperties.isIncludeTransitiveDependencies());
this.model = new RepositoryLibraryPropertiesModel(defaultProperties.getVersion(), false, false, defaultProperties.isIncludeTransitiveDependencies(),
defaultProperties.getExcludedDependencies());
editor = new RepositoryLibraryPropertiesEditor(project, model, libraryDescription);
}
@@ -50,7 +50,8 @@ public class RepositoryLibraryWithDescriptionEditor
RepositoryLibraryPropertiesModel model = new RepositoryLibraryPropertiesModel(
properties.getVersion(),
RepositoryUtils.libraryHasSources(myEditorComponent.getLibraryEditor()),
RepositoryUtils.libraryHasJavaDocs(myEditorComponent.getLibraryEditor()), properties.isIncludeTransitiveDependencies());
RepositoryUtils.libraryHasJavaDocs(myEditorComponent.getLibraryEditor()), properties.isIncludeTransitiveDependencies(),
properties.getExcludedDependencies());
final Project project = myEditorComponent.getProject();
assert project != null : "EditorComponent's project must not be null in order to be used with RepositoryLibraryWithDescriptionEditor";
@@ -65,6 +66,7 @@ public class RepositoryLibraryWithDescriptionEditor
}
myEditorComponent.getProperties().changeVersion(model.getVersion());
myEditorComponent.getProperties().setIncludeTransitiveDependencies(model.isIncludeTransitiveDependencies());
myEditorComponent.getProperties().setExcludedDependencies(model.getExcludedDependencies());
if (wasGeneratedName) {
myEditorComponent.renameLibrary(RepositoryLibraryType.getInstance().getDescription(properties));
}
@@ -0,0 +1,114 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.jarRepository.settings;
import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.panel.ComponentPanelBuilder;
import com.intellij.ui.CheckboxTree;
import com.intellij.ui.CheckboxTreeBase;
import com.intellij.ui.CheckedTreeNode;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.ui.UI;
import com.intellij.util.ui.tree.TreeUtil;
import org.eclipse.aether.artifact.Artifact;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.aether.ArtifactDependencyNode;
import javax.swing.*;
import java.util.*;
class DependencyExclusionEditor {
private final CheckboxTree myDependenciesTree;
private final CheckedTreeNode myRootNode;
private final JPanel myMainPanel;
public DependencyExclusionEditor(ArtifactDependencyNode root, JPanel parentComponent) {
myMainPanel = parentComponent;
myRootNode = createDependencyTreeNode(root);
CheckboxTreeBase.CheckPolicy policy = new CheckboxTreeBase.CheckPolicy(false, true, true, false);
myDependenciesTree = new CheckboxTree(new CheckboxTree.CheckboxTreeCellRenderer() {
{
myIgnoreInheritance = true;
}
@Override
public void customizeRenderer(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
if (!(value instanceof CheckedTreeNode)) return;
Object userObject = ((CheckedTreeNode)value).getUserObject();
if (!(userObject instanceof Artifact)) return;
Artifact artifact = (Artifact)userObject;
getTextRenderer().append(artifact.getGroupId() + ":" + artifact.getArtifactId(), SimpleTextAttributes.REGULAR_ATTRIBUTES, true);
getTextRenderer().append(":" + artifact.getVersion(), SimpleTextAttributes.GRAYED_ATTRIBUTES, true);
}
}, myRootNode, policy);
myDependenciesTree.setRootVisible(false);
}
@Nullable
public Set<String> selectExcludedDependencies(List<String> excludedDependencies) {
uncheckExcludedNodes(myRootNode, new HashSet<>(excludedDependencies), false);
TreeUtil.expandAll(myDependenciesTree);
ComponentPanelBuilder panelBuilder =
UI.PanelFactory.panel(new JBScrollPane(myDependenciesTree))
.withLabel("Specify which transitive dependencies should be included into the library.")
.moveLabelOnTop();
DialogBuilder dialogBuilder =
new DialogBuilder(myMainPanel)
.title("Configure Transitive Dependencies")
.centerPanel(panelBuilder.createPanel());
dialogBuilder.setPreferredFocusComponent(myDependenciesTree);
if (dialogBuilder.showAndGet()) {
return collectUncheckedNodes(myRootNode, new LinkedHashSet<>());
}
return null;
}
private static void uncheckExcludedNodes(CheckedTreeNode node, Set<String> excluded, boolean parentIsExcluded) {
boolean isExcluded = parentIsExcluded || excluded.contains(getGroupAndArtifactId(node));
node.setChecked(!isExcluded);
Enumeration children = node.children();
while (children.hasMoreElements()) {
Object child = children.nextElement();
uncheckExcludedNodes((CheckedTreeNode)child, excluded, isExcluded);
}
}
private static Set<String> collectUncheckedNodes(CheckedTreeNode node, Set<String> result) {
if (node.isChecked()) {
Enumeration children = node.children();
while (children.hasMoreElements()) {
Object child = children.nextElement();
collectUncheckedNodes((CheckedTreeNode)child, result);
}
}
else {
result.add(getGroupAndArtifactId(node));
}
return result;
}
@NotNull
private static String getGroupAndArtifactId(CheckedTreeNode node) {
Artifact artifact = (Artifact)node.getUserObject();
return artifact.getGroupId() + ":" + artifact.getArtifactId();
}
@NotNull
private static CheckedTreeNode createDependencyTreeNode(ArtifactDependencyNode node) {
CheckedTreeNode treeNode = new CheckedTreeNode(node.getArtifact());
for (ArtifactDependencyNode dependency : node.getDependencies()) {
treeNode.add(createDependencyTreeNode(dependency));
}
return treeNode;
}
}
@@ -135,14 +135,14 @@
<text value="Download &amp;JavaDocs"/>
</properties>
</component>
<component id="75440" class="com.intellij.ui.components.JBCheckBox" binding="myIncludeTransitiveDepsCheckBox">
<grid id="2c1fe" binding="myTransitiveDependenciesPanel" layout-manager="FlowLayout" hgap="0" vgap="0" flow-align="1">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Include &amp;transitive dependencies"/>
</properties>
</component>
<properties/>
<border type="none"/>
<children/>
</grid>
</children>
</grid>
</children>
@@ -19,15 +19,21 @@ import com.google.common.base.Strings;
import com.intellij.jarRepository.JarRepositoryManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.ui.CollectionComboBoxModel;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.labels.SwingActionLink;
import com.intellij.util.containers.JBIterable;
import com.intellij.util.ui.ThreeStateCheckBox;
import com.intellij.util.ui.UI;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.aether.ArtifactDependencyNode;
import org.jetbrains.idea.maven.utils.library.RepositoryLibraryDescription;
import org.jetbrains.idea.maven.utils.library.propertiesEditor.RepositoryLibraryPropertiesModel;
@@ -39,11 +45,11 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.*;
import java.util.List;
public class RepositoryLibraryPropertiesEditor {
private static final Logger LOG = Logger.getInstance(RepositoryLibraryPropertiesEditor.class);
@NotNull private final Project project;
State currentState;
List<String> versions;
@@ -59,10 +65,12 @@ public class RepositoryLibraryPropertiesEditor {
private JBCheckBox downloadSourcesCheckBox;
private JBCheckBox downloadJavaDocsCheckBox;
private JBLabel mavenCoordinates;
private JBCheckBox myIncludeTransitiveDepsCheckBox;
private final ThreeStateCheckBox myIncludeTransitiveDepsCheckBox;
private JPanel myPropertiesPanel;
private JPanel myTransitiveDependenciesPanel;
@NotNull private final ModelChangeListener onChangeListener;
private final SwingActionLink myManageDependenciesLink;
public interface ModelChangeListener {
void onChange(RepositoryLibraryPropertiesEditor editor);
@@ -90,7 +98,18 @@ public class RepositoryLibraryPropertiesEditor {
this.project = project == null ? ProjectManager.getInstance().getDefaultProject() : project;
repositoryLibraryDescription = description;
mavenCoordinates.setCopyable(true);
myIncludeTransitiveDepsCheckBox.setVisible(allowExcludingTransitiveDependencies);
myIncludeTransitiveDepsCheckBox = new ThreeStateCheckBox(UIUtil.replaceMnemonicAmpersand("Include &transitive dependencies"));
myIncludeTransitiveDepsCheckBox.setThirdStateEnabled(false);
myTransitiveDependenciesPanel.add(myIncludeTransitiveDepsCheckBox);
myManageDependenciesLink = new SwingActionLink(new AbstractAction("Configure") {
@Override
public void actionPerformed(ActionEvent e) {
configureTransitiveDependencies();
}
});
myManageDependenciesLink.setBorder(UI.Borders.emptyLeft(10));
myTransitiveDependenciesPanel.add(myManageDependenciesLink);
myTransitiveDependenciesPanel.setVisible(allowExcludingTransitiveDependencies);
myReloadButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -104,9 +123,25 @@ public class RepositoryLibraryPropertiesEditor {
mavenCoordinates.setText(repositoryLibraryDescription.getMavenCoordinates(model.getVersion()));
}
};
updateManageDependenciesLink();
reloadVersionsAsync();
}
private void configureTransitiveDependencies() {
String selectedVersion = getSelectedVersion();
LOG.assertTrue(selectedVersion != null);
ArtifactDependencyNode root = JarRepositoryManager.loadDependenciesTree(repositoryLibraryDescription, selectedVersion, project);
if (root == null) return;
Set<String> dependencies = new DependencyExclusionEditor(root, mainPanel).selectExcludedDependencies(model.getExcludedDependencies());
if (dependencies != null) {
model.setExcludedDependencies(dependencies);
updateIncludeTransitiveDepsCheckBoxState();
onChangeListener.onChange(this);
}
}
private static VersionKind getVersionKind(String version) {
if (Strings.isNullOrEmpty(version)) {
return VersionKind.Unselected;
@@ -168,6 +203,7 @@ public class RepositoryLibraryPropertiesEditor {
int selection = getSelection(model.getVersion(), versions);
versionSelector.setSelectedIndex(selection);
onChangeListener.onChange(this);
updateManageDependenciesLink();
}
private VersionKind getSelectedVersionKind() {
@@ -225,6 +261,7 @@ public class RepositoryLibraryPropertiesEditor {
public void itemStateChanged(ItemEvent e) {
model.setVersion(getSelectedVersion());
onChangeListener.onChange(RepositoryLibraryPropertiesEditor.this);
updateManageDependenciesLink();
}
});
downloadSourcesCheckBox.setSelected(model.isDownloadSources());
@@ -243,16 +280,31 @@ public class RepositoryLibraryPropertiesEditor {
onChangeListener.onChange(RepositoryLibraryPropertiesEditor.this);
}
});
myIncludeTransitiveDepsCheckBox.setSelected(model.isIncludeTransitiveDependencies());
updateIncludeTransitiveDepsCheckBoxState();
myIncludeTransitiveDepsCheckBox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
model.setIncludeTransitiveDependencies(myIncludeTransitiveDepsCheckBox.isSelected());
updateManageDependenciesLink();
ThreeStateCheckBox.State state = myIncludeTransitiveDepsCheckBox.getState();
if (state != ThreeStateCheckBox.State.DONT_CARE) {
model.setExcludedDependencies(Collections.emptyList());
}
model.setIncludeTransitiveDependencies(state != ThreeStateCheckBox.State.NOT_SELECTED);
onChangeListener.onChange(RepositoryLibraryPropertiesEditor.this);
}
});
updateManageDependenciesLink();
}
private void updateIncludeTransitiveDepsCheckBoxState() {
myIncludeTransitiveDepsCheckBox.setState(!model.isIncludeTransitiveDependencies() ? ThreeStateCheckBox.State.NOT_SELECTED :
model.getExcludedDependencies().isEmpty() ? ThreeStateCheckBox.State.SELECTED : ThreeStateCheckBox.State.DONT_CARE);
}
private void updateManageDependenciesLink() {
boolean enable = myIncludeTransitiveDepsCheckBox.getState() != ThreeStateCheckBox.State.NOT_SELECTED && getSelectedVersion() != null;
myManageDependenciesLink.setEnabled(enable);
}
private void versionsLoaded(final @Nullable List<String> versions) {
this.versions = versions;
@@ -80,7 +80,8 @@ abstract class ConvertToRepositoryLibraryActionBase(protected val context: Struc
private fun downloadLibraryAndReplace(library: LibraryEx,
mavenCoordinates: JpsMavenRepositoryLibraryDescriptor) {
val libraryProperties = RepositoryLibraryProperties(mavenCoordinates.groupId, mavenCoordinates.artifactId, mavenCoordinates.version, mavenCoordinates.isIncludeTransitiveDependencies)
val libraryProperties = RepositoryLibraryProperties(mavenCoordinates.groupId, mavenCoordinates.artifactId, mavenCoordinates.version,
mavenCoordinates.isIncludeTransitiveDependencies, mavenCoordinates.excludedDependencies)
val hasSources = RepositoryUtils.libraryHasSources(library)
val hasJavadoc = RepositoryUtils.libraryHasJavaDocs(library)
LOG.debug("Resolving $mavenCoordinates")
@@ -151,7 +152,8 @@ abstract class ConvertToRepositoryLibraryActionBase(protected val context: Struc
return null
}
return JpsMavenRepositoryLibraryDescriptor(dialog.coordinateText, dialog.includeTransitiveDependencies)
return JpsMavenRepositoryLibraryDescriptor(dialog.coordinateText, dialog.includeTransitiveDependencies,
emptyList<String>())
}
private fun replaceByLibrary(library: Library, configuration: NewLibraryConfiguration) {
@@ -74,7 +74,8 @@ public class RepositoryLibrarySupport {
libraryDescription.getGroupId(),
libraryDescription.getArtifactId(),
model.getVersion(),
model.isIncludeTransitiveDependencies());
model.isIncludeTransitiveDependencies(),
model.getExcludedDependencies());
final LibraryEx library = (LibraryEx)modifiableModel.createLibrary(
LibraryEditingUtil.suggestNewLibraryName(modifiableModel, RepositoryLibraryType.getInstance().getDescription(libraryProperties)),
RepositoryLibraryType.REPOSITORY_LIBRARY_KIND);
@@ -16,27 +16,35 @@
package org.jetbrains.idea.maven.utils.library.propertiesEditor;
import com.google.common.base.Strings;
import com.intellij.util.containers.ContainerUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class RepositoryLibraryPropertiesModel {
private String version;
private boolean downloadSources;
private boolean downloadJavaDocs;
private boolean includeTransitiveDependencies;
private List<String> myExcludedDependencies;
public RepositoryLibraryPropertiesModel(String version, boolean downloadSources, boolean downloadJavaDocs) {
this(version, downloadSources, downloadJavaDocs, true);
this(version, downloadSources, downloadJavaDocs, true, ContainerUtil.emptyList());
}
public RepositoryLibraryPropertiesModel(String version, boolean downloadSources, boolean downloadJavaDocs,
boolean includeTransitiveDependencies) {
boolean includeTransitiveDependencies, List<String> excludedDependencies) {
this.version = version;
this.downloadSources = downloadSources;
this.downloadJavaDocs = downloadJavaDocs;
this.includeTransitiveDependencies = includeTransitiveDependencies;
myExcludedDependencies = new ArrayList<>(excludedDependencies);
}
public RepositoryLibraryPropertiesModel clone() {
return new RepositoryLibraryPropertiesModel(version, downloadSources, downloadJavaDocs, includeTransitiveDependencies);
return new RepositoryLibraryPropertiesModel(version, downloadSources, downloadJavaDocs, includeTransitiveDependencies,
new ArrayList<>(myExcludedDependencies));
}
public boolean isValid() {
@@ -51,6 +59,14 @@ public class RepositoryLibraryPropertiesModel {
this.includeTransitiveDependencies = includeTransitiveDependencies;
}
public List<String> getExcludedDependencies() {
return myExcludedDependencies;
}
public void setExcludedDependencies(Collection<String> excludedDependencies) {
myExcludedDependencies = new ArrayList<>(excludedDependencies);
}
public boolean isDownloadSources() {
return downloadSources;
}
@@ -86,7 +102,7 @@ public class RepositoryLibraryPropertiesModel {
if (downloadJavaDocs != model.downloadJavaDocs) return false;
if (includeTransitiveDependencies != model.includeTransitiveDependencies) return false;
if (version != null ? !version.equals(model.version) : model.version != null) return false;
if (!myExcludedDependencies.equals(model.myExcludedDependencies)) return false;
return true;
}
@@ -96,6 +112,7 @@ public class RepositoryLibraryPropertiesModel {
result = 31 * result + (downloadJavaDocs ? 1 : 0);
result = 31 * result + (includeTransitiveDependencies ? 1 : 0);
result = 31 * result + (version != null ? version.hashCode() : 0);
result = 31 * result + myExcludedDependencies.hashCode();
return result;
}
}
@@ -112,7 +112,7 @@ public abstract class AbstractTestFrameworkIntegrationTest extends BaseConfigura
ArtifactRepositoryManager repoManager) throws Exception {
Collection<File> files = repoManager.resolveDependency(descriptor.getGroupId(), descriptor.getArtifactId(), descriptor.getVersion(),
descriptor.isIncludeTransitiveDependencies());
descriptor.isIncludeTransitiveDependencies(), descriptor.getExcludedDependencies());
assertFalse("No files retrieved for: " + descriptor.getGroupId(), files.isEmpty());
for (File artifact : files) {
VirtualFile libJarLocal = LocalFileSystem.getInstance().findFileByIoFile(artifact);
@@ -0,0 +1,53 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.roots.libraries;
import com.intellij.jarRepository.RepositoryLibraryType;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.roots.impl.libraries.LibraryEx;
import com.intellij.openapi.roots.impl.libraries.LibraryTableBase;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.roots.ModuleRootManagerTestCase;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.utils.library.RepositoryLibraryProperties;
import java.io.IOException;
public class RepositoryLibrarySerializationTest extends ModuleRootManagerTestCase {
public void testPlain() throws JDOMException, IOException {
RepositoryLibraryProperties properties = loadLibrary("plain");
assertEquals("junit", properties.getGroupId());
assertEquals("junit", properties.getArtifactId());
assertEquals("3.8.1", properties.getVersion());
assertTrue(properties.isIncludeTransitiveDependencies());
assertEmpty(properties.getExcludedDependencies());
}
public void testWithoutTransitiveDependencies() throws JDOMException, IOException {
RepositoryLibraryProperties properties = loadLibrary("without-transitive-dependencies");
assertFalse(properties.isIncludeTransitiveDependencies());
assertEmpty(properties.getExcludedDependencies());
}
public void testWithExcludedDependencies() throws JDOMException, IOException {
RepositoryLibraryProperties properties = loadLibrary("with-excluded-dependencies");
assertTrue(properties.isIncludeTransitiveDependencies());
assertSameElements(properties.getExcludedDependencies(), "org.apache.httpcomponents:httpclient");
}
@NotNull
private RepositoryLibraryProperties loadLibrary(String name) throws JDOMException, IOException {
String libraryPath = "jps/model-serialization/testData/repositoryLibraries/.idea/libraries/" + name + ".xml";
Element element = JDOMUtil.load(PathManagerEx.findFileUnderCommunityHome(libraryPath));
LibraryTableBase libraryTable = (LibraryTableBase)LibraryTablesRegistrar.getInstance().getLibraryTable(myProject);
libraryTable.loadState(element);
LibraryEx library = (LibraryEx)libraryTable.getLibraryByName(name);
assertNotNull(library);
assertSame(RepositoryLibraryType.REPOSITORY_LIBRARY_KIND, library.getKind());
RepositoryLibraryProperties properties = (RepositoryLibraryProperties)library.getProperties();
assertNotNull(properties);
return properties;
}
}
@@ -17,7 +17,7 @@ package org.jetbrains.idea.maven.utils.library;
import com.intellij.jarRepository.RepositoryLibraryDefinition;
import com.intellij.openapi.roots.DependencyScope;
import java.util.HashMap;
import com.intellij.util.containers.ContainerUtil;
import icons.OpenapiIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -25,6 +25,7 @@ import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor;
import javax.swing.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class RepositoryLibraryDescription {
@@ -112,7 +113,7 @@ public class RepositoryLibraryDescription {
}
public RepositoryLibraryProperties createDefaultProperties() {
return new RepositoryLibraryProperties(getGroupId(), getArtifactId(), ReleaseVersionId, true);
return new RepositoryLibraryProperties(getGroupId(), getArtifactId(), ReleaseVersionId, true, ContainerUtil.emptyList());
}
public String getDisplayName(String version) {
@@ -3,10 +3,16 @@ package org.jetbrains.idea.maven.utils.library;
import com.intellij.openapi.roots.libraries.LibraryProperties;
import com.intellij.openapi.util.Comparing;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.annotations.Attribute;
import com.intellij.util.xmlb.annotations.Transient;
import com.intellij.util.xmlb.annotations.XCollection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
/**
@@ -19,15 +25,19 @@ public class RepositoryLibraryProperties extends LibraryProperties<RepositoryLib
}
public RepositoryLibraryProperties(String mavenId, final boolean includeTransitiveDependencies) {
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(mavenId, includeTransitiveDependencies);
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(mavenId, includeTransitiveDependencies, Collections.emptyList());
}
public RepositoryLibraryProperties(@NotNull String groupId, @NotNull String artifactId, @NotNull String version) {
this(groupId, artifactId, version, true);
this(groupId, artifactId, version, true, ContainerUtil.emptyList());
}
public RepositoryLibraryProperties(@NotNull String groupId, @NotNull String artifactId, @NotNull String version, boolean includeTransitiveDependencies) {
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(groupId, artifactId, version, includeTransitiveDependencies);
public RepositoryLibraryProperties(@NotNull String groupId,
@NotNull String artifactId,
@NotNull String version,
boolean includeTransitiveDependencies, @NotNull List<String> excludedDependencies) {
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(groupId, artifactId, version, includeTransitiveDependencies,
excludedDependencies);
}
@Override
@@ -56,7 +66,7 @@ public class RepositoryLibraryProperties extends LibraryProperties<RepositoryLib
}
public void setMavenId(String mavenId) {
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(mavenId, isIncludeTransitiveDependencies());
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(mavenId, isIncludeTransitiveDependencies(), getExcludedDependencies());
}
@Attribute("include-transitive-deps")
@@ -65,7 +75,7 @@ public class RepositoryLibraryProperties extends LibraryProperties<RepositoryLib
}
public void setIncludeTransitiveDependencies(boolean value) {
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(getMavenId(), value);
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(getMavenId(), value, getExcludedDependencies());
}
public String getGroupId() {
@@ -81,7 +91,7 @@ public class RepositoryLibraryProperties extends LibraryProperties<RepositoryLib
}
public void changeVersion(String version) {
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(getGroupId(), getArtifactId(), version, myDescriptor.isIncludeTransitiveDependencies());
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(getGroupId(), getArtifactId(), version, myDescriptor.isIncludeTransitiveDependencies(), myDescriptor.getExcludedDependencies());
}
private String call(Function<JpsMavenRepositoryLibraryDescriptor, String> method) {
@@ -89,8 +99,31 @@ public class RepositoryLibraryProperties extends LibraryProperties<RepositoryLib
return descriptor != null ? method.apply(descriptor) : null;
}
/**
* Returns list of excluded transitive dependencies in {@code "<groupId>:<artifactId>"} format.
*/
@Transient
public List<String> getExcludedDependencies() {
return myDescriptor != null ? myDescriptor.getExcludedDependencies() : Collections.emptyList();
}
public void setExcludedDependencies(List<String> dependencyMavenIds) {
myDescriptor = new JpsMavenRepositoryLibraryDescriptor(getMavenId(), isIncludeTransitiveDependencies(), dependencyMavenIds);
}
@SuppressWarnings("unused") //we need to have a separate method here because XmlSerializer fails if the returned list is unmodifiable
@XCollection(propertyElementName = "exclude", elementName = "dependency", valueAttributeName = "maven-id")
public List<String> getExcludedDependenciesBean() {
return myDescriptor != null ? new ArrayList<>(myDescriptor.getExcludedDependencies()) : new ArrayList<>();
}
@SuppressWarnings("unused") //used by XmlSerializer
public void setExcludedDependenciesBean(List<String> dependencyMavenIds) {
setExcludedDependencies(dependencyMavenIds);
}
@NotNull
public JpsMavenRepositoryLibraryDescriptor getRepositoryLibraryDescriptor() {
return myDescriptor != null ? myDescriptor : new JpsMavenRepositoryLibraryDescriptor(null, true);
return myDescriptor != null ? myDescriptor : new JpsMavenRepositoryLibraryDescriptor(null, true, Collections.emptyList());
}
}
@@ -147,7 +147,8 @@ public class DependencyResolvingBuilder extends ModuleLevelBuilder{
context.processMessage(new ProgressMessage("Resolving '" + lib.getName() + "' library..."));
LOG.debug("Downloading missing files for " + lib.getName() + " library: " + required);
final Collection<File> resolved = repoManager.resolveDependency(descriptor.getGroupId(), descriptor.getArtifactId(),
descriptor.getVersion(), descriptor.isIncludeTransitiveDependencies());
descriptor.getVersion(), descriptor.isIncludeTransitiveDependencies(),
descriptor.getExcludedDependencies());
if (!resolved.isEmpty()) {
syncPaths(required, resolved);
}
@@ -18,6 +18,8 @@ package org.jetbrains.jps.model.library;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
@@ -29,25 +31,28 @@ public class JpsMavenRepositoryLibraryDescriptor {
private final String myArtifactId;
private final String myVersion;
private final boolean myIncludeTransitiveDependencies;
private final List<String> myExcludedDependencies;
public JpsMavenRepositoryLibraryDescriptor(@NotNull String groupId, @NotNull String artifactId, @NotNull String version) {
this(groupId, artifactId, version, true);
this(groupId, artifactId, version, true, Collections.emptyList());
}
public JpsMavenRepositoryLibraryDescriptor(@NotNull String groupId, @NotNull String artifactId, @NotNull String version,
boolean includeTransitiveDependencies) {
boolean includeTransitiveDependencies, @NotNull List<String> excludedDependencies) {
myGroupId = groupId;
myArtifactId = artifactId;
myVersion = version;
myIncludeTransitiveDependencies = includeTransitiveDependencies;
myExcludedDependencies = excludedDependencies;
myMavenId = groupId + ":" + artifactId + ":" + version;
}
public JpsMavenRepositoryLibraryDescriptor(@Nullable String mavenId) {
this(mavenId, true);
this(mavenId, true, Collections.emptyList());
}
public JpsMavenRepositoryLibraryDescriptor(@Nullable String mavenId, boolean includeTransitiveDependencies) {
public JpsMavenRepositoryLibraryDescriptor(@Nullable String mavenId,
boolean includeTransitiveDependencies, List<String> excludedDependencies) {
myMavenId = mavenId;
myIncludeTransitiveDependencies = includeTransitiveDependencies;
if (mavenId == null) {
@@ -59,6 +64,7 @@ public class JpsMavenRepositoryLibraryDescriptor {
myArtifactId = parts.length > 1 ? parts[1] : null;
myVersion = parts.length > 2 ? parts[2] : null;
}
myExcludedDependencies = excludedDependencies;
}
@@ -78,6 +84,13 @@ public class JpsMavenRepositoryLibraryDescriptor {
return myIncludeTransitiveDependencies;
}
/**
* Returns list of excluded transitive dependencies in {@code "<groupId>:<artifactId>"} format.
*/
public List<String> getExcludedDependencies() {
return myExcludedDependencies;
}
public String getVersion() {
return myVersion;
}
@@ -88,12 +101,13 @@ public class JpsMavenRepositoryLibraryDescriptor {
if (o == null || getClass() != o.getClass()) return false;
JpsMavenRepositoryLibraryDescriptor that = (JpsMavenRepositoryLibraryDescriptor)o;
return Objects.equals(myMavenId, that.myMavenId) && myIncludeTransitiveDependencies == that.myIncludeTransitiveDependencies;
return Objects.equals(myMavenId, that.myMavenId) && myIncludeTransitiveDependencies == that.myIncludeTransitiveDependencies
&& myExcludedDependencies.equals(that.myExcludedDependencies);
}
@Override
public int hashCode() {
return Objects.hashCode(myMavenId) * 31 + (myIncludeTransitiveDependencies ? 1 : 0);
return myExcludedDependencies.hashCode() * 31 * 31 + Objects.hashCode(myMavenId) * 31 + (myIncludeTransitiveDependencies ? 1 : 0);
}
@Override
@@ -17,6 +17,7 @@ package org.jetbrains.jps.model.serialization.java;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -387,6 +388,8 @@ public class JpsJavaModelSerializerExtension extends JpsModelSerializerExtension
private static class JpsRepositoryLibraryPropertiesSerializer extends JpsLibraryPropertiesSerializer<JpsSimpleElement<JpsMavenRepositoryLibraryDescriptor>> {
private static final String MAVEN_ID_ATTRIBUTE = "maven-id";
private static final String INCLUDE_TRANSITIVE_DEPS_ATTRIBUTE = "include-transitive-deps";
private static final String EXCLUDE_TAG = "exclude";
private static final String DEPENDENCY_TAG = "dependency";
public JpsRepositoryLibraryPropertiesSerializer() {
super(JpsRepositoryLibraryType.INSTANCE, JpsRepositoryLibraryType.INSTANCE.getTypeId());
@@ -394,10 +397,19 @@ public class JpsJavaModelSerializerExtension extends JpsModelSerializerExtension
@Override
public JpsSimpleElement<JpsMavenRepositoryLibraryDescriptor> loadProperties(@Nullable Element elem) {
return JpsElementFactory.getInstance().createSimpleElement(new JpsMavenRepositoryLibraryDescriptor(
elem != null ? elem.getAttributeValue(MAVEN_ID_ATTRIBUTE, (String)null) : null,
elem == null || Boolean.parseBoolean(elem.getAttributeValue(INCLUDE_TRANSITIVE_DEPS_ATTRIBUTE, "true"))
));
return JpsElementFactory.getInstance().createSimpleElement(loadDescriptor(elem));
}
@NotNull
private static JpsMavenRepositoryLibraryDescriptor loadDescriptor(@Nullable Element elem) {
if (elem == null) return new JpsMavenRepositoryLibraryDescriptor(null);
boolean includeTransitiveDependencies = Boolean.parseBoolean(elem.getAttributeValue(INCLUDE_TRANSITIVE_DEPS_ATTRIBUTE, "true"));
Element excludeTag = elem.getChild(EXCLUDE_TAG);
List<Element> dependencyTags = excludeTag != null ? excludeTag.getChildren(DEPENDENCY_TAG) : Collections.emptyList();
List<String> excludedDependencies = ContainerUtil.map(dependencyTags, it -> it.getAttributeValue(MAVEN_ID_ATTRIBUTE));
return new JpsMavenRepositoryLibraryDescriptor(elem.getAttributeValue(MAVEN_ID_ATTRIBUTE, (String)null),
includeTransitiveDependencies, excludedDependencies);
}
@Override
@@ -406,6 +418,14 @@ public class JpsJavaModelSerializerExtension extends JpsModelSerializerExtension
if (mavenId != null) {
element.setAttribute(MAVEN_ID_ATTRIBUTE, mavenId);
}
List<String> excludedDependencies = properties.getData().getExcludedDependencies();
if (!excludedDependencies.isEmpty()) {
Element excludeTag = new Element(EXCLUDE_TAG);
element.addContent(excludeTag);
for (String dependency : excludedDependencies) {
excludeTag.addContent(new Element(DEPENDENCY_TAG).setAttribute(MAVEN_ID_ATTRIBUTE, dependency));
}
}
}
}
}
@@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="plain" type="repository">
<properties maven-id="junit:junit:3.8.1"/>
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/3.8.1/junit-3.8.1.jar!/"/>
</CLASSES>
<JAVADOC/>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/3.8.1/junit-3.8.1-sources.jar!/"/>
</SOURCES>
</library>
</component>
@@ -0,0 +1,15 @@
<component name="libraryTable">
<library name="with-excluded-dependencies" type="repository">
<properties maven-id="org.apache.httpcomponents:fluent-hc:4.5.5">
<exclude>
<dependency maven-id="org.apache.httpcomponents:httpclient"/>
</exclude>
</properties>
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/httpcomponents/fluent-hc/4.5.5/fluent-hc-4.5.5.jar!/"/>
<root url="jar://$MAVEN_REPOSITORY$/commons-logging/commons-logging/1.2/commons-logging-1.2.jar!/"/>
</CLASSES>
<JAVADOC/>
<SOURCES/>
</library>
</component>
@@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="without-transitive-dependencies" type="repository">
<properties include-transitive-deps="false" maven-id="junit:junit:4.12"/>
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/4.12/junit-4.12.jar!/"/>
</CLASSES>
<JAVADOC/>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/4.12/junit-4.12-sources.jar!/"/>
</SOURCES>
</library>
</component>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
@@ -0,0 +1,43 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.jps.model.serialization;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.JpsSimpleElement;
import org.jetbrains.jps.model.library.JpsLibrary;
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor;
import org.jetbrains.jps.model.library.JpsRepositoryLibraryType;
import org.jetbrains.jps.model.library.JpsTypedLibrary;
public class JpsRepositoryLibrarySerializationTest extends JpsSerializationTestCase {
public void testPlain() {
JpsMavenRepositoryLibraryDescriptor properties = loadLibrary("plain");
assertEquals("junit", properties.getGroupId());
assertEquals("junit", properties.getArtifactId());
assertEquals("3.8.1", properties.getVersion());
assertTrue(properties.isIncludeTransitiveDependencies());
assertEmpty(properties.getExcludedDependencies());
}
public void testWithoutTransitiveDependencies() {
JpsMavenRepositoryLibraryDescriptor properties = loadLibrary("without-transitive-dependencies");
assertFalse(properties.isIncludeTransitiveDependencies());
assertEmpty(properties.getExcludedDependencies());
}
public void testWithExcludedDependencies() {
JpsMavenRepositoryLibraryDescriptor properties = loadLibrary("with-excluded-dependencies");
assertTrue(properties.isIncludeTransitiveDependencies());
assertSameElements(properties.getExcludedDependencies(), "org.apache.httpcomponents:httpclient");
}
@NotNull
private JpsMavenRepositoryLibraryDescriptor loadLibrary(String name) {
loadProject("/jps/model-serialization/testData/repositoryLibraries");
JpsLibrary library = myProject.getLibraryCollection().findLibrary(name);
assertNotNull(library);
assertSame(JpsRepositoryLibraryType.INSTANCE, library.getType());
JpsTypedLibrary<JpsSimpleElement<JpsMavenRepositoryLibraryDescriptor>> typed = library.asTyped(JpsRepositoryLibraryType.INSTANCE);
assertNotNull(typed);
return typed.getProperties().getData();
}
}