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 3 # found in the LICENSE file. 4 5 import os 6 import sys 7 8 from docs_server_utils import StringIdentity 9 from file_system import FileSystem, FileNotFoundError, StatInfo, ToUnicode 10 from future import Future 11 12 def _ConvertToFilepath(path): 13 return path.replace('/', os.sep) 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 os.path.isdir(path): 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 63 class LocalFileSystem(FileSystem): 64 '''FileSystem implementation which fetches resources from the local 65 filesystem. 66 ''' 67 def __init__(self, base_path): 68 self._base_path = _ConvertToFilepath(base_path) 69 70 @staticmethod 71 def Create(): 72 return LocalFileSystem(os.path.join(sys.path[0], os.pardir, os.pardir)) 73 74 def Read(self, paths, binary=False): 75 result = {} 76 for path in paths: 77 full_path = os.path.join(self._base_path, 78 _ConvertToFilepath(path).lstrip(os.sep)) 79 if path.endswith('/'): 80 result[path] = _ListDir(full_path) 81 else: 82 result[path] = _ReadFile(full_path, binary) 83 return Future(value=result) 84 85 def Stat(self, path): 86 full_path = os.path.join(self._base_path, 87 _ConvertToFilepath(path).lstrip(os.sep)) 88 return _CreateStatInfo(full_path) 89 90 def GetIdentity(self): 91 return '@'.join((self.__class__.__name__, StringIdentity(self._base_path))) 92