blob: 2012e145f107aca5fec8eceec31b1cb07c78137e [file] [log] [blame]
# 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