| /* |
| * Copyright 2006 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.util.tools; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.LineNumberReader; |
| import java.io.OutputStream; |
| import java.io.PrintWriter; |
| import java.io.StringReader; |
| import java.net.URI; |
| import java.net.URL; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| /** |
| * A smattering of useful functions. |
| */ |
| public final class Utility { |
| |
| |
| private static String sInstallPath = null; |
| /** |
| * A pattern that expresses version strings. It has two groups the prefix (a dotted integer |
| * sequence) and a suffix (a regular string) |
| * |
| * Examples: 1.6.7, 1.2_b10 |
| * |
| */ |
| private static Pattern versionPattern = |
| Pattern.compile("([0-9]+(?:\\.[0-9]+)*)((?:_[a-zA-Z0-9]+)?)"); |
| |
| /** |
| * Helper that ignores exceptions during close, because what are you going to |
| * do? |
| */ |
| public static void close(AutoCloseable closeable) { |
| try { |
| if (closeable != null) { |
| closeable.close(); |
| } |
| } catch (Exception e) { |
| } |
| } |
| |
| /** |
| * @param parent Parent directory |
| * @param fileName New file name |
| * @param overwrite Is overwriting an existing file allowed? |
| * @return Handle to the file |
| * @throws IOException If the file cannot be created, or if the file already |
| * existed and overwrite was false. |
| */ |
| public static File createNormalFile(File parent, String fileName, |
| boolean overwrite, boolean ignore) throws IOException { |
| File file = new File(parent, fileName); |
| if (file.createNewFile()) { |
| System.out.println("Created file " + file); |
| return file; |
| } |
| |
| if (!file.exists() || file.isDirectory()) { |
| throw new IOException(file.getPath() + " : could not create normal file."); |
| } |
| |
| if (ignore) { |
| System.out.println(file + " already exists; skipping"); |
| return null; |
| } |
| |
| if (!overwrite) { |
| throw new IOException( |
| file.getPath() |
| + " : already exists; please remove it or use the -overwrite or -ignore option."); |
| } |
| |
| System.out.println("Overwriting existing file " + file); |
| return file; |
| } |
| |
| /** |
| * @param parent Parent directory of the requested directory. |
| * @param dirName Requested name for the directory. |
| * @param create Create the directory if it does not already exist? |
| * @return A {@link File} representing a directory that now exists. |
| * @throws IOException If the directory is not found and/or cannot be created. |
| */ |
| public static File getDirectory(File parent, String dirName, boolean create) |
| throws IOException { |
| File dir = new File(parent, dirName); |
| boolean alreadyExisted = dir.exists(); |
| |
| if (create) { |
| // No need to check mkdirs result because we check for dir.exists() |
| dir.mkdirs(); |
| } |
| |
| if (!dir.exists() || !dir.isDirectory()) { |
| if (create) { |
| throw new IOException(dir.getPath() + " : could not create directory."); |
| } else { |
| throw new IOException(dir.getPath() + " : could not find directory."); |
| } |
| } |
| |
| if (create && !alreadyExisted) { |
| System.out.println("Created directory " + dir); |
| } |
| |
| return dir; |
| } |
| |
| /** |
| * @param dirPath Requested path for the directory. |
| * @param create Create the directory if it does not already exist? |
| * @return A {@link File} representing a directory that now exists. |
| * @throws IOException If the directory is not found and/or cannot be created. |
| */ |
| public static File getDirectory(String dirPath, boolean create) |
| throws IOException { |
| return getDirectory(null, dirPath, create); |
| } |
| |
| /** |
| * Gets the contents of a file from the class path as a String. Note: this |
| * method is only guaranteed to work for resources in the same class loader |
| * that contains this {@link Utility} class. |
| * |
| * @param partialPath the partial path to the resource on the class path |
| * @return the contents of the file |
| * @throws IOException if the file could not be found or an error occurred |
| * while reading it |
| */ |
| public static String getFileFromClassPath(String partialPath) |
| throws IOException { |
| InputStream in = Utility.class.getClassLoader().getResourceAsStream( |
| partialPath); |
| try { |
| if (in == null) { |
| throw new FileNotFoundException(partialPath); |
| } |
| ByteArrayOutputStream os = new ByteArrayOutputStream(); |
| streamOut(in, os, 1024); |
| return new String(os.toByteArray(), "UTF-8"); |
| } finally { |
| close(in); |
| } |
| } |
| |
| public static String getInstallPath() { |
| if (sInstallPath == null) { |
| computeInstallationPath(); |
| } |
| return sInstallPath; |
| } |
| |
| /** |
| * Creates a randomly-named temporary directory. |
| * |
| * @param baseDir base directory to contain the new directory. May be |
| * {@code null}, in which case the directory given by the |
| * {@code java.io.tmpdir} system property will be used. |
| * @param prefix the initial characters of the new directory name |
| * @return a newly-created temporary directory; the caller must delete this |
| * directory (either when done or on VM exit) |
| */ |
| public static File makeTemporaryDirectory(File baseDir, String prefix) |
| throws IOException { |
| if (baseDir == null) { |
| baseDir = new File(System.getProperty("java.io.tmpdir")); |
| } |
| // No need to check the result of this mkdirs call because |
| // we will detect the subsequent failure |
| baseDir.mkdirs(); |
| |
| // Try this a few times due to non-atomic delete+mkdir operations. |
| for (int tries = 0; tries < 3; ++tries) { |
| File result = File.createTempFile(prefix, null, baseDir); |
| if (!result.delete()) { |
| throw new IOException("Couldn't delete temporary file " |
| + result.getAbsolutePath() + " to replace with a directory."); |
| } |
| if (result.mkdirs()) { |
| // Success. |
| return result; |
| } |
| } |
| throw new IOException( |
| "Couldn't create temporary directory after 3 tries in " |
| + baseDir.getAbsolutePath()); |
| } |
| |
| public static void streamOut(InputStream in, OutputStream out, int bufferSize) |
| throws IOException { |
| assert (bufferSize >= 0); |
| |
| byte[] buffer = new byte[bufferSize]; |
| int bytesRead = 0; |
| while (true) { |
| bytesRead = in.read(buffer); |
| if (bytesRead >= 0) { |
| // Copy the bytes out. |
| out.write(buffer, 0, bytesRead); |
| } else { |
| // End of input stream. |
| return; |
| } |
| } |
| } |
| |
| public static void writeTemplateBinaryFile(File file, byte[] contents) throws IOException { |
| |
| FileOutputStream o = new FileOutputStream(file); |
| o.write(contents); |
| close(o); |
| } |
| |
| public static void writeTemplateFile(File file, String contents, |
| Map<String, String> replacements) throws IOException { |
| |
| String replacedContents = contents; |
| Set<Entry<String, String>> entries = replacements.entrySet(); |
| for (Iterator<Entry<String, String>> iter = entries.iterator(); iter.hasNext();) { |
| Entry<String, String> entry = iter.next(); |
| String replaceThis = entry.getKey(); |
| String withThis = entry.getValue(); |
| withThis = withThis.replaceAll("\\\\", "\\\\\\\\"); |
| withThis = withThis.replaceAll("\\$", "\\\\\\$"); |
| replacedContents = replacedContents.replaceAll(replaceThis, withThis); |
| } |
| |
| PrintWriter pw = new PrintWriter(file); |
| LineNumberReader lnr = new LineNumberReader(new StringReader(replacedContents)); |
| for (String line = lnr.readLine(); line != null; line = lnr.readLine()) { |
| pw.println(line); |
| } |
| close(pw); |
| } |
| |
| private static void computeInstallationPath() { |
| try { |
| String override = System.getProperty("gwt.devjar"); |
| if (override == null) { |
| String partialPath = Utility.class.getName().replace('.', '/').concat( |
| ".class"); |
| URL url = Utility.class.getClassLoader().getResource(partialPath); |
| if (url != null && "jar".equals(url.getProtocol())) { |
| String path = url.toString(); |
| String jarPath = path.substring(path.indexOf("file:"), |
| path.lastIndexOf('!')); |
| File devJarFile = new File(URI.create(jarPath)); |
| if (!devJarFile.isFile()) { |
| throw new IOException("Could not find jar file; " |
| + devJarFile.getCanonicalPath() |
| + " does not appear to be a valid file"); |
| } |
| |
| String dirPath = jarPath.substring(0, jarPath.lastIndexOf('/') + 1); |
| File installDirFile = new File(URI.create(dirPath)); |
| if (!installDirFile.isDirectory()) { |
| throw new IOException("Could not find installation directory; " |
| + installDirFile.getCanonicalPath() |
| + " does not appear to be a valid directory"); |
| } |
| |
| sInstallPath = installDirFile.getCanonicalPath().replace( |
| File.separatorChar, '/'); |
| } else { |
| throw new IOException( |
| "Cannot determine installation directory; apparently not running from a jar"); |
| } |
| } else { |
| override = override.replace('\\', '/'); |
| int pos = override.lastIndexOf('/'); |
| if (pos < 0) { |
| sInstallPath = ""; |
| } else { |
| sInstallPath = override.substring(0, pos); |
| } |
| } |
| } catch (IOException e) { |
| throw new RuntimeException( |
| "Installation problem detected, please reinstall GWT", e); |
| } |
| } |
| |
| /** |
| * Handles comparison between version numbers (the right way(TM)). |
| * |
| * Examples of version strings: 1.6.7, 1.2_b10 |
| * |
| * @param v1 the first version to compare. |
| * @param v2 the second version to compare. |
| * @return a negative integer, zero, or a positive integer as the first argument is less than, |
| * equal to, or greater than the second. |
| * @throws IllegalArgumentException if the version number are not proper (i.e. the do not comply |
| * with the following regular expression |
| * [0-9]+(.[0-9]+)*(_[a-zA-Z0-9]+)? |
| */ |
| public static int versionCompare(String v1, String v2) { |
| Matcher v1Matcher = versionPattern.matcher(v1); |
| Matcher v2Matcher = versionPattern.matcher(v2); |
| if (!v1Matcher.matches() || !v2Matcher.matches()) { |
| throw new IllegalArgumentException(v1Matcher.matches() ? v2 : v1 + " is not a proper version" |
| + " string"); |
| } |
| |
| String[] v1Prefix = v1Matcher.group(1).split("\\."); |
| String[] v2Prefix = v2Matcher.group(1).split("\\."); |
| for (int i = 0; i < v1Prefix.length; i++) { |
| if (v2Prefix.length <= i) { |
| return 1; // v1 > v2 |
| } |
| int compare = Integer.parseInt(v1Prefix[i]) - Integer.parseInt(v2Prefix[i]); |
| if (compare != 0) { |
| return compare; |
| } |
| } |
| // So far they are equal (or v2 is longer than v1) |
| if (v2Prefix.length == v1Prefix.length) { |
| // then it is up to the suffixes |
| return v1Matcher.group(2).compareTo(v2Matcher.group(2)); |
| } |
| |
| // v2 is greater than v1, |
| return -1; |
| } |
| } |