15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 6b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)import sys 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from docs_server_utils import StringIdentity 9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)from file_system import FileSystem, FileNotFoundError, StatInfo 10effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochfrom future import Future 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from path_util import AssertIsDirectory, AssertIsValid 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from test_util import ChromiumPath 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def _ConvertToFilepath(path): 16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return path.replace('/', os.sep) 17b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 19a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def _ConvertFromFilepath(path): 20a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return path.replace(os.sep, '/') 21a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)def _ReadFile(filename): 24a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) try: 25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) with open(filename, 'rb') as f: 26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return f.read() 27a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) except IOError as e: 28a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) raise FileNotFoundError('Read failed for %s: %s' % (filename, e)) 29a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 31a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def _ListDir(dir_name): 32a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) all_files = [] 33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) try: 34a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) files = os.listdir(dir_name) 35a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) except OSError as e: 36a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) raise FileNotFoundError('os.listdir failed for %s: %s' % (dir_name, e)) 37a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) for os_path in files: 38a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) posix_path = _ConvertFromFilepath(os_path) 39a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if os_path.startswith('.'): 40a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) continue 41a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if os.path.isdir(os.path.join(dir_name, os_path)): 42a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) all_files.append(posix_path + '/') 43a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) else: 44a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) all_files.append(posix_path) 45a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return all_files 46a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 48a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def _CreateStatInfo(path): 49a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) try: 50a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) path_mtime = os.stat(path).st_mtime 51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if os.path.isdir(path): 52a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) child_versions = dict((_ConvertFromFilepath(filename), 53a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) os.stat(os.path.join(path, filename)).st_mtime) 54a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) for filename in os.listdir(path)) 55a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) # This file system stat mimics subversion, where the stat of directories 56a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) # is max(file stats). That means we need to recursively check the whole 57a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) # file system tree :\ so approximate that by just checking this dir. 58a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) version = max([path_mtime] + child_versions.values()) 59a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) else: 60a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) child_versions = None 61a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) version = path_mtime 62a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return StatInfo(version, child_versions) 63a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) except OSError as e: 64a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) raise FileNotFoundError('os.stat failed for %s: %s' % (path, e)) 65a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class LocalFileSystem(FileSystem): 68b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) '''FileSystem implementation which fetches resources from the local 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filesystem. 70b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ''' 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, base_path): 72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) # Enforce POSIX path, so path validity checks pass for Windows. 73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) base_path = base_path.replace(os.sep, '/') 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AssertIsDirectory(base_path) 75b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self._base_path = _ConvertToFilepath(base_path) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) @staticmethod 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def Create(*path): 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return LocalFileSystem(ChromiumPath(*path)) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 81e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch def Read(self, paths, skip_not_found=False): 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def resolve(): 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result = {} 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for path in paths: 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AssertIsValid(path) 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) full_path = os.path.join(self._base_path, 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) _ConvertToFilepath(path).lstrip(os.sep)) 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if path == '' or path.endswith('/'): 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result[path] = _ListDir(full_path) 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else: 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result[path] = _ReadFile(full_path) 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return result 93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return Future(callback=resolve) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def Refresh(self): 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Future(value=()) 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def Stat(self, path): 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AssertIsValid(path) 100a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) full_path = os.path.join(self._base_path, 101a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) _ConvertToFilepath(path).lstrip(os.sep)) 102a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return _CreateStatInfo(full_path) 103b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 104b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def GetIdentity(self): 105b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return '@'.join((self.__class__.__name__, StringIdentity(self._base_path))) 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def __repr__(self): 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return 'LocalFileSystem(%s)' % self._base_path 109