Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add check for valid Dart SDK to preference page #99

Merged
merged 11 commits into from
Jul 16, 2019
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
*******************************************************************************/
package org.eclipse.dartboard.preference;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.dartboard.Constants;
import org.eclipse.dartboard.Messages;
Expand Down Expand Up @@ -107,32 +108,18 @@ public boolean performOk() {
* @return
*/
private Path getPath(String location) {

if (dartSDKLocationEditor.isValid()) {
Path path = null;
try {
path = Paths.get(location);
path = path.toRealPath();
boolean isWindows = Platform.OS_WIN32.equals(Platform.getOS());
path = Paths.get(location + "bin" + File.separator + (isWindows ? "dart.exe" : "dart")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
// Since we append /bin/dart to resolve the symbolic links, we need to get 2
// levels up here.
path = path.toRealPath().toAbsolutePath().getParent().getParent();
} catch (IOException e) {
LOG.error("Couldn't follow symlink", e); //$NON-NLS-1$
}

if (path == null) {
return null;
}

// Sometimes users put in the path to the Dart executable directly, instead of
// the directory of the installation. Here we use the parent first (which should
// be /bin)
if (path.endsWith("dart") && !Files.isDirectory(path)) { //$NON-NLS-1$
path = path.getParent();
}
// Sometimes users put in the path when it still contains the /bin portion.
// Since we only want the root of the Dart SDK installation we use the parent if
// /bin was supplied.
if (path.endsWith("bin")) {//$NON-NLS-1$
path = path.getParent();
}

return path;
} else {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
package org.eclipse.dartboard.preference;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.eclipse.core.runtime.Platform;
import org.eclipse.dartboard.Messages;
import org.eclipse.jface.preference.DirectoryFieldEditor;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DartSDKLocationFieldEditor extends DirectoryFieldEditor {

private static final Logger LOG = LoggerFactory.getLogger(DartSDKLocationFieldEditor.class);
jonas-jonas marked this conversation as resolved.
Show resolved Hide resolved

public DartSDKLocationFieldEditor(String preferencesKey, String label, Composite parent) {
super(preferencesKey, label, parent);
setValidateStrategy(VALIDATE_ON_KEY_STROKE);
Expand All @@ -17,15 +29,85 @@ public DartSDKLocationFieldEditor(String preferencesKey, String label, Composite
@Override
protected boolean doCheckState() {
String location = getTextControl().getText();
File file = new File(location);
boolean isValid = file.exists();
boolean isValid = isValidDartSDK(location);
if (!isValid) {
setErrorMessage(Messages.Preference_SDKNotFound_Message);
showErrorMessage();
}
return isValid;
}

/**
* Checks if a given path is the root directory of a Dart SDK installation.
*
* Returns false if the path does not exist or the given location can not be
* converted to a {@link Path}.
*
* Similarly if the Path is not a directory, false is returned.
*
* If the location is a symbolic link but it can not be resolved, false is
* returned.
*
* If the process to test the version string returned by the Dart executable can
* not be executed, false is returned.
*
* Finally, if the returned version string does not start with "Dart VM
* version", false is returned.
*
* @param location - A {@link String} that should be checked to be a Dart SDK
* root directory.
* @return <code>false</code> if the location is not a Dart SDK root directory,
* <code>true</code> otherwise.
*/
@SuppressWarnings("nls")
private boolean isValidDartSDK(String location) {
boolean isWindows = Platform.OS_WIN32.equals(Platform.getOS());
Path path = null;
// On Windows if a certain wrong combination of characters are entered a
// InvalidPathException is thrown. In that case we can assume that the location
// entered is not a valid Dart SDK directory either.
try {
path = Paths.get(location).resolve("bin" + File.separator + (isWindows ? "dart.exe" : "dart"));
} catch (InvalidPathException e) {
return false;
}
// If the entered file doesn't exist, there is no need to run it
// Similarly if the file is a directory it can't be the dart executable
if (!Files.exists(path) || Files.isDirectory(path)) {
return false;
}
// Follow symbolic links
try {
path = path.toRealPath();
} catch (IOException e1) {
LOG.error("Couldn't follow symlink", e1);
return false;
}


String executablePath = path.toAbsolutePath().toString();

String[] commands;
if (isWindows) {
commands = new String[] { "cmd", "/c", executablePath + ".exe --version" };
jonas-jonas marked this conversation as resolved.
Show resolved Hide resolved
} else {
commands = new String[] { "/bin/bash", "-c", executablePath + " --version" };
}

ProcessBuilder processBuilder = new ProcessBuilder(commands);

processBuilder.redirectErrorStream(true);
String version = null;
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(processBuilder.start().getInputStream()))) {
version = reader.readLine();
} catch (IOException e) {
return false;
}

return version.startsWith("Dart VM version");
}

protected void addModifyListener(ModifyListener listener) {
getTextControl().addModifyListener(listener);
}
Expand Down