Home | History | Annotate | Download | only in server2
      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