Merged from trunk -r15449:15451
authorFabian Groffen <grobian@gentoo.org>
Sat, 27 Feb 2010 19:01:26 +0000 (19:01 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 27 Feb 2010 19:01:26 +0000 (19:01 -0000)
   | 15450   | Move cacheddir and listdir to portage.util.listdir.          |
   | zmedico |                                                              |

   | 15451   | Fix broken references to                                     |
   | zmedico | portage._doebuild_manifest_exempt_depend.                    |

svn path=/main/branches/prefix/; revision=15480

pym/portage/__init__.py
pym/portage/dbapi/bintree.py
pym/portage/dbapi/porttree.py
pym/portage/dbapi/vartree.py
pym/portage/package/ebuild/doebuild.py
pym/portage/util/digraph.py
pym/portage/util/listdir.py [new file with mode: 0644]

index bab3e4ae07a49230687f282f5d846237d5c2561b..c4724d4097ca8f6e9b60d4eba2bc72885567c430 100644 (file)
@@ -122,6 +122,7 @@ try:
                        'stack_lists,unique_array,varexpand,writedict,writemsg,' + \
                        'writemsg_stdout,write_atomic',
                'portage.util.digraph:digraph',
+               'portage.util.listdir:cacheddir,listdir',
                'portage.versions',
                'portage.versions:best,catpkgsplit,catsplit,cpv_getkey,' + \
                        'cpv_getkey@getCPFromCPV,endversion_keys,' + \
@@ -534,145 +535,6 @@ def abssymlink(symlink):
                mylink=mydir+"/"+mylink
        return os.path.normpath(mylink)
 
-dircache = {}
-cacheHit=0
-cacheMiss=0
-cacheStale=0
-def cacheddir(my_original_path, ignorecvs, ignorelist, EmptyOnError, followSymlinks=True):
-       global cacheHit,cacheMiss,cacheStale
-       mypath = normalize_path(my_original_path)
-       if mypath in dircache:
-               cacheHit += 1
-               cached_mtime, list, ftype = dircache[mypath]
-       else:
-               cacheMiss += 1
-               cached_mtime, list, ftype = -1, [], []
-       try:
-               pathstat = os.stat(mypath)
-               if stat.S_ISDIR(pathstat[stat.ST_MODE]):
-                       mtime = pathstat.st_mtime
-               else:
-                       raise portage.exception.DirectoryNotFound(mypath)
-       except EnvironmentError as e:
-               if e.errno == portage.exception.PermissionDenied.errno:
-                       raise portage.exception.PermissionDenied(mypath)
-               del e
-               return [], []
-       except portage.exception.PortageException:
-               return [], []
-       # Python retuns mtime in seconds, so if it was changed in the last few seconds, it could be invalid
-       if mtime != cached_mtime or time.time() - mtime < 4:
-               if mypath in dircache:
-                       cacheStale += 1
-               try:
-                       list = os.listdir(mypath)
-               except EnvironmentError as e:
-                       if e.errno != errno.EACCES:
-                               raise
-                       del e
-                       raise portage.exception.PermissionDenied(mypath)
-               ftype = []
-               for x in list:
-                       try:
-                               if followSymlinks:
-                                       pathstat = os.stat(mypath+"/"+x)
-                               else:
-                                       pathstat = os.lstat(mypath+"/"+x)
-
-                               if stat.S_ISREG(pathstat[stat.ST_MODE]):
-                                       ftype.append(0)
-                               elif stat.S_ISDIR(pathstat[stat.ST_MODE]):
-                                       ftype.append(1)
-                               elif stat.S_ISLNK(pathstat[stat.ST_MODE]):
-                                       ftype.append(2)
-                               else:
-                                       ftype.append(3)
-                       except (IOError, OSError):
-                               ftype.append(3)
-               dircache[mypath] = mtime, list, ftype
-
-       ret_list = []
-       ret_ftype = []
-       for x in range(0, len(list)):
-               if list[x] in ignorelist:
-                       pass
-               elif ignorecvs:
-                       if list[x][:2] != ".#":
-                               ret_list.append(list[x])
-                               ret_ftype.append(ftype[x])
-               else:
-                       ret_list.append(list[x])
-                       ret_ftype.append(ftype[x])
-
-       writemsg("cacheddirStats: H:%d/M:%d/S:%d\n" % (cacheHit, cacheMiss, cacheStale),10)
-       return ret_list, ret_ftype
-
-_ignorecvs_dirs = ('CVS', 'SCCS', '.svn', '.git')
-
-def listdir(mypath, recursive=False, filesonly=False, ignorecvs=False, ignorelist=[], followSymlinks=True,
-       EmptyOnError=False, dirsonly=False):
-       """
-       Portage-specific implementation of os.listdir
-
-       @param mypath: Path whose contents you wish to list
-       @type mypath: String
-       @param recursive: Recursively scan directories contained within mypath
-       @type recursive: Boolean
-       @param filesonly; Only return files, not more directories
-       @type filesonly: Boolean
-       @param ignorecvs: Ignore CVS directories ('CVS','SCCS','.svn','.git')
-       @type ignorecvs: Boolean
-       @param ignorelist: List of filenames/directories to exclude
-       @type ignorelist: List
-       @param followSymlinks: Follow Symlink'd files and directories
-       @type followSymlinks: Boolean
-       @param EmptyOnError: Return [] if an error occurs (deprecated, always True)
-       @type EmptyOnError: Boolean
-       @param dirsonly: Only return directories.
-       @type dirsonly: Boolean
-       @rtype: List
-       @returns: A list of files and directories (or just files or just directories) or an empty list.
-       """
-
-       list, ftype = cacheddir(mypath, ignorecvs, ignorelist, EmptyOnError, followSymlinks)
-
-       if list is None:
-               list=[]
-       if ftype is None:
-               ftype=[]
-
-       if not (filesonly or dirsonly or recursive):
-               return list
-
-       if recursive:
-               x=0
-               while x<len(ftype):
-                       if ftype[x] == 1 and not \
-                               (ignorecvs and os.path.basename(list[x]) in _ignorecvs_dirs):
-                               l,f = cacheddir(mypath+"/"+list[x], ignorecvs, ignorelist, EmptyOnError,
-                                       followSymlinks)
-
-                               l=l[:]
-                               for y in range(0,len(l)):
-                                       l[y]=list[x]+"/"+l[y]
-                               list=list+l
-                               ftype=ftype+f
-                       x+=1
-       if filesonly:
-               rlist=[]
-               for x in range(0,len(ftype)):
-                       if ftype[x]==0:
-                               rlist=rlist+[list[x]]
-       elif dirsonly:
-               rlist = []
-               for x in range(0, len(ftype)):
-                       if ftype[x] == 1:
-                               rlist = rlist + [list[x]]       
-       else:
-               rlist=list
-
-       return rlist
-
 #parse /etc/env.d and generate /etc/profile.env
 
 def env_update(makelinks=1, target_root=None, prev_mtimes=None, contents=None,
@@ -1017,209 +879,6 @@ def ExtractKernelVersion(base_dir):
 
        return (version,None)
 
-# XXX This would be to replace getstatusoutput completely.
-# XXX Issue: cannot block execution. Deadlock condition.
-def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakeroot=0, **keywords):
-       """
-       Spawn a subprocess with extra portage-specific options.
-       Optiosn include:
-
-       Sandbox: Sandbox means the spawned process will be limited in its ability t
-       read and write files (normally this means it is restricted to ${D}/)
-       SElinux Sandbox: Enables sandboxing on SElinux
-       Reduced Privileges: Drops privilages such that the process runs as portage:portage
-       instead of as root.
-
-       Notes: os.system cannot be used because it messes with signal handling.  Instead we
-       use the portage.process spawn* family of functions.
-
-       This function waits for the process to terminate.
-
-       @param mystring: Command to run
-       @type mystring: String
-       @param mysettings: Either a Dict of Key,Value pairs or an instance of portage.config
-       @type mysettings: Dictionary or config instance
-       @param debug: Ignored
-       @type debug: Boolean
-       @param free: Enable sandboxing for this process
-       @type free: Boolean
-       @param droppriv: Drop to portage:portage when running this command
-       @type droppriv: Boolean
-       @param sesandbox: Enable SELinux Sandboxing (toggles a context switch)
-       @type sesandbox: Boolean
-       @param fakeroot: Run this command with faked root privileges
-       @type fakeroot: Boolean
-       @param keywords: Extra options encoded as a dict, to be passed to spawn
-       @type keywords: Dictionary
-       @rtype: Integer
-       @returns:
-       1. The return code of the spawned process.
-       """
-
-       if isinstance(mysettings, dict):
-               env=mysettings
-               keywords["opt_name"]="[ %s ]" % "portage"
-       else:
-               check_config_instance(mysettings)
-               env=mysettings.environ()
-               if mysettings.mycpv is not None:
-                       keywords["opt_name"] = "[%s]" % mysettings.mycpv
-               else:
-                       keywords["opt_name"] = "[%s/%s]" % \
-                               (mysettings.get("CATEGORY",""), mysettings.get("PF",""))
-
-       fd_pipes = keywords.get("fd_pipes")
-       if fd_pipes is None:
-               fd_pipes = {
-                       0:sys.stdin.fileno(),
-                       1:sys.stdout.fileno(),
-                       2:sys.stderr.fileno(),
-               }
-       # In some cases the above print statements don't flush stdout, so
-       # it needs to be flushed before allowing a child process to use it
-       # so that output always shows in the correct order.
-       stdout_filenos = (sys.stdout.fileno(), sys.stderr.fileno())
-       for fd in fd_pipes.values():
-               if fd in stdout_filenos:
-                       sys.stdout.flush()
-                       sys.stderr.flush()
-                       break
-
-       # The default policy for the sesandbox domain only allows entry (via exec)
-       # from shells and from binaries that belong to portage (the number of entry
-       # points is minimized).  The "tee" binary is not among the allowed entry
-       # points, so it is spawned outside of the sesandbox domain and reads from a
-       # pseudo-terminal that connects two domains.
-       logfile = keywords.get("logfile")
-       mypids = []
-       master_fd = None
-       slave_fd = None
-       fd_pipes_orig = None
-       got_pty = False
-       if logfile:
-               del keywords["logfile"]
-               if 1 not in fd_pipes or 2 not in fd_pipes:
-                       raise ValueError(fd_pipes)
-
-               got_pty, master_fd, slave_fd = \
-                       _create_pty_or_pipe(copy_term_size=fd_pipes[1])
-
-               if not got_pty and 'sesandbox' in mysettings.features \
-                       and mysettings.selinux_enabled():
-                       # With sesandbox, logging works through a pty but not through a
-                       # normal pipe. So, disable logging if ptys are broken.
-                       # See Bug #162404.
-                       logfile = None
-                       os.close(master_fd)
-                       master_fd = None
-                       os.close(slave_fd)
-                       slave_fd = None
-
-       if logfile:
-
-               fd_pipes.setdefault(0, sys.stdin.fileno())
-               fd_pipes_orig = fd_pipes.copy()
-
-               # We must set non-blocking mode before we close the slave_fd
-               # since otherwise the fcntl call can fail on FreeBSD (the child
-               # process might have already exited and closed slave_fd so we
-               # have to keep it open in order to avoid FreeBSD potentially
-               # generating an EAGAIN exception).
-               import fcntl
-               fcntl.fcntl(master_fd, fcntl.F_SETFL,
-                       fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
-
-               fd_pipes[0] = fd_pipes_orig[0]
-               fd_pipes[1] = slave_fd
-               fd_pipes[2] = slave_fd
-               keywords["fd_pipes"] = fd_pipes
-
-       features = mysettings.features
-       # TODO: Enable fakeroot to be used together with droppriv.  The
-       # fake ownership/permissions will have to be converted to real
-       # permissions in the merge phase.
-       fakeroot = fakeroot and uid != 0 and portage.process.fakeroot_capable
-       if droppriv and not uid and portage_gid and portage_uid:
-               keywords.update({"uid":portage_uid,"gid":portage_gid,
-                       "groups":userpriv_groups,"umask":0o02})
-       if not free:
-               free=((droppriv and "usersandbox" not in features) or \
-                       (not droppriv and "sandbox" not in features and \
-                       "usersandbox" not in features and not fakeroot))
-
-       if not free and not (fakeroot or process.sandbox_capable):
-               free = True
-
-       if free or "SANDBOX_ACTIVE" in os.environ:
-               keywords["opt_name"] += " bash"
-               spawn_func = portage.process.spawn_bash
-       elif fakeroot:
-               keywords["opt_name"] += " fakeroot"
-               keywords["fakeroot_state"] = os.path.join(mysettings["T"], "fakeroot.state")
-               spawn_func = portage.process.spawn_fakeroot
-       else:
-               keywords["opt_name"] += " sandbox"
-               spawn_func = portage.process.spawn_sandbox
-
-       if sesandbox:
-               spawn_func = selinux.spawn_wrapper(spawn_func,
-                       mysettings["PORTAGE_SANDBOX_T"])
-
-       returnpid = keywords.get("returnpid")
-       keywords["returnpid"] = True
-       try:
-               mypids.extend(spawn_func(mystring, env=env, **keywords))
-       finally:
-               if logfile:
-                       os.close(slave_fd)
-
-       if returnpid:
-               return mypids
-
-       if logfile:
-               log_file = open(_unicode_encode(logfile), mode='ab')
-               apply_secpass_permissions(logfile,
-                       uid=portage_uid, gid=portage_gid, mode=0o664)
-               stdout_file = os.fdopen(os.dup(fd_pipes_orig[1]), 'wb')
-               master_file = os.fdopen(master_fd, 'rb')
-               iwtd = [master_file]
-               owtd = []
-               ewtd = []
-               import array, select
-               buffsize = 65536
-               eof = False
-               while not eof:
-                       events = select.select(iwtd, owtd, ewtd)
-                       for f in events[0]:
-                               # Use non-blocking mode to prevent read
-                               # calls from blocking indefinitely.
-                               buf = array.array('B')
-                               try:
-                                       buf.fromfile(f, buffsize)
-                               except EOFError:
-                                       pass
-                               if not buf:
-                                       eof = True
-                                       break
-                               if f is master_file:
-                                       buf.tofile(stdout_file)
-                                       stdout_file.flush()
-                                       buf.tofile(log_file)
-                                       log_file.flush()
-               log_file.close()
-               stdout_file.close()
-               master_file.close()
-       pid = mypids[-1]
-       retval = os.waitpid(pid, 0)[1]
-       portage.process.spawned_pids.remove(pid)
-       if retval != os.EX_OK:
-               if retval & 0xff:
-                       return (retval & 0xff) << 8
-               return retval >> 8
-       return retval
-
-=======
->>>>>>> .merge-right.r15449
 def digestgen(myarchives=None, mysettings=None,
        overwrite=None, manifestonly=None, myportdb=None):
        """
index f08f150f4fbe700c7050e4424ef23dc2fd58f873..18278c11434dc0142cf139b98a709da2cadc872d 100644 (file)
@@ -13,6 +13,7 @@ portage.proxy.lazyimport.lazyimport(globals(),
        'portage.package.ebuild.doebuild:_vdb_use_conditional_atoms',
        'portage.update:update_dbentries',
        'portage.util:ensure_dirs,normalize_path,writemsg,writemsg_stdout',
+       'portage.util.listdir:listdir',
        'portage.versions:best,catpkgsplit,catsplit',
 )
 
@@ -23,7 +24,7 @@ from portage.exception import InvalidPackageName, \
 from portage.const import EAPI
 from portage.localization import _
 
-from portage import dep_expand, listdir, _movefile
+from portage import dep_expand, _movefile
 from portage import os
 from portage import _encodings
 from portage import _unicode_decode
index 51e260102fb60cce654887a7f40cca169ab46141..7dd81f7b5f62fb184a4c8a5adb63b2a24f42723c 100644 (file)
@@ -11,9 +11,11 @@ __all__ = [
 import portage
 portage.proxy.lazyimport.lazyimport(globals(),
        'portage.checksum',
-       'portage.dep:dep_getkey,match_from_list,paren_reduce,use_reduce',
+       'portage.dep:dep_getkey,flatten,match_from_list,paren_reduce,use_reduce',
        'portage.env.loaders:KeyValuePairFileLoader',
+       'portage.package.ebuild.doebuild:doebuild',
        'portage.util:ensure_dirs,writemsg,writemsg_level',
+       'portage.util.listdir:listdir',
        'portage.versions:best,catpkgsplit,_pkgsplit@pkgsplit,ver_regexp',
 )
 
@@ -27,8 +29,8 @@ from portage.exception import PortageException, \
 from portage.localization import _
 from portage.manifest import Manifest
 
-from portage import eclass_cache, auxdbkeys, doebuild, flatten, \
-       listdir, dep_expand, eapi_is_supported, dep_check, \
+from portage import eclass_cache, auxdbkeys, \
+       dep_expand, eapi_is_supported, dep_check, \
        _eapi_is_deprecated
 from portage import os
 from portage import _encodings
index a4348616cd2aee213976b66b08602dbf6c6ffc97..0ae1e5739724c6a9bb5ba2822b53b711250422d1 100644 (file)
@@ -12,7 +12,7 @@ __all__ = ["PreservedLibsRegistry", "LinkageMap",
 import portage
 portage.proxy.lazyimport.lazyimport(globals(),
        'portage.checksum:_perform_md5_merge@perform_md5',
-       'portage.dep:dep_getkey,isjustname,match_from_list,' + \
+       'portage.dep:dep_getkey,isjustname,flatten,match_from_list,' + \
                'use_reduce,paren_reduce,_slot_re',
        'portage.elog:elog_process',
        'portage.locks:lockdir,unlockdir',
@@ -24,7 +24,10 @@ portage.proxy.lazyimport.lazyimport(globals(),
        'portage.util:apply_secpass_permissions,ConfigProtect,ensure_dirs,' + \
                'writemsg,writemsg_level,write_atomic,atomic_ofstream,writedict,' + \
                'grabfile,grabdict,normalize_path,new_protect_filename,getlibpaths',
-       'portage.versions:best,catpkgsplit,catsplit,pkgcmp,_pkgsplit@pkgsplit',
+       'portage.util.digraph:digraph',
+       'portage.util.listdir:dircache,listdir',
+       'portage.versions:best,catpkgsplit,catsplit,cpv_getkey,pkgcmp,' + \
+               '_pkgsplit@pkgsplit',
 )
 
 from portage.const import CACHE_PATH, CONFIG_MEMORY_FILE, \
@@ -36,9 +39,8 @@ from portage.exception import CommandNotFound, \
        FileNotFound, PermissionDenied, UnsupportedAPIException
 from portage.localization import _
 
-from portage import listdir, dep_expand, digraph, flatten, \
-       env_update, \
-       abssymlink, movefile, _movefile, bsd_chflags, cpv_getkey
+from portage import dep_expand, env_update, \
+       abssymlink, movefile, _movefile, bsd_chflags
 
 # This is a special version of the os module, wrapped for unicode support.
 from portage import os
@@ -2077,7 +2079,6 @@ class vardbapi(dbapi):
                self.mtdircache.pop(pkg_dblink.cat, None)
                self.matchcache.pop(pkg_dblink.cat, None)
                self.cpcache.pop(pkg_dblink.mysplit[0], None)
-               from portage import dircache
                dircache.pop(pkg_dblink.dbcatdir, None)
 
        def match(self, origdep, use_cache=1):
index d7259b4699833f4343701707356fe73eb01680c7..b2824d4cc4acc7eeefe825074d4ef654d3babba6 100644 (file)
@@ -280,7 +280,7 @@ def _doebuild_exit_status_unlink(exit_status_file):
        if os.path.exists(exit_status_file):
                os.unlink(exit_status_file)
 
-_doebuild_manifest_exempt_depend = 0
+
 _doebuild_manifest_cache = None
 _doebuild_broken_ebuilds = set()
 _doebuild_broken_manifests = set()
@@ -401,16 +401,13 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        noiselevel=-1)
                return 1
 
-       global _doebuild_manifest_exempt_depend
-
        if "strict" in features and \
                "digest" not in features and \
                tree == "porttree" and \
                mydo not in ("digest", "manifest", "help") and \
-               not _doebuild_manifest_exempt_depend:
+               not portage._doebuild_manifest_exempt_depend:
                # Always verify the ebuild checksums before executing it.
-               global _doebuild_manifest_cache, _doebuild_broken_ebuilds, \
-                       _doebuild_broken_ebuilds
+               global _doebuild_manifest_cache, _doebuild_broken_ebuilds
 
                if myebuild in _doebuild_broken_ebuilds:
                        return 1
@@ -508,7 +505,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                if mydo in ("digest", "manifest", "help"):
                        # Temporarily exempt the depend phase from manifest checks, in case
                        # aux_get calls trigger cache generation.
-                       _doebuild_manifest_exempt_depend += 1
+                       portage._doebuild_manifest_exempt_depend += 1
 
                # If we don't need much space and we don't need a constant location,
                # we can temporarily override PORTAGE_TMPDIR with a random temp dir
@@ -1023,7 +1020,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                if mydo in ("digest", "manifest", "help"):
                        # If necessary, depend phase has been triggered by aux_get calls
                        # and the exemption is no longer needed.
-                       _doebuild_manifest_exempt_depend -= 1
+                       portage._doebuild_manifest_exempt_depend -= 1
 
 def _validate_deps(mysettings, myroot, mydo, mydbapi):
 
index ef7b06fc7b716870b2aec1402c2dda22d8266365..dbb86a3c4ce9fb7e474a987ea82e347c1a049531 100644 (file)
@@ -2,6 +2,8 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Id$
 
+__all__ = ['digraph']
+
 from portage.util import writemsg
 
 class digraph(object):
diff --git a/pym/portage/util/listdir.py b/pym/portage/util/listdir.py
new file mode 100644 (file)
index 0000000..82705ac
--- /dev/null
@@ -0,0 +1,153 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+__all__ = ['cacheddir', 'listdir']
+
+import errno
+import stat
+import time
+
+from portage import os
+from portage.exception import DirectoryNotFound, PermissionDenied, PortageException
+from portage.util import normalize_path, writemsg
+
+dircache = {}
+cacheHit = 0
+cacheMiss = 0
+cacheStale = 0
+
+def cacheddir(my_original_path, ignorecvs, ignorelist, EmptyOnError, followSymlinks=True):
+       global cacheHit,cacheMiss,cacheStale
+       mypath = normalize_path(my_original_path)
+       if mypath in dircache:
+               cacheHit += 1
+               cached_mtime, list, ftype = dircache[mypath]
+       else:
+               cacheMiss += 1
+               cached_mtime, list, ftype = -1, [], []
+       try:
+               pathstat = os.stat(mypath)
+               if stat.S_ISDIR(pathstat[stat.ST_MODE]):
+                       mtime = pathstat.st_mtime
+               else:
+                       raise DirectoryNotFound(mypath)
+       except EnvironmentError as e:
+               if e.errno == PermissionDenied.errno:
+                       raise PermissionDenied(mypath)
+               del e
+               return [], []
+       except PortageException:
+               return [], []
+       # Python retuns mtime in seconds, so if it was changed in the last few seconds, it could be invalid
+       if mtime != cached_mtime or time.time() - mtime < 4:
+               if mypath in dircache:
+                       cacheStale += 1
+               try:
+                       list = os.listdir(mypath)
+               except EnvironmentError as e:
+                       if e.errno != errno.EACCES:
+                               raise
+                       del e
+                       raise PermissionDenied(mypath)
+               ftype = []
+               for x in list:
+                       try:
+                               if followSymlinks:
+                                       pathstat = os.stat(mypath+"/"+x)
+                               else:
+                                       pathstat = os.lstat(mypath+"/"+x)
+
+                               if stat.S_ISREG(pathstat[stat.ST_MODE]):
+                                       ftype.append(0)
+                               elif stat.S_ISDIR(pathstat[stat.ST_MODE]):
+                                       ftype.append(1)
+                               elif stat.S_ISLNK(pathstat[stat.ST_MODE]):
+                                       ftype.append(2)
+                               else:
+                                       ftype.append(3)
+                       except (IOError, OSError):
+                               ftype.append(3)
+               dircache[mypath] = mtime, list, ftype
+
+       ret_list = []
+       ret_ftype = []
+       for x in range(0, len(list)):
+               if list[x] in ignorelist:
+                       pass
+               elif ignorecvs:
+                       if list[x][:2] != ".#":
+                               ret_list.append(list[x])
+                               ret_ftype.append(ftype[x])
+               else:
+                       ret_list.append(list[x])
+                       ret_ftype.append(ftype[x])
+
+       writemsg("cacheddirStats: H:%d/M:%d/S:%d\n" % (cacheHit, cacheMiss, cacheStale),10)
+       return ret_list, ret_ftype
+
+_ignorecvs_dirs = ('CVS', 'SCCS', '.svn', '.git')
+
+def listdir(mypath, recursive=False, filesonly=False, ignorecvs=False, ignorelist=[], followSymlinks=True,
+       EmptyOnError=False, dirsonly=False):
+       """
+       Portage-specific implementation of os.listdir
+
+       @param mypath: Path whose contents you wish to list
+       @type mypath: String
+       @param recursive: Recursively scan directories contained within mypath
+       @type recursive: Boolean
+       @param filesonly; Only return files, not more directories
+       @type filesonly: Boolean
+       @param ignorecvs: Ignore CVS directories ('CVS','SCCS','.svn','.git')
+       @type ignorecvs: Boolean
+       @param ignorelist: List of filenames/directories to exclude
+       @type ignorelist: List
+       @param followSymlinks: Follow Symlink'd files and directories
+       @type followSymlinks: Boolean
+       @param EmptyOnError: Return [] if an error occurs (deprecated, always True)
+       @type EmptyOnError: Boolean
+       @param dirsonly: Only return directories.
+       @type dirsonly: Boolean
+       @rtype: List
+       @returns: A list of files and directories (or just files or just directories) or an empty list.
+       """
+
+       list, ftype = cacheddir(mypath, ignorecvs, ignorelist, EmptyOnError, followSymlinks)
+
+       if list is None:
+               list=[]
+       if ftype is None:
+               ftype=[]
+
+       if not (filesonly or dirsonly or recursive):
+               return list
+
+       if recursive:
+               x=0
+               while x<len(ftype):
+                       if ftype[x] == 1 and not \
+                               (ignorecvs and os.path.basename(list[x]) in _ignorecvs_dirs):
+                               l,f = cacheddir(mypath+"/"+list[x], ignorecvs, ignorelist, EmptyOnError,
+                                       followSymlinks)
+
+                               l=l[:]
+                               for y in range(0,len(l)):
+                                       l[y]=list[x]+"/"+l[y]
+                               list=list+l
+                               ftype=ftype+f
+                       x+=1
+       if filesonly:
+               rlist=[]
+               for x in range(0,len(ftype)):
+                       if ftype[x]==0:
+                               rlist=rlist+[list[x]]
+       elif dirsonly:
+               rlist = []
+               for x in range(0, len(ftype)):
+                       if ftype[x] == 1:
+                               rlist = rlist + [list[x]]       
+       else:
+               rlist=list
+
+       return rlist