filesystem_mock.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. # Copyright (c) 2011 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. import errno
  5. import fnmatch
  6. import os
  7. import re
  8. import StringIO
  9. def _RaiseNotFound(path):
  10. raise IOError(errno.ENOENT, path, os.strerror(errno.ENOENT))
  11. class MockFileSystem(object):
  12. """Stripped-down version of WebKit's webkitpy.common.system.filesystem_mock
  13. Implements a filesystem-like interface on top of a dict of filenames ->
  14. file contents. A file content value of None indicates that the file should
  15. not exist (IOError will be raised if it is opened;
  16. reading from a missing key raises a KeyError, not an IOError."""
  17. def __init__(self, files=None):
  18. self.files = files or {}
  19. self.written_files = {}
  20. self._sep = '/'
  21. @property
  22. def sep(self):
  23. return self._sep
  24. def _split(self, path):
  25. return path.rsplit(self.sep, 1)
  26. def abspath(self, path):
  27. if path.endswith(self.sep):
  28. return path[:-1]
  29. return path
  30. def basename(self, path):
  31. if self.sep not in path:
  32. return ''
  33. return self._split(path)[-1] or self.sep
  34. def dirname(self, path):
  35. if self.sep not in path:
  36. return ''
  37. return self._split(path)[0] or self.sep
  38. def exists(self, path):
  39. return self.isfile(path) or self.isdir(path)
  40. def isabs(self, path):
  41. return path.startswith(self.sep)
  42. def isfile(self, path):
  43. return path in self.files and self.files[path] is not None
  44. def isdir(self, path):
  45. if path in self.files:
  46. return False
  47. if not path.endswith(self.sep):
  48. path += self.sep
  49. # We need to use a copy of the keys here in order to avoid switching
  50. # to a different thread and potentially modifying the dict in
  51. # mid-iteration.
  52. files = self.files.keys()[:]
  53. return any(f.startswith(path) for f in files)
  54. def join(self, *comps):
  55. # TODO: Might want tests for this and/or a better comment about how
  56. # it works.
  57. return re.sub(re.escape(os.path.sep), self.sep, os.path.join(*comps))
  58. def glob(self, path):
  59. return fnmatch.filter(self.files.keys(), path)
  60. def open_for_reading(self, path):
  61. return StringIO.StringIO(self.read_binary_file(path))
  62. def read_binary_file(self, path):
  63. # Intentionally raises KeyError if we don't recognize the path.
  64. if self.files[path] is None:
  65. _RaiseNotFound(path)
  66. return self.files[path]
  67. @staticmethod
  68. def relpath(path, base):
  69. # This implementation is wrong in many ways; assert to check them for now.
  70. assert path.startswith(base)
  71. assert base.endswith('/')
  72. return path[len(base):]