Index: trac/env.py
===================================================================
--- trac/env.py	(revision 5999)
+++ trac/env.py	(working copy)
@@ -329,8 +329,8 @@
                      .replace('%(path)s', self.path) \
                      .replace('%(basename)s', os.path.basename(self.path)) \
                      .replace('%(project)s', self.project_name)
-        self.log = logger_factory(logtype, logfile, self.log_level, self.path,
-                                  format=format)
+        self.log, self._log_hdlr = logger_factory(logtype, logfile,
+                            self.log_level, self.path, format=format)
 
     def get_known_users(self, cnx=None):
         """Generator that yields information about all known users, i.e. users
@@ -516,12 +516,14 @@
         env_cache_lock.acquire()
         try:
             env = env_cache.get(env_path)
+            if env and env.config.parse_if_needed():
+                # The environment is dirty - shut it down and remove from cache
+                env.shutdown()
+                env.log.removeHandler(env._log_hdlr)
+                env_cache.pop(env_path)
+                env = None
             if env is None:
                 env = env_cache.setdefault(env_path, open_environment(env_path))
-            else:
-                # Re-parse the configuration file if it changed since the last
-                # the time it was parsed
-                env.config.parse_if_needed()
         finally:
             env_cache_lock.release()
     else:
Index: trac/admin/web_ui.py
===================================================================
--- trac/admin/web_ui.py	(revision 5999)
+++ trac/admin/web_ui.py	(working copy)
@@ -381,7 +381,7 @@
                 self._do_update(req)
             anchor = ''
             if req.args.has_key('plugin'):
-                anchor = '#no' + req.args.get('plugin')
+                anchor = '#no%d' % (int(req.args.get('plugin')) + 1)
             req.redirect(req.href.admin(cat, page) + anchor)
 
         return self._render_view(req)
@@ -426,6 +426,9 @@
 
         # TODO: Validate that the uploaded file is actually a valid Trac plugin
 
+        # Make the environment reset itself on the next request
+        self.env.config.touch()
+
     def _do_uninstall(self, req):
         """Uninstall a plugin."""
         plugin_filename = req.args.get('plugin_filename')
@@ -437,6 +440,9 @@
         self.log.info('Uninstalling plugin %s', plugin_filename)
         os.remove(plugin_path)
 
+        # Make the environment reset itself on the next request
+        self.env.config.touch()
+
     def _do_update(self, req):
         """Update component enablement."""
         components = req.args.getlist('component')
Index: trac/config.py
===================================================================
--- trac/config.py	(revision 5999)
+++ trac/config.py	(working copy)
@@ -174,13 +174,16 @@
             fileobj.close()
 
     def parse_if_needed(self):
-        # Load global configuration
         if not self.filename or not os.path.isfile(self.filename):
-            return
+            return False
+
+        changed = False
         modtime = os.path.getmtime(self.filename)
         if modtime > self._lastmtime:
+            self.parser._sections = {}
             self.parser.read(self.filename)
             self._lastmtime = modtime
+            changed = True
 
         if self.parser.has_option('inherit', 'file'):
             filename = self.parser.get('inherit', 'file')
@@ -189,12 +192,19 @@
                                         filename)
             if not self.parent or self.parent.filename != filename:
                 self.parent = Configuration(filename)
+                changed = True
             else:
-                self.parent.parse_if_needed()
+                changed |= self.parent.parse_if_needed()
         elif self.parent:
+            changed = True
             self.parent = None
 
+        return changed
 
+    def touch(self):
+        os.utime(self.filename, None)
+
+
 class Section(object):
     """Proxy for a specific configuration section.
     
@@ -292,7 +302,9 @@
         """
         if self.config.parser.has_option(self.name, name):
             path = self.config.parser.get(self.name, name)
-            if path and not os.path.isabs(path):
+            if not path:
+                return default
+            if not os.path.isabs(path):
                 path = os.path.join(os.path.dirname(self.config.filename),
                                     path)
             return os.path.normcase(os.path.realpath(path))
Index: trac/tests/env.py
===================================================================
--- trac/tests/env.py	(revision 5999)
+++ trac/tests/env.py	(working copy)
@@ -1,4 +1,5 @@
 from trac import db_default
+from trac.db import sqlite_backend
 from trac.env import Environment
 
 import os.path
Index: trac/log.py
===================================================================
--- trac/log.py	(revision 5999)
+++ trac/log.py	(working copy)
@@ -44,7 +44,7 @@
             format = '%(asctime)s ' + format
     datefmt = ''
     if logtype == 'stderr':
-        datefmt = '%X'        
+        datefmt = '%X'
     level = level.upper()
     if level in ('DEBUG', 'ALL'):
         logger.setLevel(logging.DEBUG)
@@ -60,4 +60,4 @@
     hdlr.setFormatter(formatter)
     logger.addHandler(hdlr) 
 
-    return logger
+    return logger, hdlr
Index: trac/util/__init__.py
===================================================================
--- trac/util/__init__.py	(revision 5999)
+++ trac/util/__init__.py	(working copy)
@@ -228,6 +228,10 @@
         pkginfo = email.message_from_string(dist.get_metadata('PKG-INFO'))
         for attr in [key for key in attrs if key in pkginfo]:
             info[normalize(attr)] = pkginfo[attr]
+    except IOError, e:
+        err = 'Failed to read PKG-INFO file for %s: %s' % (dist, e)
+        for attr in attrs:
+            info[normalize(attr)] = err
     except email.Errors.MessageError, e:
         err = 'Failed to parse PKG-INFO file for %s: %s' % (dist, e)
         for attr in attrs:

