[pypy-svn] r48247 - pypy/dist/pypy/translator/goal

tismer at codespeak.net tismer at codespeak.net
Fri Nov 2 06:08:01 CET 2007


Author: tismer
Date: Fri Nov  2 06:08:00 2007
New Revision: 48247

Modified:
   pypy/dist/pypy/translator/goal/app_main.py
Log:
this is still not completely correct, but way better than before.
Nobody will believe that I hacked a week on this, already, because it cannot
be debugged without compilation...

Modified: pypy/dist/pypy/translator/goal/app_main.py
==============================================================================
--- pypy/dist/pypy/translator/goal/app_main.py	(original)
+++ pypy/dist/pypy/translator/goal/app_main.py	Fri Nov  2 06:08:00 2007
@@ -16,14 +16,14 @@
   --info         print translation information about this PyPy executable
 """
 
-import sys, os
+import sys
 
 DEBUG = False       # dump exceptions before calling the except hook
 
 originalexcepthook = sys.__excepthook__
 
 def run_toplevel(f, *fargs, **fkwds):
-    """Calls f() and handle all OperationErrors.
+    """Calls f() and handles all OperationErrors.
     Intended use is to run the main program or one interactive statement.
     run_protected() handles details like forwarding exceptions to
     sys.excepthook(), catching SystemExit, printing a newline after
@@ -144,16 +144,120 @@
 # ____________________________________________________________
 # Main entry point
 
+# faking os, until we really are able to import it from source
+"""
+Why fake_os ?
+-------------
+
+When pypy is starting, the builtin modules are there, but os.path
+is a Python module. The current startup code depends on os.py,
+which had the side effect that os.py got frozen into the binary.
+
+Os.py is a wrapper for system specific built-in modules and tries
+to unify the interface. One problem is os.environ which looks
+very differently per os.
+Due to the way os.py initializes its environ variable on Windows,
+it s hard to get a correct os.getenv that uses the actual environment
+variables. In order to fix that without modifying os.py, we need to
+re-import it several times, before and after compilation.
+
+When compiling the source, we first create a fake_os class instance.
+fake_os contains all of os, when compiling.reduction seems to be not
+appropriate, since lots of other modules are sucked in, at the same time.
+A complete reduction is possible, but would require much more work.
+
+In the course of creating fake_os, we import the real os. We keep a record
+of which modules were imported, before.
+
+During start of the entry_point, we call os.setup().
+This repeats an import of the specific parts in os.name.
+Depending of the underlying os, this might or might not
+cause a redefinition of certain os variables, but this happens
+exactly like in os.py's initialization.
+We then capture the variable environ, which may or may not come from the
+specific os.
+After that, we re-initialize our dict to what is expected in standard
+os. The effect of all this magic is that we have captured the environ
+cariable, again, and we now can redefine os.getenv to use this fresh
+variable, being accurate and not frozen.
+
+At this point, we finally can compute the location of our import.
+
+As a side effect, the involved modules are re-imported, although they had
+been compiled in, so PyPy behaves really conformant, making all .py
+modules changeable, again.
+"""
+
+from pypy.rlib.objectmodel import we_are_translated
+
+class fake_os:
+    def __init__(self):
+        import sys
+        self.pre_import = sys.modules.keys()
+        import os
+        self.os = os
+        # make ourselves a clone of os
+        self.__dict__.update(self.os.__dict__)
+
+    def setup(self):
+        # we now repeat the os-specific initialization, which
+        # must be done before importing os, since os hides
+        # variables after initialization.
+        specifics = __import__(self.os.name)
+        self.__dict__.update(specifics.__dict__)
+        # depending on the os, we now might or might not have
+        # a new environ variable. However, we can now
+        # repeat the environ initialisation from os.py
+        environ = self.os._Environ(self.environ)
+        # to be safe, reset our dict to be like os
+        self.__dict__.update(self.os.__dict__)
+        # but now we insert the fresh environ
+        self.environ = environ
+        del self.getenv
+        # use our method, instead of the os's one's
+        assert self.getenv
+        
+    def teardown(self):
+        for mod in sys.modules.keys():
+            if mod not in self.pre_import:
+                del sys.modules[mod]
+        global os
+        import os
+
+    def getenv(self, key, default=None):
+        """Get an environment variable, return None if it doesn't exist.
+        The optional second argument can specify an alternate default."""
+        return self.environ.get(key, default)
+        
+os = fake_os()
+
 AUTOSUBPATH = 'share' + os.sep + 'pypy-%d.%d'
 
+# hack to determine if we are on windows. Maybe there is a better way...
+DRIVE_LETTER_SEP = ''
+try:
+    here = os.getcwd()
+    try:
+        os.chdir('C:')
+        DRIVE_LETTER_SEP = ':'
+    finally:
+        os.chdir(here)
+except os.OSError:
+    DRIVE_LETTER_SEP = None
+IS_WINDOWS = DRIVE_LETTER_SEP is not None
+# XXX extend here
+
 def entry_point(executable, argv):
     # find the full path to the executable, assuming that if there is no '/'
     # in the provided one then we must look along the $PATH
-    if os.sep not in executable:
+    os.setup() # this is the faked one
+    if os.sep not in executable and DRIVE_LETTER_SEP not in executable:
         path = os.getenv('PATH')
         if path:
             for dir in path.split(os.pathsep):
                 fn = os.path.join(dir, executable)
+                if we_are_translated and IS_WINDOWS and not fn.lower().endswith('.exe'):
+                    fn += '.exe'
                 if os.path.isfile(fn):
                     executable = fn
                     break
@@ -177,7 +281,9 @@
                 continue
         sys.path = newpath      # found!
         break
-
+    
+    os.teardown() # from now on this is the real one
+    
     go_interactive = False
     run_command = False
     import_site = True



More information about the Pypy-commit mailing list