added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / ibex / tool / Compiler.java
index 7c771a6..3b3dddd 100644 (file)
@@ -1,3 +1,7 @@
+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
 package org.ibex.tool;
 
 import java.io.*;
@@ -31,6 +35,7 @@ public class Compiler {
         List srcdir = new ArrayList();
         String source = null, target = null, blddir = null, mainclass = null;
        boolean buildjar = false;
+       boolean keepjar = false;
 
        if (args.length == 0) args = new String[] { "--help" };
         for (int i=0; i < args.length; i++) {
@@ -48,6 +53,8 @@ public class Compiler {
                        if (blddir != null) { System.out.println("cannot specify both -d and -j"); return; }
                         blddir = args[++i];
                         break;
+                    case 'J':
+                       keepjar = true;
                     case 'j':
                         if (i == args.length - 1) {
                             System.out.println("Missing parameter: "+args[i]); return; }
@@ -90,7 +97,7 @@ public class Compiler {
 
         Compiler c = new Compiler();
         if (blddir != null) {
-           if (buildjar) c.setBuildJar(blddir);
+           if (buildjar) c.setBuildJar(blddir, keepjar);
            else          c.setBuildDir(blddir);
        }
         if (source != null) c.setSource(source);
@@ -104,7 +111,9 @@ public class Compiler {
         c.setVerbose(verbose);
         c.setWarnings(warnings);
         c.setVeryVerbose(veryverbose);
-        c.compile();
+        boolean hasErrors = c.compile();
+        if (hasErrors) Runtime.getRuntime().exit(-1);
+        Runtime.getRuntime().exit(0);
     }
     private static void printHelp() {
         System.out.println("Usage java -cp ... org.ibex.tool.Compiler [options] <source dir> ...");
@@ -132,6 +141,7 @@ public class Compiler {
 
     private File builddir = null;
     private boolean buildzip = false;
+    private boolean keepzip = false;
     private ZipOutputStream jarfile = null;
     private String mainclass = null;
 
@@ -157,9 +167,10 @@ public class Compiler {
     }
 
     public void setMainClass(String mainclass) { this.mainclass = mainclass; }
-    public void setBuildJar(String dir) throws IOException {
+    public void setBuildJar(String dir, boolean keepjar) throws IOException {
        builddir = new File(dir == null ? "." : dir);
        buildzip = true;
+        if (keepjar) keepzip = true;
     }
     public void setBuildDir(String dir) throws IOException {
        builddir = new File(dir == null ? "." : dir);
@@ -191,14 +202,24 @@ public class Compiler {
     public void setVeryVerbose(boolean v) { veryverbose = v; }
     public void setWarnings(boolean w) { warnings = w; }
 
-    public void compile() throws IOException {
+    ZipInputStream keptzip = null;
+
+    public boolean compile() throws IOException {
         List s = new ArrayList();
 
        if (buildzip) {
+            if (keepzip) {
+                File f = builddir;
+                if (f.exists()) {
+                    keptzip = new ZipInputStream(new FileInputStream(f));
+                    f.delete();
+                }
+            }
            Manifest m = new Manifest();
            m.getMainAttributes().putValue("Manifest-Version", "1.0");
            if (mainclass != null) m.getMainAttributes().putValue("Main-Class", mainclass);
            jarfile = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(builddir)), m);
+            entries.add("META-INF/MANIFEST.MF");
        }
         for (int i=0; i < sourcedirs.length; i++) {
             File src = new File(sourcedirs[i]);
@@ -234,12 +255,29 @@ public class Compiler {
         if (warnings && !hasErrors) { out.write(w.toString()); out.flush(); }
         warn = null;
        try {
-           if (jarfile != null) jarfile.close();
+           if (jarfile != null) {
+                if (keptzip != null) {
+                    byte[] buf = new byte[1024 * 16];
+                    for(ZipEntry ze = keptzip.getNextEntry(); ze != null; ze = keptzip.getNextEntry()) {
+                        if (entries.contains(ze.getName())) continue;
+                        message("   preserving: " + ze.getName());
+                        jarfile.putNextEntry(ze);
+                        while(true) {
+                            int numread = keptzip.read(buf, 0, buf.length);
+                            if (numread == -1) break;
+                            jarfile.write(buf, 0, numread);
+                        }
+                    }
+                }
+                jarfile.close();
+            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (verbose) System.out.print(clearing + "   \r");
+        return hasErrors;
     }
+    List entries = new ArrayList();
 
     private final FilenameFilter filterSrcs = new FilenameFilter() {
         public boolean accept(File dir, String name) { return name.endsWith(".java"); }
@@ -247,33 +285,7 @@ public class Compiler {
     private final FileFilter filterDirs = new FileFilter() {
         public boolean accept(File path) { return path.isDirectory(); }
     };
-    private byte[] bytes(File bfile) {
-        byte[] bytes = new byte[2 * 1024];
-        int pos = 0, in = 0;
-        try {
-            InputStream bin = new FileInputStream(bfile);
-            while ((in = bin.read(bytes, pos, bytes.length - pos)) != -1) {
-                pos += in;
-                if (pos == bytes.length) {
-                    byte[] newbytes= new byte[pos * 2];
-                    System.arraycopy(bytes, 0, newbytes, 0, pos);
-                    bytes = newbytes;
-                }
-            }
-            bin.close();
-        } catch (IOException e) {
-            System.out.println("Error reading class file"); // FIXME
-            e.printStackTrace(); return null;
-        }
-
-        if (pos != bytes.length) {
-            byte[] newbytes= new byte[pos * 2];
-            System.arraycopy(bytes, 0, newbytes, 0, pos);
-            bytes = newbytes;
-        }
 
-        return bytes;
-    }
     private void filterSources(List s, File dir, char[][] pack, String srcdir) {
         List bclasses = new ArrayList();
         File bdir = new File(builddir, str(pack, File.separatorChar));
@@ -388,7 +400,7 @@ public class Compiler {
     // Compiler Parameters ////////////////////////////////////////////////////
 
     // FEATURE: may be able to use this to block access to APIs generated for stack objects
-    final AccessRestriction access = new AccessRestriction(null, null, null, null);
+    final AccessRestriction access = null;
 
     /** Used by compiler to resolve classes. */
     final INameEnvironment env = new INameEnvironment() {
@@ -402,17 +414,14 @@ public class Compiler {
                 if (veryverbose) System.out.println("  found in classloader: "+ c);
                 IBinaryType b = (IBinaryType)loaded.get(c);
                 if (b == null) loaded.put(c, b = new ClassFileReader(
-                    read(c.getResourceAsStream(classname)),
-                    (str(p, '/') + '/' + classname).toCharArray()));
+                    bytes(c), (str(p, '/') + '/' + classname).toCharArray()));
                 return new NameEnvironmentAnswer(b, access);
             } catch (ClassNotFoundException e) {
+            } catch (LinkageError e) {
             } catch (ClassFormatException e) {
                 e.printStackTrace();
                 throw new Error("ClassFormatException reading system class: " +
                     str(p, '.')+new String(n));
-            } catch (IOException e) {
-                e.printStackTrace();
-                throw new Error("IOException reading system class: "+str(p, '.')+new String(n));
             }
 
             // cut out searches for java.* packages in sources list
@@ -440,8 +449,8 @@ public class Compiler {
                     }
                 }
             } catch (ClassFormatException e) {
-                System.out.println("Unexpected ClassFormatException"); // FIXME
-                e.printStackTrace(); return null;
+                e.printStackTrace();
+                throw new Error("unexpected ClassFormatException resolving compiled class: "+e);
             }
             if (veryverbose) System.out.println("  not found");
             return null;
@@ -508,15 +517,13 @@ public class Compiler {
                        pct = "(" + pct + "%) ";
                        */
                        String printme = " writing: " + pct + str(pack(name),'.') + "." + new String(name(name));
-                       if (clearing.length() < printme.length()) clearing = "";
-                       else clearing = clearing.substring(printme.length());
-                       System.out.print(printme + clearing + "\r");
-                       for(clearing = ""; clearing.length() < printme.length() + 5; clearing += " ");
+                        message(printme);
                    }
                    if (buildzip) {
                        try {
                            jarfile.putNextEntry(new ZipEntry(str(pack(name), '/') + "/" + new String(name(name)) + ".class"));
                            jarfile.write(c[i].getBytes());
+                            entries.add(str(pack(name), '/') + "/" + new String(name(name)) + ".class");
                        } catch (java.util.zip.ZipException ze) {
                            // HACK: horrendous hack
                            if (ze.getMessage().indexOf("duplicate entry") != -1) {
@@ -543,8 +550,15 @@ public class Compiler {
         }
     };
 
+    public static void message(String printme) {
+        if (clearing.length() < printme.length()) clearing = "";
+        else clearing = clearing.substring(printme.length());
+        System.out.print(printme + clearing + "\r");
+        for(clearing = ""; clearing.length() < printme.length() + 5; clearing += " ");
+    }
+
     int percent = 0;
-    String clearing = "";
+    static String clearing = "";
 
     /** Problem creater for compiler. */
     private final IProblemFactory problems = new DefaultProblemFactory();
@@ -652,23 +666,37 @@ public class Compiler {
         return sb.toString().toCharArray();
     }
 
-    private static byte[] read(InputStream in) throws IOException {
-        byte[] bytes = new byte[16];
-        int off = 0, ret;
-        while ((ret = in.read(bytes, off, bytes.length - off)) != -1) {
-            off += ret;
-            if (off == bytes.length) {
-                byte[] nb = new byte[bytes.length * 2];
-                System.arraycopy(bytes, 0, nb, 0, bytes.length);
-                bytes = nb;
+    private static byte[] bytes(Class c) {
+        return bytes(c.getResourceAsStream('/' + c.getName().replace('.', '/') + ".class"));
+    }
+    private static byte[] bytes(File bfile) {
+        try { return bytes(new FileInputStream(bfile)); }
+        catch (FileNotFoundException e) { throw new Error("FileNotFoundException reading bytes: "+e); }
+    }
+    private static byte[] bytes(InputStream bin) {
+        byte[] bytes = new byte[2 * 1024];
+        int pos = 0, in = 0;
+        try {
+            while ((in = bin.read(bytes, pos, bytes.length - pos)) != -1) {
+                pos += in;
+                if (pos == bytes.length) {
+                    byte[] newbytes= new byte[pos * 2];
+                    System.arraycopy(bytes, 0, newbytes, 0, pos);
+                    bytes = newbytes;
+                }
             }
+            bin.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new Error("IOException reading class file: "+e);
         }
-        if (off != bytes.length) {
-            byte[] nb = new byte[off];
-            System.arraycopy(bytes, 0, nb, 0, off);
-            bytes = nb;
+
+        if (pos != bytes.length) {
+            byte[] newbytes= new byte[pos * 2];
+            System.arraycopy(bytes, 0, newbytes, 0, pos);
+            bytes = newbytes;
         }
+
         return bytes;
     }
-
 }