Skip to content

Commit

Permalink
Improve workspace lock error dialog.
Browse files Browse the repository at this point in the history
Write workspace lock info like user, host, java process id, display
properties onto .lock file if the lock was successful.
Read the current lock data in case of lock was unsuccessful and shown it
in error dialog.
If the .lock file has no info then nothing is shown. For older eclipse
versions.

see #2343
  • Loading branch information
raghucssit committed Oct 1, 2024
1 parent 70a2d11 commit f34d747
Showing 1 changed file with 170 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
Expand All @@ -49,7 +51,11 @@
import org.eclipse.osgi.service.datalocation.Location;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
Expand Down Expand Up @@ -79,6 +85,20 @@ public class IDEApplication implements IApplication, IExecutableExtension {

private static final String VERSION_FILENAME = "version.ini"; //$NON-NLS-1$

private static final String LOCK_FILENAME = ".lock"; //$NON-NLS-1$

private static final String DISPLAY_VAR = "DISPLAY"; //$NON-NLS-1$

private static final String PROCESS_ID = "process-id"; //$NON-NLS-1$

private static final String DISPLAY = "display"; //$NON-NLS-1$

private static final String HOST = "host"; //$NON-NLS-1$

private static final String USER = "user"; //$NON-NLS-1$

private static final String USER_NAME = "user.name"; //$NON-NLS-1$

// Use the branding plug-in of the platform feature since this is most likely
// to change on an update of the IDE.
private static final String WORKSPACE_CHECK_REFERENCE_BUNDLE_NAME = "org.eclipse.platform"; //$NON-NLS-1$
Expand Down Expand Up @@ -225,6 +245,7 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
try {
if (instanceLoc.lock()) {
writeWorkspaceVersion();
writeWsLockInfo();
return null;
}

Expand Down Expand Up @@ -313,6 +334,7 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
if (instanceLoc.set(workspaceUrl, true)) {
launchData.writePersistedData();
writeWorkspaceVersion();
writeWsLockInfo();
return null;
}
} catch (IllegalStateException e) {
Expand All @@ -332,17 +354,164 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {

// by this point it has been determined that the workspace is
// already in use -- force the user to choose again

String lockInfo = getWorkspaceLockInfo(workspaceUrl);

MessageDialog dialog = new MessageDialog(null, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle,
null, NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceInUseMessage, workspaceUrl.getFile()),
MessageDialog.ERROR, 1, IDEWorkbenchMessages.IDEApplication_workspaceInUse_Retry,
IDEWorkbenchMessages.IDEApplication_workspaceInUse_Choose);
IDEWorkbenchMessages.IDEApplication_workspaceInUse_Choose) {
@Override
protected Control createCustomArea(Composite parent) {
if (lockInfo == null || lockInfo.isBlank()) {
return null;
}

String displayText = "Workspace lock is held by the following owner:\n".concat(lockInfo); //$NON-NLS-1$

Composite container = new Composite(parent, SWT.NONE);
container.setLayout(new FillLayout());

Label multiLineText = new Label(container, SWT.NONE);
multiLineText.setText(displayText);

return container;
}
};
// the return value influences the next loop's iteration
returnValue = dialog.open();
// Remember the locked workspace as recent workspace
launchData.writePersistedData();
}
}

/**
* Read workspace lock file and parse all the properties present. Based on the
* eclipse version and operating system some or all the properties may not
* present. In such scenario it will return empty string.
*
* @return Previous lock owner details.
*/
private String getWorkspaceLockInfo(URL workspaceUrl) {
File lockFile = getLockFile(workspaceUrl);
StringBuilder sb = new StringBuilder();
Properties props = new Properties();
try (FileInputStream is = new FileInputStream(lockFile)) {
props.load(is);
String prop = props.getProperty(USER);
if (prop != null) {
sb.append("user: ").append(prop).append(System.lineSeparator()); //$NON-NLS-1$
}
prop = props.getProperty(HOST);
if (prop != null) {
sb.append("host: ").append(prop).append(System.lineSeparator()); //$NON-NLS-1$
}
prop = props.getProperty(DISPLAY);
if (prop != null) {
sb.append("display: ").append(prop).append(System.lineSeparator()); //$NON-NLS-1$
}
prop = props.getProperty(PROCESS_ID);
if (prop != null) {
sb.append("process-id: ").append(prop).append(System.lineSeparator()); //$NON-NLS-1$
}
return sb.toString();
} catch (Exception e) {
IDEWorkbenchPlugin.log("Could not read lock file: ", e); //$NON-NLS-1$
}
return null;
}

/**
* Write lock owner details onto workspace lock file. Data includes user, host,
* display and current java process id.
*/
private void writeWsLockInfo() {
Location instanceLoc = Platform.getInstanceLocation();
if (instanceLoc == null || instanceLoc.isReadOnly()) {
return;
}

File lockFile = getLockFile(instanceLoc.getURL());
if (lockFile == null) {
return;
}

Properties props = new Properties();

String user = System.getProperty(USER_NAME);
if (user != null) {
props.setProperty(USER, user);
}
String host = getHostName();
if (host != null) {
props.setProperty(HOST, host);
}
String display = getDisplay();
if (display != null) {
props.setProperty(DISPLAY, display);
}
String pid = getProcessId();
if (pid != null) {
props.setProperty(PROCESS_ID, pid);
}

try (OutputStream output = new FileOutputStream(lockFile)) {
props.store(output, null);
} catch (IOException e) {
IDEWorkbenchPlugin.log("Could not modify lock file", e); //$NON-NLS-1$
}
}

private String getDisplay() {
String displayEnv = null;
try {
displayEnv = System.getenv(DISPLAY_VAR);
} catch (Exception e) {
IDEWorkbenchPlugin.log("Failed to read DISPLAY variable.", e); //$NON-NLS-1$
}
return displayEnv;
}

private String getProcessId() {
Long pid = null;
try {
pid = ProcessHandle.current().pid();
} catch (Exception e) {
IDEWorkbenchPlugin.log("Failed to read Java process id.", e); //$NON-NLS-1$
}
return pid != null ? pid.toString() : null;
}

private String getHostName() {
String hostName = null;
try {
hostName = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
IDEWorkbenchPlugin.log("Failed to read host name.", e); //$NON-NLS-1$
}
return hostName;
}

private File getLockFile(URL workspaceUrl) {
if (workspaceUrl == null) {
return null;
}

// make sure the directory exists
File metaDir = new File(workspaceUrl.getPath(), METADATA_FOLDER);
if (!metaDir.exists()) {
return null;
}

// make sure the file exists
File lockFile = new File(metaDir, LOCK_FILENAME);
if (!lockFile.exists()) {
return null;
}

return lockFile;
}

@SuppressWarnings("rawtypes")
private static boolean isDevLaunchMode(Map args) {
// see org.eclipse.pde.internal.core.PluginPathFinder.isDevLaunchMode()
Expand Down

0 comments on commit f34d747

Please sign in to comment.