""" Get directory listing for various Internet protocols. XXX This submodule is still experimental. Copyright (c) 2001-2002, eGenix.com Software GmbH; mailto:info@egenix.com See the documentation for further information on copyrights, or contact the author. All Rights Reserved. """ # Python imports: import urllib, ftplib, os, stat, exceptions import posixpath # Package local imports: import URL ### FTP scheme def ftp_listdir(ftp, url): path = url.path or '/' listing = ftp.nlst(path) files = [] dirs = [] for filename in listing: try: size = ftp.size(filename) except (ftplib.error_perm, ftplib.error_temp): size = -1 if size >= 0: files.append(url + filename) else: dirs.append(url + filename) return dirs, files # Cache for better performance _ftp_cache = {} _max_ftp_cache_size = 5 def ftp_open(url): connection = (url.host, url.port or ftplib.FTP_PORT, url.user, url.passwd) ftp = _ftp_cache.get(connection, None) if ftp is not None: if ftp._in_use: # Open a new connection ftp = None else: # Check the connection try: ftp.voidcmd('TYPE A') except ftplib.all_errors: ftp = None if ftp is None: ftp = ftplib.FTP() ftp.connect(url.host, url.port or ftplib.FTP_PORT) if url.user: ftp.login(url.user, url.passwd) else: # Anonymous ftp.login('anonymous', 'anonymous@internet.domain') # Manage the FTP cache if len(_ftp_cache) >= _max_ftp_cache_size: for k,v in _ftp_cache.items(): if not v._in_use: del _ftp_cache[k] if len(_ftp_cache) >= _max_ftp_cache_size: _ftp_cache.clear() # Note that we only store one FTP object per connection; this may # overwrite a previously cached version, which will then get # garbage collected after having finished _ftp_cache[connection] = ftp ftp._in_use = 1 return ftp def ftp_close(ftp): ftp._in_use = 0 # Leave in cache for subsequent usage; timeouts are handled in ftp_open() ### File scheme def file_listdir(url): path = url.path or '.' if os.path.isfile(path): return [], [path] listing = os.listdir(path) files = [] dirs = [] for filename in listing: if os.path.isdir(filename): dirs.append(url + filename) elif os.path.isfile(filename): files.append(url + filename) return dirs, files ### Generic API def list(url): """ Returns a tuple (directories, files) providing a list of directory and file URLs which can be found at the given URL. The directory and file names are made absolute to URL's network location. Supported schemes are '' (no scheme = local file), 'file' and 'ftp'. """ url = URL.URL(url) scheme = url.scheme if scheme == 'ftp': ftp = ftp_open(url) try: values = ftp_listdir(ftp, url) finally: ftp_close(ftp) return values elif scheme == 'file' or scheme == '': return file_listdir(url) else: raise ValueError, 'unsupported scheme "%s"' % scheme