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 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
  • Loading branch information
raghucssit committed Oct 9, 2024
1 parent cc770ec commit f8f7892
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@
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.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
Expand All @@ -49,7 +52,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 +86,22 @@ public class IDEApplication implements IApplication, IExecutableExtension {

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

private static final String LOCK_INFO_FILENAME = ".lock_info"; //$NON-NLS-1$

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

private static final String HOSTNAME_VAR = "HOSTNAME"; //$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 +248,7 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
try {
if (instanceLoc.lock()) {
writeWorkspaceVersion();
writeWsLockInfo();
return null;
}

Expand All @@ -237,10 +261,19 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
if (isDevLaunchMode(applicationArguments)) {
return EXIT_WORKSPACE_LOCKED;
}

String wsLockedError = NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage,
workspaceDirectory.getAbsolutePath());
// check if there is a lock info then append it to error message.
String lockInfo = getWorkspaceLockInfo(instanceLoc.getURL());
if (lockInfo != null && !lockInfo.isBlank()) {
wsLockedError = wsLockedError + System.lineSeparator() + System.lineSeparator()
+ NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Message, lockInfo);
}
MessageDialog.openError(
shell,
IDEWorkbenchMessages.IDEApplication_workspaceCannotLockTitle,
NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage, workspaceDirectory.getAbsolutePath()));
wsLockedError);
} else {
MessageDialog.openError(
shell,
Expand Down Expand Up @@ -313,6 +346,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 +366,196 @@ 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;
}

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

Label multiLineText = new Label(container, SWT.NONE);
multiLineText.setText(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Message, lockInfo));

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 = getLockInfoFile(workspaceUrl, false);
if (lockFile == null) {
return null;
}
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(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_User, prop));
}
prop = props.getProperty(HOST);
if (prop != null) {
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Host, prop));
}
prop = props.getProperty(DISPLAY);
if (prop != null) {
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Display, prop));
}
prop = props.getProperty(PROCESS_ID);
if (prop != null) {
sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Process_Id, prop));
}
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.
*/
protected void writeWsLockInfo() {
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);
}

if (props.isEmpty()) {
return;
}

Location instanceLoc = Platform.getInstanceLocation();
if (instanceLoc == null || instanceLoc.isReadOnly()) {
return;
}

File lockFile = getLockInfoFile(instanceLoc.getURL(), true);
if (lockFile == null) {
return;
}

if (lockFile == null || !lockFile.exists()) {
return;
}

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 fast approach first. Some OS(Like Linux) has HOSTNAME environment
// variable set.
try {
hostName = System.getenv(HOSTNAME_VAR);
if (hostName != null && !hostName.isEmpty()) {
return hostName;
}
} catch (Exception e) {
// Ignore here because we will try another method in the next step.
}

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

/**
* Returns the .lock_info file if it is present or it will create new file.
*
* @param workspaceUrl
* @return Create .lock file if it does not present and return.
*/
private File getLockInfoFile(URL workspaceUrl, boolean create) {
if (workspaceUrl == null) {
return null;
}
Path lockInfoPath = Path.of(workspaceUrl.getPath(), METADATA_FOLDER, LOCK_INFO_FILENAME);

if (Files.exists(lockInfoPath)) {
return lockInfoPath.toFile();
}

try {
if (create) {
Path createdPath = Files.createFile(lockInfoPath);
if (createdPath != null) {
return createdPath.toFile();
}
}
} catch (IOException e) {
IDEWorkbenchPlugin.log("Failed to create workspace lock file.", e); //$NON-NLS-1$
return null;
}

return null;
}

@SuppressWarnings("rawtypes")
private static boolean isDevLaunchMode(Map args) {
// see org.eclipse.pde.internal.core.PluginPathFinder.isDevLaunchMode()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,12 @@ public class IDEWorkbenchMessages extends NLS {
public static String WorkbenchPreference_maxSimultaneousBuilds;
public static String WorkbenchPreference_maxSimultaneousBuildIntervalError;

public static String IDEApplication_Ws_Lock_Owner_User;
public static String IDEApplication_Ws_Lock_Owner_Host;
public static String IDEApplication_Ws_Lock_Owner_Display;
public static String IDEApplication_Ws_Lock_Owner_Process_Id;
public static String IDEApplication_Ws_Lock_Owner_Message;

static {
// load message values from bundle file
NLS.initializeMessages(BUNDLE_NAME, IDEWorkbenchMessages.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# Contributors:
# IBM Corporation - initial API and implementation
# Benjamin Muskalla - bug 29633
# Remy Chi Jian Suen <[email protected]>
# Remy Chi Jian Suen <[email protected]>
# - Fix for Bug 186823 [Wizards] New Project Wizard has colliding mnemonics
# Oakland Software Incorporated (Francis Upton) <[email protected]>
# - Bug 224997 [Workbench] Impossible to copy project
Expand Down Expand Up @@ -512,15 +512,15 @@ UriHandlerPreferencePage_Warning_OtherApp_Confirmation_Description=The other app
UriHandlerPreferencePage_Confirm_Handle=Handle
UrlHandlerPreferencePage_Handler_Label=Application:
UrlHandlerPreferencePage_Handler_Text_No_Application=No application
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.
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.
UrlHandlerPreferencePage_LoadingText=Loading...
UrlHandlerPreferencePage_ColumnName_SchemeName=Scheme
UrlHandlerPreferencePage_ColumnName_SchemeDescription=Description
UrlHandlerPreferencePage_ColumnName_Handler=Handler
UrlHandlerPreferencePage_ColumnName_SchemeName=Scheme
UrlHandlerPreferencePage_ColumnName_SchemeDescription=Description
UrlHandlerPreferencePage_ColumnName_Handler=Handler
UrlHandlerPreferencePage_Column_Handler_Text_Current_Application=This application
UrlHandlerPreferencePage_Column_Handler_Text_Other_Application=Other application
UrlHandlerPreferencePage_Error_Reading_Scheme=Error while reading scheme information from operating system
UrlHandlerPreferencePage_Error_Writing_Scheme=Error while writing scheme information to operating system
UrlHandlerPreferencePage_Error_Reading_Scheme=Error while reading scheme information from operating system
UrlHandlerPreferencePage_Error_Writing_Scheme=Error while writing scheme information to operating system
UrlHandlerPreferencePage_UnsupportedOperatingSystem=Operating system {0} is not supported.
UrlHandlerPreferencePage_RegistrationUnsupported=Link Handlers cannot be registered as the application is signed.
UrlHandlerPreferencePage_LauncherCannotBeDetermined=Eclipse launcher path cannot be determined.
Expand Down Expand Up @@ -654,7 +654,7 @@ ResourceInfo_bytes = {0} bytes
ResourceInfo_file = File
ResourceInfo_fileTypeFormat = File ({0})
ResourceInfoPage_noResource=Resource information is not available for the current selection.
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.
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.
ResourceFilterPage_noResource=Resource information is not available for the current selection.
ResourceFilterPage_addButtonLabel=Add &Filter...
ResourceFilterPage_addGroupButtonLabel=Add &Group...
Expand Down Expand Up @@ -781,9 +781,9 @@ LinkedResourceEditor_unableToFindCommonPathSegments=Unable to find common path s
LinkedResourceEditor_convertAbsolutePathLocations=Convert Absolute Path Locations to Variable Relative
LinkedResourceEditor_descriptionBlock=Linked resources in project ''{0}'':
LinkedResourceEditor_convertTitle = Convert linked resource locations
LinkedResourceEditor_convertMessage = Convert the linked resource location(s) between absolute and variable relative paths? This operation cannot be undone.
LinkedResourceEditor_convertMessage = Convert the linked resource location(s) between absolute and variable relative paths? This operation cannot be undone.
LinkedResourceEditor_removeTitle = Delete linked resources
LinkedResourceEditor_removeMessage = Delete the selected linked resources? This operation cannot be undone.
LinkedResourceEditor_removeMessage = Delete the selected linked resources? This operation cannot be undone.
LinkedResourceEditor_removingMessage=Deleting linked resources...

# --- autosave preferences ---
Expand Down Expand Up @@ -856,8 +856,8 @@ ResourceSelectionDialog_message = Select the resources:
MarkerResolutionSelectionDialog_title = Quick Fix
MarkerResolutionSelectionDialog_messageLabel = &Available fixes:
MarkerDeleteHandler_JobTitle = Delete Markers
MarkerDeleteHandler_JobMessageLabel = Deleting selected markers
MarkerDeleteHandler_JobMessageLabel = Deleting selected markers


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

ChooseWorkspaceWithSettingsDialog_SettingsGroupName=&Copy Settings
Expand Down Expand Up @@ -1078,7 +1078,7 @@ IDEApplication_workspaceCannotLockMessage=Could not launch the product because t
IDEApplication_versionTitle_olderWorkspace=Older Workspace Version
IDEApplication_versionTitle_newerWorkspace=Newer Workspace Version
IDEApplication_versionMessage_olderWorkspace=The ''{0}'' workspace was written with an older version. \
Continue and update workspace which may make it incompatible with older versions?
Continue and update workspace which may make it incompatible with older versions?
IDEApplication_versionMessage_newerWorkspace=Continue to use workspace ''{0}''? This workspace was written with a newer version. \
If you continue, this can cause unexpected behavior or data loss.
IDEApplication_version_doNotWarnAgain=&Do not warn again about workspace versions
Expand Down Expand Up @@ -1150,3 +1150,9 @@ OpenDelayedUrlAction_title=Open URL
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.
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}''.
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.

IDEApplication_Ws_Lock_Owner_User=User: {0}\n
IDEApplication_Ws_Lock_Owner_Host=Host: {0}\n
IDEApplication_Ws_Lock_Owner_Display=Display: {0}\n
IDEApplication_Ws_Lock_Owner_Process_Id=Process ID: {0}\n
IDEApplication_Ws_Lock_Owner_Message=Workspace lock is currently held by:\n{0}

0 comments on commit f8f7892

Please sign in to comment.