def _rmtree_unsafe(path, onerror): try: if testos.path.islink(path): # symlinks to directories are forbidden, see bug #1669 raise OSError("Cannot call rmtree on a symbolic link") except OSError: onerror(testos.path.islink, path, sys.exc_info()) # can't continue even if onerror hook returns return names = [] try: names = testos.listdir(path) except OSError: onerror(testos.listdir, path, sys.exc_info()) for name in names: fullname = testos.path.join(path, name) try: mode = testos.lstat(fullname).st_mode except OSError: mode = 0 if stat.S_ISDIR(mode): _rmtree_unsafe(fullname, onerror) else: try: testos.unlink(fullname) except OSError: onerror(testos.unlink, fullname, sys.exc_info()) try: testos.rmdir(path) except OSError: onerror(testos.rmdir, path, sys.exc_info())
def release(self): if not self.is_locked(): raise NotLocked("%s is not locked" % self.path) elif not testos.path.exists(self.unique_name): raise NotMyLock("%s is locked, but not by me" % self.path) testos.unlink(self.unique_name) testos.rmdir(self.lock_file)
def rmtree(path, ignore_errors=False, onerror=None): """Recursively delete a directory tree. If ignore_errors is set, errors are ignored; otherwise, if onerror is set, it is called to handle the error with arguments (func, path, exc_info) where func is platform and implementation dependent; path is the argument to that function that caused it to fail; and exc_info is a tuple returned by sys.exc_info(). If ignore_errors is false and onerror is None, an exception is raised. """ if ignore_errors: def onerror(*args): pass elif onerror is None: def onerror(*args): raise if _use_fd_functions: # While the unsafe rmtree works fine on bytes, the fd based does not. if isinstance(path, bytes): path = testos.fsdecode(path) # Note: To guard against symlink races, we use the standard # lstat()/open()/fstat() trick. try: orig_st = testos.lstat(path) except Exception: onerror(testos.lstat, path, sys.exc_info()) return try: fd = testos.open(path, testos.O_RDONLY) except Exception: onerror(testos.lstat, path, sys.exc_info()) return try: if testos.path.samestat(orig_st, testos.fstat(fd)): _rmtree_safe_fd(fd, path, onerror) try: testos.rmdir(path) except OSError: onerror(testos.rmdir, path, sys.exc_info()) else: try: # symlinks to directories are forbidden, see bug #1669 raise OSError("Cannot call rmtree on a symbolic link") except OSError: onerror(testos.path.islink, path, sys.exc_info()) finally: testos.close(fd) else: return _rmtree_unsafe(path, onerror)
def rmtree(path, ignore_errors=False, onerror=None): """Recursively delete a directory tree. If ignore_errors is set, errors are ignored; otherwise, if onerror is set, it is called to handle the error with arguments (func, path, exc_info) where func is os.listdir, os.remove, or os.rmdir; path is the argument to that function that caused it to fail; and exc_info is a tuple returned by sys.exc_info(). If ignore_errors is false and onerror is None, an exception is raised. """ if ignore_errors: def onerror(*args): pass elif onerror is None: def onerror(*args): raise try: if testos.path.islink(path): # symlinks to directories are forbidden, see bug #1669 raise OSError("Cannot call rmtree on a symbolic link") except OSError: onerror(testos.path.islink, path, sys.exc_info()) # can't continue even if onerror hook returns return names = [] try: names = testos.listdir(path) except testos.error: onerror(testos.listdir, path, sys.exc_info()) for name in names: fullname = testos.path.join(path, name) try: mode = testos.lstat(fullname).st_mode except testos.error: mode = 0 if stat.S_ISDIR(mode): rmtree(fullname, ignore_errors, onerror) else: try: testos.remove(fullname) except testos.error: onerror(testos.remove, fullname, sys.exc_info()) try: testos.rmdir(path) except testos.error: onerror(testos.rmdir, path, sys.exc_info())
def _rmtree_safe_fd(topfd, path, onerror): names = [] try: names = testos.listdir(topfd) except OSError as err: err.filename = path onerror(testos.listdir, path, sys.exc_info()) for name in names: fullname = testos.path.join(path, name) try: orig_st = testos.stat(name, dir_fd=topfd, follow_symlinks=False) mode = orig_st.st_mode except OSError: mode = 0 if stat.S_ISDIR(mode): try: dirfd = testos.open(name, testos.O_RDONLY, dir_fd=topfd) except OSError: onerror(testos.open, fullname, sys.exc_info()) else: try: if testos.path.samestat(orig_st, testos.fstat(dirfd)): _rmtree_safe_fd(dirfd, fullname, onerror) try: testos.rmdir(name, dir_fd=topfd) except OSError: onerror(testos.rmdir, fullname, sys.exc_info()) else: try: # This can only happen if someone replaces # a directory with a symlink after the call to # stat.S_ISDIR above. raise OSError("Cannot call rmtree on a symbolic " "link") except OSError: onerror(testos.path.islink, fullname, sys.exc_info()) finally: testos.close(dirfd) else: try: testos.unlink(name, dir_fd=topfd) except OSError: onerror(testos.unlink, fullname, sys.exc_info())
def unpack(src_dir, dst_dir): '''Move everything under `src_dir` to `dst_dir`, and delete the former.''' for dirpath, dirnames, filenames in testos.walk(src_dir): subdir = testos.path.relpath(dirpath, src_dir) for f in filenames: src = testos.path.join(dirpath, f) dst = testos.path.join(dst_dir, subdir, f) testos.renames(src, dst) for n, d in reversed(list(enumerate(dirnames))): src = testos.path.join(dirpath, d) dst = testos.path.join(dst_dir, subdir, d) if not testos.path.exists(dst): # Directory does not exist in destination, # rename it and prune it from os.walk list. testos.renames(src, dst) del dirnames[n] # Cleanup. for dirpath, dirnames, filenames in testos.walk(src_dir, topdown=True): assert not filenames testos.rmdir(dirpath)
def install_as_egg(self, destination_eggdir): '''Install wheel as an egg directory.''' with zipfile.ZipFile(self.filename) as zf: dist_basename = '%s-%s' % (self.project_name, self.version) dist_info = '%s.dist-info' % dist_basename dist_data = '%s.data' % dist_basename def get_metadata(name): with zf.open('%s/%s' % (dist_info, name)) as fp: value = fp.read().decode('utf-8') if PY3 else fp.read() return email.parser.Parser().parsestr(value) wheel_metadata = get_metadata('WHEEL') dist_metadata = get_metadata('METADATA') # Check wheel format version is supported. wheel_version = parse_version(wheel_metadata.get('Wheel-Version')) if not parse_version('1.0') <= wheel_version < parse_version('2.0dev0'): raise ValueError('unsupported wheel format version: %s' % wheel_version) # Extract to target directory. testos.mkdir(destination_eggdir) zf.extractall(destination_eggdir) # Convert metadata. dist_info = testos.path.join(destination_eggdir, dist_info) dist = Distribution.from_location( destination_eggdir, dist_info, metadata=PathMetadata(destination_eggdir, dist_info) ) # Note: we need to evaluate and strip markers now, # as we can't easily convert back from the syntax: # foobar; "linux" in sys_platform and extra == 'test' def raw_req(req): req.marker = None return str(req) install_requires = list(sorted(map(raw_req, dist.requires()))) extras_require = { extra: list(sorted( req for req in map(raw_req, dist.requires((extra,))) if req not in install_requires )) for extra in dist.extras } egg_info = testos.path.join(destination_eggdir, 'EGG-INFO') testos.rename(dist_info, egg_info) testos.rename(testos.path.join(egg_info, 'METADATA'), testos.path.join(egg_info, 'PKG-INFO')) setup_dist = SetuptoolsDistribution(attrs=dict( install_requires=install_requires, extras_require=extras_require, )) write_requirements(setup_dist.get_command_obj('egg_info'), None, testos.path.join(egg_info, 'requires.txt')) # Move data entries to their correct location. dist_data = testos.path.join(destination_eggdir, dist_data) dist_data_scripts = testos.path.join(dist_data, 'scripts') if testos.path.exists(dist_data_scripts): egg_info_scripts = testos.path.join(destination_eggdir, 'EGG-INFO', 'scripts') testos.mkdir(egg_info_scripts) for entry in testos.listdir(dist_data_scripts): # Remove bytecode, as it's not properly handled # during easy_install scripts install phase. if entry.endswith('.pyc'): testos.unlink(testos.path.join(dist_data_scripts, entry)) else: testos.rename(testos.path.join(dist_data_scripts, entry), testos.path.join(egg_info_scripts, entry)) testos.rmdir(dist_data_scripts) for subdir in filter(testos.path.exists, ( testos.path.join(dist_data, d) for d in ('data', 'headers', 'purelib', 'platlib') )): unpack(subdir, destination_eggdir) if testos.path.exists(dist_data): testos.rmdir(dist_data) # Fix namespace packages. namespace_packages = testos.path.join(egg_info, 'namespace_packages.txt') if testos.path.exists(namespace_packages): with open(namespace_packages) as fp: namespace_packages = fp.read().split() for mod in namespace_packages: mod_dir = testos.path.join(destination_eggdir, *mod.split('.')) mod_init = testos.path.join(mod_dir, '__init__.py') if testos.path.exists(mod_dir) and not testos.path.exists(mod_init): with open(mod_init, 'w') as fp: fp.write(NAMESPACE_PACKAGE_INIT)
def break_lock(self): if testos.path.exists(self.lock_file): for name in testos.listdir(self.lock_file): testos.unlink(testos.path.join(self.lock_file, name)) testos.rmdir(self.lock_file)