... |
... |
@@ -311,7 +311,7 @@ class Downloader: |
311
|
311
|
|
312
|
312
|
return read_blobs
|
313
|
313
|
|
314
|
|
- def _fetch_file(self, digest, file_path):
|
|
314
|
+ def _fetch_file(self, digest, file_path, is_executable=False):
|
315
|
315
|
"""Fetches a file using ByteStream.Read()"""
|
316
|
316
|
if self.instance_name:
|
317
|
317
|
resource_name = '/'.join([self.instance_name, 'blobs',
|
... |
... |
@@ -332,7 +332,10 @@ class Downloader: |
332
|
332
|
|
333
|
333
|
assert byte_file.tell() == digest.size_bytes
|
334
|
334
|
|
335
|
|
- def _queue_file(self, digest, file_path):
|
|
335
|
+ if is_executable:
|
|
336
|
+ os.chmod(file_path, 0o755) # rwxr-xr-x
|
|
337
|
+
|
|
338
|
+ def _queue_file(self, digest, file_path, is_executable=False):
|
336
|
339
|
"""Queues a file for later batch download"""
|
337
|
340
|
if self.__file_request_size + digest.ByteSize() > MAX_REQUEST_SIZE:
|
338
|
341
|
self.flush()
|
... |
... |
@@ -341,22 +344,25 @@ class Downloader: |
341
|
344
|
elif self.__file_request_count >= MAX_REQUEST_COUNT:
|
342
|
345
|
self.flush()
|
343
|
346
|
|
344
|
|
- self.__file_requests[digest.hash] = (digest, file_path)
|
|
347
|
+ self.__file_requests[digest.hash] = (digest, file_path, is_executable)
|
345
|
348
|
self.__file_request_count += 1
|
346
|
349
|
self.__file_request_size += digest.ByteSize()
|
347
|
350
|
self.__file_response_size += digest.size_bytes
|
348
|
351
|
|
349
|
352
|
def _fetch_file_batch(self, batch):
|
350
|
353
|
"""Sends queued data using ContentAddressableStorage.BatchReadBlobs()"""
|
351
|
|
- batch_digests = [digest for digest, _ in batch.values()]
|
|
354
|
+ batch_digests = [digest for digest, _, _ in batch.values()]
|
352
|
355
|
batch_blobs = self._fetch_blob_batch(batch_digests)
|
353
|
356
|
|
354
|
|
- for (_, file_path), file_blob in zip(batch.values(), batch_blobs):
|
|
357
|
+ for (_, file_path, is_executable), file_blob in zip(batch.values(), batch_blobs):
|
355
|
358
|
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
356
|
359
|
|
357
|
360
|
with open(file_path, 'wb') as byte_file:
|
358
|
361
|
byte_file.write(file_blob)
|
359
|
362
|
|
|
363
|
+ if is_executable:
|
|
364
|
+ os.chmod(file_path, 0o755) # rwxr-xr-x
|
|
365
|
+
|
360
|
366
|
def _fetch_directory(self, digest, directory_path):
|
361
|
367
|
"""Fetches a file using ByteStream.GetTree()"""
|
362
|
368
|
# Better fail early if the local root path cannot be created:
|
... |
... |
@@ -414,7 +420,7 @@ class Downloader: |
414
|
420
|
for file_node in root_directory.files:
|
415
|
421
|
file_path = os.path.join(root_path, file_node.name)
|
416
|
422
|
|
417
|
|
- self._queue_file(file_node.digest, file_path)
|
|
423
|
+ self._queue_file(file_node.digest, file_path, is_executable=file_node.is_executable)
|
418
|
424
|
|
419
|
425
|
for directory_node in root_directory.directories:
|
420
|
426
|
directory_path = os.path.join(root_path, directory_node.name)
|