Changeset 12141


Ignore:
Timestamp:
09/09/09 10:26:15 (8 years ago)
Author:
mevenson
Message:

Added support for loading Lisp from JAR files.

Pathnames passed to LOAD may now specify loading from within JAR files
by using the 'jar:file:' uri schema:

(load "jar:file:///PATH/TO.jar!/foo")

would attempt to load Lisp "associated" with 'foo' in a JAR file
located '/PATH/TO.jar'. "Associated with" means that the the
following entries in the JAR are looked for:

1) 'foo._' (the initial FASL from compiling 'foo.lisp)
2) 'foo.abcl' (the packed FASL)
3) 'foo.lisp'

Associated tests have been included but currently only work under UNIX
due to the need to package up the FASLs for testing.

Location:
trunk/abcl
Files:
5 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/abcl/abcl.asd

    r12016 r12141  
    1010(defsystem :abcl :version "0.3.0")
    1111
    12 (defmethod perform :after ((o load-op) (c (eql (find-system 'abcl))))
     12(defmethod perform :after ((o load-op) (c (eql (find-system :abcl))))
    1313  ;;; Additional test suite loads would go here.
    14   (asdf:oos 'asdf:load-op :test-abcl :force t))
     14  (operate 'load-op :test-abcl :force t))
    1515
    16 (defmethod perform ((o test-op) (c (eql (find-system 'abcl))))
     16(defmethod perform ((o test-op) (c (eql (find-system :abcl))))
    1717  ;;; Additional test suite invocations would go here.
    18   (asdf:oos 'asdf:test-op :ansi-compiled :force t))
     18  (operate 'test-op :ansi-compiled :force t))
    1919
    2020;;; A collection of test suites for ABCL.
     
    2323  :depends-on (:ansi-compiled #+nil :abcl-tests))
    2424
    25 (defmethod perform :after ((o load-op) (c (eql (find-system 'test-abcl))))
     25(defmethod perform :after ((o load-op) (c (eql (find-system :test-abcl))))
    2626  #+nil (asdf:oos 'asdf:test-op :cl-bench :force t)
    27   (asdf:oos 'asdf:load-op :abcl-test-lisp :force t)
    28   (asdf:oos 'asdf:load-op :ansi-compiled :force t)
    29   (asdf:oos 'asdf:load-op :ansi-interpreted :force t))
     27  (operate 'load-op :abcl-test-lisp :force t)
     28  (operate 'load-op :ansi-compiled :force t)
     29  (operate 'load-op :ansi-interpreted :force t))
    3030
    3131(defsystem :ansi-test :version "1.0" :components
     
    3535
    3636(defsystem :ansi-interpreted :version "1.0" :depends-on (ansi-test))
    37 (defmethod perform ((o test-op) (c (eql (find-system 'ansi-interpreted))))
     37(defmethod perform ((o test-op) (c (eql (find-system :ansi-interpreted))))
    3838   "Invoke tests with:  (asdf:oos 'asdf:test-op :ansi-interpreted :force t)."
    3939   ;;; FIXME needs ASDF:OOS to be invoked with :FORCE t
     
    4242
    4343(defsystem :ansi-compiled :version "1.0" :depends-on (ansi-test))
    44 (defmethod perform ((o test-op) (c (eql (find-system 'ansi-compiled))))
     44(defmethod perform ((o test-op) (c (eql (find-system :ansi-compiled))))
    4545  "Invoke tests with:  (asdf:oos 'asdf:test-op :abcl-compiled :force t)."
    4646  (funcall (intern (symbol-name 'run) :abcl.test.ansi)
  • trunk/abcl/src/org/armedbear/lisp/Lisp.java

    r12111 r12141  
    4040import java.lang.reflect.Constructor;
    4141import java.math.BigInteger;
     42import java.net.MalformedURLException;
    4243import java.net.URL;
    4344import java.net.URLDecoder;
     
    119120        PACKAGE_LISP.usePackage(PACKAGE_EXT);
    120121        PACKAGE_LISP.usePackage(PACKAGE_SYS);
    121   PACKAGE_THREADS.usePackage(PACKAGE_CL);
     122        PACKAGE_THREADS.usePackage(PACKAGE_CL);
    122123      }
    123124    catch (Throwable t)
     
    331332      for (int i = 0; i<= last; i++) {
    332333          if (frames[i].getClassName().startsWith("org.armedbear.lisp.Primitive"))
    333       last = i;
     334            last = i;
    334335      }
    335336      // Do not include the first three frames:
     
    883884                  return (StackFrame) obj;         
    884885          return (StackFrame)// Not reached.       
    885       type_error(obj, Symbol.STACK_FRAME);
     886            type_error(obj, Symbol.STACK_FRAME);
    886887  }
    887888
     
    10751076    if (device instanceof Pathname)
    10761077      {
    1077         // We're loading a fasl from j.jar.
     1078        // Are we loading a fasl from j.jar? 
     1079        // XXX this will collide with file names from other JAR files
    10781080        URL url = Lisp.class.getResource(namestring);
     1081        if (url == null) {
     1082          // Maybe device-->namestring references another JAR file?
     1083          String jarFile = ((Pathname)device).getNamestring();
     1084          if (jarFile.startsWith("jar:file:")) {
     1085            try {
     1086              url = new URL(jarFile + "!/" + namestring);
     1087            } catch (MalformedURLException ex) {
     1088              Debug.trace(ex);
     1089            }
     1090          }
     1091        }
    10791092        if (url != null)
    10801093          {
     
    11111124                                LispObject obj = loadCompiledFunction(in, (int) size);
    11121125                                return obj != null ? obj : NIL;
     1126                              }
     1127                            else
     1128                              {
     1129                                // ASSERT type = "abcl"
     1130                                entryName
     1131                                  = defaultPathname.name.getStringValue()
     1132                                  + "." +  "abcl";//defaultPathname.type.getStringValue();
     1133                                byte in[]
     1134                                  = Utilities
     1135                                  .getZippedZipEntryAsByteArray(zipFile,
     1136                                                                entryName,
     1137                                                                namestring);
     1138                                LispObject o = loadCompiledFunction(in);
     1139                                return o != null ? o : NIL;
    11131140                              }
    11141141                          }
  • trunk/abcl/src/org/armedbear/lisp/Load.java

    r11998 r12141  
    3434package org.armedbear.lisp;
    3535
     36import java.io.ByteArrayInputStream;
     37import java.io.ByteArrayOutputStream;
    3638import java.io.File;
    3739import java.io.FileInputStream;
     
    4446import java.util.zip.ZipException;
    4547import java.util.zip.ZipFile;
     48import java.util.zip.ZipInputStream;
    4649
    4750public final class Load extends Lisp
     
    5760                    true);
    5861    }
    59 
     62   
    6063    private static final File findLoadableFile(final String filename,
    6164                                               final String dir)
    6265    {
    6366        File file = new File(dir, filename);
    64   if (!file.isFile()) {
    65       String extension = getExtension(filename);
    66       if (extension == null) {
    67     // No extension specified. Try appending ".lisp" or ".abcl".
    68     File lispFile = new File(dir, filename.concat(".lisp"));
    69     File abclFile = new File(dir, filename.concat(".abcl"));
    70     if (lispFile.isFile() && abclFile.isFile()) {
    71         if (abclFile.lastModified() > lispFile.lastModified()) {
    72       return abclFile;
    73         } else {
    74       return lispFile;
    75         }
    76     } else if (abclFile.isFile()) {
    77         return abclFile;
    78     } else if (lispFile.isFile()) {
    79         return lispFile;
     67        if (!file.isFile()) {
     68            String extension = getExtension(filename);
     69            if (extension == null) {
     70                // No extension specified. Try appending ".lisp" or ".abcl".
     71                File lispFile = new File(dir, filename.concat(".lisp"));
     72                File abclFile = new File(dir, filename.concat(".abcl"));
     73                if (lispFile.isFile() && abclFile.isFile()) {
     74                    if (abclFile.lastModified() > lispFile.lastModified()) {
     75                        return abclFile;
     76                    } else {
     77                        return lispFile;
     78                    }
     79                } else if (abclFile.isFile()) {
     80                    return abclFile;
     81                } else if (lispFile.isFile()) {
     82                    return lispFile;
    8083                }
    8184            }
     
    8588                     // no need to check again at the caller
    8689    }
    87 
     90 
    8891    public static final LispObject load(Pathname pathname,
    8992                                        String filename,
     
    9295                                        boolean ifDoesNotExist)
    9396        throws ConditionThrowable {
    94   return load(pathname, filename, verbose, print, ifDoesNotExist, false);
    95     }
    96 
     97        return load(pathname, filename, verbose, print, ifDoesNotExist, false);
     98    }
    9799
    98100    public static final LispObject load(Pathname pathname,
     
    101103                                        boolean print,
    102104                                        boolean ifDoesNotExist,
    103           boolean returnLastResult)
     105                                        boolean returnLastResult)
    104106        throws ConditionThrowable
    105107    {
    106   String dir = null;
     108        String dir = null;
    107109        if (!Utilities.isFilenameAbsolute(filename)) {
    108       dir =
    109                 coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue()).getNamestring();
    110         }
    111 
    112   File file = findLoadableFile(filename, dir);
    113         if (file == null) {
     110            dir = coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS
     111                                   .symbolValue()).getNamestring();
     112        }
     113
     114        String zipFileName = null;
     115        String zipEntryName = null;
     116        if (filename.startsWith("jar:file:")) {
     117            String s = new String(filename);
     118            s = s.substring(9);
     119            int index = s.lastIndexOf('!');
     120            if (index >= 0) {
     121                zipFileName = s.substring(0, index);
     122                zipEntryName = s.substring(index + 1);
     123                if (zipEntryName.length() > 0 && zipEntryName.charAt(0) == '/')
     124                    zipEntryName = zipEntryName.substring(1);
     125                if (Utilities.isPlatformWindows) {
     126                    if (zipFileName.length() > 0 && zipFileName.charAt(0) == '/')
     127                        zipFileName = zipFileName.substring(1);
     128                }
     129            }
     130        }
     131
     132        File file = findLoadableFile(filename, dir);
     133        if (null == file && null == zipFileName) {
    114134            if (ifDoesNotExist)
    115                 return error(new FileError("File not found: " + filename,
    116                                             pathname));
     135                return error(new FileError("File not found: " + filename, pathname));
    117136            else
    118137                return NIL;
    119138        }
    120139
    121   filename = file.getPath();
     140        if (checkZipFile(file)) {
     141            // Either we are loading a packed FASL (i.e. ZIP with suffix ".abcl")
     142            // Or we are loading from a JAR archive
     143            if (".abcl".equals(getExtension(file.getPath()))) {
     144                // So we adjust the value passed to
     145                // loadFileFromStream() to get any further loading
     146                // within this invocation of LOAD to work properly.
     147                filename = file.getPath();
     148            }
     149            zipFileName = file.getPath();
     150            zipEntryName = file.getName();
     151        }
     152       
     153        String truename = filename;
    122154        ZipFile zipfile = null;
    123         if (checkZipFile(file))
    124         {
     155
     156        boolean packedFASL = false;
     157
     158        InputStream in = null;
     159        if (zipFileName != null) {
    125160            try {
    126                 zipfile = ZipCache.getZip(file.getPath());
     161                zipfile = ZipCache.getZip(zipFileName);
    127162            }
    128163            catch (Throwable t) {
    129                 // Fall through.
    130             }
    131         }
    132         String truename = filename;
    133         InputStream in = null;
    134         if (zipfile != null) {
    135             String name = file.getName();
    136             int index = name.lastIndexOf('.');
    137             Debug.assertTrue(index >= 0);
    138             name = name.substring(0, index).concat("._");
    139             ZipEntry entry = zipfile.getEntry(name);
    140             if (entry != null) {
     164                return error (new FileError("Zip file not found: " + filename, pathname));
     165            }
     166            ZipEntry entry = zipfile.getEntry(zipEntryName);
     167            if (null == entry) {
     168                // try appending "._" to base filename
     169                int index = zipEntryName.lastIndexOf('.');
     170                if (-1 == index) index = zipEntryName.length();
     171                zipEntryName = zipEntryName.substring(0, index).concat("._");
     172                entry = zipfile.getEntry(zipEntryName);
     173            }
     174            if (null == entry) {
     175                // try appending ".abcl" to base filename
     176                int index = zipEntryName.lastIndexOf('.');
     177                if (index == -1)
     178                  index = zipEntryName.length();
     179                zipEntryName = zipEntryName.substring(0, index).concat(".abcl");
     180                entry = zipfile.getEntry(zipEntryName);
     181                if (entry != null)
     182                  packedFASL = true;
     183            }
     184            if (null == entry) {
     185                // Try looking for ".lisp"
     186                int i = zipEntryName.lastIndexOf('.');
     187                if (i == -1) {
     188                    i = zipEntryName.length();
     189                }
     190                zipEntryName = zipEntryName.substring(0, i).concat(".lisp");
     191                entry = zipfile.getEntry(zipEntryName);
     192                if (entry == null) {
     193                  return error(new LispError("Failed to find " + zipEntryName + " in "
     194                                             + zipFileName + "."));
     195                }
     196            }
     197
     198            if (null == entry) {
     199                return error(new FileError("Can't find zip file entry "
     200                                           + zipEntryName, pathname));
     201            }
     202            if (".abcl".equals(getExtension(zipEntryName))) {
     203                packedFASL = true;
     204            }
     205            if (packedFASL) {
     206                // If we are loading a packed FASL from the JAR we
     207                // have to decompress it first, and seek for the '._'
     208                // init FASL.
     209                int i = zipEntryName.lastIndexOf('.');
     210                String subZipEntryName = zipEntryName.substring(0, i).concat("._");
     211                in = Utilities.getZippedZipEntryAsInputStream(zipfile,
     212                                                              zipEntryName,
     213                                                              subZipEntryName);
     214            } else {
    141215                try {
    142216                    in = zipfile.getInputStream(entry);
     
    163237        }
    164238        try {
    165             return loadFileFromStream(null, truename,
    166                                       new Stream(in, Symbol.CHARACTER),
    167                                       verbose, print, false, returnLastResult);
     239
     240          return loadFileFromStream(null, truename,
     241                                    new Stream(in, Symbol.CHARACTER),
     242                                    verbose, print, false, returnLastResult);
    168243        }
    169244        catch (FaslVersionMismatch e) {
     
    392467                                                       boolean print,
    393468                                                       boolean auto)
    394   throws ConditionThrowable {
    395   return loadFileFromStream(pathname, truename, in, verbose, print, auto, false);
     469        throws ConditionThrowable {
     470        return loadFileFromStream(pathname, truename, in, verbose, print, auto, false);
    396471    }
    397472
     
    402477                                                       boolean print,
    403478                                                       boolean auto,
    404                    boolean returnLastResult)
     479                                                       boolean returnLastResult)
    405480        throws ConditionThrowable
    406481    {
     
    467542    private static final LispObject loadStream(Stream in, boolean print,
    468543                                               LispThread thread)
    469   throws ConditionThrowable {
    470   return loadStream(in, print, thread, false);
     544        throws ConditionThrowable {
     545        return loadStream(in, print, thread, false);
    471546    }
    472547
     
    483558        try {
    484559            final Environment env = new Environment();
    485       LispObject result = NIL;
     560            LispObject result = NIL;
    486561            while (true) {
    487562                sourcePositionBinding.value = Fixnum.getInstance(in.getOffset());
     
    497572                }
    498573            }
    499       if(returnLastResult) {
    500     return result;
    501       } else {
    502     return T;
    503       }
     574            if(returnLastResult) {
     575                return result;
     576            } else {
     577                return T;
     578            }
    504579        }
    505580        finally {
     
    514589        final Environment env = new Environment();
    515590        final SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
    516   LispObject result = NIL;
     591        LispObject result = NIL;
    517592        try {
    518593            thread.bindSpecial(_FASL_ANONYMOUS_PACKAGE_, new Package());
     
    528603        }
    529604        return result;
    530   //There's no point in using here the returnLastResult flag like in
    531   //loadStream(): this function is only called from init-fasl, which is
    532   //only called from load, which already has its own policy for choosing
    533   //whether to return T or the last value.
     605        //There's no point in using here the returnLastResult flag like in
     606        //loadStream(): this function is only called from init-fasl, which is
     607        //only called from load, which already has its own policy for choosing
     608        //whether to return T or the last value.
    534609    }
    535610
     
    601676        @Override
    602677        public LispObject execute(LispObject filespec, LispObject verbose,
    603           LispObject print, LispObject ifDoesNotExist)
    604       throws ConditionThrowable {
    605       return load(filespec, verbose, print, ifDoesNotExist, NIL);
    606   }
     678                                  LispObject print, LispObject ifDoesNotExist)
     679            throws ConditionThrowable {
     680            return load(filespec, verbose, print, ifDoesNotExist, NIL);
     681        }
    607682    };
    608683
     
    614689        @Override
    615690        public LispObject execute(LispObject filespec, LispObject verbose,
    616           LispObject print, LispObject ifDoesNotExist)
    617       throws ConditionThrowable {
    618       return load(filespec, verbose, print, ifDoesNotExist, T);
    619   }
     691                                  LispObject print, LispObject ifDoesNotExist)
     692            throws ConditionThrowable {
     693            return load(filespec, verbose, print, ifDoesNotExist, T);
     694        }
    620695    };
    621696
    622697    private static final LispObject load(LispObject filespec,
    623           LispObject verbose,
    624           LispObject print,
    625           LispObject ifDoesNotExist,
    626           LispObject returnLastResult)
    627   throws ConditionThrowable {
    628   if (filespec instanceof Stream) {
    629       if (((Stream)filespec).isOpen()) {
    630     LispObject pathname;
    631     if (filespec instanceof FileStream)
    632         pathname = ((FileStream)filespec).getPathname();
    633     else
    634         pathname = NIL;
    635     String truename;
    636     if (pathname instanceof Pathname)
    637         truename = ((Pathname)pathname).getNamestring();
    638     else
    639         truename = null;
    640     return loadFileFromStream(pathname,
    641             truename,
    642             (Stream) filespec,
    643             verbose != NIL,
    644             print != NIL,
    645             false,
    646             returnLastResult != NIL);
    647       }
    648       // If stream is closed, fall through...
    649   }
    650   Pathname pathname = coerceToPathname(filespec);
    651   if (pathname instanceof LogicalPathname)
    652       pathname = LogicalPathname.translateLogicalPathname((LogicalPathname)pathname);
    653   return load(pathname,
    654         pathname.getNamestring(),
    655         verbose != NIL,
    656         print != NIL,
    657         ifDoesNotExist != NIL,
    658         returnLastResult != NIL);
     698                                        LispObject verbose,
     699                                        LispObject print,
     700                                        LispObject ifDoesNotExist,
     701                                        LispObject returnLastResult)
     702        throws ConditionThrowable {
     703        if (filespec instanceof Stream) {
     704            if (((Stream)filespec).isOpen()) {
     705                LispObject pathname;
     706                if (filespec instanceof FileStream)
     707                    pathname = ((FileStream)filespec).getPathname();
     708                else
     709                    pathname = NIL;
     710                String truename;
     711                if (pathname instanceof Pathname)
     712                    truename = ((Pathname)pathname).getNamestring();
     713                else
     714                    truename = null;
     715                return loadFileFromStream(pathname,
     716                                          truename,
     717                                          (Stream) filespec,
     718                                          verbose != NIL,
     719                                          print != NIL,
     720                                          false,
     721                                          returnLastResult != NIL);
     722            }
     723            // If stream is closed, fall through...
     724        }
     725        Pathname pathname = coerceToPathname(filespec);
     726        if (pathname instanceof LogicalPathname)
     727            pathname = LogicalPathname.translateLogicalPathname((LogicalPathname)pathname);
     728        return load(pathname,
     729                    pathname.getNamestring(),
     730                    verbose != NIL,
     731                    print != NIL,
     732                    ifDoesNotExist != NIL,
     733                    returnLastResult != NIL);
    659734    }
    660735
  • trunk/abcl/src/org/armedbear/lisp/Utilities.java

    r11700 r12141  
    3434package org.armedbear.lisp;
    3535
     36import java.io.ByteArrayInputStream;
     37import java.io.ByteArrayOutputStream;
    3638import java.io.File;
    3739import java.io.IOException;
     40import java.io.InputStream;
     41import java.util.zip.ZipEntry;
     42import java.util.zip.ZipFile;
     43import java.util.zip.ZipInputStream;
    3844
    3945public final class Utilities extends Lisp
     
    116122        }
    117123    }
     124   
     125    public static byte[] getZippedZipEntryAsByteArray(ZipFile zipfile,
     126                                                      String entryName,
     127                                                      String subEntryName)
     128      throws ConditionThrowable
     129  {
     130      ZipEntry entry = zipfile.getEntry(entryName);
     131     
     132      ZipInputStream stream = null;
     133      try {
     134          stream = new ZipInputStream(zipfile.getInputStream(entry));
     135      }
     136      catch (IOException e) {
     137          Lisp.error(new FileError("Failed to open '" + entryName + "' in zipfile '"
     138                                   + zipfile + "': " + e.getMessage()));
     139      }
     140      //  XXX Cache the zipEntries somehow
     141      do {
     142          try {
     143              entry = stream.getNextEntry();
     144          } catch (IOException e){
     145              Lisp.error(new FileError("Failed to seek for '" + subEntryName
     146                                       + "' in '"
     147                                       + zipfile.getName() + ":" + entryName + ".:"
     148                                       + e.getMessage()));
     149          }
     150      } while (!entry.getName().equals(subEntryName));
     151     
     152      ByteArrayOutputStream buffer = new ByteArrayOutputStream();
     153        int count;
     154        byte buf[] = new byte[1024];
     155        try {
     156            while ((count = stream.read(buf, 0, buf.length)) != -1) {
     157                buffer.write(buf, 0, count);
     158            }
     159        } catch (java.io.IOException e) {
     160          Lisp.error(new FileError("Failed to read compressed '"
     161                                   + subEntryName
     162                                   + "' in '"
     163                                   + zipfile.getName() + ":" + entryName + ":"
     164                                   + e.getMessage()));
     165        }
     166        return buffer.toByteArray();
     167    }
     168   
     169    public static InputStream getZippedZipEntryAsInputStream(ZipFile zipfile,
     170                                                             String entryName,
     171                                                             String subEntryName)
     172      throws ConditionThrowable
     173  {
     174        return
     175            new ByteArrayInputStream(Utilities
     176                                     .getZippedZipEntryAsByteArray(zipfile, entryName,
     177                                                                   subEntryName));
     178  }
    118179}
     180
  • trunk/abcl/test/lisp/abcl/package.lisp

    r12016 r12141  
    11(defpackage #:abcl.test.lisp
    22  (:use #:cl #:abcl-rt)
     3  (:nicknames "ABCL-TEST")
    34  (:export #:run))
    45(in-package #:abcl.test.lisp)
Note: See TracChangeset for help on using the changeset viewer.