OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 from third_party.cloudstorage import cloudstorage_api | 5 from third_party.cloudstorage import cloudstorage_api |
6 from third_party.cloudstorage import common | 6 from third_party.cloudstorage import common |
7 from third_party.cloudstorage import errors | 7 from third_party.cloudstorage import errors |
8 | 8 |
9 from docs_server_utils import StringIdentity | 9 from docs_server_utils import StringIdentity |
10 from file_system import FileSystem, FileNotFoundError, StatInfo | 10 from file_system import FileSystem, FileNotFoundError, StatInfo |
11 from future import Gettable, Future | 11 from future import Gettable, Future |
12 | 12 |
13 import logging | 13 import logging |
14 import traceback | 14 import traceback |
15 | 15 |
| 16 # Name of the file containing the Git hash of the latest commit sync'ed |
| 17 # to Cloud Storage. This file is generated by the Github->GCS sync script |
| 18 LAST_COMMIT_HASH_FILENAME='.__lastcommit.txt' |
| 19 |
16 '''See gcs_file_system_provider.py for documentation on using Google Cloud | 20 '''See gcs_file_system_provider.py for documentation on using Google Cloud |
17 Storage as a filesystem. | 21 Storage as a filesystem. |
18 ''' | 22 ''' |
19 def _ReadFile(filename): | 23 def _ReadFile(filename): |
20 try: | 24 try: |
21 with cloudstorage_api.open(filename, 'r') as f: | 25 with cloudstorage_api.open(filename, 'r') as f: |
22 return f.read() | 26 return f.read() |
23 except errors.Error: | 27 except errors.Error: |
24 raise FileNotFoundError('Read failed for %s: %s' % (filename, | 28 raise FileNotFoundError('Read failed for %s: %s' % (filename, |
25 traceback.format_exc())) | 29 traceback.format_exc())) |
26 | 30 |
27 def _ListDir(dir_name): | 31 def _ListDir(dir_name): |
28 try: | 32 try: |
29 files = cloudstorage_api.listbucket(dir_name) | 33 files = cloudstorage_api.listbucket(dir_name) |
30 return [os_path.filename for os_path in files] | 34 return [os_path.filename for os_path in files] |
31 except errors.Error: | 35 except errors.Error: |
32 raise FileNotFoundError('cloudstorage.listbucket failed for %s: %s' % | 36 raise FileNotFoundError('cloudstorage.listbucket failed for %s: %s' % |
33 (dir_name, traceback.format_exc())) | 37 (dir_name, traceback.format_exc())) |
34 | 38 |
35 def _CreateStatInfo(bucket, path): | 39 def _CreateStatInfo(bucket, path): |
36 bucket = '/%s' % bucket | 40 bucket = '/%s' % bucket |
37 full_path = '/'.join( (bucket, path.lstrip('/')) ) | 41 full_path = '/'.join( (bucket, path.lstrip('/')) ) |
| 42 last_commit_file = '%s/%s' % (bucket, LAST_COMMIT_HASH_FILENAME) |
38 try: | 43 try: |
| 44 last_commit = _ReadFile(last_commit_file) |
39 if full_path.endswith('/'): | 45 if full_path.endswith('/'): |
40 child_versions = dict() | 46 child_versions = dict() |
41 version = 0 | |
42 # Fetching stats for all files under full_path, recursively. The | 47 # Fetching stats for all files under full_path, recursively. The |
43 # listbucket method uses a prefix approach to simulate hierarchy, | 48 # listbucket method uses a prefix approach to simulate hierarchy, |
44 # but calling it without the "delimiter" argument searches for prefix, | 49 # but calling it without the "delimiter" argument searches for prefix, |
45 # which means, for directories, everything beneath it. | 50 # which means, for directories, everything beneath it. |
46 for _file in cloudstorage_api.listbucket(full_path): | 51 for _file in cloudstorage_api.listbucket(full_path): |
47 if not _file.is_dir: | 52 filename = _file.filename[len(full_path):] |
48 # GCS doesn't have metadata for dirs | 53 child_versions[filename] = last_commit |
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 else: |
54 child_versions = None | 55 child_versions = None |
55 version = cloudstorage_api.stat(full_path).st_ctime | 56 return StatInfo(last_commit, child_versions) |
56 return StatInfo(version, child_versions) | |
57 except (TypeError, errors.Error): | 57 except (TypeError, errors.Error): |
58 raise FileNotFoundError('cloudstorage.stat failed for %s: %s' % (path, | 58 raise FileNotFoundError('cloudstorage.stat failed for %s: %s' % (path, |
59 traceback.format_exc())) | 59 traceback.format_exc())) |
60 | 60 |
61 | |
62 class CloudStorageFileSystem(FileSystem): | 61 class CloudStorageFileSystem(FileSystem): |
63 '''FileSystem implementation which fetches resources from Google Cloud | 62 '''FileSystem implementation which fetches resources from Google Cloud |
64 Storage. | 63 Storage. |
65 ''' | 64 ''' |
66 def __init__(self, bucket, debug_access_token=None, debug_bucket_prefix=None): | 65 def __init__(self, bucket, debug_access_token=None, debug_bucket_prefix=None): |
67 self._bucket = bucket | 66 self._bucket = bucket |
68 if debug_access_token: | 67 if debug_access_token: |
69 logging.debug('gcs: using debug access token: %s' % debug_access_token) | 68 logging.debug('gcs: using debug access token: %s' % debug_access_token) |
70 common.set_access_token(debug_access_token) | 69 common.set_access_token(debug_access_token) |
71 if debug_bucket_prefix: | 70 if debug_bucket_prefix: |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 def _warnAboutAuthError(self): | 110 def _warnAboutAuthError(self): |
112 logging.warn(('Authentication error on Cloud Storage. Check if your' | 111 logging.warn(('Authentication error on Cloud Storage. Check if your' |
113 ' appengine project has permissions to Read the GCS' | 112 ' appengine project has permissions to Read the GCS' |
114 ' buckets. If you are running a local appengine server,' | 113 ' buckets. If you are running a local appengine server,' |
115 ' you need to set an access_token in' | 114 ' you need to set an access_token in' |
116 ' local_debug/gcs_debug.conf.' | 115 ' local_debug/gcs_debug.conf.' |
117 ' Remember that this token expires in less than 10' | 116 ' Remember that this token expires in less than 10' |
118 ' minutes, so keep it updated. See' | 117 ' minutes, so keep it updated. See' |
119 ' gcs_file_system_provider.py for instructions.')); | 118 ' gcs_file_system_provider.py for instructions.')); |
120 logging.debug(traceback.format_exc()) | 119 logging.debug(traceback.format_exc()) |
OLD | NEW |