[Notes] [Git][BuildGrid/buildgrid][mablanch/134-download-exec-flag] 2 commits: client/cas.py: Preserve file executability on download



Title: GitLab

Martin Blanchard pushed to branch mablanch/134-download-exec-flag at BuildGrid / buildgrid

Commits:

2 changed files:

Changes:

  • buildgrid/client/cas.py
    ... ... @@ -171,7 +171,7 @@ class Downloader:
    171 171
     
    
    172 172
             return messages
    
    173 173
     
    
    174
    -    def download_file(self, digest, file_path, queue=True):
    
    174
    +    def download_file(self, digest, file_path, is_executable=False, queue=True):
    
    175 175
             """Retrieves a file from the remote CAS server.
    
    176 176
     
    
    177 177
             If queuing is allowed (`queue=True`), the download request **may** be
    
    ... ... @@ -181,6 +181,7 @@ class Downloader:
    181 181
             Args:
    
    182 182
                 digest (:obj:`Digest`): the file's digest to fetch.
    
    183 183
                 file_path (str): absolute or relative path to the local file to write.
    
    184
    +            is_executable (bool): whether the file is executable or not.
    
    184 185
                 queue (bool, optional): whether or not the download request may be
    
    185 186
                     queued and submitted as part of a batch upload request. Defaults
    
    186 187
                     to True.
    
    ... ... @@ -193,9 +194,9 @@ class Downloader:
    193 194
                 file_path = os.path.abspath(file_path)
    
    194 195
     
    
    195 196
             if not queue or digest.size_bytes > FILE_SIZE_THRESHOLD:
    
    196
    -            self._fetch_file(digest, file_path)
    
    197
    +            self._fetch_file(digest, file_path, is_executable=is_executable)
    
    197 198
             else:
    
    198
    -            self._queue_file(digest, file_path)
    
    199
    +            self._queue_file(digest, file_path, is_executable=is_executable)
    
    199 200
     
    
    200 201
         def download_directory(self, digest, directory_path):
    
    201 202
             """Retrieves a :obj:`Directory` from the remote CAS server.
    
    ... ... @@ -311,7 +312,7 @@ class Downloader:
    311 312
     
    
    312 313
             return read_blobs
    
    313 314
     
    
    314
    -    def _fetch_file(self, digest, file_path):
    
    315
    +    def _fetch_file(self, digest, file_path, is_executable=False):
    
    315 316
             """Fetches a file using ByteStream.Read()"""
    
    316 317
             if self.instance_name:
    
    317 318
                 resource_name = '/'.join([self.instance_name, 'blobs',
    
    ... ... @@ -332,7 +333,10 @@ class Downloader:
    332 333
     
    
    333 334
                 assert byte_file.tell() == digest.size_bytes
    
    334 335
     
    
    335
    -    def _queue_file(self, digest, file_path):
    
    336
    +        if is_executable:
    
    337
    +            os.chmod(file_path, 0o755)  # rwxr-xr-x / 755
    
    338
    +
    
    339
    +    def _queue_file(self, digest, file_path, is_executable=False):
    
    336 340
             """Queues a file for later batch download"""
    
    337 341
             if self.__file_request_size + digest.ByteSize() > MAX_REQUEST_SIZE:
    
    338 342
                 self.flush()
    
    ... ... @@ -341,22 +345,25 @@ class Downloader:
    341 345
             elif self.__file_request_count >= MAX_REQUEST_COUNT:
    
    342 346
                 self.flush()
    
    343 347
     
    
    344
    -        self.__file_requests[digest.hash] = (digest, file_path)
    
    348
    +        self.__file_requests[digest.hash] = (digest, file_path, is_executable)
    
    345 349
             self.__file_request_count += 1
    
    346 350
             self.__file_request_size += digest.ByteSize()
    
    347 351
             self.__file_response_size += digest.size_bytes
    
    348 352
     
    
    349 353
         def _fetch_file_batch(self, batch):
    
    350 354
             """Sends queued data using ContentAddressableStorage.BatchReadBlobs()"""
    
    351
    -        batch_digests = [digest for digest, _ in batch.values()]
    
    355
    +        batch_digests = [digest for digest, _, _ in batch.values()]
    
    352 356
             batch_blobs = self._fetch_blob_batch(batch_digests)
    
    353 357
     
    
    354
    -        for (_, file_path), file_blob in zip(batch.values(), batch_blobs):
    
    358
    +        for (_, file_path, is_executable), file_blob in zip(batch.values(), batch_blobs):
    
    355 359
                 os.makedirs(os.path.dirname(file_path), exist_ok=True)
    
    356 360
     
    
    357 361
                 with open(file_path, 'wb') as byte_file:
    
    358 362
                     byte_file.write(file_blob)
    
    359 363
     
    
    364
    +            if is_executable:
    
    365
    +                os.chmod(file_path, 0o755)  # rwxr-xr-x / 755
    
    366
    +
    
    360 367
         def _fetch_directory(self, digest, directory_path):
    
    361 368
             """Fetches a file using ByteStream.GetTree()"""
    
    362 369
             # Better fail early if the local root path cannot be created:
    
    ... ... @@ -414,7 +421,7 @@ class Downloader:
    414 421
             for file_node in root_directory.files:
    
    415 422
                 file_path = os.path.join(root_path, file_node.name)
    
    416 423
     
    
    417
    -            self._queue_file(file_node.digest, file_path)
    
    424
    +            self._queue_file(file_node.digest, file_path, is_executable=file_node.is_executable)
    
    418 425
     
    
    419 426
             for directory_node in root_directory.directories:
    
    420 427
                 directory_path = os.path.join(root_path, directory_node.name)
    

  • tests/cas/data/hello/hello.sh
    1
    +#!/bin/bash
    
    2
    +
    
    3
    +echo "Hello, World!"



  • [Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]