summaryrefslogtreecommitdiff
path: root/src/buildstream/utils.py
diff options
context:
space:
mode:
authorChandan Singh <csingh43@bloomberg.net>2019-11-11 17:07:09 +0000
committerChandan Singh <chandan@chandansingh.net>2019-11-14 21:21:06 +0000
commit122177153b14664a0e4fed85aa4f22b87cfabf56 (patch)
tree032c2e46825af91f6fe27f22b5b567eea2b7935d /src/buildstream/utils.py
parenta3ee349558f36a220f79665873b36c1b0f990c8e (diff)
downloadbuildstream-122177153b14664a0e4fed85aa4f22b87cfabf56.tar.gz
Reformat code using Black
As discussed over the mailing list, reformat code using Black. This is a one-off change to reformat all our codebase. Moving forward, we shouldn't expect such blanket reformats. Rather, we expect each change to already comply with the Black formatting style.
Diffstat (limited to 'src/buildstream/utils.py')
-rw-r--r--src/buildstream/utils.py265
1 files changed, 144 insertions, 121 deletions
diff --git a/src/buildstream/utils.py b/src/buildstream/utils.py
index de7c14b70..181ea1df9 100644
--- a/src/buildstream/utils.py
+++ b/src/buildstream/utils.py
@@ -52,7 +52,7 @@ from ._utils import url_directory_name # pylint: disable=unused-import
BST_ARBITRARY_TIMESTAMP = calendar.timegm((2011, 11, 11, 11, 11, 11))
# The separator we use for user specified aliases
-_ALIAS_SEPARATOR = ':'
+_ALIAS_SEPARATOR = ":"
_URI_SCHEMES = ["http", "https", "ftp", "file", "git", "sftp", "ssh"]
# Main process pid
@@ -74,6 +74,7 @@ class UtilError(BstError):
or either of the :class:`.ElementError` or :class:`.SourceError`
exceptions should be raised from this error.
"""
+
def __init__(self, message, reason=None):
super().__init__(message, domain=ErrorDomain.UTIL, reason=reason)
@@ -83,6 +84,7 @@ class ProgramNotFoundError(BstError):
It is normally unneeded to handle this exception from plugin code.
"""
+
def __init__(self, message, reason=None):
super().__init__(message, domain=ErrorDomain.PROG_NOT_FOUND, reason=reason)
@@ -92,7 +94,7 @@ class DirectoryExistsError(OSError):
"""
-class FileListResult():
+class FileListResult:
"""An object which stores the result of one of the operations
which run on a list of files.
"""
@@ -112,7 +114,7 @@ class FileListResult():
self.files_written = []
"""List of files that were written."""
- def combine(self, other: 'FileListResult') -> 'FileListResult':
+ def combine(self, other: "FileListResult") -> "FileListResult":
"""Create a new FileListResult that contains the results of both.
"""
ret = FileListResult()
@@ -165,10 +167,10 @@ def list_relative_paths(directory: str) -> Iterator[str]:
# We don't want "./" pre-pended to all the entries in the root of
# `directory`, prefer to have no prefix in that case.
- basepath = relpath if relpath != '.' and dirpath != directory else ''
+ basepath = relpath if relpath != "." and dirpath != directory else ""
# First yield the walked directory itself, except for the root
- if basepath != '':
+ if basepath != "":
yield basepath
# List the filenames in the walked directory
@@ -248,8 +250,7 @@ def sha256sum(filename: str) -> str:
h.update(chunk)
except OSError as e:
- raise UtilError("Failed to get a checksum of file '{}': {}"
- .format(filename, e)) from e
+ raise UtilError("Failed to get a checksum of file '{}': {}".format(filename, e)) from e
return h.hexdigest()
@@ -274,8 +275,7 @@ def safe_copy(src: str, dest: str, *, result: Optional[FileListResult] = None) -
os.unlink(dest)
except OSError as e:
if e.errno != errno.ENOENT:
- raise UtilError("Failed to remove destination file '{}': {}"
- .format(dest, e)) from e
+ raise UtilError("Failed to remove destination file '{}': {}".format(dest, e)) from e
shutil.copyfile(src, dest)
try:
@@ -291,8 +291,7 @@ def safe_copy(src: str, dest: str, *, result: Optional[FileListResult] = None) -
result.failed_attributes.append(dest)
except shutil.Error as e:
- raise UtilError("Failed to copy '{} -> {}': {}"
- .format(src, dest, e)) from e
+ raise UtilError("Failed to copy '{} -> {}': {}".format(src, dest, e)) from e
def safe_link(src: str, dest: str, *, result: Optional[FileListResult] = None, _unlink=False) -> None:
@@ -313,8 +312,7 @@ def safe_link(src: str, dest: str, *, result: Optional[FileListResult] = None, _
os.unlink(dest)
except OSError as e:
if e.errno != errno.ENOENT:
- raise UtilError("Failed to remove destination file '{}': {}"
- .format(dest, e)) from e
+ raise UtilError("Failed to remove destination file '{}': {}".format(dest, e)) from e
# If we can't link it due to cross-device hardlink, copy
try:
@@ -326,8 +324,7 @@ def safe_link(src: str, dest: str, *, result: Optional[FileListResult] = None, _
elif e.errno == errno.EXDEV:
safe_copy(src, dest)
else:
- raise UtilError("Failed to link '{} -> {}': {}"
- .format(src, dest, e)) from e
+ raise UtilError("Failed to link '{} -> {}': {}".format(src, dest, e)) from e
def safe_remove(path: str) -> bool:
@@ -363,16 +360,17 @@ def safe_remove(path: str) -> bool:
# Path does not exist
return True
- raise UtilError("Failed to remove '{}': {}"
- .format(path, e))
+ raise UtilError("Failed to remove '{}': {}".format(path, e))
-def copy_files(src: str,
- dest: str,
- *,
- filter_callback: Optional[Callable[[str], bool]] = None,
- ignore_missing: bool = False,
- report_written: bool = False) -> FileListResult:
+def copy_files(
+ src: str,
+ dest: str,
+ *,
+ filter_callback: Optional[Callable[[str], bool]] = None,
+ ignore_missing: bool = False,
+ report_written: bool = False
+) -> FileListResult:
"""Copy files from source to destination.
Args:
@@ -401,22 +399,28 @@ def copy_files(src: str,
"""
result = FileListResult()
try:
- _process_list(src, dest, safe_copy, result,
- filter_callback=filter_callback,
- ignore_missing=ignore_missing,
- report_written=report_written)
+ _process_list(
+ src,
+ dest,
+ safe_copy,
+ result,
+ filter_callback=filter_callback,
+ ignore_missing=ignore_missing,
+ report_written=report_written,
+ )
except OSError as e:
- raise UtilError("Failed to copy '{} -> {}': {}"
- .format(src, dest, e))
+ raise UtilError("Failed to copy '{} -> {}': {}".format(src, dest, e))
return result
-def link_files(src: str,
- dest: str,
- *,
- filter_callback: Optional[Callable[[str], bool]] = None,
- ignore_missing: bool = False,
- report_written: bool = False) -> FileListResult:
+def link_files(
+ src: str,
+ dest: str,
+ *,
+ filter_callback: Optional[Callable[[str], bool]] = None,
+ ignore_missing: bool = False,
+ report_written: bool = False
+) -> FileListResult:
"""Hardlink files from source to destination.
Args:
@@ -450,13 +454,17 @@ def link_files(src: str,
"""
result = FileListResult()
try:
- _process_list(src, dest, safe_link, result,
- filter_callback=filter_callback,
- ignore_missing=ignore_missing,
- report_written=report_written)
+ _process_list(
+ src,
+ dest,
+ safe_link,
+ result,
+ filter_callback=filter_callback,
+ ignore_missing=ignore_missing,
+ report_written=report_written,
+ )
except OSError as e:
- raise UtilError("Failed to link '{} -> {}': {}"
- .format(src, dest, e))
+ raise UtilError("Failed to link '{} -> {}': {}".format(src, dest, e))
return result
@@ -473,7 +481,7 @@ def get_host_tool(name: str) -> str:
Raises:
:class:`.ProgramNotFoundError`
"""
- search_path = os.environ.get('PATH')
+ search_path = os.environ.get("PATH")
program_path = shutil.which(name, path=search_path)
if not program_path:
@@ -491,22 +499,27 @@ def get_bst_version() -> Tuple[int, int]:
"""
# Import this only conditionally, it's not resolved at bash complete time
from . import __version__ # pylint: disable=cyclic-import
- versions = __version__.split('.')[:2]
- if versions[0] == '0+untagged':
- raise UtilError("Your git repository has no tags - BuildStream can't "
- "determine its version. Please run `git fetch --tags`.")
+ versions = __version__.split(".")[:2]
+
+ if versions[0] == "0+untagged":
+ raise UtilError(
+ "Your git repository has no tags - BuildStream can't "
+ "determine its version. Please run `git fetch --tags`."
+ )
try:
return (int(versions[0]), int(versions[1]))
except IndexError:
- raise UtilError("Cannot detect Major and Minor parts of the version\n"
- "Version: {} not in XX.YY.whatever format"
- .format(__version__))
+ raise UtilError(
+ "Cannot detect Major and Minor parts of the version\n"
+ "Version: {} not in XX.YY.whatever format".format(__version__)
+ )
except ValueError:
- raise UtilError("Cannot convert version to integer numbers\n"
- "Version: {} not in Integer.Integer.whatever format"
- .format(__version__))
+ raise UtilError(
+ "Cannot convert version to integer numbers\n"
+ "Version: {} not in Integer.Integer.whatever format".format(__version__)
+ )
def move_atomic(source: Union[Path, str], destination: Union[Path, str], *, ensure_parents: bool = True) -> None:
@@ -548,16 +561,18 @@ def move_atomic(source: Union[Path, str], destination: Union[Path, str], *, ensu
@contextmanager
-def save_file_atomic(filename: str,
- mode: str = 'w',
- *,
- buffering: int = -1,
- encoding: Optional[str] = None,
- errors: Optional[str] = None,
- newline: Optional[str] = None,
- closefd: bool = True,
- opener: Optional[Callable[[str, int], int]] = None,
- tempdir: Optional[str] = None) -> Iterator[IO]:
+def save_file_atomic(
+ filename: str,
+ mode: str = "w",
+ *,
+ buffering: int = -1,
+ encoding: Optional[str] = None,
+ errors: Optional[str] = None,
+ newline: Optional[str] = None,
+ closefd: bool = True,
+ opener: Optional[Callable[[str, int], int]] = None,
+ tempdir: Optional[str] = None
+) -> Iterator[IO]:
"""Save a file with a temporary name and rename it into place when ready.
This is a context manager which is meant for saving data to files.
@@ -589,8 +604,16 @@ def save_file_atomic(filename: str,
fd, tempname = tempfile.mkstemp(dir=tempdir)
os.close(fd)
- f = open(tempname, mode=mode, buffering=buffering, encoding=encoding,
- errors=errors, newline=newline, closefd=closefd, opener=opener)
+ f = open(
+ tempname,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ errors=errors,
+ newline=newline,
+ closefd=closefd,
+ opener=opener,
+ )
def cleanup_tempfile():
f.close()
@@ -604,7 +627,7 @@ def save_file_atomic(filename: str,
try:
with _signals.terminator(cleanup_tempfile):
# Disable type-checking since "IO[Any]" has no attribute "real_filename"
- f.real_filename = filename # type: ignore
+ f.real_filename = filename # type: ignore
yield f
f.close()
# This operation is atomic, at least on platforms we care about:
@@ -660,8 +683,7 @@ def _get_volume_size(path):
try:
usage = shutil.disk_usage(path)
except OSError as e:
- raise UtilError("Failed to retrieve stats on volume for path '{}': {}"
- .format(path, e)) from e
+ raise UtilError("Failed to retrieve stats on volume for path '{}': {}".format(path, e)) from e
return usage.total, usage.free
@@ -685,16 +707,16 @@ def _get_volume_size(path):
# UtilError if the string is not a valid data size.
#
def _parse_size(size, volume):
- if size == 'infinity':
+ if size == "infinity":
return None
- matches = re.fullmatch(r'([0-9]+\.?[0-9]*)([KMGT%]?)', size)
+ matches = re.fullmatch(r"([0-9]+\.?[0-9]*)([KMGT%]?)", size)
if matches is None:
raise UtilError("{} is not a valid data size.".format(size))
num, unit = matches.groups()
- if unit == '%':
+ if unit == "%":
num = float(num)
if num > 100:
raise UtilError("{}% is not a valid percentage value.".format(num))
@@ -703,8 +725,8 @@ def _parse_size(size, volume):
return disk_size * (num / 100)
- units = ('', 'K', 'M', 'G', 'T')
- return int(num) * 1024**units.index(unit)
+ units = ("", "K", "M", "G", "T")
+ return int(num) * 1024 ** units.index(unit)
# _pretty_size()
@@ -720,8 +742,8 @@ def _parse_size(size, volume):
# (str): The string representation of the number of bytes in the largest
def _pretty_size(size, dec_places=0):
psize = size
- unit = 'B'
- units = ('B', 'K', 'M', 'G', 'T')
+ unit = "B"
+ units = ("B", "K", "M", "G", "T")
for unit in units:
if psize < 1024:
break
@@ -746,19 +768,17 @@ def _force_rmtree(rootpath, **kwargs):
os.chmod(rootpath, 0o755)
for root, dirs, _ in os.walk(rootpath):
for d in dirs:
- path = os.path.join(root, d.lstrip('/'))
+ path = os.path.join(root, d.lstrip("/"))
if os.path.exists(path) and not os.path.islink(path):
try:
os.chmod(path, 0o755)
except OSError as e:
- raise UtilError("Failed to ensure write permission on file '{}': {}"
- .format(path, e))
+ raise UtilError("Failed to ensure write permission on file '{}': {}".format(path, e))
try:
shutil.rmtree(rootpath, **kwargs)
except OSError as e:
- raise UtilError("Failed to remove cache directory '{}': {}"
- .format(rootpath, e))
+ raise UtilError("Failed to remove cache directory '{}': {}".format(rootpath, e))
# Recursively make directories in target area
@@ -779,8 +799,7 @@ def _copy_directories(srcdir, destdir, target):
os.makedirs(new_dir)
yield (new_dir, mode)
else:
- raise UtilError('Source directory tree has file where '
- 'directory expected: {}'.format(old_dir))
+ raise UtilError("Source directory tree has file where " "directory expected: {}".format(old_dir))
else:
if not os.access(new_dir, os.W_OK):
# If the destination directory is not writable, change permissions to make it
@@ -806,16 +825,16 @@ def _ensure_real_directory(root, path):
try:
deststat = os.lstat(destpath)
if not stat.S_ISDIR(deststat.st_mode):
- relpath = destpath[len(root):]
+ relpath = destpath[len(root) :]
if stat.S_ISLNK(deststat.st_mode):
- filetype = 'symlink'
+ filetype = "symlink"
elif stat.S_ISREG(deststat.st_mode):
- filetype = 'regular file'
+ filetype = "regular file"
else:
- filetype = 'special file'
+ filetype = "special file"
- raise UtilError('Destination is a {}, not a directory: {}'.format(filetype, relpath))
+ raise UtilError("Destination is a {}, not a directory: {}".format(filetype, relpath))
except FileNotFoundError:
os.makedirs(destpath)
@@ -836,9 +855,9 @@ def _ensure_real_directory(root, path):
# ignore_missing: Dont raise any error if a source file is missing
#
#
-def _process_list(srcdir, destdir, actionfunc, result,
- filter_callback=None,
- ignore_missing=False, report_written=False):
+def _process_list(
+ srcdir, destdir, actionfunc, result, filter_callback=None, ignore_missing=False, report_written=False
+):
# Keep track of directory permissions, since these need to be set
# *after* files have been written.
@@ -921,7 +940,7 @@ def _process_list(srcdir, destdir, actionfunc, result,
else:
# Unsupported type.
- raise UtilError('Cannot extract {} into staging-area. Unsupported type.'.format(srcpath))
+ raise UtilError("Cannot extract {} into staging-area. Unsupported type.".format(srcpath))
# Write directory permissions now that all files have been written
for d, perms in permissions:
@@ -1035,8 +1054,9 @@ def _tempnamedfile(suffix="", prefix="tmp", dir=None): # pylint: disable=redefi
if temp is not None:
temp.close()
- with _signals.terminator(close_tempfile), \
- tempfile.NamedTemporaryFile(suffix=suffix, prefix=prefix, dir=dir) as temp:
+ with _signals.terminator(close_tempfile), tempfile.NamedTemporaryFile(
+ suffix=suffix, prefix=prefix, dir=dir
+ ) as temp:
yield temp
@@ -1145,13 +1165,13 @@ def _kill_process_tree(pid):
#
def _call(*popenargs, terminate=False, **kwargs):
- kwargs['start_new_session'] = True
+ kwargs["start_new_session"] = True
process = None
- old_preexec_fn = kwargs.get('preexec_fn')
- if 'preexec_fn' in kwargs:
- del kwargs['preexec_fn']
+ old_preexec_fn = kwargs.get("preexec_fn")
+ if "preexec_fn" in kwargs:
+ del kwargs["preexec_fn"]
def preexec_fn():
os.umask(stat.S_IWGRP | stat.S_IWOTH)
@@ -1203,7 +1223,8 @@ def _call(*popenargs, terminate=False, **kwargs):
with _signals.suspendable(suspend_proc, resume_proc), _signals.terminator(kill_proc):
process = subprocess.Popen( # pylint: disable=subprocess-popen-preexec-fn
- *popenargs, preexec_fn=preexec_fn, universal_newlines=True, **kwargs)
+ *popenargs, preexec_fn=preexec_fn, universal_newlines=True, **kwargs
+ )
output, _ = process.communicate()
exit_code = process.poll()
@@ -1237,44 +1258,44 @@ def _call(*popenargs, terminate=False, **kwargs):
#
def _glob2re(pat):
i, n = 0, len(pat)
- res = '(?ms)'
+ res = "(?ms)"
while i < n:
c = pat[i]
i = i + 1
- if c == '*':
+ if c == "*":
# fnmatch.translate() simply uses the '.*' separator here,
# we only want that for double asterisk (bash 'globstar' behavior)
#
- if i < n and pat[i] == '*':
- res = res + '.*'
+ if i < n and pat[i] == "*":
+ res = res + ".*"
i = i + 1
else:
- res = res + '[^/]*'
- elif c == '?':
+ res = res + "[^/]*"
+ elif c == "?":
# fnmatch.translate() simply uses the '.' wildcard here, but
# we dont want to match path separators here
- res = res + '[^/]'
- elif c == '[':
+ res = res + "[^/]"
+ elif c == "[":
j = i
- if j < n and pat[j] == '!':
+ if j < n and pat[j] == "!":
j = j + 1
- if j < n and pat[j] == ']':
+ if j < n and pat[j] == "]":
j = j + 1
- while j < n and pat[j] != ']':
+ while j < n and pat[j] != "]":
j = j + 1
if j >= n:
- res = res + '\\['
+ res = res + "\\["
else:
- stuff = pat[i:j].replace('\\', '\\\\')
+ stuff = pat[i:j].replace("\\", "\\\\")
i = j + 1
- if stuff[0] == '!':
- stuff = '^' + stuff[1:]
- elif stuff[0] == '^':
- stuff = '\\' + stuff
- res = '{}[{}]'.format(res, stuff)
+ if stuff[0] == "!":
+ stuff = "^" + stuff[1:]
+ elif stuff[0] == "^":
+ stuff = "\\" + stuff
+ res = "{}[{}]".format(res, stuff)
else:
res = res + re.escape(c)
- return res + r'\Z'
+ return res + r"\Z"
# _deduplicate()
@@ -1392,7 +1413,7 @@ def _deterministic_umask():
#
#
def _get_compression(tar):
- mapped_extensions = {'.tar': '', '.gz': 'gz', '.xz': 'xz', '.bz2': 'bz2'}
+ mapped_extensions = {".tar": "", ".gz": "gz", ".xz": "xz", ".bz2": "bz2"}
name, ext = os.path.splitext(tar)
@@ -1403,12 +1424,14 @@ def _get_compression(tar):
# If so, we assume we have been given an unsupported extension,
# which expects compression. Raise an error
_, suffix = os.path.splitext(name)
- if suffix == '.tar':
- raise UtilError("Expected compression with unknown file extension ('{}'), "
- "supported extensions are ('.tar'), ('.gz'), ('.xz'), ('.bz2')".format(ext))
+ if suffix == ".tar":
+ raise UtilError(
+ "Expected compression with unknown file extension ('{}'), "
+ "supported extensions are ('.tar'), ('.gz'), ('.xz'), ('.bz2')".format(ext)
+ )
# Assume just an unconventional name was provided, default to uncompressed
- return ''
+ return ""
# _is_single_threaded()