support glob for vfs

This commit is contained in:
David Rose 2010-02-24 01:58:36 +00:00
parent a252c1010d
commit 3cf40a0a28
3 changed files with 122 additions and 5 deletions

View File

@ -35,7 +35,7 @@ else:
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, unloadPrcFile, getModelPath, Thread, WindowProperties, ExecutionEnvironment, PandaSystem, Notify, StreamWriter, ConfigVariableString, initAppForGui
from pandac import PandaModules
from direct.stdpy import file
from direct.stdpy import file, glob
from direct.task.TaskManagerGlobal import taskMgr
from direct.showbase.MessengerGlobal import messenger
from direct.showbase import AppRunnerGlobal
@ -406,7 +406,7 @@ class AppRunner(DirectObject):
exception handler. This is generally the program's main loop
when running in a p3d environment (except on unusual platforms
like the iPhone, which have to hand the main loop off to the
OS, and don't use this interface. """
OS, and don't use this interface). """
try:
taskMgr.run()
@ -478,7 +478,7 @@ class AppRunner(DirectObject):
# Hang a hook so we know when the window is actually opened.
self.acceptOnce('window-event', self.__windowEvent)
# Look for the startup Python file. This may be a magic
# Look for the startup Python file. This might be a magic
# filename (like "__main__", or any filename that contains
# invalid module characters), so we can't just import it
# directly; instead, we go through the low-level importer.
@ -958,10 +958,19 @@ def dummyAppRunner(tokens = [], argv = None):
appRunner.initPackedAppEnvironment()
# Replace some of the standard Python I/O functions with the Panda
# variants that are specially crafted to respect the vfs.
__builtin__.file = file.file
__builtin__.open = file.open
os.listdir = file.listdir
os.walk = file.walk
os.path.isfile = file.isfile
os.path.isdir = file.isdir
os.path.exists = file.exists
os.path.lexists = file.lexists
os.path.getmtime = file.getmtime
os.path.getsize = file.getsize
sys.modules['glob'] = glob
return appRunner

View File

@ -5,7 +5,8 @@ SIMPLE_THREADS model, by avoiding blocking all threads while waiting
for I/O to complete. """
__all__ = [
'file', 'open', 'listdir', 'walk', 'join'
'file', 'open', 'listdir', 'walk', 'join',
'isfile', 'isdir', 'exists', 'lexists', 'getmtime', 'getsize',
]
from pandac import PandaModules as pm
@ -286,3 +287,28 @@ def walk(top, topdown = True, onerror = None, followlinks = True):
def join(a, b):
return '%s/%s' % (a, b)
def isfile(path):
return _vfs.isRegularFile(pm.Filename.fromOsSpecific(path))
def isdir(path):
return _vfs.isDirectory(pm.Filename.fromOsSpecific(path))
def exists(path):
return _vfs.exists(pm.Filename.fromOsSpecific(path))
def lexists(path):
return _vfs.exists(pm.Filename.fromOsSpecific(path))
def getmtime(path):
file = _vfs.getFile(pm.Filename.fromOsSpecific(path), True)
if not file:
raise os.error
return file.getTimestamp()
def getsize(path):
file = _vfs.getFile(pm.Filename.fromOsSpecific(path), True)
if not file:
raise os.error
return file.getFileSize()

82
direct/src/stdpy/glob.py Executable file
View File

@ -0,0 +1,82 @@
""" This module reimplements Python's native glob module using Panda
vfs constructs. This enables Python to interface more easily with Panda's
virtual file system. """
import sys
import os
import re
import fnmatch
from direct.stdpy import file
__all__ = ["glob", "iglob"]
def glob(pathname):
"""Return a list of paths matching a pathname pattern.
The pattern may contain simple shell-style wildcards a la fnmatch.
"""
return list(iglob(pathname))
def iglob(pathname):
"""Return an iterator which yields the paths matching a pathname pattern.
The pattern may contain simple shell-style wildcards a la fnmatch.
"""
if not has_magic(pathname):
if file.lexists(pathname):
yield pathname
return
dirname, basename = os.path.split(pathname)
if not dirname:
for name in glob1(os.curdir, basename):
yield name
return
if has_magic(dirname):
dirs = iglob(dirname)
else:
dirs = [dirname]
if has_magic(basename):
glob_in_dir = glob1
else:
glob_in_dir = glob0
for dirname in dirs:
for name in glob_in_dir(dirname, basename):
yield os.path.join(dirname, name)
# These 2 helper functions non-recursively glob inside a literal directory.
# They return a list of basenames. `glob1` accepts a pattern while `glob0`
# takes a literal basename (so it only has to check for its existence).
def glob1(dirname, pattern):
if not dirname:
dirname = os.curdir
if isinstance(pattern, unicode) and not isinstance(dirname, unicode):
dirname = unicode(dirname, sys.getfilesystemencoding() or
sys.getdefaultencoding())
try:
names = os.listdir(dirname)
except os.error:
return []
if pattern[0] != '.':
names = filter(lambda x: x[0] != '.', names)
return fnmatch.filter(names, pattern)
def glob0(dirname, basename):
if basename == '':
# `os.path.split()` returns an empty basename for paths ending with a
# directory separator. 'q*x/' should match only directories.
if file.isdir(dirname):
return [basename]
else:
if file.lexists(os.path.join(dirname, basename)):
return [basename]
return []
magic_check = re.compile('[*?[]')
def has_magic(s):
return magic_check.search(s) is not None