Merge pull request #1814 from apache/abderrahim/blocking-activity

plugin: don't try to pickle the exceptions thrown by blocking_activity
diff --git a/.asf.yaml b/.asf.yaml
index 7483a9a..120de7b 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -33,6 +33,9 @@
     # disable rebase button:
     rebase: false
 
+  # Close branches when pull requests are merged
+  del_branch_on_merge: true
+
   # Enable pages publishing
   ghp_branch: gh-pages
   ghp_path: /
diff --git a/.github/common.env b/.github/common.env
index eb464d3..598896c 100644
--- a/.github/common.env
+++ b/.github/common.env
@@ -1,6 +1,6 @@
 # Shared common variables
 
 CI_IMAGE_VERSION=master-643533272
-CI_TOXENV_MAIN=py37,py38-nocover,py39-nocover,py310-nocover,py311-nocover
-CI_TOXENV_PLUGINS=py37-plugins,py38-plugins-nocover,py39-plugins-nocover,py310-plugins-nocover,py311-plugins-nocover
+CI_TOXENV_MAIN=py37,py38,py39,py310,py311
+CI_TOXENV_PLUGINS=py37-plugins,py38-plugins,py39-plugins,py310-plugins,py311-plugins
 CI_TOXENV_ALL="${CI_TOXENV_MAIN},${CI_TOXENV_PLUGINS}"
diff --git a/requirements/cov-requirements.in b/requirements/cov-requirements.in
index d80d8f4..65bd5da 100644
--- a/requirements/cov-requirements.in
+++ b/requirements/cov-requirements.in
@@ -1,4 +1,4 @@
-coverage == 4.4.0
+coverage >= 6
 pytest-cov >= 2.5.0
 pytest >= 6.0.1
 Cython
diff --git a/requirements/cov-requirements.txt b/requirements/cov-requirements.txt
index dc46a1b..9df1cf0 100644
--- a/requirements/cov-requirements.txt
+++ b/requirements/cov-requirements.txt
@@ -1,5 +1,5 @@
-coverage==4.4
-pytest-cov==2.10.1
+coverage==7.0.5
+pytest-cov==4.0.0
 pytest==7.2.0
 Cython==0.29.32
 ## The following requirements were added by pip freeze:
diff --git a/src/buildstream/utils.py b/src/buildstream/utils.py
index 7d80725..267cd51 100644
--- a/src/buildstream/utils.py
+++ b/src/buildstream/utils.py
@@ -70,6 +70,10 @@
 _UMASK = os.umask(0o777)
 os.umask(_UMASK)
 
+# Only some operating systems have os.copy_file_range and even when present
+# it might not work
+_USE_CP_FILE_RANGE = hasattr(os, "copy_file_range")
+
 
 class UtilError(BstError):
     """Raised by utility functions when system calls fail.
@@ -357,6 +361,26 @@
     return h.hexdigest()
 
 
+def _copy_file_range(src, dest):
+    global _USE_CP_FILE_RANGE  # pylint: disable=global-statement
+    if not _USE_CP_FILE_RANGE:
+        return False
+    with open(src, "rb") as src_file, open(dest, "wb") as dest_file:
+        num_bytes = os.fstat(src_file.fileno()).st_size
+        while num_bytes > 0:
+            try:
+                bytes_read = os.copy_file_range(src_file.fileno(), dest_file.fileno(), num_bytes)
+                if not bytes_read:
+                    return True
+                num_bytes -= bytes_read
+            except OSError as error:
+                if error.errno in (errno.ENOSYS, errno.EXDEV):
+                    _USE_CP_FILE_RANGE = False
+                    return False
+                raise error from None
+    return True
+
+
 def safe_copy(src: str, dest: str, *, copystat: bool = True, result: Optional[FileListResult] = None) -> None:
     """Copy a file while optionally preserving attributes
 
@@ -381,7 +405,9 @@
             raise UtilError("Failed to remove destination file '{}': {}".format(dest, e)) from e
 
     try:
-        shutil.copyfile(src, dest)
+        ret = _copy_file_range(src, dest)
+        if not ret:
+            shutil.copyfile(src, dest)
     except (OSError, shutil.Error) as e:
         raise UtilError("Failed to copy '{} -> {}': {}".format(src, dest, e)) from e
 
diff --git a/tox.ini b/tox.ini
index 4b2f54c..c6998a9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -16,7 +16,7 @@
 # Tox global configuration
 #
 [tox]
-envlist = py37,py{38,39,310,311}-nocover
+envlist = py{37,38,39,310,311}
 skip_missing_interpreters = true
 isolated_build = true