Skip to content

Commit 0f54f9d

Browse files
committed
Showing a preview of the target state in the editor
Currently if one loads a target not using the planner mode there is no guarantee setting it will actually lead to a satisfiable solution. And even with planner mode there are cases where P2 can get to a different result than a real OSGi resolution or there are location types that do not resolve at all. So currently one is forced to actually set the target platform, then look at the target platform state view, identify the problem, change something and start again. This aims to add a new tab "Resolved State" that shows the resolved state of the bundles that would be set as a result of activate the current target platform.
1 parent 6f0d306 commit 0f54f9d

File tree

7 files changed

+464
-233
lines changed

7 files changed

+464
-233
lines changed

ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
public class PDEUIMessages extends NLS {
2727
private static final String BUNDLE_NAME = "org.eclipse.pde.internal.ui.pderesources";//$NON-NLS-1$
2828

29+
public static String StatePage_title;
30+
2931
public static String AbstractLauncherToolbar_noProblems;
3032

3133
public static String AbstractLauncherToolbar_noSelection;

ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ManifestEditor.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
import java.io.File;
1818
import java.io.IOException;
19+
import java.net.URI;
20+
import java.net.URISyntaxException;
1921
import java.util.Locale;
2022
import java.util.zip.ZipFile;
2123

@@ -175,6 +177,14 @@ public static IEditorPart open(Object object, boolean source) {
175177
return open(model.getPluginBase(), true);
176178
}
177179
}
180+
String location = desc.getLocation();
181+
if (location != null && location.toLowerCase().startsWith("file:")) { //$NON-NLS-1$
182+
try {
183+
File file = new File(new URI(location));
184+
return openExternalPlugin(file, ICoreConstants.BUNDLE_FILENAME_DESCRIPTOR);
185+
} catch (URISyntaxException e) {
186+
}
187+
}
178188
}
179189
return null;
180190
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Christoph Läubrich and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* Christoph Läubrich - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.pde.internal.ui.editor.targetdefinition;
15+
16+
import java.io.ByteArrayInputStream;
17+
import java.nio.charset.StandardCharsets;
18+
import java.util.Map;
19+
20+
import org.eclipse.core.runtime.ILog;
21+
import org.eclipse.core.runtime.Status;
22+
import org.eclipse.core.runtime.jobs.Job;
23+
import org.eclipse.equinox.frameworkadmin.BundleInfo;
24+
import org.eclipse.osgi.service.resolver.BundleDescription;
25+
import org.eclipse.osgi.service.resolver.State;
26+
import org.eclipse.osgi.service.resolver.StateObjectFactory;
27+
import org.eclipse.osgi.util.ManifestElement;
28+
import org.eclipse.pde.core.target.ITargetDefinition;
29+
import org.eclipse.pde.core.target.TargetBundle;
30+
import org.eclipse.pde.internal.build.BundleHelper;
31+
import org.eclipse.pde.internal.core.PDECore;
32+
import org.eclipse.pde.internal.ui.PDEUIMessages;
33+
import org.eclipse.pde.internal.ui.views.target.StateTree;
34+
import org.eclipse.swt.widgets.Composite;
35+
import org.eclipse.swt.widgets.Control;
36+
import org.eclipse.ui.PlatformUI;
37+
import org.eclipse.ui.forms.editor.FormPage;
38+
import org.osgi.framework.FrameworkUtil;
39+
40+
public class StatePage extends FormPage {
41+
42+
public static final String PAGE_ID = "state"; //$NON-NLS-1$
43+
44+
private State state;
45+
46+
private StateTree stateTree;
47+
48+
private ITargetDefinition target;
49+
50+
private Job job;
51+
52+
private boolean active;
53+
54+
public StatePage(TargetEditor editor) {
55+
super(editor, PAGE_ID, PDEUIMessages.StatePage_title);
56+
}
57+
58+
@Override
59+
public void createPartControl(Composite parent) {
60+
stateTree = new StateTree(parent);
61+
stateTree.setInput(state);
62+
}
63+
64+
@Override
65+
public Control getPartControl() {
66+
return stateTree;
67+
}
68+
69+
@Override
70+
public void setActive(boolean active) {
71+
this.active = active;
72+
super.setActive(active);
73+
loadState();
74+
}
75+
76+
private void loadState() {
77+
if (!active || state != null || target == null) {
78+
return;
79+
}
80+
TargetBundle[] targetBundles = target.getBundles();
81+
if (targetBundles == null || targetBundles.length == 0) {
82+
return;
83+
}
84+
job = Job.create("Compute Target State", monitor -> { //$NON-NLS-1$
85+
try {
86+
State targetState = BundleHelper.getPlatformAdmin().getFactory().createState(true);
87+
targetState.setPlatformProperties(
88+
PDECore.getDefault().getModelManager().getState().getState().getPlatformProperties());
89+
StateObjectFactory factory = targetState.getFactory();
90+
long id = 1;
91+
for (TargetBundle targetBundle : targetBundles) {
92+
if (targetBundle.isSourceBundle()) {
93+
continue;
94+
}
95+
BundleInfo bundleInfo = targetBundle.getBundleInfo();
96+
String manifest = bundleInfo.getManifest();
97+
if (manifest != null) {
98+
Map<String, String> bundleManifest;
99+
try (ByteArrayInputStream stream = new ByteArrayInputStream(
100+
manifest.getBytes(StandardCharsets.UTF_8))) {
101+
bundleManifest = ManifestElement.parseBundleManifest(stream);
102+
}
103+
BundleDescription bundleDescription = factory.createBundleDescription(targetState,
104+
FrameworkUtil.asDictionary(bundleManifest),
105+
String.valueOf(targetBundle.getBundleInfo().getLocation()), id++);
106+
targetState.addBundle(bundleDescription);
107+
}
108+
if (monitor.isCanceled()) {
109+
return Status.CANCEL_STATUS;
110+
}
111+
}
112+
targetState.resolve(false);
113+
if (monitor.isCanceled()) {
114+
return Status.CANCEL_STATUS;
115+
}
116+
PlatformUI.getWorkbench().getDisplay().execute(() -> {
117+
state = targetState;
118+
if (stateTree != null) {
119+
stateTree.setInput(targetState);
120+
}
121+
});
122+
} catch (Exception e) {
123+
ILog.get().error("Computing target state failed!", e); //$NON-NLS-1$
124+
}
125+
return Status.OK_STATUS;
126+
});
127+
job.schedule();
128+
}
129+
130+
public void reset() {
131+
PlatformUI.getWorkbench().getDisplay().execute(() -> {
132+
update(null);
133+
if (stateTree != null) {
134+
stateTree.setInput(null);
135+
}
136+
});
137+
}
138+
139+
protected void update(ITargetDefinition target) {
140+
if (job != null) {
141+
job.cancel();
142+
job = null;
143+
}
144+
this.state = null;
145+
this.target = target;
146+
}
147+
148+
public void updateTarget(ITargetDefinition target) {
149+
PlatformUI.getWorkbench().getDisplay().execute(() -> {
150+
update(target);
151+
loadState();
152+
});
153+
}
154+
}

ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/targetdefinition/TargetEditor.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ public class TargetEditor extends FormEditor {
132132
private ImageHyperlink fLoadHyperlink;
133133

134134
private final EventHandler fEventHandler = this::handleBrokerEvent;
135+
private StatePage statePage;
135136

136137
@Override
137138
protected FormToolkit createToolkit(Display display) {
@@ -145,6 +146,8 @@ protected void addPages() {
145146
addPage(new DefinitionPage(this));
146147
addPage(new ContentPage(this));
147148
addPage(new EnvironmentPage(this));
149+
statePage = new StatePage(this);
150+
addPage(statePage);
148151
addTextualEditorPage();
149152
} catch (CoreException e) {
150153
PDEPlugin.log(e);
@@ -650,6 +653,7 @@ public void contentsChanged(ITargetDefinition definition, Object source, boolean
650653
// Check to see if we are resolved, resolving, or cancelled
651654
if (target != null && target.isResolved()) {
652655
fContentTree.setInput(getTarget());
656+
statePage.updateTarget(getTarget());
653657
} else if (Job.getJobManager().find(getJobFamily()).length > 0) {
654658
fContentTree.setInput(null);
655659
} else {
@@ -674,6 +678,7 @@ public void contentsChanged(ITargetDefinition definition, Object source, boolean
674678
if (name == null) {
675679
name = ""; //$NON-NLS-1$
676680
}
681+
statePage.reset();
677682
Job resolveJob = new Job(NLS.bind(PDEUIMessages.TargetEditor_1, name)) {
678683
@Override
679684
protected IStatus run(IProgressMonitor monitor) {
@@ -688,6 +693,7 @@ protected IStatus run(IProgressMonitor monitor) {
688693
if (monitor.isCanceled()) {
689694
return Status.CANCEL_STATUS;
690695
}
696+
statePage.updateTarget(getTarget());
691697
// Don't return any problems because we don't want an error dialog
692698
return Status.OK_STATUS;
693699
}

ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2727,3 +2727,4 @@ ProjectUpdateChange_configure_nature_and_builder=Update natures and builder
27272727
ProjectUpdateChange_convert_manifest_to_bnd=Convert MANIFEST.MF to bnd instructions
27282728
ProjectUpdateChange_convert_build_to_bnd=Convert build.properties to bnd instructions
27292729
ProjectUpdateChange_set_pde_preference=Set {0} in preferences
2730+
StatePage_title=Target State

0 commit comments

Comments
 (0)