Index: third_party/jmake/src/org/pantsbuild/jmake/TextProjectDatabaseWriter.java |
diff --git a/third_party/jmake/src/org/pantsbuild/jmake/TextProjectDatabaseWriter.java b/third_party/jmake/src/org/pantsbuild/jmake/TextProjectDatabaseWriter.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ee5c08f5dba6de19713cade8e14629ad05773dd5 |
--- /dev/null |
+++ b/third_party/jmake/src/org/pantsbuild/jmake/TextProjectDatabaseWriter.java |
@@ -0,0 +1,144 @@ |
+/* Copyright (c) 2002-2013 Sun Microsystems, Inc. All rights reserved |
+ * |
+ * This program is distributed under the terms of |
+ * the GNU General Public License Version 2. See the LICENSE file |
+ * at the top of the source tree. |
+ */ |
+package org.pantsbuild.jmake; |
+ |
+import java.io.BufferedWriter; |
+import java.io.ByteArrayOutputStream; |
+import java.io.File; |
+import java.io.FileNotFoundException; |
+import java.io.FileOutputStream; |
+import java.io.IOException; |
+import java.io.ObjectOutputStream; |
+import java.io.OutputStreamWriter; |
+import java.io.UnsupportedEncodingException; |
+import java.io.Writer; |
+import java.util.Arrays; |
+import java.util.LinkedHashMap; |
+import java.util.LinkedHashSet; |
+import java.util.Map; |
+import java.util.Set; |
+ |
+ |
+/** |
+ * This class implements writing a text stream representing a project database. |
+ * |
+ * @see TextProjectDatabaseReader for details. |
+ * |
+ * @author Benjy Weinberger |
+ * 13 January 2013 |
+ */ |
+public class TextProjectDatabaseWriter { |
+ private static Set<String> primitives = new LinkedHashSet<String>( |
+ Arrays.asList("boolean", "byte", "char", "double", "float", "int", "long", "short", |
+ "Z", "B", "C", "D", "F", "I", "J", "S")); |
+ |
+ private ByteArrayOutputStream baos = new ByteArrayOutputStream(); // Reusable temp buffer. |
+ |
+ public void writeProjectDatabaseToFile(File outfile, Map<String, PCDEntry> pcd) { |
+ try { |
+ Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outfile), "UTF-8")); |
+ try { |
+ writeProjectDatabase(out, pcd); |
+ } finally { |
+ out.close(); |
+ } |
+ } catch (FileNotFoundException e) { |
+ throw new PrivateException(e); |
+ } catch (UnsupportedEncodingException e) { |
+ throw new PrivateException(e); |
+ } catch (IOException e) { |
+ throw new PrivateException(e); |
+ } |
+ } |
+ |
+ public void writeProjectDatabase(Writer out, Map<String,PCDEntry> pcd) { |
+ try { |
+ out.write("pcd entries:\n"); |
+ out.write(Integer.toString(pcd.size())); |
+ out.write(" items\n"); |
+ Map<String, Set<String>> depsBySource = new LinkedHashMap<String, Set<String>>(); |
+ for (PCDEntry entry : pcd.values()) { |
+ writePCDEntry(out, entry); |
+ Set<String> deps = depsBySource.get(entry.javaFileFullPath); |
+ if (deps == null) { |
+ deps = new LinkedHashSet<String>(); |
+ depsBySource.put(entry.javaFileFullPath, deps); |
+ } |
+ addDepsFromClassInfo(deps, entry.oldClassInfo); |
+ } |
+ // Write out dependency information. Note that we don't need to read this back to recreate |
+ // the PCD. We write it out here just as a convenience, so that external readers of the PDB |
+ // file don't have to grok our internal ClassInfo structures. |
+ out.write("dependencies:\n"); |
+ out.write(Integer.toString(depsBySource.size())); |
+ out.write(" items\n"); |
+ for (Map.Entry<String, Set<String>> item : depsBySource.entrySet()) { |
+ out.write(item.getKey()); |
+ for (String s : item.getValue()) { |
+ out.write('\t'); |
+ out.write(s); |
+ } |
+ out.write('\n'); |
+ } |
+ } catch (IOException e) { |
+ throw new PrivateException(e); |
+ } |
+ } |
+ |
+ private void addDepsFromClassInfo(Set<String> deps, ClassInfo ci) { |
+ for (String s : ci.cpoolRefsToClasses) { |
+ int i = 0; |
+ int j = s.length(); |
+ |
+ // Fix some inconsistencies in how we represent types internally: |
+ // Despite the comment on ci.cpoolRefsToClasses, class names may be |
+ // representing in it with '['s and with '@', '#' instead of 'L', ';'. |
+ while (s.charAt(i) == '[') i++; |
+ if (s.charAt(i) == '@') i++; |
+ if (s.endsWith("#")) j--; |
+ int k = s.indexOf('$'); |
+ |
+ // Take the outer class, on references to nested classes. |
+ if (k != -1) j = k; |
+ if (i > 0 || j < s.length()) |
+ s = s.substring(i, j); |
+ |
+ // We don't need to record deps on primitive types, or arrays of them. |
+ if (!primitives.contains(s)) |
+ deps.add(s); |
+ } |
+ } |
+ |
+ private void writePCDEntry(Writer out, PCDEntry entry) { |
+ try { |
+ out.write(entry.className); |
+ out.write('\t'); |
+ out.write(entry.javaFileFullPath); |
+ out.write('\t'); |
+ out.write(Long.toString(entry.oldClassFileLastModified)); |
+ out.write('\t'); |
+ out.write(Long.toString(entry.oldClassFileFingerprint)); |
+ out.write('\t'); |
+ out.write(classInfoToBase64(entry.oldClassInfo)); |
+ out.write('\n'); |
+ } catch (IOException e) { |
+ throw new PrivateException(e); |
+ } |
+ } |
+ |
+ private char[] classInfoToBase64(ClassInfo ci) { |
+ baos.reset(); |
+ try { |
+ ObjectOutputStream oos = new ObjectOutputStream(baos); |
+ oos.writeObject(ci); |
+ oos.close(); |
+ } catch (IOException e) { |
+ throw new PrivateException(e); |
+ } |
+ return Base64.encode(baos.toByteArray()); |
+ } |
+} |