2011-01-06 James Kozianski <koz@chromium.org>
[WebKit.git] / Tools / Scripts / webkitpy / common / system / filesystem_mock.py
1 # Copyright (C) 2009 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 #    * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 #    * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 #    * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 import errno
30 import os
31 import path
32 import re
33
34
35 class MockFileSystem(object):
36     def __init__(self, files=None):
37         """Initializes a "mock" filesystem that can be used to completely
38         stub out a filesystem.
39
40         Args:
41             files: a dict of filenames -> file contents. A file contents
42                 value of None is used to indicate that the file should
43                 not exist.
44         """
45         self.files = files or {}
46
47     def exists(self, path):
48         return self.isfile(path) or self.isdir(path)
49
50     def isfile(self, path):
51         return path in self.files and self.files[path] is not None
52
53     def isdir(self, path):
54         if path in self.files:
55             return False
56         if not path.endswith('/'):
57             path += '/'
58         return any(f.startswith(path) for f in self.files)
59
60     def join(self, *comps):
61         return re.sub(re.escape(os.path.sep), '/', os.path.join(*comps))
62
63     def listdir(self, path):
64         if not self.isdir(path):
65             raise OSError("%s is not a directory" % path)
66
67         if not path.endswith('/'):
68             path += '/'
69
70         dirs = []
71         files = []
72         for f in self.files:
73             if self.exists(f) and f.startswith(path):
74                 remaining = f[len(path):]
75                 if '/' in remaining:
76                     dir = remaining[:remaining.index('/')]
77                     if not dir in dirs:
78                         dirs.append(dir)
79                 else:
80                     files.append(remaining)
81         return dirs + files
82
83     def maybe_make_directory(self, *path):
84         # FIXME: Implement such that subsequent calls to isdir() work?
85         pass
86
87     def read_text_file(self, path):
88         return self.read_binary_file(path)
89
90     def read_binary_file(self, path):
91         if path in self.files:
92             if self.files[path] is None:
93                 raise IOError(errno.ENOENT, path, os.strerror(errno.ENOENT))
94             return self.files[path]
95
96     def write_text_file(self, path, contents):
97         return self.write_binary_file(path, contents)
98
99     def write_binary_file(self, path, contents):
100         self.files[path] = contents
101
102     def copyfile(self, source, destination):
103         if not self.exists(source):
104             raise IOError(errno.ENOENT, source, os.strerror(errno.ENOENT))
105         if self.isdir(source):
106             raise IOError(errno.EISDIR, source, os.strerror(errno.ISDIR))
107         if self.isdir(destination):
108             raise IOError(errno.EISDIR, destination, os.strerror(errno.ISDIR))
109
110         self.files[destination] = self.files[source]
111
112     def files_under(self, path):
113         if not path.endswith('/'):
114             path += '/'
115         return [file for file in self.files if file.startswith(path)]
116
117     def remove(self, path):
118         del self.files[path]