| # Copyright 2010-2013 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| __all__ = ['cacheddir', 'listdir'] |
| |
| import errno |
| import stat |
| import sys |
| |
| if sys.hexversion < 0x3000000: |
| from itertools import izip as zip |
| |
| from portage import os |
| from portage.const import VCS_DIRS |
| from portage.exception import DirectoryNotFound, PermissionDenied, PortageException |
| from portage.util import normalize_path |
| |
| # The global dircache is no longer supported, since it could |
| # be a memory leak for API consumers. Any cacheddir callers |
| # should use higher-level caches instead, when necessary. |
| # TODO: Remove dircache variable after stable portage does |
| # not use is (keep it for now, in case API consumers clear |
| # it manually). |
| dircache = {} |
| |
| def cacheddir(my_original_path, ignorecvs, ignorelist, EmptyOnError, followSymlinks=True): |
| mypath = normalize_path(my_original_path) |
| try: |
| pathstat = os.stat(mypath) |
| if not stat.S_ISDIR(pathstat.st_mode): |
| raise DirectoryNotFound(mypath) |
| except EnvironmentError as e: |
| if e.errno == PermissionDenied.errno: |
| raise PermissionDenied(mypath) |
| del e |
| return [], [] |
| except PortageException: |
| return [], [] |
| else: |
| try: |
| fpaths = os.listdir(mypath) |
| except EnvironmentError as e: |
| if e.errno != errno.EACCES: |
| raise |
| del e |
| raise PermissionDenied(mypath) |
| ftype = [] |
| for x in fpaths: |
| 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) |
| |
| if ignorelist or ignorecvs: |
| ret_list = [] |
| ret_ftype = [] |
| for file_path, file_type in zip(fpaths, ftype): |
| if file_path in ignorelist: |
| pass |
| elif ignorecvs: |
| if file_path[:2] != ".#" and \ |
| not (file_type == 1 and file_path in VCS_DIRS): |
| ret_list.append(file_path) |
| ret_ftype.append(file_type) |
| else: |
| ret_list = fpaths |
| ret_ftype = ftype |
| |
| return ret_list, ret_ftype |
| |
| 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 VCS directories |
| @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 |
| @return: A list of files and directories (or just files or just directories) or an empty list. |
| """ |
| |
| fpaths, ftype = cacheddir(mypath, ignorecvs, ignorelist, EmptyOnError, followSymlinks) |
| |
| if fpaths is None: |
| fpaths = [] |
| if ftype is None: |
| ftype = [] |
| |
| if not (filesonly or dirsonly or recursive): |
| return fpaths |
| |
| if recursive: |
| stack = list(zip(fpaths, ftype)) |
| fpaths = [] |
| ftype = [] |
| while stack: |
| file_path, file_type = stack.pop() |
| fpaths.append(file_path) |
| ftype.append(file_type) |
| if file_type == 1: |
| subdir_list, subdir_types = cacheddir( |
| os.path.join(mypath, file_path), ignorecvs, |
| ignorelist, EmptyOnError, followSymlinks) |
| stack.extend((os.path.join(file_path, x), x_type) |
| for x, x_type in zip(subdir_list, subdir_types)) |
| |
| if filesonly: |
| fpaths = [x for x, x_type in zip(fpaths, ftype) if x_type == 0] |
| |
| elif dirsonly: |
| fpaths = [x for x, x_type in zip(fpaths, ftype) if x_type == 1] |
| |
| return fpaths |