Updates PST not to use additional temp directory if that isn't necessary. 
https://reviews.apache.org/r/43299


Project: http://git-wip-us.apache.org/repos/asf/incubator-wave/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-wave/commit/470bb641
Tree: http://git-wip-us.apache.org/repos/asf/incubator-wave/tree/470bb641
Diff: http://git-wip-us.apache.org/repos/asf/incubator-wave/diff/470bb641

Branch: refs/heads/master
Commit: 470bb6419af2c9b066bee2457245be9dbe856e8f
Parents: 2078edf
Author: Andreas Kotes <count-apache....@flatline.de>
Authored: Sun Feb 7 23:11:30 2016 +0200
Committer: Yuri Zelikov <yur...@apache.org>
Committed: Sun Feb 7 23:11:30 2016 +0200

----------------------------------------------------------------------
 .../org/apache/wave/pst/PstFileDescriptor.java  |   8 +-
 .../apache/wave/pst/PstFileDescriptor.java.orig | 352 +++++++++++++++++++
 2 files changed, 356 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/470bb641/pst/src/main/java/org/apache/wave/pst/PstFileDescriptor.java
----------------------------------------------------------------------
diff --git a/pst/src/main/java/org/apache/wave/pst/PstFileDescriptor.java 
b/pst/src/main/java/org/apache/wave/pst/PstFileDescriptor.java
index 8962b0f..abdc544 100644
--- a/pst/src/main/java/org/apache/wave/pst/PstFileDescriptor.java
+++ b/pst/src/main/java/org/apache/wave/pst/PstFileDescriptor.java
@@ -76,7 +76,7 @@ public final class PstFileDescriptor {
     if (path.endsWith(".class")) {
       clazz = fromPathToClass(path);
     } else if (path.endsWith(".java")) {
-      clazz = fromPathToJava(path);
+      clazz = fromPathToJava(path, intermediateJavaDir);
     } else if (path.endsWith(".proto")) {
       clazz = fromPathToProto(path, intermediateJavaDir, protoPath);
     } else {
@@ -134,9 +134,9 @@ public final class PstFileDescriptor {
     return path.replace(File.separatorChar, '.').substring(0, path.length() - 
".class".length());
   }
 
-  private Class<?> fromPathToJava(String pathToJava) {
+  private Class<?> fromPathToJava(String pathToJava, File intermediateJavaDir) 
{
     try {
-      File dir = Files.createTempDir();
+      File dir = intermediateJavaDir;
       String[] javacCommand = new String[] {
           "javac", pathToJava, "-d", dir.getAbsolutePath(), "-verbose",
           "-cp", determineClasspath(pathToJava) + ":" + 
determineSystemClasspath()
@@ -274,7 +274,7 @@ public final class PstFileDescriptor {
           System.err.println("ERROR: couldn't find result of protoc in " + 
intermediateJavaDir);
           return null;
         }
-        return fromPathToJava(maybeJavaFilePath);
+        return fromPathToJava(maybeJavaFilePath, intermediateJavaDir);
       }
     } catch (Exception e) {
       System.err.println("WARNING: exception while processing " + pathToProto 
+ ": "

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/470bb641/pst/src/main/java/org/apache/wave/pst/PstFileDescriptor.java.orig
----------------------------------------------------------------------
diff --git a/pst/src/main/java/org/apache/wave/pst/PstFileDescriptor.java.orig 
b/pst/src/main/java/org/apache/wave/pst/PstFileDescriptor.java.orig
new file mode 100644
index 0000000..8962b0f
--- /dev/null
+++ b/pst/src/main/java/org/apache/wave/pst/PstFileDescriptor.java.orig
@@ -0,0 +1,352 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.wave.pst;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.io.CharStreams;
+import com.google.common.io.Files;
+import com.google.protobuf.Descriptors.FileDescriptor;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A loader for a {@link FileDescriptor}, accepting and handling a proto file
+ * specified as:
+ * <ul>
+ * <li>A path to a .proto file.</li>
+ * <li>A path to a .java (protoc-)compiled proto spec.</li>
+ * <li>A path to a .class (javac-) compiled proto spec.</li>
+ * <li>A proto spec that is already on the classpath.</li>
+ * </ul>
+ *
+ * @author kal...@google.com (Benjamin Kalman)
+ */
+public final class PstFileDescriptor {
+
+  private final FileDescriptor descriptor;
+
+  /**
+   * Loads the {@link FileDescriptor} from a path. The path may be a class name
+   * (e.g. foo.Bar), path to a class (e.g. bin/foo/Bar.class), or a path to a
+   * Java source file (e.g. src/foo/Bar.java).
+   *
+   * In each case it is the caller's responsibility to ensure that the 
classpath
+   * of the Java runtime is correct.
+   *
+   * @param path the path to load the proto description from
+   * @param intermediateJavaDir path to save the intermediate protoc-
+   *        generated Java file (if any)
+   * @param protoPath any additional path to pass to the protoc compiler
+   */
+  public static FileDescriptor load(String path, File intermediateJavaDir, 
File protoPath) {
+    return new PstFileDescriptor(path, intermediateJavaDir, protoPath).get();
+  }
+
+  private  PstFileDescriptor(String path, File intermediateJavaDir, File 
protoPath) {
+    Class<?> clazz = null;
+    if (path.endsWith(".class")) {
+      clazz = fromPathToClass(path);
+    } else if (path.endsWith(".java")) {
+      clazz = fromPathToJava(path);
+    } else if (path.endsWith(".proto")) {
+      clazz = fromPathToProto(path, intermediateJavaDir, protoPath);
+    } else {
+      clazz = fromClassName(path);
+    }
+
+    if (clazz == null) {
+      descriptor = null;
+    } else {
+      descriptor = asFileDescriptor(clazz);
+    }
+  }
+
+  private FileDescriptor get() {
+    return descriptor;
+  }
+
+  private Class<?> fromClassName(String className) {
+    try {
+      return Class.forName(className);
+    } catch (ClassNotFoundException e) {
+      return null;
+    }
+  }
+
+  private Class<?> fromPathToClass(String pathToClass) {
+    String currentBaseDir = new File(pathToClass).isAbsolute() ? "" : ".";
+    String currentPath = pathToClass;
+    Class<?> clazz = null;
+    while (clazz == null) {
+      clazz = loadClassAtPath(currentBaseDir, currentPath);
+      if (clazz == null) {
+        int indexOfSep = currentPath.indexOf(File.separatorChar);
+        if (indexOfSep == -1) {
+          break;
+        } else {
+          currentBaseDir += File.separator + currentPath.substring(0, 
indexOfSep);
+          currentPath = currentPath.substring(indexOfSep + 1);
+        }
+      }
+    }
+    return clazz;
+  }
+
+  private Class<?> loadClassAtPath(String baseDir, String path) {
+    try {
+      ClassLoader classLoader = new URLClassLoader(new URL[] {new 
File(baseDir).toURI().toURL()});
+      return classLoader.loadClass(getBinaryName(path));
+    } catch (Throwable t) {
+      return null;
+    }
+  }
+
+  private String getBinaryName(String path) {
+    return path.replace(File.separatorChar, '.').substring(0, path.length() - 
".class".length());
+  }
+
+  private Class<?> fromPathToJava(String pathToJava) {
+    try {
+      File dir = Files.createTempDir();
+      String[] javacCommand = new String[] {
+          "javac", pathToJava, "-d", dir.getAbsolutePath(), "-verbose",
+          "-cp", determineClasspath(pathToJava) + ":" + 
determineSystemClasspath()
+      };
+      Process javac = Runtime.getRuntime().exec(javacCommand);
+      consumeStdOut(javac);
+      List<String> stdErr = readLines(javac.getErrorStream());
+      int exitCode = javac.waitFor();
+      if (exitCode != 0) {
+        // Couldn't compile the file.
+        System.err.printf("ERROR: running \"%s\" failed (%s):",
+            Joiner.on(' ').join(javacCommand), exitCode);
+        for (String line : stdErr) {
+          System.err.println(line);
+        }
+        return null;
+      } else {
+        // Compiled the file!  Now to determine where javac put it.
+        Pattern pattern;
+        if 
(Integer.parseInt(System.getProperty("java.version").split("\\.")[1]) <= 6) {
+            // JDK 6 or lower
+            pattern = Pattern.compile("\\[wrote ([^\\]]*)\\]");
+        } else {
+            // JDK 7 or higher
+            pattern = Pattern.compile("\\[wrote 
RegularFileObject\\[([^\\]]*)\\]\\]");
+        }
+        String pathToClass = null;
+        for (String line : stdErr) {
+          Matcher lineMatcher = pattern.matcher(line);
+          if (lineMatcher.matches()) {
+            pathToClass = lineMatcher.group(1);
+            // NOTE: don't break, as the correct path is the last one matched.
+          }
+        }
+        if (pathToClass != null) {
+          return fromPathToClass(pathToClass);
+        } else {
+          System.err.println("WARNING: couldn't find javac output from javac " 
+ pathToJava);
+          return null;
+        }
+      }
+    } catch (Exception e) {
+      System.err.println("WARNING: exception while processing " + pathToJava + 
": "
+          + e.getMessage());
+      return null;
+    }
+  }
+
+  /**
+   * Fires off a background thread to consume anything written to a process'
+   * standard output. Without running this, a process that outputs too much 
data
+   * will block.
+   */
+  private void consumeStdOut(Process p) {
+    final InputStream o = p.getInputStream();
+    Thread t = new Thread() {
+      @Override
+      public void run() {
+        try {
+          while (o.read() != -1) {}
+        } catch (IOException e) {
+          e.printStackTrace();
+        }
+      }
+    };
+    t.setDaemon(true);
+    t.start();
+  }
+
+  private String determineClasspath(String pathToJava) {
+    // Try to determine the classpath component of a path by looking at the
+    // path components.
+    StringBuilder classpath = new StringBuilder();
+    if (new File(pathToJava).isAbsolute()) {
+      classpath.append(File.separator);
+    }
+
+    // This is just silly, but it will get by for now.
+    for (String component : pathToJava.split(File.separator)) {
+      if (component.equals("org")
+          || component.equals("com")
+          || component.equals("au")) {
+        return classpath.toString();
+      } else {
+        classpath.append(component + File.separator);
+      }
+    }
+
+    System.err.println("WARNING: couldn't determine classpath for " + 
pathToJava);
+    return ".";
+  }
+
+  private String determineSystemClasspath() {
+    StringBuilder s = new StringBuilder();
+    boolean needsColon = false;
+    for (URL url : ((URLClassLoader) 
ClassLoader.getSystemClassLoader()).getURLs()) {
+      if (needsColon) {
+        s.append(':');
+      }
+      s.append(url.getPath());
+      needsColon = true;
+    }
+    return s.toString();
+  }
+
+  private Class<?> fromPathToProto(String pathToProto, File 
intermediateJavaDir, File protoPath) {
+    try {
+      intermediateJavaDir.mkdirs();
+      File proto = new File(pathToProto);
+      String[] protocCommand = new String[] {
+          "protoc", tryGetRelativePath(proto),
+          "-I" + protoPath.getPath(),
+          "--java_out", intermediateJavaDir.getAbsolutePath()
+      };
+      Process protoc = Runtime.getRuntime().exec(protocCommand);
+      // TODO(ben): configure timeout?
+      killProcessAfter(10, TimeUnit.SECONDS, protoc);
+      int exitCode = protoc.waitFor();
+      if (exitCode != 0) {
+        // Couldn't compile the file.
+        System.err.printf("ERROR: running \"%s\" failed (%s):",
+            Joiner.on(' ').join(protocCommand), exitCode);
+        for (String line : readLines(protoc.getErrorStream())) {
+          System.err.println(line);
+        }
+        return null;
+      } else {
+        final String javaFileName = capitalize(stripSuffix(".proto", 
proto.getName())) + ".java";
+        String maybeJavaFilePath = find(intermediateJavaDir, new 
Predicate<File>() {
+          @Override public boolean apply(File f) {
+            return f.getName().equals(javaFileName);
+          }
+        });
+        if (maybeJavaFilePath == null) {
+          System.err.println("ERROR: couldn't find result of protoc in " + 
intermediateJavaDir);
+          return null;
+        }
+        return fromPathToJava(maybeJavaFilePath);
+      }
+    } catch (Exception e) {
+      System.err.println("WARNING: exception while processing " + pathToProto 
+ ": "
+          + e.getMessage());
+      e.printStackTrace();
+      return null;
+    }
+  }
+
+  private String find(File dir, Predicate<File> predicate) {
+    for (File file : dir.listFiles()) {
+      if (file.isDirectory()) {
+        String path = find(file, predicate);
+        if (path != null) {
+          return path;
+        }
+      }
+      if (predicate.apply(file)) {
+        return file.getAbsolutePath();
+      }
+    }
+    return null;
+  }
+
+  private String tryGetRelativePath(File file) {
+    String pwd = System.getProperty("user.dir");
+    return stripPrefix(pwd + File.separator, file.getAbsolutePath());
+  }
+
+  private String stripPrefix(String prefix, String s) {
+    return s.startsWith(prefix) ? s.substring(prefix.length()) : s;
+  }
+
+  private String stripSuffix(String suffix, String s) {
+    return s.endsWith(suffix) ? s.substring(0, s.length() - suffix.length()) : 
s;
+  }
+
+  private String capitalize(String s) {
+    return Character.toUpperCase(s.charAt(0)) + s.substring(1);
+  }
+
+  private List<String> readLines(InputStream is) {
+    try {
+      return CharStreams.readLines(new InputStreamReader(is));
+    } catch (IOException e) {
+     e.printStackTrace();
+      // TODO(kalman): this is a bit hacky, deal with it properly.
+      return Collections.singletonList("(Error, couldn't read lines from the 
input stream. " +
+          "Try running the command external to PST to view the output.)");
+    }
+  }
+
+  private FileDescriptor asFileDescriptor(Class<?> clazz) {
+    try {
+      Method method = clazz.getMethod("getDescriptor");
+      return (FileDescriptor) method.invoke(null);
+    } catch (Exception e) {
+      return null;
+    }
+  }
+
+  private void killProcessAfter(final long delay, final TimeUnit unit, final 
Process process) {
+    Thread processKiller = new Thread() {
+      @Override public void run() {
+        try {
+          Thread.sleep(unit.toMillis(delay));
+          process.destroy();
+        } catch (InterruptedException e) {
+        }
+      }
+    };
+    processKiller.setDaemon(true);
+    processKiller.start();
+  }
+}

Reply via email to