package hudson.plugins.rake; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; import java.util.regex.Pattern; /** * Ruby utility class. It's used to detect ruby local installations among other features. * * @author David Calavera */ public class Util { private static final String[] RUBY_EXECUTABLES = {"ruby", "jruby"}; public static File getExecutable(String path) { String execName = isWindows()?"rake.bat":"rake"; File parent = isJruby(path) || isCustom(path, execName)? new File(path) : new File(path).getParentFile().getParentFile(); return new File(parent, "bin/" + execName); } public static boolean isWindows() { String name = System.getProperty("os.name"); return name != null?name.contains("Windows") : File.separatorChar == '\\'; } public static boolean isLinux() { return System.getProperty("os.name").endsWith("Linux"); } public static boolean isMac() { return System.getProperty("os.name").equalsIgnoreCase("Mac OS X"); } public static boolean isJruby(String path) { String execName = isWindows()?"jruby.bat":"jruby"; return new File(path, "bin/" + execName).exists(); } public static boolean isCustom(String path, String execName) { return new File(path, "bin/" + execName).exists(); } public static boolean hasGemsInstalled(String path) { File[] gems = getGemsDir(path); for (File gem : gems) { if (gem != null && gem.exists() && gem.isDirectory()) { return true; } } return false; } public static File[] getGemsDir(String path) { if (path.startsWith("$")) { path = System.getenv(path.substring(1)); } File[] gemDirsFiltered = new File[0]; for (File gemsBaseFile : getDefaultGemPaths(path)) { if (gemsBaseFile.exists()) { gemDirsFiltered = gemsBaseFile.listFiles(gemDirFilter); if (gemDirsFiltered != null && gemDirsFiltered.length > 0) { break; } } } return gemDirsFiltered != null ? gemDirsFiltered : new File[0]; } public static File[] getDefaultGemPaths(String path) { return new File []{new File(path + "/lib/ruby/gems"), new File(path + "/gems")}; } public static boolean isRakeInstalled(File... gemsDirArray) { for (File gemsDir : gemsDirArray) { File specPath = new File(gemsDir, "specifications"); if (specPath.exists() && specPath.listFiles(rakeFilter) != null) { return true; } } return false; } private static FilenameFilter rakeFilter = new FilenameFilter() { private final Pattern rakePattern = Pattern.compile("rake\\-([\\d.]+).gemspec"); public boolean accept(File path, String file) { return rakePattern.matcher(file).matches(); } }; private static FilenameFilter gemDirFilter = new FilenameFilter() { Pattern gemVersionPattern = Pattern.compile("\\d+.\\d+(?:.\\d+)?"); public boolean accept(File path, String file) { return gemVersionPattern.matcher(file).matches(); } }; public static Collection<File> getRubyInstallations() throws IOException { String systemPath = System.getenv("PATH"); if (systemPath == null) systemPath = System.getenv("path"); Collection<File> rubyVersions = new LinkedHashSet<File>(); if (systemPath != null) { Set<String> candidates = new LinkedHashSet<String>(Arrays.asList(systemPath.split(File.pathSeparator))); for (String path : candidates) { for (String ruby : RUBY_EXECUTABLES) { File rubyExec = getExecutableWithExceptions(path, ruby); if (rubyExec.isFile() && !rubyVersions.contains(rubyExec.getCanonicalFile().getParentFile())) { File parent = rubyExec.getCanonicalFile().getParentFile(); File[] gemsDir = getGemsDir(parent.getCanonicalPath()); if (!isRakeInstalled(gemsDir) && (isMac() || isJruby(parent.getParent()))) { parent = parent.getParentFile(); gemsDir = getGemsDir(parent.getAbsolutePath()); } if (gemsDir != null && isRakeInstalled(gemsDir)) { rubyVersions.add(parent); } } } } } return rubyVersions; } public static RubyInstallation[] getCanonicalRubies(RubyInstallation[] currentInstallations) { try { Collection<File> rubies = getRubyInstallations(); Collection<RubyInstallation> currentList = new LinkedHashSet<RubyInstallation>(Arrays.asList(currentInstallations)); out: for (File ruby : rubies) { for (RubyInstallation current : currentList) { if (current.getCanonicalExecutable().equals(getExecutable(ruby.getCanonicalPath()).getCanonicalFile())) { continue out; } } currentList.add(new RubyInstallation(ruby.getName(), ruby.getCanonicalPath())); } return currentList.toArray(new RubyInstallation[currentList.size()]); } catch (IOException e) { hudson.Util.displayIOException(e, null); } return new RubyInstallation[0]; } public static boolean isAlreadyInstalled(RubyInstallation[] current, String path) { try { for (RubyInstallation ruby : current) { if (new File(ruby.getPath()).getCanonicalPath().equals(new File(path).getCanonicalPath())) { return true; } } } catch (IOException e) { hudson.Util.displayIOException(e, null); } return false; } private static File getExecutableWithExceptions(String path, String exec) throws IOException { File rubyExec = isWindows()?new File(path, exec + ".exe"):new File(path, exec); if (isLinux() && rubyExec.exists() && rubyExec.getAbsolutePath().equals("/usr/bin/ruby")) { rubyExec = new File("/usr/lib/ruby/ruby"); } return rubyExec; } }