Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
preferences.setValue(ICoreConstants.WORKSPACE_TARGET_HANDLE, ""); //$NON-NLS-1$
}
preferences.setValue(ICoreConstants.WORKSPACE_TARGET_HANDLE, memento);
storeActiveTargetFileStamp(preferences);


loadJRE(subMon.split(3));
Expand Down Expand Up @@ -173,6 +174,22 @@ private void loadJRE(IProgressMonitor monitor) {
monitor.done();
}

/**
* Records the disk modification timestamp of the active target's backing
* file so that on the next workspace start we can detect external changes
* (e.g. {@code git pull}) and reload automatically. Cleared for handles
* that are not file-backed so a stale stamp doesn't trigger a spurious
* reload after the user switches target type.
*/
private void storeActiveTargetFileStamp(PDEPreferencesManager preferences) {
java.io.File file = fTarget == null ? null : TargetPlatformService.backingFile(fTarget.getHandle());
if (file != null) {
preferences.setValue(ICoreConstants.WORKSPACE_TARGET_FILE_STAMP, Long.toString(file.lastModified()));
} else {
preferences.setToDefault(ICoreConstants.WORKSPACE_TARGET_FILE_STAMP);
}
}

/**
* Resets the PDE workspace models with the new state information
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,16 @@ public interface ICoreConstants {
*/
String WORKSPACE_TARGET_HANDLE = "workspace_target_handle"; //$NON-NLS-1$

/**
* Preference key storing the disk modification timestamp of the active workspace
* target file at the time it was last loaded via {@code LoadTargetDefinitionJob}.
* Used on workspace startup to detect that the .target file has been modified
* externally (e.g. by a {@code git pull}) since the last load, so the platform
* can be reloaded automatically. Only meaningful when the active target is a
* {@code WorkspaceFileTargetHandle}.
*/
String WORKSPACE_TARGET_FILE_STAMP = "workspace_target_file_stamp"; //$NON-NLS-1$

/**
* Preference key for the workspace bundle overriding target bundle for the
* same id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ public void start(BundleContext context) throws Exception {

fTargetPlatformService = context.registerService(ITargetPlatformService.class,
TargetPlatformService.getDefault(), new Hashtable<>());
((TargetPlatformService) TargetPlatformService.getDefault()).start();
fBundleProjectService = context.registerService(IBundleProjectService.class, BundleProjectService.getDefault(),
new Hashtable<>());

Expand Down Expand Up @@ -446,6 +447,7 @@ public void stop(BundleContext context) throws CoreException {
PluginModelManager.shutdownInstance();

if (fTargetPlatformService != null) {
((TargetPlatformService) TargetPlatformService.getDefault()).stop();
fTargetPlatformService.unregister();
fTargetPlatformService = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
Expand All @@ -62,6 +65,7 @@
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.ITargetHandle;
import org.eclipse.pde.core.target.LoadTargetDefinitionJob;
import org.eclipse.pde.core.target.ITargetLocation;
import org.eclipse.pde.core.target.ITargetPlatformService;
import org.eclipse.pde.core.target.NameVersionDescriptor;
Expand Down Expand Up @@ -103,6 +107,15 @@ public class TargetPlatformService implements ITargetPlatformService {
*/
private StringBuilder fVMArguments;

/**
* Workspace path of the active target's underlying file, when the active
* target is a {@link WorkspaceFileTargetHandle}. {@code null} otherwise.
* Read by the resource listener to detect external changes.
*/
private volatile IPath fActiveTargetFilePath;

private IResourceChangeListener fActiveTargetFileListener;

private TargetPlatformService() {
}

Expand Down Expand Up @@ -330,11 +343,116 @@ public synchronized ITargetDefinition getWorkspaceTargetDefinition() throws Core
*/
public void setWorkspaceTargetDefinition(ITargetDefinition target, boolean asyncEvents) {
ITargetDefinition oldTarget = fWorkspaceTarget.getAndSet(target);
refreshActiveTargetFilePath(target);
if (!Objects.equals(oldTarget, target)) {
notifyEvent(TargetEvents.TOPIC_WORKSPACE_TARGET_CHANGED, target, asyncEvents);
}
}

private void refreshActiveTargetFilePath(ITargetDefinition target) {
if (target != null && target.getHandle() instanceof WorkspaceFileTargetHandle wsHandle) {
fActiveTargetFilePath = wsHandle.getTargetFile().getFullPath();
} else {
fActiveTargetFilePath = null;
}
}

/**
* Registers a workspace listener that schedules a reload of the target
* platform whenever the active target's underlying {@code .target} file
* changes on disk. Only applies when the active target is a workspace
* file (handles backed by external/local files are not watched here).
*/
public void start() {
if (fActiveTargetFileListener != null) {
return;
}
fActiveTargetFileListener = this::onResourceChanged;
ResourcesPlugin.getWorkspace().addResourceChangeListener(fActiveTargetFileListener,
IResourceChangeEvent.POST_CHANGE);
reloadIfActiveTargetFileChangedSinceLastSession();
}

/**
* If the active target is backed by a file on disk and its modification
* timestamp differs from the one recorded on the last successful
* {@link LoadTargetDefinitionJob}, schedule a reload. Catches edits made
* while the workspace was closed (e.g. {@code git pull}) for both workspace
* {@code .target} files and external {@code file:} URIs - workspace resource
* events cannot detect either.
*/
private void reloadIfActiveTargetFileChangedSinceLastSession() {
try {
ITargetHandle handle = getWorkspaceTargetHandle();
File file = backingFile(handle);
if (file == null || !file.isFile()) {
return;
}
PDEPreferencesManager preferences = PDECore.getDefault().getPreferencesManager();
String storedStamp = preferences.getString(ICoreConstants.WORKSPACE_TARGET_FILE_STAMP);
if (storedStamp == null || storedStamp.isEmpty()) {
// No baseline yet (first run, or older workspace). Don't trigger a
// reload here; the next explicit load will record the stamp.
return;
}
long previousStamp;
try {
previousStamp = Long.parseLong(storedStamp);
} catch (NumberFormatException e) {
return;
}
long currentStamp = file.lastModified();
if (currentStamp != 0 && currentStamp != previousStamp) {
LoadTargetDefinitionJob.load(handle.getTargetDefinition());
}
} catch (CoreException e) {
PDECore.log(e);
}
}

/**
* Returns the on-disk file backing the given handle, if any. Workspace and
* external file handles are file-backed; remote and local-metadata handles
* return {@code null}.
*/
public static File backingFile(ITargetHandle handle) {
if (handle instanceof WorkspaceFileTargetHandle wsHandle) {
IPath location = wsHandle.getTargetFile().getLocation();
return location == null ? null : location.toFile();
}
if (handle instanceof ExternalFileTargetHandle extHandle) {
return URIUtil.toFile(extHandle.getLocation());
}
return null;
}

public void stop() {
if (fActiveTargetFileListener != null) {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(fActiveTargetFileListener);
fActiveTargetFileListener = null;
}
}

private void onResourceChanged(IResourceChangeEvent event) {
IPath path = fActiveTargetFilePath;
if (path == null || event.getDelta() == null) {
return;
}
IResourceDelta delta = event.getDelta().findMember(path);
if (delta == null || delta.getKind() != IResourceDelta.CHANGED
|| (delta.getFlags() & IResourceDelta.CONTENT) == 0) {
return;
}
try {
ITargetHandle handle = getWorkspaceTargetHandle();
if (handle != null && handle.exists()) {
LoadTargetDefinitionJob.load(handle.getTargetDefinition());
}
} catch (CoreException e) {
PDECore.log(e);
}
}

public static void scheduleEvent(String topic, Object data) {
notifyEvent(topic, data, true);
}
Expand Down
3 changes: 2 additions & 1 deletion ui/org.eclipse.pde.spy.core/forceQualifierUpdate.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# To force a version qualifier update add the bug here
https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1184
https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1659
https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1659
https://github.com/eclipse-pde/eclipse.pde/pull/2326
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ public void process(IExtensionRegistry extRegistry) {
// Bind the command with the binding, and add the view ID as
// parameter.
// The part class name will be the ID of the part descriptor
bindSpyKeyBinding(bindingTable, shortCut, command, partID);
if (shortCut != null && !shortCut.isBlank()) {
bindSpyKeyBinding(bindingTable, shortCut, command, partID);
}

// Add the descriptor in application
addSpyPartDescriptor(partID, partName, iconPath, partClass, desc);
Expand Down
Loading