Skip to content

Commit f8f7892

Browse files
committed
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 #2343
1 parent cc770ec commit f8f7892

File tree

3 files changed

+243
-18
lines changed

3 files changed

+243
-18
lines changed

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

Lines changed: 215 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 HOSTNAME_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();
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();
316350
return null;
317351
}
318352
} catch (IllegalStateException e) {
@@ -332,17 +366,196 @@ 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+
private String getWorkspaceLockInfo(URL workspaceUrl) {
406+
File lockFile = getLockInfoFile(workspaceUrl, false);
407+
if (lockFile == null) {
408+
return null;
409+
}
410+
StringBuilder sb = new StringBuilder();
411+
Properties props = new Properties();
412+
try (FileInputStream is = new FileInputStream(lockFile)) {
413+
props.load(is);
414+
String prop = props.getProperty(USER);
415+
if (prop != null) {
416+
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_User, prop));
417+
}
418+
prop = props.getProperty(HOST);
419+
if (prop != null) {
420+
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Host, prop));
421+
}
422+
prop = props.getProperty(DISPLAY);
423+
if (prop != null) {
424+
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Display, prop));
425+
}
426+
prop = props.getProperty(PROCESS_ID);
427+
if (prop != null) {
428+
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Process_Id, prop));
429+
}
430+
return sb.toString();
431+
} catch (Exception e) {
432+
IDEWorkbenchPlugin.log("Could not read lock file: ", e); //$NON-NLS-1$
433+
}
434+
return null;
435+
}
436+
437+
/**
438+
* Write lock owner details onto workspace lock file. Data includes user, host,
439+
* display and current java process id.
440+
*/
441+
protected void writeWsLockInfo() {
442+
Properties props = new Properties();
443+
444+
String user = System.getProperty(USER_NAME);
445+
if (user != null) {
446+
props.setProperty(USER, user);
447+
}
448+
String host = getHostName();
449+
if (host != null) {
450+
props.setProperty(HOST, host);
451+
}
452+
String display = getDisplay();
453+
if (display != null) {
454+
props.setProperty(DISPLAY, display);
455+
}
456+
String pid = getProcessId();
457+
if (pid != null) {
458+
props.setProperty(PROCESS_ID, pid);
459+
}
460+
461+
if (props.isEmpty()) {
462+
return;
463+
}
464+
465+
Location instanceLoc = Platform.getInstanceLocation();
466+
if (instanceLoc == null || instanceLoc.isReadOnly()) {
467+
return;
468+
}
469+
470+
File lockFile = getLockInfoFile(instanceLoc.getURL(), true);
471+
if (lockFile == null) {
472+
return;
473+
}
474+
475+
if (lockFile == null || !lockFile.exists()) {
476+
return;
477+
}
478+
479+
try (OutputStream output = new FileOutputStream(lockFile)) {
480+
props.store(output, null);
481+
} catch (IOException e) {
482+
IDEWorkbenchPlugin.log("Could not modify lock file", e); //$NON-NLS-1$
483+
}
484+
}
485+
486+
private String getDisplay() {
487+
String displayEnv = null;
488+
try {
489+
displayEnv = System.getenv(DISPLAY_VAR);
490+
} catch (Exception e) {
491+
IDEWorkbenchPlugin.log("Failed to read DISPLAY variable.", e); //$NON-NLS-1$
492+
}
493+
return displayEnv;
494+
}
495+
496+
private String getProcessId() {
497+
Long pid = null;
498+
try {
499+
pid = ProcessHandle.current().pid();
500+
} catch (Exception e) {
501+
IDEWorkbenchPlugin.log("Failed to read Java process id.", e); //$NON-NLS-1$
502+
}
503+
return pid != null ? pid.toString() : null;
504+
}
505+
506+
private String getHostName() {
507+
String hostName = null;
508+
509+
// Try fast approach first. Some OS(Like Linux) has HOSTNAME environment
510+
// variable set.
511+
try {
512+
hostName = System.getenv(HOSTNAME_VAR);
513+
if (hostName != null && !hostName.isEmpty()) {
514+
return hostName;
515+
}
516+
} catch (Exception e) {
517+
// Ignore here because we will try another method in the next step.
518+
}
519+
520+
try {
521+
hostName = InetAddress.getLocalHost().getHostName();
522+
} catch (Exception e) {
523+
IDEWorkbenchPlugin.log("Failed to read host name.", e); //$NON-NLS-1$
524+
}
525+
return hostName;
526+
}
527+
528+
/**
529+
* Returns the .lock_info file if it is present or it will create new file.
530+
*
531+
* @param workspaceUrl
532+
* @return Create .lock file if it does not present and return.
533+
*/
534+
private File getLockInfoFile(URL workspaceUrl, boolean create) {
535+
if (workspaceUrl == null) {
536+
return null;
537+
}
538+
Path lockInfoPath = Path.of(workspaceUrl.getPath(), METADATA_FOLDER, LOCK_INFO_FILENAME);
539+
540+
if (Files.exists(lockInfoPath)) {
541+
return lockInfoPath.toFile();
542+
}
543+
544+
try {
545+
if (create) {
546+
Path createdPath = Files.createFile(lockInfoPath);
547+
if (createdPath != null) {
548+
return createdPath.toFile();
549+
}
550+
}
551+
} catch (IOException e) {
552+
IDEWorkbenchPlugin.log("Failed to create workspace lock file.", e); //$NON-NLS-1$
553+
return null;
554+
}
555+
556+
return null;
557+
}
558+
346559
@SuppressWarnings("rawtypes")
347560
private static boolean isDevLaunchMode(Map args) {
348561
// 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_Display;
1153+
public static String IDEApplication_Ws_Lock_Owner_Process_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: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# Contributors:
1212
# IBM Corporation - initial API and implementation
1313
# Benjamin Muskalla - bug 29633
14-
# Remy Chi Jian Suen <[email protected]>
14+
# Remy Chi Jian Suen <[email protected]>
1515
# - Fix for Bug 186823 [Wizards] New Project Wizard has colliding mnemonics
1616
# Oakland Software Incorporated (Francis Upton) <[email protected]>
1717
# - Bug 224997 [Workbench] Impossible to copy project
@@ -512,15 +512,15 @@ UriHandlerPreferencePage_Warning_OtherApp_Confirmation_Description=The other app
512512
UriHandlerPreferencePage_Confirm_Handle=Handle
513513
UrlHandlerPreferencePage_Handler_Label=Application:
514514
UrlHandlerPreferencePage_Handler_Text_No_Application=No application
515-
UrlHandlerPreferencePage_Page_Description=Link handlers define how your application deals with hyperlinks using a given scheme.\nThis page allows you to enable and disable link handlers in this application.
515+
UrlHandlerPreferencePage_Page_Description=Link handlers define how your application deals with hyperlinks using a given scheme.\nThis page allows you to enable and disable link handlers in this application.
516516
UrlHandlerPreferencePage_LoadingText=Loading...
517-
UrlHandlerPreferencePage_ColumnName_SchemeName=Scheme
518-
UrlHandlerPreferencePage_ColumnName_SchemeDescription=Description
519-
UrlHandlerPreferencePage_ColumnName_Handler=Handler
517+
UrlHandlerPreferencePage_ColumnName_SchemeName=Scheme
518+
UrlHandlerPreferencePage_ColumnName_SchemeDescription=Description
519+
UrlHandlerPreferencePage_ColumnName_Handler=Handler
520520
UrlHandlerPreferencePage_Column_Handler_Text_Current_Application=This application
521521
UrlHandlerPreferencePage_Column_Handler_Text_Other_Application=Other application
522-
UrlHandlerPreferencePage_Error_Reading_Scheme=Error while reading scheme information from operating system
523-
UrlHandlerPreferencePage_Error_Writing_Scheme=Error while writing scheme information to operating system
522+
UrlHandlerPreferencePage_Error_Reading_Scheme=Error while reading scheme information from operating system
523+
UrlHandlerPreferencePage_Error_Writing_Scheme=Error while writing scheme information to operating system
524524
UrlHandlerPreferencePage_UnsupportedOperatingSystem=Operating system {0} is not supported.
525525
UrlHandlerPreferencePage_RegistrationUnsupported=Link Handlers cannot be registered as the application is signed.
526526
UrlHandlerPreferencePage_LauncherCannotBeDetermined=Eclipse launcher path cannot be determined.
@@ -654,7 +654,7 @@ ResourceInfo_bytes = {0} bytes
654654
ResourceInfo_file = File
655655
ResourceInfo_fileTypeFormat = File ({0})
656656
ResourceInfoPage_noResource=Resource information is not available for the current selection.
657-
ResourceFilterPage_title=A file system object will be added to the workspace tree during the refresh operation\nif it matches any of the include filters and doesn't match any of the exclude filters.
657+
ResourceFilterPage_title=A file system object will be added to the workspace tree during the refresh operation\nif it matches any of the include filters and doesn't match any of the exclude filters.
658658
ResourceFilterPage_noResource=Resource information is not available for the current selection.
659659
ResourceFilterPage_addButtonLabel=Add &Filter...
660660
ResourceFilterPage_addGroupButtonLabel=Add &Group...
@@ -781,9 +781,9 @@ LinkedResourceEditor_unableToFindCommonPathSegments=Unable to find common path s
781781
LinkedResourceEditor_convertAbsolutePathLocations=Convert Absolute Path Locations to Variable Relative
782782
LinkedResourceEditor_descriptionBlock=Linked resources in project ''{0}'':
783783
LinkedResourceEditor_convertTitle = Convert linked resource locations
784-
LinkedResourceEditor_convertMessage = Convert the linked resource location(s) between absolute and variable relative paths? This operation cannot be undone.
784+
LinkedResourceEditor_convertMessage = Convert the linked resource location(s) between absolute and variable relative paths? This operation cannot be undone.
785785
LinkedResourceEditor_removeTitle = Delete linked resources
786-
LinkedResourceEditor_removeMessage = Delete the selected linked resources? This operation cannot be undone.
786+
LinkedResourceEditor_removeMessage = Delete the selected linked resources? This operation cannot be undone.
787787
LinkedResourceEditor_removingMessage=Deleting linked resources...
788788

789789
# --- autosave preferences ---
@@ -856,8 +856,8 @@ ResourceSelectionDialog_message = Select the resources:
856856
MarkerResolutionSelectionDialog_title = Quick Fix
857857
MarkerResolutionSelectionDialog_messageLabel = &Available fixes:
858858
MarkerDeleteHandler_JobTitle = Delete Markers
859-
MarkerDeleteHandler_JobMessageLabel = Deleting selected markers
860-
859+
MarkerDeleteHandler_JobMessageLabel = Deleting selected markers
860+
861861

862862
FilteredResourcesSelectionDialog_showDerivedResourcesAction=Show &Derived Resources
863863
FilteredResourcesSelectionDialog_groupResourcesWithSameUndelyingLocation=&Filter Duplicated Resources
@@ -917,7 +917,7 @@ ImportTypeDialog_titleFilesLinking= Link Files
917917
ImportTypeDialog_question=Select how files and folders should be imported into the project:
918918
ImportTypeDialog_questionFilesOnly=Select how files should be imported into the project:
919919
ImportTypeDialog_moveFilesAndDirectories=&Move files and folders
920-
ImportTypeDialog_copyFilesAndDirectories=&Copy files and folders
920+
ImportTypeDialog_copyFilesAndDirectories=&Copy files and folders
921921
ImportTypeDialog_moveFiles=&Move files
922922
ImportTypeDialog_copyFiles=&Copy files
923923
ImportTypeDialog_recreateFilesAndDirectories=Link to files and recreate folder structure with &virtual folders
@@ -1046,10 +1046,10 @@ ChooseWorkspaceDialog_directoryBrowserTitle=Select Workspace Directory
10461046
ChooseWorkspaceDialog_directoryBrowserMessage=Select the workspace directory to use.
10471047
ChooseWorkspaceDialog_removeWorkspaceSelection=Remove from launcher selection
10481048
ChooseWorkspaceDialog_recentWorkspaces=&Recent Workspaces
1049-
ChooseWorkspaceDialog_ResolvedAbsolutePath=Full path: {0}
1049+
ChooseWorkspaceDialog_ResolvedAbsolutePath=Full path: {0}
10501050
ChooseWorkspaceDialog_TildeNonExpandedWarning=\u26A0\uFE0F '~' is not expanded, full path: {0}
10511051
ChooseWorkspaceDialog_InvalidPathWarning=\u26A0\uFE0F The path is invalid on this system: {0}
1052-
ChooseWorkspaceDialog_NotWriteablePathWarning=\u26A0\uFE0F The path may not be writable by the current user: {0}
1052+
ChooseWorkspaceDialog_NotWriteablePathWarning=\u26A0\uFE0F The path may not be writable by the current user: {0}
10531053
ChooseWorkspaceDialog_useDefaultMessage=&Use this as the default and do not ask again
10541054

10551055
ChooseWorkspaceWithSettingsDialog_SettingsGroupName=&Copy Settings
@@ -1078,7 +1078,7 @@ IDEApplication_workspaceCannotLockMessage=Could not launch the product because t
10781078
IDEApplication_versionTitle_olderWorkspace=Older Workspace Version
10791079
IDEApplication_versionTitle_newerWorkspace=Newer Workspace Version
10801080
IDEApplication_versionMessage_olderWorkspace=The ''{0}'' workspace was written with an older version. \
1081-
Continue and update workspace which may make it incompatible with older versions?
1081+
Continue and update workspace which may make it incompatible with older versions?
10821082
IDEApplication_versionMessage_newerWorkspace=Continue to use workspace ''{0}''? This workspace was written with a newer version. \
10831083
If you continue, this can cause unexpected behavior or data loss.
10841084
IDEApplication_version_doNotWarnAgain=&Do not warn again about workspace versions
@@ -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: {0}\n
1155+
IDEApplication_Ws_Lock_Owner_Host=Host: {0}\n
1156+
IDEApplication_Ws_Lock_Owner_Display=Display: {0}\n
1157+
IDEApplication_Ws_Lock_Owner_Process_Id=Process ID: {0}\n
1158+
IDEApplication_Ws_Lock_Owner_Message=Workspace lock is currently held by:\n{0}

0 commit comments

Comments
 (0)