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
JBIDE-21175 - ensure more reliable locating of vagrant command #831
Merged
robstryker
merged 1 commit into
jbosstools:jbosstools-4.3.x
from
robstryker:JBIDE-21175_maint
Dec 4, 2015
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
...n.core/src/org/jboss/tools/openshift/internal/common/core/util/CommandLocationBinary.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2015 Red Hat, Inc. | ||
* Distributed under license by Red Hat, Inc. All rights reserved. | ||
* This program is made available under the terms of the | ||
* Eclipse Public License v1.0 which accompanies this distribution, | ||
* and is available at http://www.eclipse.org/legal/epl-v10.html | ||
* | ||
* Contributors: | ||
* Red Hat Incorporated - initial API and implementation | ||
******************************************************************************/ | ||
package org.jboss.tools.openshift.internal.common.core.util; | ||
|
||
import java.util.HashMap; | ||
|
||
/** | ||
* A class representing a binary available on multiple platforms. | ||
*/ | ||
public class CommandLocationBinary { | ||
private HashMap<String, String> commandMap; | ||
private HashMap<String, String> defaultLocMap; | ||
private String defaultPlatform; | ||
private String commandName; | ||
private String foundLoc = null; | ||
private boolean searchFailed = false; | ||
|
||
public CommandLocationBinary(String commandName) { | ||
commandMap = new HashMap<String,String>(); | ||
defaultLocMap = new HashMap<String,String>(); | ||
this.commandName = commandName; | ||
} | ||
|
||
/** | ||
* Add a default command location for a given platform. | ||
* | ||
* @param platform | ||
* @param command | ||
* @param loc | ||
*/ | ||
public void addPlatformLocation(String platform, String loc) { | ||
defaultLocMap.put(platform, loc); | ||
} | ||
|
||
public void addPlatformCommandName(String platform, String command) { | ||
commandMap.put(platform, command); | ||
} | ||
|
||
/** | ||
* Set which command / default location should be used in the event that | ||
* the user is on an unexpected platform such as OS_AIX, it can use the command name | ||
* and default location of a differing platform, such as OS_LINUX | ||
* | ||
* @param platform | ||
*/ | ||
public void setDefaultPlatform(String platform) { | ||
this.defaultPlatform = platform; | ||
} | ||
|
||
public String getCommand(String platform) { | ||
return commandMap.containsKey(platform) ? commandMap.get(platform) : commandName; | ||
} | ||
|
||
public String getDefaultLoc(String platform) { | ||
return defaultLocMap.containsKey(platform) ? defaultLocMap.get(platform) : defaultLocMap.get(defaultPlatform); | ||
} | ||
|
||
public String findLocation() { | ||
return findLocation(2000); | ||
} | ||
|
||
public String findLocation(int timeout) { | ||
if( foundLoc != null || searchFailed ) | ||
return foundLoc; | ||
|
||
String searched = CommandLocationLookupStrategy.get().search(this, timeout); | ||
if( searched == null ) { | ||
searchFailed = true; | ||
} | ||
foundLoc = searched; | ||
return searched; | ||
} | ||
} |
164 changes: 164 additions & 0 deletions
164
...rc/org/jboss/tools/openshift/internal/common/core/util/CommandLocationLookupStrategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2015 Red Hat, Inc. | ||
* Distributed under license by Red Hat, Inc. All rights reserved. | ||
* This program is made available under the terms of the | ||
* Eclipse Public License v1.0 which accompanies this distribution, | ||
* and is available at http://www.eclipse.org/legal/epl-v10.html | ||
* | ||
* Contributors: | ||
* Red Hat Incorporated - initial API and implementation | ||
******************************************************************************/ | ||
package org.jboss.tools.openshift.internal.common.core.util; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.util.ArrayList; | ||
import java.util.concurrent.Callable; | ||
|
||
import org.apache.commons.lang.StringUtils; | ||
import org.eclipse.core.runtime.Platform; | ||
|
||
public class CommandLocationLookupStrategy { | ||
private static final String LINUX_WHICH = "which "; | ||
private static final String WINDOWS_WHERE = "where "; | ||
private static final String LINUX_PATHVAR = "PATH"; | ||
private static final String WINDOWS_PATHVAR = "Path"; | ||
|
||
public static final CommandLocationLookupStrategy WINDOWS_STRATEGY = | ||
new CommandLocationLookupStrategy(WINDOWS_WHERE, ";", WINDOWS_PATHVAR, new String[]{".exe", ".com"}); | ||
public static final CommandLocationLookupStrategy LINUX_STRATEGY = | ||
new CommandLocationLookupStrategy(LINUX_WHICH, ":", LINUX_PATHVAR, new String[]{}); | ||
|
||
public static CommandLocationLookupStrategy get() { | ||
String os = Platform.getOS(); | ||
if( Platform.OS_WIN32.equals(os)) { | ||
return WINDOWS_STRATEGY; | ||
} | ||
return LINUX_STRATEGY; | ||
} | ||
|
||
private String which, delim, pathvar; | ||
private String[] suffixes; | ||
public CommandLocationLookupStrategy(String which, String delim, String pathvar, String[] suffixes) { | ||
this.which = which; | ||
this.delim = delim; | ||
this.pathvar = pathvar; | ||
this.suffixes = suffixes; | ||
} | ||
|
||
public String search(CommandLocationBinary binary) { | ||
return search(binary, 2000); | ||
} | ||
|
||
public String search(CommandLocationBinary binary, int timeout) { | ||
String cmd = binary.getCommand(Platform.getOS()); | ||
String defaultLoc = binary.getDefaultLoc(Platform.getOS()); | ||
return findLocation(defaultLoc, cmd, which, delim, pathvar, timeout); | ||
} | ||
|
||
/** | ||
* This method will try to find the given command. | ||
* | ||
* If the default location exists, it will use that. | ||
* | ||
* It will then attempt to search for the command name (with all possible suffixes) | ||
* somewhere in the system path. | ||
* | ||
* If that still fails, it will run one where / which command to locate the command. | ||
* This will be called without the suffix. | ||
* | ||
* @param defaultLoc | ||
* @param cmd | ||
* @param which | ||
* @param delim | ||
* @param pathvar | ||
* @param timeout | ||
* @return | ||
*/ | ||
private String findLocation(String defaultLoc, String cmd, String which, String delim, String pathvar, int timeout) { | ||
if( defaultLoc != null && new File(defaultLoc).exists()) { | ||
return defaultLoc; | ||
} | ||
String ret = searchPath(System.getenv(pathvar), delim, cmd); | ||
if( ret == null ) { | ||
ret = runCommand(which + cmd, timeout); | ||
} | ||
return ret; | ||
} | ||
|
||
/** | ||
* Get all possible command names by appending the various suffixes to the command name | ||
* @param commandName | ||
* @return | ||
*/ | ||
private String[] getPossibleCommandNames(String commandName) { | ||
ArrayList<String> ret = new ArrayList<String>(5); | ||
ret.add(commandName); | ||
for( int i = 0; i < suffixes.length; i++ ) { | ||
ret.add(commandName + suffixes[i]); | ||
} | ||
return (String[]) ret.toArray(new String[ret.size()]); | ||
} | ||
|
||
private String searchPath(String path, String delim, String commandName) { | ||
String[] roots = path.split(delim); | ||
String[] withSuffixes = getPossibleCommandNames(commandName); | ||
for( int i = 0; i < roots.length; i++ ) { | ||
for( int j = 0; j < withSuffixes.length; j++ ) { | ||
File test = new File(roots[i], withSuffixes[j]); | ||
if( test.exists()) { | ||
return test.getAbsolutePath(); | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
private String runCommand(final String cmd, int timeout) { | ||
if( timeout == -1 ) { | ||
return runCommand(cmd); | ||
} else { | ||
String path = ThreadUtils.runWithTimeout(timeout, new Callable<String>() { | ||
@Override | ||
public String call() throws Exception { | ||
return runCommand(cmd); | ||
} | ||
}); | ||
return path; | ||
} | ||
} | ||
|
||
private String runCommand(String cmd) { | ||
|
||
Process p = null; | ||
try { | ||
p = Runtime.getRuntime().exec(cmd); | ||
try { | ||
p.waitFor(); | ||
} catch(InterruptedException ie) { | ||
// Ignore, expected | ||
} | ||
if(p.exitValue() == 0) { | ||
InputStream is = p.getInputStream(); | ||
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); | ||
String cmdOutput = s.hasNext() ? s.next() : ""; | ||
if( !cmdOutput.isEmpty()) { | ||
cmdOutput = StringUtils.trim(cmdOutput); | ||
if( new File(cmdOutput).exists()) | ||
return cmdOutput; | ||
} | ||
} | ||
|
||
} catch(IOException ioe) { | ||
// Ignore this | ||
} finally { | ||
if( p != null ) { | ||
p.destroy(); | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
|
||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
im wondering if we are better of launching this similar to what @gercan and @ibuziuk been doing for npm and cordova cli tools.
i.e. call out via bash or cmd.exe making it up to the user to have it properly configured in PATH
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are times we call out via Runtime.exec() in which case the existing path is in control. But there are also times we use the external tools launch configuration, in which case we need to know the full location. In general, we use the launch config when we want a console to appear with the output, and we use Runtime.exec() when we just want it done in the background.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did some perf-testing on windows and linux. This method is only a little bit slow when it has to go out to which / where, and it will only perform this once per workspace, and only if vagrant isn't found in the path already. Everything's already cached, and it won't try a second time, so the perf. hit is very very very low and the ability to work around path errors is tremendous.
I believe this patch is for the best.