[Python-checkins] python/nondist/sandbox/setuptools/setuptools archive_util.py, NONE, 1.1 sandbox.py, NONE, 1.1

pje@users.sourceforge.net pje at users.sourceforge.net
Sun Jun 12 03:12:36 CEST 2005


Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4594/setuptools
Added Files:
	archive_util.py sandbox.py 
Log Message:
Split setup-running and archive-extraction utilities into separate modules,
for easy use by tools other than EasyInstall.
--- NEW FILE: archive_util.py ---
"""Utilities for extracting common archive formats"""
__all__ = [
 "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter",
 "UnrecognizedFormat", "extraction_drivers"
]
import zipfile, tarfile, os
from pkg_resources import ensure_directory
class UnrecognizedFormat(RuntimeError):
 """Couldn't recognize the archive type"""
def default_filter(src,dst):
 """The default progress/filter callback; returns True for all files"""
 
 return True
def unpack_archive(filename, extract_dir, progress_filter=default_filter,
 drivers=None
):
 """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat``
 `progress_filter` is a function taking two arguments: a source path
 internal to the archive ('/'-separated), and a filesystem path where it
 will be extracted. The callback must return a true value, or else that
 file or directory will be skipped. The callback can thus be used to
 report on the progress of the extraction, as well as to filter the items
 extracted.
 `drivers`, if supplied, must be a non-empty sequence of functions with the
 same signature as this function (minus the `drivers` argument), that raise
 ``UnrecognizedFormat`` if they do not support extracting the designated
 archive type. The `drivers` are tried in sequence until one is found that
 does not raise an error, or until all are exhausted (in which case
 ``UnrecognizedFormat`` is raised). If you do not supply a sequence of
 drivers, the module's ``extraction_drivers`` constant will be used, which
 means that ``unpack_zipfile`` and ``unpack_tarfile`` will be tried, in that
 order.
 """
 for driver in drivers or extraction_drivers:
 try:
 driver(filename, extract_dir, progress_filter)
 except UnrecognizedFormat:
 continue
 else:
 return
 else:
 raise UnrecognizedFormat(
 "Not a recognized archive type: %s" % filename
 )
def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
 """Unpack zip `filename` to `extract_dir`
 Raises ``UnrecognizedFormat`` if `filename` is not a zipfile (as determined
 by ``zipfile.is_zipfile()``). See ``unpack_archive()`` for an explanation
 of the `progress_filter` argument.
 """
 if not zipfile.is_zipfile(filename):
 raise UnrecognizedFormat("%s is not a zip file" % (filename,))
 z = zipfile.ZipFile(filename)
 try:
 for info in z.infolist():
 name = info.filename
 # don't extract absolute paths or ones with .. in them
 if name.startswith('/') or '..' in name:
 continue
 target = os.path.join(extract_dir,name)
 if not progress_filter(name,target):
 continue
 if name.endswith('/'):
 # directory
 ensure_directory(target)
 else:
 # file
 ensure_directory(target)
 data = z.read(info.filename)
 f = open(target,'wb')
 try:
 f.write(data)
 finally:
 f.close()
 del data
 finally:
 z.close()
def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
 """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir`
 Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined
 by ``tarfile.open()``). See ``unpack_archive()`` for an explanation
 of the `progress_filter` argument.
 """
 try:
 tarobj = tarfile.open(filename)
 except tarfile.TarError:
 raise UnrecognizedFormat(
 "%s is not a compressed or uncompressed tar file" % (filename,)
 )
 try:
 tarobj.chown = lambda *args: None # don't do any chowning!
 for member in tarobj:
 if member.isfile() or member.isdir():
 name = member.name
 # don't extract absolute paths or ones with .. in them
 if not name.startswith('/') and '..' not in name:
 dst = os.path.join(extract_dir, *name.split('/')) 
 if progress_filter(name, dst):
 tarobj.extract(member,extract_dir)
 return True
 finally:
 tarobj.close()
extraction_drivers = unpack_zipfile, unpack_tarfile
--- NEW FILE: sandbox.py ---
import os, sys, __builtin__
_os = sys.modules[os.name]
_open = open
__all__ = [
 "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup",
]
def run_setup(setup_script, *args):
 """Run a distutils setup script, sandboxed in its directory"""
 old_dir = os.getcwd()
 save_argv = sys.argv[:]
 save_path = sys.path[:]
 setup_dir = os.path.abspath(os.path.dirname(setup_script))
 try:
 os.chdir(setup_dir)
 try:
 sys.argv[:] = [setup_script]+list(args)
 sys.path.insert(0, setup_dir)
 DirectorySandbox(setup_dir).run(
 lambda: execfile(
 "setup.py",
 {'__file__':setup_script, '__name__':'__main__'}
 )
 )
 except SystemExit, v:
 if v.args and v.args[0]:
 raise
 # Normal exit, just return
 finally:
 os.chdir(old_dir)
 sys.path[:] = save_path
 sys.argv[:] = save_argv
class AbstractSandbox:
 """Wrap 'os' module and 'open()' builtin for virtualizing setup scripts"""
 _active = False
 def __init__(self):
 self._attrs = [
 name for name in dir(_os)
 if not name.startswith('_') and hasattr(self,name)
 ]
 def _copy(self, source):
 for name in self._attrs:
 setattr(os, name, getattr(source,name))
 def run(self, func):
 """Run 'func' under os sandboxing"""
 try:
 self._copy(self)
 __builtin__.open = __builtin__.file = self._open
 self._active = True
 return func()
 finally:
 self._active = False
 __builtin__.open = __builtin__.file = _open
 self._copy(_os)
 def _mk_dual_path_wrapper(name):
 original = getattr(_os,name)
 def wrap(self,src,dst,*args,**kw):
 if self._active:
 src,dst = self._remap_pair(name,src,dst,*args,**kw)
 return original(src,dst,*args,**kw)
 return wrap
 for name in ["rename", "link", "symlink"]:
 if hasattr(_os,name): locals()[name] = _mk_dual_path_wrapper(name)
 def _mk_single_path_wrapper(name, original=None):
 original = original or getattr(_os,name)
 def wrap(self,path,*args,**kw):
 if self._active:
 path = self._remap_input(name,path,*args,**kw)
 return original(path,*args,**kw)
 return wrap
 _open = _mk_single_path_wrapper('file', _open)
 for name in [
 "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir",
 "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat",
 "startfile", "mkfifo", "mknod", "pathconf", "access"
 ]:
 if hasattr(_os,name): locals()[name] = _mk_single_path_wrapper(name)
 def _mk_single_with_return(name):
 original = getattr(_os,name)
 def wrap(self,path,*args,**kw):
 if self._active:
 path = self._remap_input(name,path,*args,**kw)
 return self._remap_output(name, original(path,*args,**kw))
 return original(path,*args,**kw)
 return wrap
 for name in ['readlink', 'tempnam']:
 if hasattr(_os,name): locals()[name] = _mk_single_with_return(name)
 def _mk_query(name):
 original = getattr(_os,name)
 def wrap(self,*args,**kw):
 retval = original(*args,**kw)
 if self._active:
 return self._remap_output(name, retval)
 return retval
 return wrap
 for name in ['getcwd', 'tmpnam']:
 if hasattr(_os,name): locals()[name] = _mk_query(name)
 def _validate_path(self,path):
 """Called to remap or validate any path, whether input or output"""
 return path
 def _remap_input(self,operation,path,*args,**kw):
 """Called for path inputs"""
 return self._validate_path(path)
 def _remap_output(self,operation,path):
 """Called for path outputs"""
 return self._validate_path(path)
 def _remap_pair(self,operation,src,dst,*args,**kw):
 """Called for path pairs like rename, link, and symlink operations"""
 return (
 self._remap_input(operation+'-from',src,*args,**kw),
 self._remap_input(operation+'-to',dst,*args,**kw)
 )
class DirectorySandbox(AbstractSandbox):
 """Restrict operations to a single subdirectory - pseudo-chroot"""
 write_ops = dict.fromkeys([
 "open", "chmod", "chown", "mkdir", "remove", "unlink", "rmdir",
 "utime", "lchown", "chroot", "mkfifo", "mknod", "tempnam",
 ])
 def __init__(self,sandbox):
 self._sandbox = os.path.realpath(sandbox)
 self._prefix = os.path.join(self._sandbox,'')
 AbstractSandbox.__init__(self)
 def _violation(self, operation, *args, **kw):
 raise SandboxViolation(operation, args, kw)
 def _open(self, path, mode='r', *args, **kw):
 if mode not in ('r', 'rt', 'rb', 'rU') and not self._ok(path):
 self._violation("open", path, mode, *args, **kw)
 return _open(path,mode,*args,**kw)
 def tmpnam(self):
 self._violation("tmpnam")
 def _ok(self,path):
 active = self._active
 try:
 self._active = False
 realpath = os.path.realpath(path)
 if realpath==self._sandbox or realpath.startswith(self._prefix):
 return True
 finally:
 self._active = active
 def _remap_input(self,operation,path,*args,**kw):
 """Called for path inputs"""
 if operation in self.write_ops and not self._ok(path):
 self._violation(operation, os.path.realpath(path), *args, **kw)
 return path
 def _remap_pair(self,operation,src,dst,*args,**kw):
 """Called for path pairs like rename, link, and symlink operations"""
 if not self._ok(src) or not self._ok(dst):
 self._violation(operation, src, dst, *args, **kw)
 return (src,dst)
class SandboxViolation(RuntimeError):
 """A setup script attempted to modify the filesystem outside the sandbox"""
 def __str__(self):
 return """SandboxViolation: %s%r %s
The package setup script has attempted to modify files on your system
that are not within the EasyInstall build area, and has been aborted.
This package cannot be safely installed by EasyInstall, and may not
support alternate installation locations even if you run its setup
script by hand. Please inform the package's author and the EasyInstall
maintainers to find out if a fix or workaround is available.""" % self.args


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /