This is an automated email from the ASF dual-hosted git repository.

tvb pushed a commit to branch tristan/assert-buildbox-casd-version
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 9ccb9b70e5b01a831e2deaf0bbb815bea284c866
Author: Tristan van Berkom <[email protected]>
AuthorDate: Sun Jul 3 19:06:27 2022 +0900

    _cas/casdprocessmanager.py: Assert minimal required version of buildbox-casd
    
    Here we pass along the Messenger object to the casdprocessmanager so that
    we can issue a warning on startup in the case that we are unable to properly
    determine the installed buildbox-casd version.
    
    An error is raised if we successfully identify the installed version and
    it is less than the required version.
    
    Fixes #1189
---
 src/buildstream/_cas/cascache.py           |  5 ++-
 src/buildstream/_cas/casdprocessmanager.py | 70 +++++++++++++++++++++++++++++-
 src/buildstream/_context.py                |  1 +
 3 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/src/buildstream/_cas/cascache.py b/src/buildstream/_cas/cascache.py
index c6a58098f..eb3cc9161 100644
--- a/src/buildstream/_cas/cascache.py
+++ b/src/buildstream/_cas/cascache.py
@@ -71,7 +71,8 @@ class CASCache:
         remote_cache_spec=None,
         protect_session_blobs=True,
         log_level=CASLogLevel.WARNING,
-        log_directory=None
+        log_directory=None,
+        messenger=None
     ):
         self.casdir = os.path.join(path, "cas")
         self.tmpdir = os.path.join(path, "tmp")
@@ -88,7 +89,7 @@ class CASCache:
             assert log_directory is not None, "log_directory is required when 
casd is True"
             log_dir = os.path.join(log_directory, "_casd")
             self._casd_process_manager = CASDProcessManager(
-                path, log_dir, log_level, cache_quota, remote_cache_spec, 
protect_session_blobs
+                path, log_dir, log_level, cache_quota, remote_cache_spec, 
protect_session_blobs, messenger
             )
 
             self._casd_channel = self._casd_process_manager.create_channel()
diff --git a/src/buildstream/_cas/casdprocessmanager.py 
b/src/buildstream/_cas/casdprocessmanager.py
index 34f830483..3c003d0b1 100644
--- a/src/buildstream/_cas/casdprocessmanager.py
+++ b/src/buildstream/_cas/casdprocessmanager.py
@@ -18,6 +18,7 @@
 import contextlib
 import threading
 import os
+import re
 import random
 import shutil
 import stat
@@ -25,6 +26,7 @@ import subprocess
 import tempfile
 import time
 import psutil
+from subprocess import CalledProcessError
 
 import grpc
 
@@ -40,6 +42,14 @@ _CASD_MAX_LOGFILES = 10
 _CASD_TIMEOUT = 300  # in seconds
 
 
+#
+# Minimum required version of buildbox-casd
+#
+_REQUIRED_CASD_MAJOR = 0
+_REQUIRED_CASD_MINOR = 0
+_REQUIRED_CASD_MICRO = 58
+
+
 # CASDProcessManager
 #
 # This manages the subprocess that runs buildbox-casd.
@@ -51,14 +61,18 @@ _CASD_TIMEOUT = 300  # in seconds
 #     cache_quota (int): User configured cache quota
 #     remote_cache_spec (RemoteSpec): Optional remote cache server
 #     protect_session_blobs (bool): Disable expiry for blobs used in the 
current session
+#     messenger (Messenger): The messenger to report warnings through the UI
 #
 class CASDProcessManager:
-    def __init__(self, path, log_dir, log_level, cache_quota, 
remote_cache_spec, protect_session_blobs):
+    def __init__(self, path, log_dir, log_level, cache_quota, 
remote_cache_spec, protect_session_blobs, messenger):
         self._log_dir = log_dir
 
         self._socket_path = self._make_socket_path(path)
         self._connection_string = "unix:" + self._socket_path
 
+        # Early version check
+        self._check_casd_version(messenger)
+
         casd_args = [utils.get_host_tool("buildbox-casd")]
         casd_args.append("--bind=" + self._connection_string)
         casd_args.append("--log-level=" + log_level.value)
@@ -92,6 +106,60 @@ class CASDProcessManager:
                 casd_args, cwd=path, stdout=logfile_fp, 
stderr=subprocess.STDOUT, preexec_fn=os.setpgrp
             )
 
+    # _check_casd_version()
+    #
+    # Check for minimal acceptable version of buildbox-casd.
+    #
+    # If the version is unacceptable, then an error is raised.
+    #
+    # If buildbox-casd was built without version information available (or has 
reported
+    # version information with a string which we are unprepared to parse), then
+    # a warning is produced to inform the user.
+    #
+    def _check_casd_version(self, messenger):
+        #
+        # We specify a trailing "path" argument because some versions of 
buildbox-casd
+        # require specifying the storage path even for invoking the --version 
option.
+        #
+        casd_args = [utils.get_host_tool("buildbox-casd")]
+        casd_args.append("--version")
+        casd_args.append("/")
+
+        try:
+            version_output = subprocess.check_output(casd_args)
+        except CalledProcessError as e:
+            raise CASCacheError("Error checking buildbox-casd version") from e
+
+        version_output = version_output.decode("utf-8")
+        version_match = re.match(r".*buildbox-casd (\d+).(\d+).(\d+).*", 
version_output)
+
+        if version_match:
+            version_major = int(version_match.group(1))
+            version_minor = int(version_match.group(2))
+            version_micro = int(version_match.group(3))
+
+            acceptable_version = True
+            if version_major < _REQUIRED_CASD_MAJOR:
+                acceptable_version = False
+            elif version_major == _REQUIRED_CASD_MAJOR:
+                if version_minor < _REQUIRED_CASD_MINOR:
+                    acceptable_version = False
+                elif version_minor == _REQUIRED_CASD_MINOR:
+                    if version_micro < _REQUIRED_CASD_MICRO:
+                        acceptable_version = False
+
+            if not acceptable_version:
+                raise CASCacheError(
+                    "BuildStream requires buildbox-casd >= {}.{}.{}".format(
+                        _REQUIRED_CASD_MAJOR, _REQUIRED_CASD_MINOR, 
_REQUIRED_CASD_MICRO
+                    ),
+                    detail="Currently installed: {}".format(version_output),
+                )
+        elif messenger:
+            messenger.warn(
+                "Unable to determine buildbox-casd version", 
detail="buildbox-casd reported: {}".format(version_output)
+            )
+
     # _make_socket_path()
     #
     # Create a path to the CASD socket, ensuring that we don't exceed
diff --git a/src/buildstream/_context.py b/src/buildstream/_context.py
index dfe369479..ecca27c10 100644
--- a/src/buildstream/_context.py
+++ b/src/buildstream/_context.py
@@ -688,6 +688,7 @@ class Context:
                 remote_cache_spec=self.remote_cache_spec,
                 log_level=log_level,
                 log_directory=self.logdir,
+                messenger=self.messenger,
             )
         return self._cascache
 

Reply via email to