| OLD | NEW |
| (Empty) | |
| 1 # Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 from third_party.cloudstorage import cloudstorage_api |
| 6 from third_party.cloudstorage import common |
| 7 from third_party.cloudstorage import errors |
| 8 |
| 9 from docs_server_utils import StringIdentity |
| 10 from file_system import FileSystem, FileNotFoundError, StatInfo |
| 11 from future import Gettable, Future |
| 12 |
| 13 import logging |
| 14 import traceback |
| 15 |
| 16 '''See gcs_file_system_provider.py for documentation on using Google Cloud |
| 17 Storage as a filesystem. |
| 18 ''' |
| 19 def _ReadFile(filename): |
| 20 try: |
| 21 with cloudstorage_api.open(filename, 'r') as f: |
| 22 return f.read() |
| 23 except errors.Error: |
| 24 raise FileNotFoundError('Read failed for %s: %s' % (filename, |
| 25 traceback.format_exc())) |
| 26 |
| 27 def _ListDir(dir_name): |
| 28 try: |
| 29 files = cloudstorage_api.listbucket(dir_name) |
| 30 return [os_path.filename for os_path in files] |
| 31 except errors.Error: |
| 32 raise FileNotFoundError('cloudstorage.listbucket failed for %s: %s' % |
| 33 (dir_name, traceback.format_exc())) |
| 34 |
| 35 def _CreateStatInfo(bucket, path): |
| 36 bucket = '/%s' % bucket |
| 37 full_path = '/'.join( (bucket, path.lstrip('/')) ) |
| 38 try: |
| 39 if full_path.endswith('/'): |
| 40 child_versions = dict() |
| 41 version = 0 |
| 42 # Fetching stats for all files under full_path, recursively. The |
| 43 # listbucket method uses a prefix approach to simulate hierarchy, |
| 44 # but calling it without the "delimiter" argument searches for prefix, |
| 45 # which means, for directories, everything beneath it. |
| 46 for _file in cloudstorage_api.listbucket(full_path): |
| 47 if not _file.is_dir: |
| 48 # GCS doesn't have metadata for dirs |
| 49 child_stat = cloudstorage_api.stat('%s' % _file.filename).st_ctime |
| 50 filename = _file.filename[len(bucket)+1:] |
| 51 child_versions[filename] = child_stat |
| 52 version = max(version, child_stat) |
| 53 else: |
| 54 child_versions = None |
| 55 version = cloudstorage_api.stat(full_path).st_ctime |
| 56 return StatInfo(version, child_versions) |
| 57 except (TypeError, errors.Error): |
| 58 raise FileNotFoundError('cloudstorage.stat failed for %s: %s' % (path, |
| 59 traceback.format_exc())) |
| 60 |
| 61 |
| 62 class CloudStorageFileSystem(FileSystem): |
| 63 '''FileSystem implementation which fetches resources from Google Cloud |
| 64 Storage. |
| 65 ''' |
| 66 def __init__(self, bucket, debug_access_token=None, debug_bucket_prefix=None): |
| 67 self._bucket = bucket |
| 68 if debug_access_token: |
| 69 logging.debug('gcs: using debug access token: %s' % debug_access_token) |
| 70 common.set_access_token(debug_access_token) |
| 71 if debug_bucket_prefix: |
| 72 logging.debug('gcs: prefixing all bucket names with %s' % |
| 73 debug_bucket_prefix) |
| 74 self._bucket = debug_bucket_prefix + self._bucket |
| 75 |
| 76 def Read(self, paths): |
| 77 def resolve(): |
| 78 try: |
| 79 result = {} |
| 80 for path in paths: |
| 81 full_path = '/%s/%s' % (self._bucket, path.lstrip('/')) |
| 82 logging.debug('gcs: requested path %s, reading %s' % |
| 83 (path, full_path)) |
| 84 if path == '' or path.endswith('/'): |
| 85 result[path] = _ListDir(full_path) |
| 86 else: |
| 87 result[path] = _ReadFile(full_path) |
| 88 return result |
| 89 except errors.AuthorizationError: |
| 90 self._warnAboutAuthError() |
| 91 raise |
| 92 |
| 93 return Future(delegate=Gettable(resolve)) |
| 94 |
| 95 def Refresh(self): |
| 96 return Future(value=()) |
| 97 |
| 98 def Stat(self, path): |
| 99 try: |
| 100 return _CreateStatInfo(self._bucket, path) |
| 101 except errors.AuthorizationError: |
| 102 self._warnAboutAuthError() |
| 103 raise |
| 104 |
| 105 def GetIdentity(self): |
| 106 return '@'.join((self.__class__.__name__, StringIdentity(self._bucket))) |
| 107 |
| 108 def __repr__(self): |
| 109 return 'LocalFileSystem(%s)' % self._bucket |
| 110 |
| 111 def _warnAboutAuthError(self): |
| 112 logging.warn(('Authentication error on Cloud Storage. Check if your' |
| 113 ' appengine project has permissions to Read the GCS' |
| 114 ' buckets. If you are running a local appengine server,' |
| 115 ' you need to set an access_token in' |
| 116 ' local_debug/gcs_debug.conf.' |
| 117 ' Remember that this token expires in less than 10' |
| 118 ' minutes, so keep it updated. See' |
| 119 ' gcs_file_system_provider.py for instructions.')); |
| 120 logging.debug(traceback.format_exc()) |
| OLD | NEW |