diff --git a/m2e-dev.target b/m2e-dev.target new file mode 100644 index 0000000000..4c79ff3e34 --- /dev/null +++ b/m2e-dev.target @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/org.eclipse.m2e.pde.feature/build.properties b/org.eclipse.m2e.pde.feature/build.properties new file mode 100644 index 0000000000..64f93a9f0b --- /dev/null +++ b/org.eclipse.m2e.pde.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/org.eclipse.m2e.pde.feature/feature.xml b/org.eclipse.m2e.pde.feature/feature.xml new file mode 100644 index 0000000000..84e90b0648 --- /dev/null +++ b/org.eclipse.m2e.pde.feature/feature.xml @@ -0,0 +1,49 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.m2e.pde.feature/pom.xml b/org.eclipse.m2e.pde.feature/pom.xml new file mode 100644 index 0000000000..d537998bb5 --- /dev/null +++ b/org.eclipse.m2e.pde.feature/pom.xml @@ -0,0 +1,23 @@ + + + + 4.0.0 + + + org.eclipse.m2e + m2e-core + 1.16.0-SNAPSHOT + + + org.eclipse.m2e.pde.feature + eclipse-feature + 1.17.0-SNAPSHOT + diff --git a/org.eclipse.m2e.pde.ui/META-INF/MANIFEST.MF b/org.eclipse.m2e.pde.ui/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..8e3b74b1d6 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: PDE Integration UI +Bundle-SymbolicName: org.eclipse.m2e.pde.ui;singleton:=true +Bundle-Version: 1.17.0.qualifier +Automatic-Module-Name: org.eclipse.m2e.pde.ui +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Require-Bundle: org.eclipse.core.runtime;bundle-version="3.19.0", + org.eclipse.jface, + org.eclipse.pde.ui;bundle-version="3.12.0", + org.eclipse.equinox.frameworkadmin;bundle-version="2.1.400", + biz.aQute.bndlib;bundle-version="5.1.2", + org.eclipse.m2e.maven.runtime, + org.eclipse.m2e.core, + org.eclipse.m2e.pde, + org.eclipse.pde;bundle-version="3.13.1200" +Bundle-ActivationPolicy: lazy +Bundle-Activator: org.eclipse.m2e.pde.ui.Activator diff --git a/org.eclipse.m2e.pde.ui/build.properties b/org.eclipse.m2e.pde.ui/build.properties new file mode 100644 index 0000000000..6c480f39f1 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + icons/ diff --git a/org.eclipse.m2e.pde.ui/icons/error_st_obj.gif b/org.eclipse.m2e.pde.ui/icons/error_st_obj.gif new file mode 100644 index 0000000000..0bc60689c6 Binary files /dev/null and b/org.eclipse.m2e.pde.ui/icons/error_st_obj.gif differ diff --git a/org.eclipse.m2e.pde.ui/icons/jar_obj.gif b/org.eclipse.m2e.pde.ui/icons/jar_obj.gif new file mode 100644 index 0000000000..2fa1d777bc Binary files /dev/null and b/org.eclipse.m2e.pde.ui/icons/jar_obj.gif differ diff --git a/org.eclipse.m2e.pde.ui/icons/m2.gif b/org.eclipse.m2e.pde.ui/icons/m2.gif new file mode 100644 index 0000000000..4b0c0589d8 Binary files /dev/null and b/org.eclipse.m2e.pde.ui/icons/m2.gif differ diff --git a/org.eclipse.m2e.pde.ui/icons/new_m2_project_wizard.gif b/org.eclipse.m2e.pde.ui/icons/new_m2_project_wizard.gif new file mode 100644 index 0000000000..8f18a52b25 Binary files /dev/null and b/org.eclipse.m2e.pde.ui/icons/new_m2_project_wizard.gif differ diff --git a/org.eclipse.m2e.pde.ui/icons/show_inherited_dependencies.gif b/org.eclipse.m2e.pde.ui/icons/show_inherited_dependencies.gif new file mode 100644 index 0000000000..a326000dae Binary files /dev/null and b/org.eclipse.m2e.pde.ui/icons/show_inherited_dependencies.gif differ diff --git a/org.eclipse.m2e.pde.ui/plugin.xml b/org.eclipse.m2e.pde.ui/plugin.xml new file mode 100644 index 0000000000..e63d8921a6 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/plugin.xml @@ -0,0 +1,60 @@ + + + + + + + + Add a maven artifact (and dependencies) to your target platform + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.m2e.pde.ui/pom.xml b/org.eclipse.m2e.pde.ui/pom.xml new file mode 100644 index 0000000000..e4fd888b79 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + + org.eclipse.m2e + m2e-core + 1.16.0-SNAPSHOT + + + org.eclipse.m2e.pde.ui + 1.17.0-SNAPSHOT + eclipse-plugin + + Maven PDE UI Integration + \ No newline at end of file diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/Activator.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/Activator.java new file mode 100644 index 0000000000..e4763b8c80 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/Activator.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui; + +import org.eclipse.m2e.pde.ui.adapter.DependencyNodeAdapterFactory; +import org.eclipse.m2e.pde.ui.adapter.MavenTargetAdapterFactory; +import org.eclipse.m2e.pde.ui.adapter.MavenTargetBundleAdapterFactory; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + + @Override + public void start(BundleContext context) throws Exception { + + } + + @Override + public void stop(BundleContext context) throws Exception { + DependencyNodeAdapterFactory.LABEL_PROVIDER.dispose(); + DependencyNodeAdapterFactory.TREE_CONTENT_PROVIDER.dispose(); + MavenTargetAdapterFactory.LABEL_PROVIDER.dispose(); + MavenTargetAdapterFactory.TREE_CONTENT_PROVIDER.dispose(); + MavenTargetBundleAdapterFactory.LABEL_PROVIDER.dispose(); + } + +} diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/MavenTargetLocationUpdater.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/MavenTargetLocationUpdater.java new file mode 100644 index 0000000000..871272b36c --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/MavenTargetLocationUpdater.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.m2e.pde.MavenTargetLocation; +import org.eclipse.pde.core.target.ITargetDefinition; +import org.eclipse.pde.core.target.ITargetLocation; +import org.eclipse.pde.ui.target.ITargetLocationUpdater; + +public class MavenTargetLocationUpdater implements ITargetLocationUpdater { + + @Override + public boolean canUpdate(ITargetDefinition target, ITargetLocation targetLocation) { + return targetLocation instanceof MavenTargetLocation; + } + + @Override + public IStatus update(ITargetDefinition target, ITargetLocation targetLocation, IProgressMonitor monitor) { + MavenTargetLocation location = (MavenTargetLocation) targetLocation; + location.refresh(); + return Status.OK_STATUS; + } + +} diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/adapter/DependencyNodeAdapterFactory.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/adapter/DependencyNodeAdapterFactory.java new file mode 100644 index 0000000000..9b13eeeee5 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/adapter/DependencyNodeAdapterFactory.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui.adapter; + +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.m2e.pde.ui.provider.DependencyNodeLabelProvider; +import org.eclipse.m2e.pde.ui.provider.MavenTargetTreeContentProvider; + +public class DependencyNodeAdapterFactory implements IAdapterFactory { + + public static final ITreeContentProvider TREE_CONTENT_PROVIDER = new MavenTargetTreeContentProvider(); + public static final ILabelProvider LABEL_PROVIDER = new DependencyNodeLabelProvider(); + + @Override + public T getAdapter(Object adaptableObject, Class adapterType) { + if (adaptableObject instanceof DependencyNode) { + if (adapterType == ITreeContentProvider.class) { + return adapterType.cast(TREE_CONTENT_PROVIDER); + } else if (adapterType == ILabelProvider.class) { + return adapterType.cast(LABEL_PROVIDER); + } + } + return null; + } + + @Override + public Class[] getAdapterList() { + return new Class[] { ITreeContentProvider.class, ILabelProvider.class }; + } + +} diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/adapter/MavenTargetAdapterFactory.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/adapter/MavenTargetAdapterFactory.java new file mode 100644 index 0000000000..fac414f8d7 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/adapter/MavenTargetAdapterFactory.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui.adapter; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.m2e.pde.MavenTargetLocation; +import org.eclipse.m2e.pde.ui.MavenTargetLocationUpdater; +import org.eclipse.m2e.pde.ui.editor.MavenTargetLocationEditor; +import org.eclipse.m2e.pde.ui.provider.MavenTargetLocationLabelProvider; +import org.eclipse.m2e.pde.ui.provider.MavenTargetTreeContentProvider; +import org.eclipse.pde.ui.target.ITargetLocationEditor; +import org.eclipse.pde.ui.target.ITargetLocationUpdater; + +public class MavenTargetAdapterFactory implements IAdapterFactory { + + public static final ILabelProvider LABEL_PROVIDER = new MavenTargetLocationLabelProvider(); + public static final ITreeContentProvider TREE_CONTENT_PROVIDER = new MavenTargetTreeContentProvider(); + private static final MavenTargetLocationEditor LOCATION_EDITOR = new MavenTargetLocationEditor(); + private static final MavenTargetLocationUpdater LOCATION_UPDATER = new MavenTargetLocationUpdater(); + + @Override + public Class[] getAdapterList() { + return new Class[] { ILabelProvider.class, ITreeContentProvider.class, ITargetLocationEditor.class, + ITargetLocationUpdater.class }; + } + + @Override + public T getAdapter(Object adaptableObject, Class adapterType) { + if (adaptableObject instanceof MavenTargetLocation) { + if (adapterType == ILabelProvider.class) { + return adapterType.cast(LABEL_PROVIDER); + } else if (adapterType == ITreeContentProvider.class) { + return adapterType.cast(TREE_CONTENT_PROVIDER); + } else if (adapterType == ITargetLocationEditor.class) { + return adapterType.cast(LOCATION_EDITOR); + } else if (adapterType == ITargetLocationUpdater.class) { + return adapterType.cast(LOCATION_UPDATER); + } + } + return null; + } + +} diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/adapter/MavenTargetBundleAdapterFactory.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/adapter/MavenTargetBundleAdapterFactory.java new file mode 100644 index 0000000000..ef6a7afba6 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/adapter/MavenTargetBundleAdapterFactory.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui.adapter; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.m2e.pde.MavenTargetBundle; +import org.eclipse.m2e.pde.ui.provider.MavenTargetBundleLabelProvider; + +public class MavenTargetBundleAdapterFactory implements IAdapterFactory { + + public static final ILabelProvider LABEL_PROVIDER = new MavenTargetBundleLabelProvider(); + + @Override + public T getAdapter(Object adaptableObject, Class adapterType) { + if (adaptableObject instanceof MavenTargetBundle) { + if (adapterType == ILabelProvider.class) { + return adapterType.cast(LABEL_PROVIDER); + } + } + return null; + } + + @Override + public Class[] getAdapterList() { + return new Class[] { ILabelProvider.class }; + } + +} diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/editor/MavenTargetLocationEditor.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/editor/MavenTargetLocationEditor.java new file mode 100644 index 0000000000..3efb20bb6b --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/editor/MavenTargetLocationEditor.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui.editor; + +import org.eclipse.jface.wizard.IWizard; +import org.eclipse.m2e.pde.MavenTargetLocation; +import org.eclipse.pde.core.target.ITargetDefinition; +import org.eclipse.pde.core.target.ITargetLocation; +import org.eclipse.pde.ui.target.ITargetLocationEditor; + +public class MavenTargetLocationEditor implements ITargetLocationEditor { + + @Override + public boolean canEdit(ITargetDefinition target, ITargetLocation targetLocation) { + return targetLocation instanceof MavenTargetLocation; + } + + @Override + public IWizard getEditWizard(ITargetDefinition target, ITargetLocation targetLocation) { + MavenTargetLocationWizard wizard = new MavenTargetLocationWizard((MavenTargetLocation) targetLocation); + wizard.setTarget(target); + return wizard; + } + +} diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/editor/MavenTargetLocationWizard.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/editor/MavenTargetLocationWizard.java new file mode 100644 index 0000000000..1fdaf075bb --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/editor/MavenTargetLocationWizard.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui.editor; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ComboViewer; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.m2e.pde.MavenTargetLocation; +import org.eclipse.m2e.pde.MissingMetadataMode; +import org.eclipse.pde.core.target.ITargetDefinition; +import org.eclipse.pde.core.target.ITargetLocation; +import org.eclipse.pde.ui.target.ITargetLocationWizard; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CCombo; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +public class MavenTargetLocationWizard extends Wizard implements ITargetLocationWizard { + + private Text artifactId; + private Text groupId; + private Text version; + private CCombo type; + private MavenTargetLocation targetLocation; + private CCombo scope; + private ComboViewer metadata; + private ITargetDefinition targetDefinition; + + public MavenTargetLocationWizard() { + this(null); + } + + public MavenTargetLocationWizard(MavenTargetLocation targetLocation) { + this.targetLocation = targetLocation; + setWindowTitle("Maven Artifact Target Entry"); + WizardPage page = new WizardPage( + targetLocation == null ? "Add a new Maven dependency" : "Edit Maven Dependency") { + + @Override + public void createControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + setControl(composite); + composite.setLayout(new GridLayout(2, false)); + new Label(composite, SWT.NONE).setText("Group Id"); + groupId = fill(new Text(composite, SWT.BORDER)); + new Label(composite, SWT.NONE).setText("Artifact Id"); + artifactId = fill(new Text(composite, SWT.BORDER)); + new Label(composite, SWT.NONE).setText("Version"); + version = fill(new Text(composite, SWT.BORDER)); + new Label(composite, SWT.NONE).setText("Type"); + type = new CCombo(composite, SWT.BORDER); + type.add("jar"); + type.add("bundle"); + new Label(composite, SWT.NONE).setText("Missing OSGi-Manifest"); + metadata = new ComboViewer(composite); + metadata.setContentProvider(ArrayContentProvider.getInstance()); + metadata.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + if (element instanceof MissingMetadataMode) { + return ((MissingMetadataMode) element).name().toLowerCase(); + } + return super.getText(element); + } + + }); + metadata.setInput(MissingMetadataMode.values()); + new Label(composite, SWT.NONE).setText("Dependencies scope"); + scope = new CCombo(composite, SWT.BORDER); + scope.add(""); + scope.add("compile"); + scope.add("test"); + scope.add("provided"); + if (targetLocation != null) { + artifactId.setText(targetLocation.getArtifactId()); + groupId.setText(targetLocation.getGroupId()); + version.setText(targetLocation.getVersion()); + type.setText(targetLocation.getArtifactType()); + scope.setText(targetLocation.getDependencyScope()); + metadata.setSelection(new StructuredSelection(targetLocation.getMetadataMode())); + } else { + artifactId.setText(""); + groupId.setText(""); + version.setText(""); + type.setText(MavenTargetLocation.DEFAULT_PACKAGE_TYPE); + scope.setText(MavenTargetLocation.DEFAULT_DEPENDENCY_SCOPE); + metadata.setSelection(new StructuredSelection(MavenTargetLocation.DEFAULT_METADATA_MODE)); + } + } + + private Text fill(Text text) { + GridData data = new GridData(GridData.FILL_HORIZONTAL); + data.grabExcessHorizontalSpace = true; + text.setLayoutData(data); + return text; + } + }; + page.setImageDescriptor(ImageDescriptor.createFromURL( + MavenTargetLocationWizard.class.getResource("/icons/new_m2_project_wizard.gif"))); + page.setTitle(page.getName()); + page.setDescription("Enter the desired maven artifact to add to the target platform"); + addPage(page); + + } + + @Override + public void setTarget(ITargetDefinition target) { + this.targetDefinition = target; + } + + @Override + public ITargetLocation[] getLocations() { + return new ITargetLocation[] { targetLocation }; + } + + @Override + public boolean performFinish() { + if (targetLocation == null) { + targetLocation = new MavenTargetLocation(groupId.getText(), artifactId.getText(), version.getText(), + type.getText(), (MissingMetadataMode) metadata.getStructuredSelection().getFirstElement(), + scope.getText()); + } else { + ITargetLocation[] locations = targetDefinition.getTargetLocations().clone(); + for (int i = 0; i < locations.length; i++) { + if (locations[i] == targetLocation) { + locations[i] = new MavenTargetLocation(groupId.getText(), artifactId.getText(), version.getText(), + type.getText(), (MissingMetadataMode) metadata.getStructuredSelection().getFirstElement(), + scope.getText()); + } + + } + targetDefinition.setTargetLocations(locations); + } + return true; + } + +} diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/DependencyNodeLabelProvider.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/DependencyNodeLabelProvider.java new file mode 100644 index 0000000000..d6e302b653 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/DependencyNodeLabelProvider.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui.provider; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.m2e.pde.MavenTargetLocation; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; + +public class DependencyNodeLabelProvider implements ILabelProvider { + private Image inheritedImage; + private Image jarImage; + private Image errorImage; + + @Override + public String getText(Object element) { + if (element instanceof DependencyNode) { + DependencyNode node = (DependencyNode) element; + Artifact artifact = node.getArtifact(); + MavenTargetLocation location = getTargetLocation(node); + String baseLabel = artifact.getGroupId() + ":" + artifact.getArtifactId() + " (" + artifact.getVersion() + + ")"; + if (location != null) { + if (location.isIgnored(artifact)) { + return "(ignored) " + baseLabel; + } else if (location.isFailed(artifact)) { + return "(failed) " + baseLabel; + } + } + return baseLabel; + } + return String.valueOf(element); + } + + private MavenTargetLocation getTargetLocation(DependencyNode node) { + Object object = node.getData().get(MavenTargetLocation.DEPENDENCYNODE_PARENT); + if (object instanceof DependencyNode) { + return getTargetLocation((DependencyNode) object); + } else if (object instanceof MavenTargetLocation) { + return (MavenTargetLocation) object; + } else { + return null; + } + } + + @Override + public Image getImage(Object element) { + if (element instanceof DependencyNode) { + DependencyNode node = (DependencyNode) element; + MavenTargetLocation location = getTargetLocation(node); + Display current = Display.getCurrent(); + if (location != null) { + if (location.isIgnored(node.getArtifact())) { + if (jarImage == null && current != null) { + jarImage = new Image(current, DependencyNodeLabelProvider.class + .getResourceAsStream("/icons/jar_obj.gif")); + } + return jarImage; + } else if (location.isFailed(node.getArtifact())) { + if (errorImage == null && current != null) { + errorImage = new Image(current, + DependencyNodeLabelProvider.class.getResourceAsStream("/icons/error_st_obj.gif")); + } + return errorImage; + } + } + if (inheritedImage == null && current != null) { + inheritedImage = new Image(current, DependencyNodeLabelProvider.class + .getResourceAsStream("/icons/show_inherited_dependencies.gif")); + } + return inheritedImage; + } + return null; + } + + @Override + public void addListener(ILabelProviderListener listener) { + + } + + @Override + public void dispose() { + if (inheritedImage != null) { + inheritedImage.dispose(); + } + if (jarImage != null) { + jarImage.dispose(); + } + if (errorImage != null) { + errorImage.dispose(); + } + } + + @Override + public boolean isLabelProperty(Object element, String property) { + return false; + } + + @Override + public void removeListener(ILabelProviderListener listener) { + + } + +} diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/MavenTargetBundleLabelProvider.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/MavenTargetBundleLabelProvider.java new file mode 100644 index 0000000000..b1ef8d9b08 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/MavenTargetBundleLabelProvider.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2018 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui.provider; + +import org.eclipse.m2e.pde.MavenTargetBundle; +import org.eclipse.m2e.pde.ui.adapter.MavenTargetAdapterFactory; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; + +@SuppressWarnings("restriction") +public class MavenTargetBundleLabelProvider + extends org.eclipse.pde.internal.ui.shared.target.StyledBundleLabelProvider { + + private Image image; + + public MavenTargetBundleLabelProvider() { + super(true, false); + } + + @Override + public org.eclipse.swt.graphics.Image getImage(Object element) { + if (element instanceof MavenTargetBundle) { + if (((MavenTargetBundle) element).isWrapped()) { + Display current = Display.getCurrent(); + if (image == null && current != null) { + image = new Image(current, + MavenTargetAdapterFactory.class.getResourceAsStream("/icons/jar_obj.gif")); + } + return image; + } + } + return super.getImage(element); + } + + @Override + public void dispose() { + super.dispose(); + if (image != null) { + image.dispose(); + } + } + +} diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/MavenTargetLocationLabelProvider.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/MavenTargetLocationLabelProvider.java new file mode 100644 index 0000000000..4ed922863b --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/MavenTargetLocationLabelProvider.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui.provider; + +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.m2e.pde.MavenTargetLocation; +import org.eclipse.m2e.pde.ui.adapter.MavenTargetAdapterFactory; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; + +public class MavenTargetLocationLabelProvider implements ILabelProvider { + private Image image; + + @Override + public String getText(Object element) { + if (element instanceof MavenTargetLocation) { + MavenTargetLocation location = (MavenTargetLocation) element; + return location.getGroupId() + ":" + location.getArtifactId() + " (" + location.getVersion() + ")"; + } + return String.valueOf(element); + } + + @Override + public Image getImage(Object element) { + Display current = Display.getCurrent(); + if (image == null && current != null) { + image = new Image(current, MavenTargetAdapterFactory.class.getResourceAsStream("/icons/m2.gif")); + } + return image; + } + + @Override + public void addListener(ILabelProviderListener listener) { + + } + + @Override + public void dispose() { + image.dispose(); + + } + + @Override + public boolean isLabelProperty(Object element, String property) { + return false; + } + + @Override + public void removeListener(ILabelProviderListener listener) { + + } + +} diff --git a/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/MavenTargetTreeContentProvider.java b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/MavenTargetTreeContentProvider.java new file mode 100644 index 0000000000..9b69c11e65 --- /dev/null +++ b/org.eclipse.m2e.pde.ui/src/org/eclipse/m2e/pde/ui/provider/MavenTargetTreeContentProvider.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde.ui.provider; + +import java.util.List; + +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.m2e.pde.MavenTargetLocation; + +public class MavenTargetTreeContentProvider implements ITreeContentProvider { + + @Override + public Object[] getElements(Object inputElement) { + return getChildren(inputElement); + } + + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof MavenTargetLocation) { + MavenTargetLocation location = (MavenTargetLocation) parentElement; + List nodes = location.getDependencyNodes(); + if (nodes != null) { + for (DependencyNode dependencyNode : nodes) { + if (dependencyNode.getData().containsKey(MavenTargetLocation.DEPENDENCYNODE_IS_ROOT)) { + dependencyNode.setData(MavenTargetLocation.DEPENDENCYNODE_PARENT, parentElement); + return getChildren(dependencyNode); + } + } + } + } else if (parentElement instanceof DependencyNode) { + DependencyNode[] dependencyNodes = ((DependencyNode) parentElement).getChildren() + .toArray(new DependencyNode[0]); + for (DependencyNode dependencyNode : dependencyNodes) { + dependencyNode.setData(MavenTargetLocation.DEPENDENCYNODE_PARENT, parentElement); + } + return dependencyNodes; + } + return null; + } + + @Override + public Object getParent(Object element) { + if (element instanceof DependencyNode) { + DependencyNode dependencyNode = (DependencyNode) element; + Object parent = dependencyNode.getData().get(MavenTargetLocation.DEPENDENCYNODE_PARENT); + if (parent instanceof DependencyNode) { + DependencyNode dp = (DependencyNode) parent; + if (dp.getData().containsKey(MavenTargetLocation.DEPENDENCYNODE_IS_ROOT)) { + return getParent(dp); + } + } + return parent; + } + return null; + } + + @Override + public boolean hasChildren(Object element) { + if (element instanceof MavenTargetLocation) { + MavenTargetLocation location = (MavenTargetLocation) element; + List dependencyNodes = location.getDependencyNodes(); + return dependencyNodes != null && !dependencyNodes.isEmpty(); + } else if (element instanceof DependencyNode) { + DependencyNode node = (DependencyNode) element; + return !node.getChildren().isEmpty(); + } + return false; + } + +} diff --git a/org.eclipse.m2e.pde/META-INF/MANIFEST.MF b/org.eclipse.m2e.pde/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..b00df12c30 --- /dev/null +++ b/org.eclipse.m2e.pde/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: M2E PDE Integration +Bundle-SymbolicName: org.eclipse.m2e.pde;singleton:=true +Bundle-Version: 1.17.0.qualifier +Automatic-Module-Name: org.eclipse.m2e.pde +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Require-Bundle: org.eclipse.core.runtime;bundle-version="3.19.0", + org.eclipse.pde.ui;bundle-version="3.12.0", + org.eclipse.equinox.frameworkadmin;bundle-version="2.1.400", + biz.aQute.bndlib;bundle-version="5.1.2", + org.eclipse.m2e.maven.runtime, + org.eclipse.m2e.core +Export-Package: org.eclipse.m2e.pde diff --git a/org.eclipse.m2e.pde/build.properties b/org.eclipse.m2e.pde/build.properties new file mode 100644 index 0000000000..e9863e281e --- /dev/null +++ b/org.eclipse.m2e.pde/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.eclipse.m2e.pde/plugin.xml b/org.eclipse.m2e.pde/plugin.xml new file mode 100644 index 0000000000..c664d3ec46 --- /dev/null +++ b/org.eclipse.m2e.pde/plugin.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/org.eclipse.m2e.pde/pom.xml b/org.eclipse.m2e.pde/pom.xml new file mode 100644 index 0000000000..2f11cb1eb2 --- /dev/null +++ b/org.eclipse.m2e.pde/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + + org.eclipse.m2e + m2e-core + 1.16.0-SNAPSHOT + + + org.eclipse.m2e.pde + 1.17.0-SNAPSHOT + eclipse-plugin + + Maven PDE Integration + \ No newline at end of file diff --git a/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetBundle.java b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetBundle.java new file mode 100644 index 0000000000..3732608a34 --- /dev/null +++ b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetBundle.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde; + +import java.io.File; +import java.util.jar.Manifest; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.equinox.frameworkadmin.BundleInfo; +import org.eclipse.pde.core.target.TargetBundle; + +import aQute.bnd.osgi.Analyzer; +import aQute.bnd.osgi.Jar; + +public class MavenTargetBundle extends TargetBundle { + + private TargetBundle bundle; + private IStatus status; + private BundleInfo bundleInfo; + private boolean isWrapped; + + @Override + public BundleInfo getBundleInfo() { + if (bundle == null) { + return bundleInfo; + } + return bundle.getBundleInfo(); + } + + @Override + public boolean isSourceBundle() { + if (bundle == null) { + return false; + } + return bundle.isSourceBundle(); + } + + @Override + public BundleInfo getSourceTarget() { + if (bundle == null) { + return null; + } + return bundle.getSourceTarget(); + } + + @Override + public boolean isFragment() { + if (bundle == null) { + return false; + } + return bundle.isFragment(); + } + + @Override + public String getSourcePath() { + if (bundle == null) { + return null; + } + return bundle.getSourcePath(); + } + + public MavenTargetBundle(Artifact artifact, MissingMetadataMode metadataMode) { + File file = artifact.getFile(); + this.bundleInfo = new BundleInfo(artifact.getGroupId() + "." + artifact.getArtifactId(), artifact.getVersion(), + file != null ? file.toURI() : null, -1, false); + try { + bundle = new TargetBundle(file); + } catch (Exception ex) { + if (metadataMode == MissingMetadataMode.ERROR) { + status = new Status(Status.ERROR, MavenTargetBundle.class.getPackage().getName(), + artifact + " is not a bundle", ex); + } else if (metadataMode == MissingMetadataMode.GENERATE) { + try { + bundle = getWrappedArtifact(artifact, bundleInfo); + isWrapped = true; + } catch (Exception e) { + // not possible then + String message = artifact + " is not a bundle and cannot be automatically bundled as such "; + if (e.getMessage() != null) { + message += " (" + e.getMessage() + ")"; + } + status = new Status(Status.ERROR, MavenTargetBundle.class.getPackage().getName(), message, e); + } + } else { + status = Status.CANCEL_STATUS; + } + } + } + + public static TargetBundle getWrappedArtifact(Artifact artifact, BundleInfo bundleInfo) throws Exception { + synchronized (artifact) { + File file = artifact.getFile(); + String name = file.getName(); + File wrappedFile = new File(file.getParentFile(), name + ".wrapped"); + if (!wrappedFile.exists() || file.lastModified() > wrappedFile.lastModified()) { + try (Jar jar = new Jar(file)) { + Manifest originalManifest = jar.getManifest(); + try (Analyzer analyzer = new Analyzer();) { + analyzer.setJar(jar); + if (originalManifest != null) { + analyzer.mergeManifest(originalManifest); + } + analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*;resolution:=optional"); + analyzer.setProperty(Analyzer.EXPORT_PACKAGE, "*;-noimport:=true"); + analyzer.setProperty(Analyzer.BUNDLE_SYMBOLICNAME, createSymbolicName(artifact)); + analyzer.setProperty(Analyzer.BUNDLE_NAME, "Derived from " + artifact.getGroupId() + ":" + + artifact.getArtifactId() + ":" + artifact.getVersion()); + analyzer.setBundleVersion(createBundleVersion(artifact)); + jar.setManifest(analyzer.calcManifest()); + jar.write(wrappedFile); + } + } + return new TargetBundle(wrappedFile); + } + try { + return new TargetBundle(wrappedFile); + } catch (Exception e) { + // cached file seems invalid/stale... + file.delete(); + return getWrappedArtifact(artifact, bundleInfo); + } + } + } + + public static String createBundleVersion(Artifact artifact) { + String version = artifact.getVersion(); + if (version == null || version.isEmpty()) { + return "0"; + } + return version.replaceAll("[^a-zA-Z0-9\\.]", ".").replaceAll("\\.\\.+", "."); + } + + public static String createSymbolicName(Artifact artifact) { + + return "wrapped." + artifact.getGroupId() + "." + artifact.getArtifactId(); + } + + public boolean isWrapped() { + return isWrapped; + } + + @Override + public IStatus getStatus() { + if (bundle == null) { + if (status == null) { + return Status.OK_STATUS; + } + return status; + } + return bundle.getStatus(); + } + + @Override + public int hashCode() { + return getBundleInfo().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MavenTargetBundle) { + MavenTargetBundle other = (MavenTargetBundle) obj; + return getBundleInfo().equals(other.getBundleInfo()); + } + return false; + } +} diff --git a/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetLocation.java b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetLocation.java new file mode 100644 index 0000000000..ce60a92225 --- /dev/null +++ b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetLocation.java @@ -0,0 +1,287 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.apache.maven.RepositoryUtils; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.resolution.DependencyRequest; +import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.m2e.core.MavenPlugin; +import org.eclipse.m2e.core.embedder.ICallable; +import org.eclipse.m2e.core.embedder.IMaven; +import org.eclipse.m2e.core.embedder.IMavenExecutionContext; +import org.eclipse.m2e.core.internal.MavenPluginActivator; +import org.eclipse.pde.core.target.ITargetDefinition; +import org.eclipse.pde.core.target.TargetBundle; +import org.eclipse.pde.core.target.TargetFeature; +import org.eclipse.pde.internal.core.target.AbstractBundleContainer; + +@SuppressWarnings("restriction") +public class MavenTargetLocation extends AbstractBundleContainer { + + public static final String ELEMENT_TYPE = "type"; + public static final String ELEMENT_VERSION = "version"; + public static final String ELEMENT_ARTIFACT_ID = "artifactId"; + public static final String ELEMENT_GROUP_ID = "groupId"; + public static final String ATTRIBUTE_DEPENDENCY_SCOPE = "includeDependencyScope"; + public static final String ATTRIBUTE_MISSING_META_DATA = "missingManfiest"; + public static final String DEFAULT_DEPENDENCY_SCOPE = ""; + public static final MissingMetadataMode DEFAULT_METADATA_MODE = MissingMetadataMode.GENERATE; + public static final String DEFAULT_PACKAGE_TYPE = "jar"; + public static final String DEPENDENCYNODE_IS_ROOT = "dependencynode.root"; + public static final String DEPENDENCYNODE_PARENT = "dependencynode.parent"; + + private final String artifactId; + private final String groupId; + private final String version; + private final String artifactType; + private final String dependencyScope; + private final MissingMetadataMode metadataMode; + private List targetBundles; + private List dependencyNodes; + private Set ignoredArtifacts = new HashSet<>(); + + private Set failedArtifacts = new HashSet<>(); + + public MavenTargetLocation(String groupId, String artifactId, String version, String artifactType, + MissingMetadataMode metadataMode, String dependencyScope) { + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + this.artifactType = artifactType; + this.metadataMode = metadataMode; + this.dependencyScope = dependencyScope; + } + + @Override + protected TargetBundle[] resolveBundles(ITargetDefinition definition, IProgressMonitor monitor) + throws CoreException { + if (targetBundles == null) { + ignoredArtifacts.clear(); + targetBundles = new ArrayList<>(); + IMaven maven = MavenPlugin.getMaven(); + List repositories = maven.getArtifactRepositories(); + Artifact artifact = RepositoryUtils.toArtifact(maven.resolve(getGroupId(), getArtifactId(), getVersion(), + getArtifactType(), null, repositories, monitor)); + if (artifact != null) { + if (dependencyScope != null && !dependencyScope.isBlank()) { + IMavenExecutionContext context = maven.createExecutionContext(); + PreorderNodeListGenerator dependecies = context.execute(new ICallable() { + + @Override + public PreorderNodeListGenerator call(IMavenExecutionContext context, IProgressMonitor monitor) + throws CoreException { + try { + CollectRequest collectRequest = new CollectRequest(); + collectRequest.setRoot(new Dependency(artifact, dependencyScope)); + collectRequest.setRepositories(RepositoryUtils.toRepos(repositories)); + + RepositorySystem repoSystem = MavenPluginActivator.getDefault().getRepositorySystem(); + DependencyNode node = repoSystem + .collectDependencies(context.getRepositorySession(), collectRequest).getRoot(); + node.setData(DEPENDENCYNODE_IS_ROOT, true); + node.setData(DEPENDENCYNODE_PARENT, MavenTargetLocation.this); + DependencyRequest dependencyRequest = new DependencyRequest(); + dependencyRequest.setRoot(node); + repoSystem.resolveDependencies(context.getRepositorySession(), dependencyRequest); + PreorderNodeListGenerator nlg = new PreorderNodeListGenerator(); + node.accept(nlg); + return nlg; + } catch (RepositoryException e) { + e.printStackTrace(); + throw new CoreException( + new Status(IStatus.ERROR, MavenTargetLocation.class.getPackage().getName(), + "Resolving dependencies failed", e)); + } catch (RuntimeException e) { + e.printStackTrace(); + throw new CoreException(new Status(IStatus.ERROR, + MavenTargetLocation.class.getPackage().getName(), "Internal error", e)); + } + } + }, monitor); + + for (Artifact a : dependecies.getArtifacts(true)) { + addBundleForArtifact(a); + } + dependencyNodes = dependecies.getNodes(); + } else { + addBundleForArtifact(artifact); + } + } + } + return targetBundles.toArray(new TargetBundle[0]); + } + + private void addBundleForArtifact(Artifact artifact) { + TargetBundle bundle = createTargetBundle(artifact); + IStatus status = bundle.getStatus(); + if (status.isOK()) { + targetBundles.add(bundle); + } else if (status.matches(IStatus.CANCEL)) { + ignoredArtifacts.add(artifact); + } else { + failedArtifacts.add(artifact); + // failed ones must be added to the target as well to fail resolution of the TP + targetBundles.add(bundle); + } + } + + public int getDependencyCount() { + if (targetBundles == null) { + return -1; + } + return targetBundles.size() - 1; + } + + private TargetBundle createTargetBundle(Artifact artifact) { + return new MavenTargetBundle(artifact, metadataMode); + } + + public List getDependencyNodes() { + return dependencyNodes; + } + + @Override + protected TargetFeature[] resolveFeatures(ITargetDefinition definition, IProgressMonitor monitor) + throws CoreException { + // XXX it would be possible to deploy features as maven artifacts, are there any + // examples? + return new TargetFeature[] {}; + } + + @Override + public String getType() { + return "Maven"; + } + + @Override + public String getLocation(boolean resolve) throws CoreException { + return System.getProperty("java.io.tmpdir"); + } + + @Override + public int hashCode() { + return Objects.hash(artifactId, artifactType, dependencyNodes, dependencyScope, failedArtifacts, groupId, + ignoredArtifacts, metadataMode, targetBundles, version); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MavenTargetLocation other = (MavenTargetLocation) obj; + return Objects.equals(artifactId, other.artifactId) && Objects.equals(artifactType, other.artifactType) + && Objects.equals(dependencyNodes, other.dependencyNodes) + && Objects.equals(dependencyScope, other.dependencyScope) + && Objects.equals(failedArtifacts, other.failedArtifacts) && Objects.equals(groupId, other.groupId) + && Objects.equals(ignoredArtifacts, other.ignoredArtifacts) && metadataMode == other.metadataMode + && Objects.equals(targetBundles, other.targetBundles) && Objects.equals(version, other.version); + } + + @Override + public String serialize() { + StringBuilder xml = new StringBuilder(); + xml.append(""); + xml.append("<" + ELEMENT_GROUP_ID + ">"); + xml.append(groupId); + xml.append(""); + xml.append("<" + ELEMENT_ARTIFACT_ID + ">"); + xml.append(artifactId); + xml.append(""); + xml.append("<" + ELEMENT_VERSION + ">"); + xml.append(version); + xml.append(""); + xml.append("<" + ELEMENT_TYPE + ">"); + xml.append(artifactType); + xml.append(""); + xml.append(""); + return xml.toString(); + } + + public String getArtifactId() { + return artifactId; + } + + public String getGroupId() { + return groupId; + } + + public String getVersion() { + return version; + } + + public MissingMetadataMode getMetadataMode() { + if (metadataMode == null) { + return DEFAULT_METADATA_MODE; + } + return metadataMode; + } + + public void refresh() { + dependencyNodes = null; + targetBundles = null; + } + + public String getArtifactType() { + if (artifactType != null && !artifactType.trim().isEmpty()) { + return artifactType; + } + return DEFAULT_PACKAGE_TYPE; + } + + public String getDependencyScope() { + if (dependencyScope != null && !dependencyScope.trim().isEmpty()) { + return dependencyScope; + } + return DEFAULT_DEPENDENCY_SCOPE; + } + + public boolean isIgnored(Artifact artifact) { + return ignoredArtifacts.contains(artifact); + } + + public boolean isFailed(Artifact artifact) { + return failedArtifacts.contains(artifact); + } +} diff --git a/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetLocationFactory.java b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetLocationFactory.java new file mode 100644 index 0000000000..bf03e9498e --- /dev/null +++ b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetLocationFactory.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.pde.core.target.ITargetLocation; +import org.eclipse.pde.core.target.ITargetLocationFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +public class MavenTargetLocationFactory implements ITargetLocationFactory { + + @Override + public ITargetLocation getTargetLocation(String type, String serializedXML) throws CoreException { + try { + DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document document = docBuilder + .parse(new ByteArrayInputStream(serializedXML.getBytes(StandardCharsets.UTF_8))); + Element location = document.getDocumentElement(); + MissingMetadataMode mode = MissingMetadataMode + .valueOf(location.getAttribute(MavenTargetLocation.ATTRIBUTE_MISSING_META_DATA).toUpperCase()); + String dependencyScope = location.getAttribute(MavenTargetLocation.ATTRIBUTE_DEPENDENCY_SCOPE); + String artifactId = getText(MavenTargetLocation.ELEMENT_ARTIFACT_ID, location); + String groupId = getText(MavenTargetLocation.ELEMENT_GROUP_ID, location); + String version = getText(MavenTargetLocation.ELEMENT_VERSION, location); + String artifactType = getText(MavenTargetLocation.ELEMENT_TYPE, location); + return new MavenTargetLocation(groupId, artifactId, version, artifactType, mode, dependencyScope); + } catch (Exception e) { + throw new CoreException(new Status(IStatus.ERROR, MavenTargetLocationFactory.class.getPackage().getName(), + e.getMessage(), e)); + } + + } + + private String getText(String tagName, Element location) { + NodeList nodeList = location.getElementsByTagName(tagName); + for (int i = 0; i < nodeList.getLength(); i++) { + String textContent = nodeList.item(i).getTextContent(); + if (textContent != null) { + return textContent; + } + } + return ""; + } + +} diff --git a/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MissingMetadataMode.java b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MissingMetadataMode.java new file mode 100644 index 0000000000..2f27d393a8 --- /dev/null +++ b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MissingMetadataMode.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2020 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde; + +public enum MissingMetadataMode { + IGNORE, ERROR, GENERATE; +} diff --git a/org.eclipse.m2e.site/category.xml b/org.eclipse.m2e.site/category.xml index e7e7651372..f032b94a9f 100644 --- a/org.eclipse.m2e.site/category.xml +++ b/org.eclipse.m2e.site/category.xml @@ -15,5 +15,8 @@ + + + diff --git a/org.eclipse.m2e.site/org.eclipse.m2e.site.product b/org.eclipse.m2e.site/org.eclipse.m2e.site.product index 7df88ed61f..4d3d00d55a 100644 --- a/org.eclipse.m2e.site/org.eclipse.m2e.site.product +++ b/org.eclipse.m2e.site/org.eclipse.m2e.site.product @@ -4,10 +4,11 @@ - - - - + + + + + diff --git a/pom.xml b/pom.xml index d1fe6ada89..32a851b4ab 100644 --- a/pom.xml +++ b/pom.xml @@ -93,6 +93,11 @@ p2 https://download.eclipse.org/wildwebdeveloper/releases/latest/ + + BND + p2 + https://bndtools.jfrog.io/bndtools/update-latest + org.eclipse.m2e.tests.common @@ -141,6 +148,7 @@ org.eclipse.m2e.sse.ui.feature org.eclipse.m2e.sdk.feature org.eclipse.m2e.logback.feature + org.eclipse.m2e.pde.feature org.eclipse.m2e.site