Commits

Jim Baker committed 7c3e5ed

Initial commit of spike code

Comments (0)

Files changed (4)

 
 def makepath(*paths):
     dir = os.path.join(*paths)
-    if _is_jython and (dir == '__classpath__' or
-                       dir.startswith('__pyclasspath__')):
+    if _is_jython:
+        if (dir == '__classpath__' or
+            dir.startswith('__pyclasspath__')):
             return dir, dir
+        elif dir.startswith('jar:file:'):
+            dir = os.path.normpath(dir)   # FIXME May not work on Windows!
+            return dir, os.path.normcase(dir)
     try:
         dir = os.path.abspath(dir)
     except OSError:
                     continue
                 line = line.rstrip()
                 dir, dircase = makepath(sitedir, line)
-                if not dircase in known_paths and os.path.exists(dir):
+                if not dircase in known_paths and (os.path.exists(dir) or jython_url_exists(dir)):
                     sys.path.append(dir)
                     known_paths.add(dircase)
             except Exception as err:
     return known_paths
 
 
+def jython_getentries(sitedir):
+    from java.net import URL  # delay this import for now
+    path = sitedir.split("!")[1][1:]
+    if not path:
+        return []
+    packages = set()
+    jar = URL(sitedir).openConnection().getJarFile()
+    for entry in jar.entries():
+        name = entry.name
+        if name.startswith(path):
+            try:
+                package = str(name.split(path)[1].split("/")[1])
+                if package:
+                    packages.add(package)
+            except Exception, ex:
+                pass  # ignore, following the standard import logic
+    packages = sorted(packages)
+    return packages
+
+
+def jython_url_exists(path):
+    return True  # should work for proper setup FIXME FIXME
+    from java.net import URL  # delay this import for now
+    if not path.startswith("jar:file:"):
+        return False
+    try:                                            
+        URL(path).openConnection().getInputStream().close()
+        return True
+    except:
+        return False
+                                                   
+
 def addsitedir(sitedir, known_paths=None):
     """Add 'sitedir' argument to sys.path if missing and handle .pth files in
     'sitedir'"""
     sitedir, sitedircase = makepath(sitedir)
     if not sitedircase in known_paths:
         sys.path.append(sitedir)        # Add path component
-    try:
-        names = os.listdir(sitedir)
-    except os.error:
-        return
+    if sitedir.startswith("jar:file:"):
+        names = jython_getentries(sitedir)
+    else:
+        try:
+            names = os.listdir(sitedir)
+        except os.error:
+            return
     dotpth = os.extsep + "pth"
     names = [name for name in names if name.endswith(dotpth)]
     for name in sorted(names):

src/org/python/core/PyFile.java

  */
 package org.python.core;
 
+import java.io.IOError;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.concurrent.Callable;
 
 import org.python.core.io.BinaryIOWrapper;
         }
         String mode = ap.getString(1, "r");
         int bufsize = ap.getInt(2, -1);
-        file___init__(new FileIO((PyString) name, parseMode(mode)), name, mode, bufsize);
+        if (((PyString) name).startswith(Py.newString("jar:file:"))) {
+            try {
+                URL url = new URL(name.toString());
+                parseMode(mode); // check mode is read only FIXME
+                file___init__(new StreamIO(url.openConnection().getInputStream(), true), name, mode, bufsize);
+            } catch (MalformedURLException ex) {
+                throw Py.ValueError("not a valid jar url: " + name.toString() + ", e=" + ex);
+            } catch (IOException ex) {
+                throw Py.IOError(ex);
+            }
+        } else {
+            file___init__(new FileIO((PyString) name, parseMode(mode)), name, mode, bufsize);
+        }
         closer = new Closer(file, Py.getSystemState());
     }
 

src/org/python/core/PySystemState.java

     }
 
     private static String getPath(PySystemState sys, String path) {
-        if (path != null) {
+        if (path != null && !path.startsWith("jar:file:")) {
             path = getFile(sys, path).getAbsolutePath();
         }
         return path;
         // Cause sys to export the console handler that was installed
         Py.defaultSystemState.__setattr__("_jy_console", Py.java2py(Py.getConsole()));
 
+        // Now late enough to add site-packages if standalone
+        if (standalone && Options.importSite) {
+            PyObject site = imp.load("site");
+            // FIXME this doesn't roundtrip if this was originally vfs or vfszip
+            // FIXME probably this simply write out a warning in this case, degrade to
+            // FIXME old approach
+            // using addPaths will tokenize on : - this is clearly not desirable!
+            site.invoke("addsitedir",Py.newString("jar:file:" + jarFileName + "!/Lib/site-packages"));
+        }
+
+
         return Py.defaultSystemState;
     }
 
         }
         if (standalone) {
             // standalone jython: add the /Lib directory inside JYTHON_JAR to the path
+            // FIXME probably want to the same for
             addPaths(path, jarFileName + "/Lib");
+
         }
 
         return path;

src/org/python/core/imp.java

 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.python.compiler.Module;
+import org.python.core.io.StreamIO;
 import org.python.core.util.FileUtil;
 import org.python.core.util.PlatformUtil;
 
     }
 
     private static InputStream makeStream(File file) {
+        String path = file.getPath();
+        if (path.startsWith("jar:file:")) {
+            try {
+                Py.writeDebug(IMPORT_LOG, "Attempting to open jar url " + path);
+                InputStream istream = (new URL(path)).openConnection().getInputStream();
+                Py.writeDebug(IMPORT_LOG, "Opened jar url=" + path + ", stream=" + istream);
+                return istream;
+            } catch (MalformedURLException ex) {
+                throw Py.ValueError("not a valid jar url: " + path + ", e=" + ex);
+            } catch (IOException ex) {
+                throw Py.IOError(ex);
+            }
+        }
         try {
             return new FileInputStream(file);
         } catch (IOException ioe) {
         return createFromPyClass(name, stream, false, sourceName, compiledName);
     }
 
+    static boolean urlExists(File file) {
+        try {
+            // probe for the file in the jar (or potentially some other URL source)
+            new URL(file.getPath()).openConnection().getInputStream().close();
+            return true;
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
     static PyObject loadFromSource(PySystemState sys, String name, String modName, String entry) {
         String dirName = sys.getPath(entry);
+        Py.writeDebug(IMPORT_LOG, "FIXME entry=" + entry + ", dirName=" + dirName);
         String sourceName = "__init__.py";
         String compiledName = "__init__$py.class";
         // display names are for identification purposes (e.g. __file__): when entry is
         File sourceFile = new File(dir, sourceName);
         File compiledFile = new File(dir, compiledName);
 
+        // FIXME is dirName a jar url? then there's no way to check if if it's truly a directory without trying.
+        // FIXME SO DO THAT
+        // FIXME this also suggest we should extract this jar url logic in one place - this is a bit complex right now
+        // FIXME but first try it out :)
+        // FIXME Also means we have to try it both ways!
+
+        boolean isJarURL = dir.getPath().startsWith("jar:file:");
+
         boolean pkg = false;
         try {
             pkg = dir.isDirectory() && caseok(dir, name)
             // ok
         }
 
+        if (isJarURL && urlExists(new File(dir, "__init__.py"))) {
+            pkg = true;
+        }
+
         if (!pkg) {
-            Py.writeDebug(IMPORT_LOG, "trying source " + dir.getPath());
+            Py.writeDebug(IMPORT_LOG, "FIXME trying source " + dir.getPath());
             sourceName = name + ".py";
             compiledName = name + "$py.class";
             displaySourceName = new File(displayDirName, sourceName).getPath();
 
         try {
             if (sourceFile.isFile() && caseok(sourceFile, sourceName)) {
+                // FIXME another place we need to fix up metadata related to jar urls
                 long pyTime = sourceFile.lastModified();
                 if (compiledFile.isFile() && caseok(compiledFile, compiledName)) {
-                    Py.writeDebug(IMPORT_LOG, "trying precompiled " + compiledFile.getPath());
+                    Py.writeDebug(IMPORT_LOG, "FIXME trying precompiled path=" + compiledFile.getPath());
                     long classTime = compiledFile.lastModified();
                     if (classTime >= pyTime) {
                         PyObject ret = createFromPyClass(modName, makeStream(compiledFile), true,
             }
 
             // If no source, try loading precompiled
-            Py.writeDebug(IMPORT_LOG, "trying precompiled with no source " + compiledFile.getPath());
-            if (compiledFile.isFile() && caseok(compiledFile, compiledName)) {
+            Py.writeDebug(IMPORT_LOG, "trying precompiled with no source path=" + compiledFile.getPath() + ", isJarURL=" + isJarURL);
+            if ((compiledFile.isFile() && caseok(compiledFile, compiledName)) || (isJarURL && urlExists(compiledFile))) {
                 return createFromPyClass(modName, makeStream(compiledFile), true, displaySourceName,
                                          displayCompiledName);
             }