Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ Require-Bundle: org.eclipse.jdt.junit.core;bundle-version="[3.6.0,4.0.0)",
org.eclipse.pde.build;bundle-version="[3.12.300,4.0.0)",
org.eclipse.pde.core;bundle-version="[3.2.0,4.0.0)",
org.eclipse.jdt.debug;bundle-version="[3.2.0,4.0.0)",
org.eclipse.core.filesystem;bundle-version="[1.0.0,2.0.0)"
org.eclipse.core.filesystem;bundle-version="[1.0.0,2.0.0)",
org.eclipse.equinox.p2.core;bundle-version="[2.10.0,3.0.0)",
org.eclipse.equinox.p2.metadata;bundle-version="[2.8.0,3.0.0)",
org.eclipse.equinox.p2.repository;bundle-version="[2.8.0,3.0.0)"
Bundle-Activator: org.eclipse.pde.internal.launching.PDELaunchingPlugin
Export-Package: org.eclipse.pde.internal.launching;x-friends:="org.eclipse.pde.ui,
org.eclipse.pde.unittest.junit",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public interface ILaunchingPreferenceConstants {
* arguments when creating a new launch configuration
*/
public static final String ADD_SWT_NON_DISPOSAL_REPORTING = "Preferences.Launching.addSwtNonDisposalReporting";//$NON-NLS-1$

/**
* Boolean preference whether to search in enabled repositories for source bundles
*/
public static final String PROP_SEARCH_REPOSITORIES_FOR_SOURCE = "Preferences.Launching.searchRepositoriesForSource";//$NON-NLS-1$

// OSGi Frameworks
public static final String DEFAULT_OSGI_FRAMEOWRK = "Preference.default.osgi.framework"; //$NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public void initializeDefaultPreferences() {
prefs.putBoolean(ILaunchingPreferenceConstants.PROP_JUNIT_ADD_NEW_WORKSPACE_PLUGINS, false);
prefs.putBoolean(ILaunchingPreferenceConstants.PROP_JUNIT_VALIDATE_LAUNCH, true);
prefs.putBoolean(ILaunchingPreferenceConstants.ADD_SWT_NON_DISPOSAL_REPORTING, true);
prefs.putBoolean(ILaunchingPreferenceConstants.PROP_SEARCH_REPOSITORIES_FOR_SOURCE, false);

// copy over instance scope prefs from UI plugin
IEclipsePreferences oldInstancePrefs = InstanceScope.INSTANCE.getNode(IPDEConstants.UI_PLUGIN_ID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,21 @@ public synchronized void dispose() {
return fOSGiRuntimeVersion;
}

/**
* Searches for source in P2 repositories as a fallback.
* This has lower priority than workspace and target platform sources.
*
* @param bundleId the symbolic name of the bundle
* @param typeName the qualified name of the source type
* @return source element or <code>null</code>
*/
Object findSourceInRepositories(String bundleId, String typeName) throws CoreException {
RepositorySourceContainer container = new RepositorySourceContainer(bundleId);
Object[] result = container.findSourceElements(typeName);
if (result != null && result.length > 0) {
return result[0];
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,12 @@ private Object getSourceElement(String location, String id, String typeName, boo
}
}
}

// As a last resort, search in repositories for source bundles
result = fDirector.findSourceInRepositories(id, typeName);
if (result != null) {
return result;
}
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*******************************************************************************
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.pde.internal.launching.sourcelookup;

import java.io.File;
import java.net.URI;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.sourcelookup.ISourceContainerType;
import org.eclipse.debug.core.sourcelookup.containers.AbstractSourceContainer;
import org.eclipse.debug.core.sourcelookup.containers.ExternalArchiveSourceContainer;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.IProvisioningAgentProvider;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.artifact.IFileArtifactRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.internal.core.target.P2TargetUtils;
import org.eclipse.pde.internal.launching.IPDEConstants;
import org.eclipse.pde.internal.launching.PDELaunchingPlugin;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

/**
* Source container that searches for source bundles in enabled P2 repositories.
* This is used as a fallback when source cannot be found in workspace or target platform.
*
* @since 3.8
*/
public class RepositorySourceContainer extends AbstractSourceContainer {

/**
* Unique identifier for this source container type
*/
public static final String TYPE_ID = IPDEConstants.PLUGIN_ID + ".containerType.repository"; //$NON-NLS-1$

private final String fBundleId;

/**
* Constructs a repository source container for the given bundle.
*
* @param bundleId symbolic name of the bundle to search for source
*/
public RepositorySourceContainer(String bundleId) {
fBundleId = bundleId;
}

@Override
public String getName() {
return NLS.bind("Repository Source: {0}", fBundleId); //$NON-NLS-1$
}

@Override
public ISourceContainerType getType() {
return getSourceContainerType(TYPE_ID);
}

@Override
public Object[] findSourceElements(String name) throws CoreException {
// Only search if the preference is enabled
if (!PDELaunchingPlugin.getDefault().getPreferenceManager()
.getBoolean(org.eclipse.pde.internal.launching.ILaunchingPreferenceConstants.PROP_SEARCH_REPOSITORIES_FOR_SOURCE)) {
return EMPTY;
}

// Search for source bundle in repositories
File sourceBundle = findSourceBundle(fBundleId);
if (sourceBundle != null && sourceBundle.exists()) {
// Create an external archive source container for the source bundle
ExternalArchiveSourceContainer container = new ExternalArchiveSourceContainer(
sourceBundle.getAbsolutePath(), true);
return container.findSourceElements(name);
}

return EMPTY;
}

/**
* Searches enabled P2 repositories for a source bundle matching the given bundle ID.
*
* @param bundleId the symbolic name of the bundle
* @return the source bundle file, or null if not found
*/
private File findSourceBundle(String bundleId) {
try {
IProvisioningAgent agent = getProvisioningAgent();
if (agent == null) {
return null;
}

IMetadataRepositoryManager metadataManager = agent.getService(IMetadataRepositoryManager.class);
IArtifactRepositoryManager artifactManager = agent.getService(IArtifactRepositoryManager.class);

if (metadataManager == null || artifactManager == null) {
return null;
}

// Get all known repositories
URI[] metadataRepos = metadataManager.getKnownRepositories(IMetadataRepositoryManager.REPOSITORIES_ALL);

for (URI repoUri : metadataRepos) {
try {
// Load the metadata repository
IMetadataRepository metadataRepo = metadataManager.loadRepository(repoUri, null);

// Query for source bundles matching the bundle ID
// Source bundles typically have .source appended to the ID
String sourceId = bundleId + ".source"; //$NON-NLS-1$
IQuery<IInstallableUnit> query = QueryUtil.createLatestQuery(
QueryUtil.createIUQuery(sourceId));
IQueryResult<IInstallableUnit> result = metadataRepo.query(query, null);

if (!result.isEmpty()) {
IInstallableUnit sourceIU = result.iterator().next();

// Get the artifact from the artifact repository
for (IArtifactKey key : sourceIU.getArtifacts()) {
File sourceFile = getArtifactFile(artifactManager, key, repoUri);
if (sourceFile != null && sourceFile.exists()) {
return sourceFile;
}
}
}
} catch (Exception e) {
// Continue searching in other repositories
PDELaunchingPlugin.log(new Status(IStatus.WARNING, IPDEConstants.PLUGIN_ID,
"Error searching repository: " + repoUri, e)); //$NON-NLS-1$
}
}
} catch (Exception e) {
PDELaunchingPlugin.log(new Status(IStatus.ERROR, IPDEConstants.PLUGIN_ID,
"Error searching for source bundle: " + bundleId, e)); //$NON-NLS-1$
}

return null;
}

/**
* Gets the provisioning agent for P2 operations.
*/
private IProvisioningAgent getProvisioningAgent() {
BundleContext context = PDELaunchingPlugin.getDefault().getBundle().getBundleContext();
ServiceReference<IProvisioningAgentProvider> reference = context
.getServiceReference(IProvisioningAgentProvider.class);
if (reference != null) {
IProvisioningAgentProvider agentProvider = context.getService(reference);
if (agentProvider != null) {
try {
return agentProvider.createAgent(P2TargetUtils.AGENT_LOCATION);
} catch (Exception e) {
PDELaunchingPlugin.log(e);
} finally {
context.ungetService(reference);
}
}
}
return null;
}

/**
* Retrieves the local file for an artifact from the repository.
*/
private File getArtifactFile(IArtifactRepositoryManager manager, IArtifactKey key, URI repoUri) {
try {
IArtifactRepository artifactRepo = manager.loadRepository(repoUri, null);
if (artifactRepo instanceof IFileArtifactRepository fileRepo) {
File location = fileRepo.getArtifactFile(key);
if (location != null && location.exists()) {
return location;
}
}
} catch (Exception e) {
// Ignore and return null
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2713,6 +2713,8 @@ public class PDEUIMessages extends NLS {

public static String LaunchingPreferencePage_description;

public static String LaunchingPreferencePage_searchRepositoriesForSource;

public static String RemoveLazyLoadingDirectiveResolution_remove;

public static String RemoveAutomaticModuleResolution_remove;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2194,6 +2194,7 @@ LauncherSection_launcherName=Launcher Name:
LauncherSection_dialogTitle=Image Selection
LauncherSection_dialogMessage=Select an image:
LaunchingPreferencePage_description=Settings for Plug-in launches
LaunchingPreferencePage_searchRepositoriesForSource=Search in repositories for source bundles (may be slower)
RemoveLazyLoadingDirectiveResolution_remove=Remove lazy activation header
RemoveAutomaticModuleResolution_remove=Remove automatic module name header
ProductDefinitonWizardPage_applicationDefinition=<form><p>An Eclipse product must be associated with an <a href="applications">application</a>, the default entry point for the product when it is running.</p></form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ protected boolean isFile() {

private Button fAddSwtNonDisposalReporting;

private Button fSearchRepositoriesForSource;

private Text fRuntimeWorkspaceLocation;
private Button fRuntimeWorkspaceLocationRadio;
private Button fRuntimeWorkspacesContainerRadio;
Expand Down Expand Up @@ -188,6 +190,11 @@ protected Control createContents(Composite parent) {
fAddSwtNonDisposalReporting
.setSelection(launchingStore.getBoolean(ILaunchingPreferenceConstants.ADD_SWT_NON_DISPOSAL_REPORTING));

fSearchRepositoriesForSource = new Button(optionComp, SWT.CHECK);
fSearchRepositoriesForSource.setText(PDEUIMessages.LaunchingPreferencePage_searchRepositoriesForSource);
fSearchRepositoriesForSource
.setSelection(launchingStore.getBoolean(ILaunchingPreferenceConstants.PROP_SEARCH_REPOSITORIES_FOR_SOURCE));

new DefaultRuntimeWorkspaceBlock().createControl(composite);
fRuntimeWorkspaceLocation
.setText(launchingStore.getString(ILaunchingPreferenceConstants.PROP_RUNTIME_WORKSPACE_LOCATION));
Expand Down Expand Up @@ -250,6 +257,8 @@ public boolean performOk() {
fJunitAutoValidate.getSelection());
launchingStore.setValueOrRemove(ILaunchingPreferenceConstants.ADD_SWT_NON_DISPOSAL_REPORTING,
fAddSwtNonDisposalReporting.getSelection());
launchingStore.setValueOrRemove(ILaunchingPreferenceConstants.PROP_SEARCH_REPOSITORIES_FOR_SOURCE,
fSearchRepositoriesForSource.getSelection());
try {
launchingStore.flush();
} catch (BackingStoreException e) {
Expand Down Expand Up @@ -287,6 +296,8 @@ protected void performDefaults() {
launchingStore.getDefaultBoolean(ILaunchingPreferenceConstants.PROP_JUNIT_ADD_NEW_WORKSPACE_PLUGINS));
fJunitAutoValidate.setSelection(
launchingStore.getDefaultBoolean(ILaunchingPreferenceConstants.PROP_JUNIT_VALIDATE_LAUNCH));
fSearchRepositoriesForSource.setSelection(
launchingStore.getDefaultBoolean(ILaunchingPreferenceConstants.PROP_SEARCH_REPOSITORIES_FOR_SOURCE));
}

@Override
Expand Down