| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 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 import os | 5 import os |
| 6 import sys | 6 import sys |
| 7 | 7 |
| 8 from docs_server_utils import StringIdentity | 8 from docs_server_utils import StringIdentity |
| 9 from file_system import FileSystem, FileNotFoundError, StatInfo, ToUnicode | 9 from file_system import FileSystem, FileNotFoundError, StatInfo, ToUnicode |
| 10 from future import Future | 10 from future import Future |
| 11 | 11 |
| 12 def _ConvertToFilepath(path): | 12 def _ConvertToFilepath(path): |
| 13 return path.replace('/', os.sep) | 13 return path.replace('/', os.sep) |
| 14 | 14 |
| 15 def _ConvertFromFilepath(path): |
| 16 return path.replace(os.sep, '/') |
| 17 |
| 18 def _ReadFile(filename, binary): |
| 19 try: |
| 20 mode = 'rb' if binary else 'r' |
| 21 with open(filename, mode) as f: |
| 22 contents = f.read() |
| 23 if binary: |
| 24 return contents |
| 25 return ToUnicode(contents) |
| 26 except IOError as e: |
| 27 raise FileNotFoundError('Read failed for %s: %s' % (filename, e)) |
| 28 |
| 29 def _ListDir(dir_name): |
| 30 all_files = [] |
| 31 try: |
| 32 files = os.listdir(dir_name) |
| 33 except OSError as e: |
| 34 raise FileNotFoundError('os.listdir failed for %s: %s' % (dir_name, e)) |
| 35 for os_path in files: |
| 36 posix_path = _ConvertFromFilepath(os_path) |
| 37 if os_path.startswith('.'): |
| 38 continue |
| 39 if os.path.isdir(os.path.join(dir_name, os_path)): |
| 40 all_files.append(posix_path + '/') |
| 41 else: |
| 42 all_files.append(posix_path) |
| 43 return all_files |
| 44 |
| 45 def _CreateStatInfo(path): |
| 46 try: |
| 47 path_mtime = os.stat(path).st_mtime |
| 48 if path.endswith('/'): |
| 49 child_versions = dict((_ConvertFromFilepath(filename), |
| 50 os.stat(os.path.join(path, filename)).st_mtime) |
| 51 for filename in os.listdir(path)) |
| 52 # This file system stat mimics subversion, where the stat of directories |
| 53 # is max(file stats). That means we need to recursively check the whole |
| 54 # file system tree :\ so approximate that by just checking this dir. |
| 55 version = max([path_mtime] + child_versions.values()) |
| 56 else: |
| 57 child_versions = None |
| 58 version = path_mtime |
| 59 return StatInfo(version, child_versions) |
| 60 except OSError as e: |
| 61 raise FileNotFoundError('os.stat failed for %s: %s' % (path, e)) |
| 62 |
| 15 class LocalFileSystem(FileSystem): | 63 class LocalFileSystem(FileSystem): |
| 16 '''FileSystem implementation which fetches resources from the local | 64 '''FileSystem implementation which fetches resources from the local |
| 17 filesystem. | 65 filesystem. |
| 18 ''' | 66 ''' |
| 19 def __init__(self, base_path): | 67 def __init__(self, base_path): |
| 20 self._base_path = _ConvertToFilepath(base_path) | 68 self._base_path = _ConvertToFilepath(base_path) |
| 21 | 69 |
| 22 @staticmethod | 70 @staticmethod |
| 23 def Create(): | 71 def Create(): |
| 24 return LocalFileSystem(os.path.join(sys.path[0], os.pardir, os.pardir)) | 72 return LocalFileSystem(os.path.join(sys.path[0], os.pardir, os.pardir)) |
| 25 | 73 |
| 26 def _ReadFile(self, filename, binary): | |
| 27 try: | |
| 28 mode = 'rb' if binary else 'r' | |
| 29 with open(os.path.join(self._base_path, filename), mode) as f: | |
| 30 contents = f.read() | |
| 31 if binary: | |
| 32 return contents | |
| 33 return ToUnicode(contents) | |
| 34 except IOError as e: | |
| 35 raise FileNotFoundError('Read failed for %s: %s' % (filename, e)) | |
| 36 | |
| 37 def _ListDir(self, dir_name): | |
| 38 all_files = [] | |
| 39 full_path = os.path.join(self._base_path, dir_name) | |
| 40 try: | |
| 41 files = os.listdir(full_path) | |
| 42 except OSError as e: | |
| 43 raise FileNotFoundError('os.listdir failed for %s: %s' % (dir_name, e)) | |
| 44 for path in files: | |
| 45 if path.startswith('.'): | |
| 46 continue | |
| 47 if os.path.isdir(os.path.join(full_path, path)): | |
| 48 all_files.append(path + '/') | |
| 49 else: | |
| 50 all_files.append(path) | |
| 51 return all_files | |
| 52 | |
| 53 def Read(self, paths, binary=False): | 74 def Read(self, paths, binary=False): |
| 54 result = {} | 75 result = {} |
| 55 for path in paths: | 76 for path in paths: |
| 77 full_path = os.path.join(self._base_path, |
| 78 _ConvertToFilepath(path).lstrip(os.sep)) |
| 56 if path.endswith('/'): | 79 if path.endswith('/'): |
| 57 result[path] = self._ListDir(_ConvertToFilepath(path)) | 80 result[path] = _ListDir(full_path) |
| 58 else: | 81 else: |
| 59 result[path] = self._ReadFile(_ConvertToFilepath(path), binary) | 82 result[path] = _ReadFile(full_path, binary) |
| 60 return Future(value=result) | 83 return Future(value=result) |
| 61 | 84 |
| 62 def _CreateStatInfo(self, path): | |
| 63 try: | |
| 64 path_mtime = os.stat(path).st_mtime | |
| 65 if path.endswith('/'): | |
| 66 child_versions = dict( | |
| 67 (filename, os.stat(os.path.join(path, filename)).st_mtime) | |
| 68 for filename in os.listdir(path)) | |
| 69 # This file system stat mimics subversion, where the stat of directories | |
| 70 # is max(file stats). That means we need to recursively check the whole | |
| 71 # file system tree :\ so approximate that by just checking this dir. | |
| 72 version = max([path_mtime] + child_versions.values()) | |
| 73 else: | |
| 74 child_versions = None | |
| 75 version = path_mtime | |
| 76 return StatInfo(version, child_versions) | |
| 77 except OSError as e: | |
| 78 raise FileNotFoundError('os.stat failed for %s: %s' % (path, e)) | |
| 79 | |
| 80 def Stat(self, path): | 85 def Stat(self, path): |
| 81 return self._CreateStatInfo(os.path.join(self._base_path, path)) | 86 full_path = os.path.join(self._base_path, |
| 87 _ConvertToFilepath(path).lstrip(os.sep)) |
| 88 return _CreateStatInfo(full_path) |
| 82 | 89 |
| 83 def GetIdentity(self): | 90 def GetIdentity(self): |
| 84 return '@'.join((self.__class__.__name__, StringIdentity(self._base_path))) | 91 return '@'.join((self.__class__.__name__, StringIdentity(self._base_path))) |
| OLD | NEW |