summaryrefslogtreecommitdiff
path: root/lib/spack/llnl/util/filesystem.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/llnl/util/filesystem.py')
-rw-r--r--lib/spack/llnl/util/filesystem.py444
1 files changed, 225 insertions, 219 deletions
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py
index 185f45d131..1740fb71c0 100644
--- a/lib/spack/llnl/util/filesystem.py
+++ b/lib/spack/llnl/util/filesystem.py
@@ -27,7 +27,7 @@ from llnl.util.symlink import symlink
from spack.util.executable import Executable
from spack.util.path import path_to_os_path, system_path_filter
-is_windows = _platform == 'win32'
+is_windows = _platform == "win32"
if not is_windows:
import grp
@@ -37,56 +37,57 @@ else:
__all__ = [
- 'FileFilter',
- 'FileList',
- 'HeaderList',
- 'LibraryList',
- 'ancestor',
- 'can_access',
- 'change_sed_delimiter',
- 'copy_mode',
- 'filter_file',
- 'find',
- 'find_headers',
- 'find_all_headers',
- 'find_libraries',
- 'find_system_libraries',
- 'fix_darwin_install_name',
- 'force_remove',
- 'force_symlink',
- 'getuid',
- 'chgrp',
- 'chmod_x',
- 'copy',
- 'install',
- 'copy_tree',
- 'install_tree',
- 'is_exe',
- 'join_path',
- 'last_modification_time_recursive',
- 'library_extensions',
- 'mkdirp',
- 'partition_path',
- 'prefixes',
- 'remove_dead_links',
- 'remove_directory_contents',
- 'remove_if_dead_link',
- 'remove_linked_tree',
- 'rename',
- 'set_executable',
- 'set_install_permissions',
- 'touch',
- 'touchp',
- 'traverse_tree',
- 'unset_executable_mode',
- 'working_dir',
- 'keep_modification_time'
+ "FileFilter",
+ "FileList",
+ "HeaderList",
+ "LibraryList",
+ "ancestor",
+ "can_access",
+ "change_sed_delimiter",
+ "copy_mode",
+ "filter_file",
+ "find",
+ "find_headers",
+ "find_all_headers",
+ "find_libraries",
+ "find_system_libraries",
+ "fix_darwin_install_name",
+ "force_remove",
+ "force_symlink",
+ "getuid",
+ "chgrp",
+ "chmod_x",
+ "copy",
+ "install",
+ "copy_tree",
+ "install_tree",
+ "is_exe",
+ "join_path",
+ "last_modification_time_recursive",
+ "library_extensions",
+ "mkdirp",
+ "partition_path",
+ "prefixes",
+ "remove_dead_links",
+ "remove_directory_contents",
+ "remove_if_dead_link",
+ "remove_linked_tree",
+ "rename",
+ "set_executable",
+ "set_install_permissions",
+ "touch",
+ "touchp",
+ "traverse_tree",
+ "unset_executable_mode",
+ "working_dir",
+ "keep_modification_time",
]
def getuid():
if is_windows:
import ctypes
+
if ctypes.windll.shell32.IsUserAnAdmin() == 0:
return 1
return 0
@@ -111,7 +112,7 @@ def path_contains_subdirectory(path, root):
#: This generates the library filenames that may appear on any OS.
-library_extensions = ['a', 'la', 'so', 'tbd', 'dylib']
+library_extensions = ["a", "la", "so", "tbd", "dylib"]
def possible_library_filenames(library_names):
@@ -120,8 +121,9 @@ def possible_library_filenames(library_names):
"""
lib_extensions = library_extensions
return set(
- '.'.join((lib, extension)) for lib, extension in
- itertools.product(library_names, lib_extensions))
+ ".".join((lib, extension))
+ for lib, extension in itertools.product(library_names, lib_extensions)
+ )
def paths_containing_libs(paths, library_names):
@@ -174,19 +176,21 @@ def filter_file(regex, repl, *filenames, **kwargs):
file is copied verbatim. Default is to filter until the end of the
file.
"""
- string = kwargs.get('string', False)
- backup = kwargs.get('backup', False)
- ignore_absent = kwargs.get('ignore_absent', False)
- stop_at = kwargs.get('stop_at', None)
+ string = kwargs.get("string", False)
+ backup = kwargs.get("backup", False)
+ ignore_absent = kwargs.get("ignore_absent", False)
+ stop_at = kwargs.get("stop_at", None)
# Allow strings to use \1, \2, etc. for replacement, like sed
if not callable(repl):
- unescaped = repl.replace(r'\\', '\\')
+ unescaped = repl.replace(r"\\", "\\")
def replace_groups_with_groupid(m):
def groupid_to_group(x):
return m.group(int(x.group(1)))
- return re.sub(r'\\([1-9])', groupid_to_group, unescaped)
+
+ return re.sub(r"\\([1-9])", groupid_to_group, unescaped)
+
repl = replace_groups_with_groupid
if string:
@@ -217,16 +221,16 @@ def filter_file(regex, repl, *filenames, **kwargs):
try:
extra_kwargs = {}
if sys.version_info > (3, 0):
- extra_kwargs = {'errors': 'surrogateescape'}
+ extra_kwargs = {"errors": "surrogateescape"}
# Open as a text file and filter until the end of the file is
# reached or we found a marker in the line if it was specified
- with open(tmp_filename, mode='r', **extra_kwargs) as input_file:
- with open(filename, mode='w', **extra_kwargs) as output_file:
+ with open(tmp_filename, mode="r", **extra_kwargs) as input_file:
+ with open(filename, mode="w", **extra_kwargs) as output_file:
# Using iter and readline is a workaround needed not to
# disable input_file.tell(), which will happen if we call
# input_file.next() implicitly via the for loop
- for line in iter(input_file.readline, ''):
+ for line in iter(input_file.readline, ""):
if stop_at is not None:
current_position = input_file.tell()
if stop_at == line.strip():
@@ -240,9 +244,9 @@ def filter_file(regex, repl, *filenames, **kwargs):
# If we stopped filtering at some point, reopen the file in
# binary mode and copy verbatim the remaining part
if current_position and stop_at:
- with open(tmp_filename, mode='rb') as input_file:
+ with open(tmp_filename, mode="rb") as input_file:
input_file.seek(current_position)
- with open(filename, mode='ab') as output_file:
+ with open(filename, mode="ab") as output_file:
output_file.writelines(input_file.readlines())
except BaseException:
@@ -281,26 +285,26 @@ def change_sed_delimiter(old_delim, new_delim, *filenames):
new_delim (str): The delimiter to replace with
*filenames: One or more files to search and replace
"""
- assert(len(old_delim) == 1)
- assert(len(new_delim) == 1)
+ assert len(old_delim) == 1
+ assert len(new_delim) == 1
# TODO: handle these cases one day?
- assert(old_delim != '"')
- assert(old_delim != "'")
- assert(new_delim != '"')
- assert(new_delim != "'")
+ assert old_delim != '"'
+ assert old_delim != "'"
+ assert new_delim != '"'
+ assert new_delim != "'"
whole_lines = "^s@([^@]*)@(.*)@[gIp]$"
- whole_lines = whole_lines.replace('@', old_delim)
+ whole_lines = whole_lines.replace("@", old_delim)
single_quoted = r"'s@((?:\\'|[^@'])*)@((?:\\'|[^'])*)@[gIp]?'"
- single_quoted = single_quoted.replace('@', old_delim)
+ single_quoted = single_quoted.replace("@", old_delim)
double_quoted = r'"s@((?:\\"|[^@"])*)@((?:\\"|[^"])*)@[gIp]?"'
- double_quoted = double_quoted.replace('@', old_delim)
+ double_quoted = double_quoted.replace("@", old_delim)
- repl = r's@\1@\2@g'
- repl = repl.replace('@', new_delim)
+ repl = r"s@\1@\2@g"
+ repl = repl.replace("@", new_delim)
filenames = path_to_os_path(*filenames)
for f in filenames:
filter_file(whole_lines, repl, f)
@@ -324,8 +328,7 @@ def exploding_archive_catch(stage):
# Expand all tarballs in their own directory to contain
# exploding tarballs.
- tarball_container = os.path.join(stage.path,
- "spack-expanded-archive")
+ tarball_container = os.path.join(stage.path, "spack-expanded-archive")
mkdirp(tarball_container)
orig_dir = os.getcwd()
os.chdir(tarball_container)
@@ -349,7 +352,7 @@ def exploding_archive_handler(tarball_container, stage):
where archive is being expanded
"""
files = os.listdir(tarball_container)
- non_hidden = [f for f in files if not f.startswith('.')]
+ non_hidden = [f for f in files if not f.startswith(".")]
if len(non_hidden) == 1:
src = os.path.join(tarball_container, non_hidden[0])
if os.path.isdir(src):
@@ -377,11 +380,13 @@ def get_owner_uid(path, err_msg=None):
p_stat = os.stat(path)
if p_stat.st_mode & stat.S_IRWXU != stat.S_IRWXU:
- tty.error("Expected {0} to support mode {1}, but it is {2}"
- .format(path, stat.S_IRWXU, p_stat.st_mode))
+ tty.error(
+ "Expected {0} to support mode {1}, but it is {2}".format(
+ path, stat.S_IRWXU, p_stat.st_mode
+ )
+ )
- raise OSError(errno.EACCES,
- err_msg.format(path, path) if err_msg else "")
+ raise OSError(errno.EACCES, err_msg.format(path, path) if err_msg else "")
else:
p_stat = os.stat(path)
@@ -389,8 +394,8 @@ def get_owner_uid(path, err_msg=None):
owner_uid = p_stat.st_uid
else:
sid = win32security.GetFileSecurity(
- path, win32security.OWNER_SECURITY_INFORMATION) \
- .GetSecurityDescriptorOwner()
+ path, win32security.OWNER_SECURITY_INFORMATION
+ ).GetSecurityDescriptorOwner()
owner_uid = win32security.LookupAccountSid(None, sid)[0]
return owner_uid
@@ -460,8 +465,7 @@ def chmod_x(entry, perms):
@system_path_filter
def copy_mode(src, dest):
- """Set the mode of dest to that of src unless it is a link.
- """
+ """Set the mode of dest to that of src unless it is a link."""
if os.path.islink(dest):
return
src_mode = os.stat(src).st_mode
@@ -504,17 +508,17 @@ def copy(src, dest, _permissions=False):
not a directory
"""
if _permissions:
- tty.debug('Installing {0} to {1}'.format(src, dest))
+ tty.debug("Installing {0} to {1}".format(src, dest))
else:
- tty.debug('Copying {0} to {1}'.format(src, dest))
+ tty.debug("Copying {0} to {1}".format(src, dest))
files = glob.glob(src)
if not files:
raise IOError("No such file or directory: '{0}'".format(src))
if len(files) > 1 and not os.path.isdir(dest):
raise ValueError(
- "'{0}' matches multiple files but '{1}' is not a directory".format(
- src, dest))
+ "'{0}' matches multiple files but '{1}' is not a directory".format(src, dest)
+ )
for src in files:
# Expand dest to its eventual full path if it is a directory.
@@ -592,9 +596,9 @@ def copy_tree(src, dest, symlinks=True, ignore=None, _permissions=False):
ValueError: if *src* is a parent directory of *dest*
"""
if _permissions:
- tty.debug('Installing {0} to {1}'.format(src, dest))
+ tty.debug("Installing {0} to {1}".format(src, dest))
else:
- tty.debug('Copying {0} to {1}'.format(src, dest))
+ tty.debug("Copying {0} to {1}".format(src, dest))
abs_dest = os.path.abspath(dest)
if not abs_dest.endswith(os.path.sep):
@@ -612,15 +616,20 @@ def copy_tree(src, dest, symlinks=True, ignore=None, _permissions=False):
# Stop early to avoid unnecessary recursion if being asked to copy
# from a parent directory.
if abs_dest.startswith(abs_src):
- raise ValueError('Cannot copy ancestor directory {0} into {1}'.
- format(abs_src, abs_dest))
+ raise ValueError(
+ "Cannot copy ancestor directory {0} into {1}".format(abs_src, abs_dest)
+ )
mkdirp(abs_dest)
- for s, d in traverse_tree(abs_src, abs_dest, order='pre',
- follow_symlinks=not symlinks,
- ignore=ignore,
- follow_nonexisting=True):
+ for s, d in traverse_tree(
+ abs_src,
+ abs_dest,
+ order="pre",
+ follow_symlinks=not symlinks,
+ ignore=ignore,
+ follow_nonexisting=True,
+ ):
if os.path.islink(s):
link_target = resolve_link_target_relative_to_the_link(s)
if symlinks:
@@ -628,8 +637,7 @@ def copy_tree(src, dest, symlinks=True, ignore=None, _permissions=False):
if os.path.isabs(target):
new_target = re.sub(abs_src, abs_dest, target)
if new_target != target:
- tty.debug("Redirecting link {0} to {1}"
- .format(target, new_target))
+ tty.debug("Redirecting link {0} to {1}".format(target, new_target))
target = new_target
symlink(target, d)
@@ -679,10 +687,9 @@ def get_filetype(path_name):
"""
Return the output of file path_name as a string to identify file type.
"""
- file = Executable('file')
- file.add_default_env('LC_ALL', 'C')
- output = file('-b', '-h', '%s' % path_name,
- output=str, error=str)
+ file = Executable("file")
+ file.add_default_env("LC_ALL", "C")
+ output = file("-b", "-h", "%s" % path_name, output=str, error=str)
return output.strip()
@@ -703,8 +710,8 @@ def is_nonsymlink_exe_with_shebang(path):
return False
# Should start with a shebang
- with open(path, 'rb') as f:
- return f.read(2) == b'#!'
+ with open(path, "rb") as f:
+ return f.read(2) == b"#!"
except (IOError, OSError):
return False
@@ -736,16 +743,16 @@ def mkdirp(*paths, **kwargs):
intermediate get the same permissions specified in the arguments to
mkdirp -- default value is 'args'
"""
- mode = kwargs.get('mode', None)
- group = kwargs.get('group', None)
- default_perms = kwargs.get('default_perms', 'args')
+ mode = kwargs.get("mode", None)
+ group = kwargs.get("group", None)
+ default_perms = kwargs.get("default_perms", "args")
paths = path_to_os_path(*paths)
for path in paths:
if not os.path.exists(path):
try:
# detect missing intermediate folders
intermediate_folders = []
- last_parent = ''
+ last_parent = ""
intermediate_path = os.path.dirname(path)
@@ -772,10 +779,10 @@ def mkdirp(*paths, **kwargs):
# ones and if mode_intermediate has been specified, otherwise
# intermediate folders list is not populated at all and default
# OS mode will be used
- if default_perms == 'args':
+ if default_perms == "args":
intermediate_mode = mode
intermediate_group = group
- elif default_perms == 'parents':
+ elif default_perms == "parents":
stat_info = os.stat(last_parent)
intermediate_mode = stat_info.st_mode
intermediate_group = stat_info.st_gid
@@ -788,10 +795,8 @@ def mkdirp(*paths, **kwargs):
if intermediate_mode is not None:
os.chmod(intermediate_path, intermediate_mode)
if intermediate_group is not None:
- chgrp_if_not_world_writable(intermediate_path,
- intermediate_group)
- os.chmod(intermediate_path,
- intermediate_mode) # reset sticky bit after
+ chgrp_if_not_world_writable(intermediate_path, intermediate_group)
+ os.chmod(intermediate_path, intermediate_mode) # reset sticky bit after
except OSError as e:
if e.errno != errno.EEXIST or not os.path.isdir(path):
@@ -803,7 +808,7 @@ def mkdirp(*paths, **kwargs):
@system_path_filter
def force_remove(*paths):
"""Remove files without printing errors. Like ``rm -f``, does NOT
- remove directories."""
+ remove directories."""
for path in paths:
try:
os.remove(path)
@@ -814,7 +819,7 @@ def force_remove(*paths):
@contextmanager
@system_path_filter
def working_dir(dirname, **kwargs):
- if kwargs.get('create', False):
+ if kwargs.get("create", False):
mkdirp(dirname)
orig_dir = os.getcwd()
@@ -847,19 +852,17 @@ def replace_directory_transaction(directory_name):
# Check the input is indeed a directory with absolute path.
# Raise before anything is done to avoid moving the wrong directory
directory_name = os.path.abspath(directory_name)
- assert os.path.isdir(directory_name), 'Not a directory: ' + directory_name
+ assert os.path.isdir(directory_name), "Not a directory: " + directory_name
# Note: directory_name is normalized here, meaning the trailing slash is dropped,
# so dirname is the directory's parent not the directory itself.
- tmpdir = tempfile.mkdtemp(
- dir=os.path.dirname(directory_name),
- prefix='.backup')
+ tmpdir = tempfile.mkdtemp(dir=os.path.dirname(directory_name), prefix=".backup")
# We have to jump through hoops to support Windows, since
# os.rename(directory_name, tmpdir) errors there.
- backup_dir = os.path.join(tmpdir, 'backup')
+ backup_dir = os.path.join(tmpdir, "backup")
os.rename(directory_name, backup_dir)
- tty.debug('Directory moved [src={0}, dest={1}]'.format(directory_name, backup_dir))
+ tty.debug("Directory moved [src={0}, dest={1}]".format(directory_name, backup_dir))
try:
yield backup_dir
@@ -874,12 +877,12 @@ def replace_directory_transaction(directory_name):
except Exception as outer_exception:
raise CouldNotRestoreDirectoryBackup(inner_exception, outer_exception)
- tty.debug('Directory recovered [{0}]'.format(directory_name))
+ tty.debug("Directory recovered [{0}]".format(directory_name))
raise
else:
# Otherwise delete the temporary directory
shutil.rmtree(tmpdir, ignore_errors=True)
- tty.debug('Temporary directory deleted [{0}]'.format(tmpdir))
+ tty.debug("Temporary directory deleted [{0}]".format(tmpdir))
@system_path_filter
@@ -904,7 +907,7 @@ def hash_directory(directory, ignore=[]):
# TODO: if caching big files becomes an issue, convert this to
# TODO: read in chunks. Currently it's used only for testing
# TODO: purposes.
- with open(filename, 'rb') as f:
+ with open(filename, "rb") as f:
md5_hash.update(f.read())
return md5_hash.hexdigest()
@@ -916,15 +919,15 @@ def write_tmp_and_move(filename):
"""Write to a temporary file, then move into place."""
dirname = os.path.dirname(filename)
basename = os.path.basename(filename)
- tmp = os.path.join(dirname, '.%s.tmp' % basename)
- with open(tmp, 'w') as f:
+ tmp = os.path.join(dirname, ".%s.tmp" % basename)
+ with open(tmp, "w") as f:
yield f
shutil.move(tmp, filename)
@contextmanager
@system_path_filter
-def open_if_filename(str_or_file, mode='r'):
+def open_if_filename(str_or_file, mode="r"):
"""Takes either a path or a file object, and opens it if it is a path.
If it's a file object, just yields the file object.
@@ -940,9 +943,9 @@ def open_if_filename(str_or_file, mode='r'):
def touch(path):
"""Creates an empty file at the specified path."""
if is_windows:
- perms = (os.O_WRONLY | os.O_CREAT)
+ perms = os.O_WRONLY | os.O_CREAT
else:
- perms = (os.O_WRONLY | os.O_CREAT | os.O_NONBLOCK | os.O_NOCTTY)
+ perms = os.O_WRONLY | os.O_CREAT | os.O_NONBLOCK | os.O_NOCTTY
fd = None
try:
fd = os.open(path, perms)
@@ -954,8 +957,7 @@ def touch(path):
@system_path_filter
def touchp(path):
- """Like ``touch``, but creates any parent directories needed for the file.
- """
+ """Like ``touch``, but creates any parent directories needed for the file."""
mkdirp(os.path.dirname(path))
touch(path)
@@ -990,8 +992,7 @@ def ancestor(dir, n=1):
def get_single_file(directory):
fnames = os.listdir(directory)
if len(fnames) != 1:
- raise ValueError("Expected exactly 1 file, got {0}"
- .format(str(len(fnames))))
+ raise ValueError("Expected exactly 1 file, got {0}".format(str(len(fnames))))
return fnames[0]
@@ -1025,7 +1026,7 @@ def can_access(file_name):
@system_path_filter
-def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
+def traverse_tree(source_root, dest_root, rel_path="", **kwargs):
"""Traverse two filesystem trees simultaneously.
Walks the LinkTree directory in pre or post order. Yields each
@@ -1057,16 +1058,16 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
``src`` that do not exit in ``dest``. Default is True
follow_links (bool): Whether to descend into symlinks in ``src``
"""
- follow_nonexisting = kwargs.get('follow_nonexisting', True)
- follow_links = kwargs.get('follow_link', False)
+ follow_nonexisting = kwargs.get("follow_nonexisting", True)
+ follow_links = kwargs.get("follow_link", False)
# Yield in pre or post order?
- order = kwargs.get('order', 'pre')
- if order not in ('pre', 'post'):
+ order = kwargs.get("order", "pre")
+ if order not in ("pre", "post"):
raise ValueError("Order must be 'pre' or 'post'.")
# List of relative paths to ignore under the src root.
- ignore = kwargs.get('ignore', None) or (lambda filename: False)
+ ignore = kwargs.get("ignore", None) or (lambda filename: False)
# Don't descend into ignored directories
if ignore(rel_path):
@@ -1076,7 +1077,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
dest_path = os.path.join(dest_root, rel_path)
# preorder yields directories before children
- if order == 'pre':
+ if order == "pre":
yield (source_path, dest_path)
for f in os.listdir(source_path):
@@ -1088,14 +1089,12 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
# TODO: for symlinks, os.path.isdir looks for the link target. If the
# target is relative to the link, then that may not resolve properly
# relative to our cwd - see resolve_link_target_relative_to_the_link
- if os.path.isdir(source_child) and (
- follow_links or not os.path.islink(source_child)):
+ if os.path.isdir(source_child) and (follow_links or not os.path.islink(source_child)):
# When follow_nonexisting isn't set, don't descend into dirs
# in source that do not exist in dest
if follow_nonexisting or os.path.exists(dest_child):
- tuples = traverse_tree(
- source_root, dest_root, rel_child, **kwargs)
+ tuples = traverse_tree(source_root, dest_root, rel_child, **kwargs)
for t in tuples:
yield t
@@ -1103,7 +1102,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
elif not ignore(os.path.join(rel_path, f)):
yield (source_child, dest_child)
- if order == 'post':
+ if order == "post":
yield (source_path, dest_path)
@@ -1134,7 +1133,7 @@ def lexists_islink_isdir(path):
return True, is_link, is_dir
-def visit_directory_tree(root, visitor, rel_path='', depth=0):
+def visit_directory_tree(root, visitor, rel_path="", depth=0):
"""
Recurses the directory root depth-first through a visitor pattern
@@ -1172,8 +1171,7 @@ def visit_directory_tree(root, visitor, rel_path='', depth=0):
try:
isdir = f.is_dir()
except OSError as e:
- if is_windows and hasattr(e, 'winerror')\
- and e.winerror == 5 and islink:
+ if is_windows and hasattr(e, "winerror") and e.winerror == 5 and islink:
# if path is a symlink, determine destination and
# evaluate file vs directory
link_target = resolve_link_target_relative_to_the_link(f)
@@ -1221,9 +1219,11 @@ def set_executable(path):
def last_modification_time_recursive(path):
path = os.path.abspath(path)
times = [os.stat(path).st_mtime]
- times.extend(os.stat(os.path.join(root, name)).st_mtime
- for root, dirs, files in os.walk(path)
- for name in dirs + files)
+ times.extend(
+ os.stat(os.path.join(root, name)).st_mtime
+ for root, dirs, files in os.walk(path)
+ for name in dirs + files
+ )
return max(times)
@@ -1282,18 +1282,23 @@ def readonly_file_handler(ignore_errors=False):
and will raise a separate error if it is ever invoked (by accident)
on a non-Windows system.
"""
+
def error_remove_readonly(func, path, exc):
if not is_windows:
raise RuntimeError("This method should only be invoked on Windows")
excvalue = exc[1]
- if is_windows and func in (os.rmdir, os.remove, os.unlink) and\
- excvalue.errno == errno.EACCES:
+ if (
+ is_windows
+ and func in (os.rmdir, os.remove, os.unlink)
+ and excvalue.errno == errno.EACCES
+ ):
# change the file to be readable,writable,executable: 0777
os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
# retry
func(path)
elif not ignore_errors:
raise
+
return error_remove_readonly
@@ -1309,13 +1314,13 @@ def remove_linked_tree(path):
Parameters:
path (str): Directory to be removed
"""
- kwargs = {'ignore_errors': True}
+ kwargs = {"ignore_errors": True}
# Windows readonly files cannot be removed by Python
# directly.
if is_windows:
- kwargs['ignore_errors'] = False
- kwargs['onerror'] = readonly_file_handler(ignore_errors=True)
+ kwargs["ignore_errors"] = False
+ kwargs["onerror"] = readonly_file_handler(ignore_errors=True)
if os.path.exists(path):
if os.path.islink(path):
@@ -1344,9 +1349,7 @@ def safe_remove(*files_or_dirs):
# Sort them so that shorter paths like "/foo/bar" come before
# nested paths like "/foo/bar/baz.yaml". This simplifies the
# handling of temporary copies below
- sorted_matches = sorted([
- os.path.abspath(x) for x in itertools.chain(*glob_matches)
- ], key=len)
+ sorted_matches = sorted([os.path.abspath(x) for x in itertools.chain(*glob_matches)], key=len)
# Copy files and directories in a temporary location
removed, dst_root = {}, tempfile.mkdtemp()
@@ -1361,7 +1364,7 @@ def safe_remove(*files_or_dirs):
continue
# The monotonic ID is a simple way to make the filename
# or directory name unique in the temporary folder
- basename = os.path.basename(file_or_dir) + '-{0}'.format(id)
+ basename = os.path.basename(file_or_dir) + "-{0}".format(id)
temporary_path = os.path.join(dst_root, basename)
shutil.move(file_or_dir, temporary_path)
removed[file_or_dir] = temporary_path
@@ -1390,11 +1393,11 @@ def fix_darwin_install_name(path):
libs = glob.glob(join_path(path, "*.dylib"))
for lib in libs:
# fix install name first:
- install_name_tool = Executable('install_name_tool')
- install_name_tool('-id', lib, lib)
- otool = Executable('otool')
- long_deps = otool('-L', lib, output=str).split('\n')
- deps = [dep.partition(' ')[0][1::] for dep in long_deps[2:-1]]
+ install_name_tool = Executable("install_name_tool")
+ install_name_tool("-id", lib, lib)
+ otool = Executable("otool")
+ long_deps = otool("-L", lib, output=str).split("\n")
+ deps = [dep.partition(" ")[0][1::] for dep in long_deps[2:-1]]
# fix all dependencies:
for dep in deps:
for loc in libs:
@@ -1404,7 +1407,7 @@ def fix_darwin_install_name(path):
# but we don't know builddir (nor how symbolic links look
# in builddir). We thus only compare the basenames.
if os.path.basename(dep) == os.path.basename(loc):
- install_name_tool('-change', dep, loc, lib)
+ install_name_tool("-change", dep, loc, lib)
break
@@ -1534,9 +1537,7 @@ class FileList(Sequence):
Returns:
list: A list of directories
"""
- return list(dedupe(
- os.path.dirname(x) for x in self.files if os.path.dirname(x)
- ))
+ return list(dedupe(os.path.dirname(x) for x in self.files if os.path.dirname(x)))
@property
def basenames(self):
@@ -1572,11 +1573,11 @@ class FileList(Sequence):
def __len__(self):
return len(self.files)
- def joined(self, separator=' '):
+ def joined(self, separator=" "):
return separator.join(self.files)
def __repr__(self):
- return self.__class__.__name__ + '(' + repr(self.files) + ')'
+ return self.__class__.__name__ + "(" + repr(self.files) + ")"
def __str__(self):
return self.joined()
@@ -1593,7 +1594,7 @@ class HeaderList(FileList):
# as "xinclude" will cause false matches.
# Avoid matching paths such as <prefix>/include/something/detail/include,
# e.g. in the CUDA Toolkit which ships internal libc++ headers.
- include_regex = re.compile(r'(.*?)(\binclude\b)(.*)')
+ include_regex = re.compile(r"(.*?)(\binclude\b)(.*)")
def __init__(self, files):
super(HeaderList, self).__init__(files)
@@ -1658,7 +1659,7 @@ class HeaderList(FileList):
name = x
# Valid extensions include: ['.cuh', '.hpp', '.hh', '.h']
- for ext in ['.cuh', '.hpp', '.hh', '.h']:
+ for ext in [".cuh", ".hpp", ".hh", ".h"]:
i = name.rfind(ext)
if i != -1:
names.append(name[:i])
@@ -1680,7 +1681,7 @@ class HeaderList(FileList):
Returns:
str: A joined list of include flags
"""
- return ' '.join(['-I' + x for x in self.directories])
+ return " ".join(["-I" + x for x in self.directories])
@property
def macro_definitions(self):
@@ -1695,7 +1696,7 @@ class HeaderList(FileList):
Returns:
str: A joined list of macro definitions
"""
- return ' '.join(self._macro_definitions)
+ return " ".join(self._macro_definitions)
@property
def cpp_flags(self):
@@ -1713,7 +1714,7 @@ class HeaderList(FileList):
"""
cpp_flags = self.include_flags
if self.macro_definitions:
- cpp_flags += ' ' + self.macro_definitions
+ cpp_flags += " " + self.macro_definitions
return cpp_flags
def add_macro(self, macro):
@@ -1752,24 +1753,30 @@ def find_headers(headers, root, recursive=False):
if isinstance(headers, six.string_types):
headers = [headers]
elif not isinstance(headers, Sequence):
- message = '{0} expects a string or sequence of strings as the '
- message += 'first argument [got {1} instead]'
+ message = "{0} expects a string or sequence of strings as the "
+ message += "first argument [got {1} instead]"
message = message.format(find_headers.__name__, type(headers))
raise TypeError(message)
# Construct the right suffix for the headers
suffixes = [
# C
- 'h',
+ "h",
# C++
- 'hpp', 'hxx', 'hh', 'H', 'txx', 'tcc', 'icc',
+ "hpp",
+ "hxx",
+ "hh",
+ "H",
+ "txx",
+ "tcc",
+ "icc",
# Fortran
- 'mod', 'inc',
+ "mod",
+ "inc",
]
# List of headers we are searching with suffixes
- headers = ['{0}.{1}'.format(header, suffix) for header in headers
- for suffix in suffixes]
+ headers = ["{0}.{1}".format(header, suffix) for header in headers for suffix in suffixes]
return HeaderList(find(root, headers, recursive))
@@ -1785,7 +1792,7 @@ def find_all_headers(root):
Returns:
List of all headers found in ``root`` and subdirectories.
"""
- return find_headers('*', root=root, recursive=True)
+ return find_headers("*", root=root, recursive=True)
class LibraryList(FileList):
@@ -1819,11 +1826,11 @@ class LibraryList(FileList):
for x in self.basenames:
name = x
- if x.startswith('lib'):
+ if x.startswith("lib"):
name = x[3:]
# Valid extensions include: ['.dylib', '.so', '.a']
- for ext in ['.dylib', '.so', '.a']:
+ for ext in [".dylib", ".so", ".a"]:
i = name.rfind(ext)
if i != -1:
names.append(name[:i])
@@ -1845,7 +1852,7 @@ class LibraryList(FileList):
Returns:
str: A joined list of search flags
"""
- return ' '.join(['-L' + x for x in self.directories])
+ return " ".join(["-L" + x for x in self.directories])
@property
def link_flags(self):
@@ -1858,7 +1865,7 @@ class LibraryList(FileList):
Returns:
str: A joined list of link flags
"""
- return ' '.join(['-l' + name for name in self.names])
+ return " ".join(["-l" + name for name in self.names])
@property
def ld_flags(self):
@@ -1871,7 +1878,7 @@ class LibraryList(FileList):
Returns:
str: A joined list of search flags and link flags
"""
- return self.search_flags + ' ' + self.link_flags
+ return self.search_flags + " " + self.link_flags
def find_system_libraries(libraries, shared=True):
@@ -1908,20 +1915,19 @@ def find_system_libraries(libraries, shared=True):
if isinstance(libraries, six.string_types):
libraries = [libraries]
elif not isinstance(libraries, Sequence):
- message = '{0} expects a string or sequence of strings as the '
- message += 'first argument [got {1} instead]'
- message = message.format(find_system_libraries.__name__,
- type(libraries))
+ message = "{0} expects a string or sequence of strings as the "
+ message += "first argument [got {1} instead]"
+ message = message.format(find_system_libraries.__name__, type(libraries))
raise TypeError(message)
libraries_found = []
search_locations = [
- '/lib64',
- '/lib',
- '/usr/lib64',
- '/usr/lib',
- '/usr/local/lib64',
- '/usr/local/lib',
+ "/lib64",
+ "/lib",
+ "/usr/lib64",
+ "/usr/lib",
+ "/usr/local/lib64",
+ "/usr/local/lib",
]
for library in libraries:
@@ -1962,24 +1968,23 @@ def find_libraries(libraries, root, shared=True, recursive=False):
if isinstance(libraries, six.string_types):
libraries = [libraries]
elif not isinstance(libraries, Sequence):
- message = '{0} expects a string or sequence of strings as the '
- message += 'first argument [got {1} instead]'
+ message = "{0} expects a string or sequence of strings as the "
+ message += "first argument [got {1} instead]"
message = message.format(find_libraries.__name__, type(libraries))
raise TypeError(message)
# Construct the right suffix for the library
if shared:
# Used on both Linux and macOS
- suffixes = ['so']
- if sys.platform == 'darwin':
+ suffixes = ["so"]
+ if sys.platform == "darwin":
# Only used on macOS
- suffixes.append('dylib')
+ suffixes.append("dylib")
else:
- suffixes = ['a']
+ suffixes = ["a"]
# List of libraries we are searching with suffixes
- libraries = ['{0}.{1}'.format(lib, suffix) for lib in libraries
- for suffix in suffixes]
+ libraries = ["{0}.{1}".format(lib, suffix) for lib in libraries for suffix in suffixes]
if not recursive:
# If not recursive, look for the libraries directly in root
@@ -1989,7 +1994,7 @@ def find_libraries(libraries, root, shared=True, recursive=False):
# perform first non-recursive search in root/lib then in root/lib64 and
# finally search all of root recursively. The search stops when the first
# match is found.
- for subdir in ('lib', 'lib64'):
+ for subdir in ("lib", "lib64"):
dirname = join_path(root, subdir)
if not os.path.isdir(dirname):
continue
@@ -2045,10 +2050,11 @@ def files_in(*search_paths):
"""
files = []
for d in filter(can_access_dir, search_paths):
- files.extend(filter(
- lambda x: os.path.isfile(x[1]),
- [(f, os.path.join(d, f)) for f in os.listdir(d)]
- ))
+ files.extend(
+ filter(
+ lambda x: os.path.isfile(x[1]), [(f, os.path.join(d, f)) for f in os.listdir(d)]
+ )
+ )
return files
@@ -2078,7 +2084,7 @@ def search_paths_for_executables(*path_hints):
path = os.path.abspath(path)
executable_paths.append(path)
- bin_dir = os.path.join(path, 'bin')
+ bin_dir = os.path.join(path, "bin")
if os.path.isdir(bin_dir):
executable_paths.append(bin_dir)
@@ -2106,11 +2112,11 @@ def search_paths_for_libraries(*path_hints):
path = os.path.abspath(path)
library_paths.append(path)
- lib_dir = os.path.join(path, 'lib')
+ lib_dir = os.path.join(path, "lib")
if os.path.isdir(lib_dir):
library_paths.append(lib_dir)
- lib64_dir = os.path.join(path, 'lib64')
+ lib64_dir = os.path.join(path, "lib64")
if os.path.isdir(lib64_dir):
library_paths.append(lib64_dir)
@@ -2140,13 +2146,13 @@ def partition_path(path, entry=None):
# Handle drive letters e.g. C:/ on Windows
entries[0] = entries[0] + sep
i = entries.index(entry)
- if '' in entries:
+ if "" in entries:
i -= 1
- return paths[:i], paths[i], paths[i + 1:]
+ return paths[:i], paths[i], paths[i + 1 :]
except ValueError:
pass
- return paths, '', []
+ return paths, "", []
@system_path_filter
@@ -2181,7 +2187,7 @@ def prefixes(path):
elif parts[0].endswith(":"):
# Handle drive letters e.g. C:/ on Windows
parts[0] = parts[0] + sep
- paths = [os.path.join(*parts[:i + 1]) for i in range(len(parts))]
+ paths = [os.path.join(*parts[: i + 1]) for i in range(len(parts))]
try:
paths.remove(sep)
@@ -2189,7 +2195,7 @@ def prefixes(path):
pass
try:
- paths.remove('.')
+ paths.remove(".")
except ValueError:
pass