Skip to content

Commit 52d1a35

Browse files
raghucssitiloveeclipse
authored andcommitted
Improve workspace lock error dialog.
Write workspace lock info like user, host, java process id, display properties onto a new file .lock_info if the lock was successful. Read the current lock data in case of lock was unsuccessful and show it in error dialog. If the .lock_info does not exist or the file has no info then nothing is shown. For older eclipse versions. see eclipse-platform#2343
1 parent 1eead54 commit 52d1a35

File tree

3 files changed

+218
-2
lines changed

3 files changed

+218
-2
lines changed

bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java

Lines changed: 206 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@
2525
import java.io.FileOutputStream;
2626
import java.io.IOException;
2727
import java.io.OutputStream;
28+
import java.net.InetAddress;
2829
import java.net.MalformedURLException;
2930
import java.net.URL;
31+
import java.nio.file.Files;
32+
import java.nio.file.Path;
3033
import java.util.LinkedHashMap;
3134
import java.util.Map;
3235
import java.util.Properties;
@@ -49,7 +52,11 @@
4952
import org.eclipse.osgi.service.datalocation.Location;
5053
import org.eclipse.osgi.util.NLS;
5154
import org.eclipse.swt.SWT;
55+
import org.eclipse.swt.layout.FillLayout;
56+
import org.eclipse.swt.widgets.Composite;
57+
import org.eclipse.swt.widgets.Control;
5258
import org.eclipse.swt.widgets.Display;
59+
import org.eclipse.swt.widgets.Label;
5360
import org.eclipse.swt.widgets.Shell;
5461
import org.eclipse.ui.IWorkbench;
5562
import org.eclipse.ui.PlatformUI;
@@ -79,6 +86,22 @@ public class IDEApplication implements IApplication, IExecutableExtension {
7986

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

89+
private static final String LOCK_INFO_FILENAME = ".lock_info"; //$NON-NLS-1$
90+
91+
private static final String DISPLAY_VAR = "DISPLAY"; //$NON-NLS-1$
92+
93+
private static final String HOST_NAME_VAR = "HOSTNAME"; //$NON-NLS-1$
94+
95+
private static final String PROCESS_ID = "process-id"; //$NON-NLS-1$
96+
97+
private static final String DISPLAY = "display"; //$NON-NLS-1$
98+
99+
private static final String HOST = "host"; //$NON-NLS-1$
100+
101+
private static final String USER = "user"; //$NON-NLS-1$
102+
103+
private static final String USER_NAME = "user.name"; //$NON-NLS-1$
104+
82105
// Use the branding plug-in of the platform feature since this is most likely
83106
// to change on an update of the IDE.
84107
private static final String WORKSPACE_CHECK_REFERENCE_BUNDLE_NAME = "org.eclipse.platform"; //$NON-NLS-1$
@@ -225,6 +248,7 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
225248
try {
226249
if (instanceLoc.lock()) {
227250
writeWorkspaceVersion();
251+
writeWsLockInfo(instanceLoc.getURL());
228252
return null;
229253
}
230254

@@ -237,10 +261,19 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
237261
if (isDevLaunchMode(applicationArguments)) {
238262
return EXIT_WORKSPACE_LOCKED;
239263
}
264+
265+
String wsLockedError = NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage,
266+
workspaceDirectory.getAbsolutePath());
267+
// check if there is a lock info then append it to error message.
268+
String lockInfo = getWorkspaceLockInfo(instanceLoc.getURL());
269+
if (lockInfo != null && !lockInfo.isBlank()) {
270+
wsLockedError = wsLockedError + System.lineSeparator() + System.lineSeparator()
271+
+ NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Message, lockInfo);
272+
}
240273
MessageDialog.openError(
241274
shell,
242275
IDEWorkbenchMessages.IDEApplication_workspaceCannotLockTitle,
243-
NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage, workspaceDirectory.getAbsolutePath()));
276+
wsLockedError);
244277
} else {
245278
MessageDialog.openError(
246279
shell,
@@ -313,6 +346,7 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
313346
if (instanceLoc.set(workspaceUrl, true)) {
314347
launchData.writePersistedData();
315348
writeWorkspaceVersion();
349+
writeWsLockInfo(instanceLoc.getURL());
316350
return null;
317351
}
318352
} catch (IllegalStateException e) {
@@ -332,17 +366,187 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
332366

333367
// by this point it has been determined that the workspace is
334368
// already in use -- force the user to choose again
369+
370+
String lockInfo = getWorkspaceLockInfo(workspaceUrl);
371+
335372
MessageDialog dialog = new MessageDialog(null, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle,
336373
null, NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceInUseMessage, workspaceUrl.getFile()),
337374
MessageDialog.ERROR, 1, IDEWorkbenchMessages.IDEApplication_workspaceInUse_Retry,
338-
IDEWorkbenchMessages.IDEApplication_workspaceInUse_Choose);
375+
IDEWorkbenchMessages.IDEApplication_workspaceInUse_Choose) {
376+
@Override
377+
protected Control createCustomArea(Composite parent) {
378+
if (lockInfo == null || lockInfo.isBlank()) {
379+
return null;
380+
}
381+
382+
Composite container = new Composite(parent, SWT.NONE);
383+
container.setLayout(new FillLayout());
384+
385+
Label multiLineText = new Label(container, SWT.NONE);
386+
multiLineText.setText(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Message, lockInfo));
387+
388+
return container;
389+
}
390+
};
339391
// the return value influences the next loop's iteration
340392
returnValue = dialog.open();
341393
// Remember the locked workspace as recent workspace
342394
launchData.writePersistedData();
343395
}
344396
}
345397

398+
/**
399+
* Read workspace lock file and parse all the properties present. Based on the
400+
* eclipse version and operating system some or all the properties may not
401+
* present. In such scenario it will return empty string.
402+
*
403+
* @return Previous lock owner details.
404+
*/
405+
protected String getWorkspaceLockInfo(URL workspaceUrl) {
406+
try {
407+
File lockFile = getLockInfoFile(workspaceUrl);
408+
if (!lockFile.exists()) {
409+
return null;
410+
}
411+
412+
StringBuilder sb = new StringBuilder();
413+
Properties props = new Properties();
414+
try (FileInputStream is = new FileInputStream(lockFile)) {
415+
props.load(is);
416+
String prop = props.getProperty(USER);
417+
if (prop != null) {
418+
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_User, prop));
419+
}
420+
prop = props.getProperty(HOST);
421+
if (prop != null) {
422+
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Host, prop));
423+
}
424+
prop = props.getProperty(DISPLAY);
425+
if (prop != null) {
426+
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Disp, prop));
427+
}
428+
prop = props.getProperty(PROCESS_ID);
429+
if (prop != null) {
430+
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_P_Id, prop));
431+
}
432+
return sb.toString();
433+
}
434+
} catch (Exception e) {
435+
IDEWorkbenchPlugin.log("Could not read lock info file: ", e); //$NON-NLS-1$
436+
437+
}
438+
return null;
439+
}
440+
441+
/**
442+
* Write lock owner details onto workspace lock file. Data includes user, host,
443+
* display and current java process id.
444+
*
445+
* @param instanceLoc
446+
*/
447+
protected void writeWsLockInfo(URL workspaceUrl) {
448+
Properties props = new Properties();
449+
450+
String user = System.getProperty(USER_NAME);
451+
if (user != null) {
452+
props.setProperty(USER, user);
453+
}
454+
String host = getHostName();
455+
if (host != null) {
456+
props.setProperty(HOST, host);
457+
}
458+
String display = getDisplay();
459+
if (display != null) {
460+
props.setProperty(DISPLAY, display);
461+
}
462+
String pid = getProcessId();
463+
if (pid != null) {
464+
props.setProperty(PROCESS_ID, pid);
465+
}
466+
467+
if (props.isEmpty()) {
468+
return;
469+
}
470+
471+
try (OutputStream output = new FileOutputStream(createLockInfoFile(workspaceUrl))) {
472+
props.store(output, null);
473+
} catch (Exception e) {
474+
IDEWorkbenchPlugin.log("Could not write lock info file", e); //$NON-NLS-1$
475+
}
476+
}
477+
478+
private String getDisplay() {
479+
String displayEnv = null;
480+
try {
481+
displayEnv = System.getenv(DISPLAY_VAR);
482+
} catch (Exception e) {
483+
IDEWorkbenchPlugin.log("Failed to read DISPLAY variable.", e); //$NON-NLS-1$
484+
}
485+
return displayEnv;
486+
}
487+
488+
private String getProcessId() {
489+
Long pid = null;
490+
try {
491+
pid = ProcessHandle.current().pid();
492+
} catch (Exception e) {
493+
IDEWorkbenchPlugin.log("Failed to read Java process id.", e); //$NON-NLS-1$
494+
}
495+
return pid != null ? pid.toString() : null;
496+
}
497+
498+
private String getHostName() {
499+
String hostName = null;
500+
501+
// Try fast approach first. Some OS(Like Linux) has HOSTNAME environment
502+
// variable set.
503+
try {
504+
hostName = System.getenv(HOST_NAME_VAR);
505+
if (hostName != null && !hostName.isEmpty()) {
506+
return hostName;
507+
}
508+
} catch (Exception e) {
509+
// Ignore here because we will try another method in the next step.
510+
}
511+
512+
try {
513+
hostName = InetAddress.getLocalHost().getHostName();
514+
} catch (Exception e) {
515+
IDEWorkbenchPlugin.log("Failed to read host name.", e); //$NON-NLS-1$
516+
}
517+
return hostName;
518+
}
519+
520+
/**
521+
* Returns the .lock_info file. Does not check if it exists.
522+
*
523+
* @param workspaceUrl
524+
* @return .lock_info file.
525+
*/
526+
private File getLockInfoFile(URL workspaceUrl) {
527+
Path lockInfoPath = Path.of(workspaceUrl.getPath(), METADATA_FOLDER, LOCK_INFO_FILENAME);
528+
return lockInfoPath.toFile();
529+
}
530+
531+
/**
532+
* Creates the .lock_info file if it does not exist.
533+
*
534+
* @param workspaceUrl
535+
* @return .lock_info file.
536+
*/
537+
private File createLockInfoFile(URL workspaceUrl) throws Exception {
538+
File lockInfoFile = getLockInfoFile(workspaceUrl);
539+
540+
if (lockInfoFile.exists())
541+
return lockInfoFile;
542+
543+
Path createdPath = Files.createFile(lockInfoFile.toPath());
544+
if (createdPath != null) {
545+
return createdPath.toFile();
546+
}
547+
return null;
548+
}
549+
346550
@SuppressWarnings("rawtypes")
347551
private static boolean isDevLaunchMode(Map args) {
348552
// see org.eclipse.pde.internal.core.PluginPathFinder.isDevLaunchMode()

bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,12 @@ public class IDEWorkbenchMessages extends NLS {
11471147
public static String WorkbenchPreference_maxSimultaneousBuilds;
11481148
public static String WorkbenchPreference_maxSimultaneousBuildIntervalError;
11491149

1150+
public static String IDEApplication_Ws_Lock_Owner_User;
1151+
public static String IDEApplication_Ws_Lock_Owner_Host;
1152+
public static String IDEApplication_Ws_Lock_Owner_Disp;
1153+
public static String IDEApplication_Ws_Lock_Owner_P_Id;
1154+
public static String IDEApplication_Ws_Lock_Owner_Message;
1155+
11501156
static {
11511157
// load message values from bundle file
11521158
NLS.initializeMessages(BUNDLE_NAME, IDEWorkbenchMessages.class);

bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,3 +1150,9 @@ OpenDelayedUrlAction_title=Open URL
11501150
editorAssociationOverride_error_couldNotCreate_message=The ''{0}'' extension from plug-in ''{1}'' to the ''org.eclipse.ui.ide.editorAssociationOverride'' extension point failed to load the editor association override class.
11511151
editorAssociationOverride_error_invalidElementName_message=An extension from plug-in ''{0}'' to the ''org.eclipse.ui.ide.editorAssociationOverride'' extension point was ignored because it contains the following invalid element: ''{1}''.
11521152
editorAssociationOverride_error_invalidExtension_message=The ''{0}'' extension from plug-in ''{1}'' to the ''org.eclipse.ui.ide.editorAssociationOverride'' extension point will be ignored because it contains invalid attributes.
1153+
1154+
IDEApplication_Ws_Lock_Owner_User=User:\t\t{0}\n
1155+
IDEApplication_Ws_Lock_Owner_Host=Host:\t\t{0}\n
1156+
IDEApplication_Ws_Lock_Owner_Disp=Display:\t\t{0}\n
1157+
IDEApplication_Ws_Lock_Owner_P_Id=Process ID:\t{0}\n
1158+
IDEApplication_Ws_Lock_Owner_Message=Workspace lock is currently held by:\n{0}

0 commit comments

Comments
 (0)