49
|
1 import re
|
|
2 import os.path
|
|
3 import types
|
|
4 import codecs
|
|
5 import logging
|
|
6 import StringIO
|
|
7 from wikked.page import Page
|
|
8 from wikked.fs import PageNotFoundError
|
|
9 from wikked.db import Database
|
|
10 from wikked.indexer import WikiIndex
|
|
11 from wikked.scm import SourceControl
|
|
12
|
|
13
|
|
14 class MockWikiParameters(object):
|
|
15 def __init__(self):
|
|
16 self.formatters = {
|
|
17 self._passthrough: ['txt', 'html']
|
|
18 }
|
|
19
|
|
20 self.config_text = ""
|
|
21 self.special_filenames = []
|
|
22
|
|
23 self.logger_factory = lambda: logging.getLogger('wikked.tests')
|
|
24 self.page_factory = lambda wiki, url: MockPage(wiki, url)
|
|
25 self.config_factory = lambda: StringIO.StringIO(self.config_text)
|
|
26 self.fs_factory = lambda cfg: MockFileSystem()
|
|
27 self.index_factory = lambda cfg: MockWikiIndex()
|
|
28 self.db_factory = lambda cfg: MockDatabase()
|
|
29 self.scm_factory = lambda cfg: MockSourceControl()
|
|
30
|
|
31 def getSpecialFilenames(self):
|
|
32 return self.special_filenames
|
|
33
|
|
34 def _passthrough(self, text):
|
|
35 return text
|
|
36
|
|
37
|
|
38 class MockPage(Page):
|
|
39 def __init__(self, wiki, url):
|
|
40 Page.__init__(self, wiki, url)
|
|
41
|
|
42
|
|
43 class MockDatabase(Database):
|
|
44 def __init__(self, content=None, logger=None):
|
|
45 Database.__init__(self, logger)
|
|
46 self.content = content
|
|
47 self._open_count = 0
|
|
48
|
|
49 def initDb(self):
|
|
50 pass
|
|
51
|
|
52 def open(self):
|
|
53 self._open_count += 1
|
|
54
|
|
55 def close(self):
|
|
56 self._open_count -= 1
|
|
57 if self._open_count < 0:
|
|
58 raise Exception(
|
|
59 "The database was closed more times than it was open.")
|
|
60
|
|
61 def reset(self, pages):
|
|
62 pass
|
|
63
|
|
64 def update(self, pages):
|
|
65 pass
|
|
66
|
|
67 def getPageUrls(self, subdir=None):
|
|
68 return []
|
|
69
|
|
70 def getPages(self, subdir=None):
|
|
71 return []
|
|
72
|
|
73 def getPage(self, url):
|
|
74 return None
|
|
75
|
|
76 def pageExists(self, url):
|
|
77 return False
|
|
78
|
|
79 def getLinksTo(self, url):
|
|
80 return []
|
|
81
|
|
82
|
|
83 class MockFileSystem():
|
|
84 def __init__(self, structure=None, slugify=Page.title_to_url, logger=None):
|
|
85 if not structure:
|
|
86 structure = []
|
|
87 if not slugify:
|
|
88 slugify = lambda x: x
|
|
89 self.structure = structure
|
|
90 self.slugify = slugify
|
|
91 self.logger = logger
|
|
92 self.excluded = []
|
|
93
|
|
94 def getPageInfos(self, subdir=None):
|
|
95 node = self._getNode(subdir)
|
|
96 for n in self._getChildren(node):
|
|
97 yield self._getPageInfo(n)
|
|
98
|
|
99 def getPageInfo(self, path):
|
|
100 node = self._getNode(path)
|
|
101 return self._getPageInfo(node)
|
|
102
|
|
103 def getPage(self, url):
|
|
104 path = self._getPath(url, True)
|
|
105 node = self._getNode(path)
|
|
106 return self._getPageInfo(node, True)
|
|
107
|
|
108 def setPage(self, path, content):
|
|
109 pass
|
|
110
|
|
111 def pageExists(self, url):
|
|
112 return False
|
|
113
|
|
114 def getPhysicalNamespacePath(self, url):
|
|
115 return None
|
|
116
|
|
117 def _getPageInfo(self, node, with_content=False):
|
|
118 path_split = os.path.splitext(node['path'])
|
|
119 url = self.slugify(path_split[0])
|
|
120 info = {
|
|
121 'url': url,
|
|
122 'path': node['path']
|
|
123 }
|
|
124 if with_content:
|
|
125 info['content'] = node['content']
|
|
126 return info
|
|
127
|
|
128 def _getNode(self, path):
|
|
129 node = self.structure
|
|
130 if path:
|
|
131 for n in path.split('/'):
|
|
132 node = node[n]
|
|
133 else:
|
|
134 path = ''
|
|
135 if isinstance(node, types.StringTypes):
|
|
136 return {'type': 'file', 'path': path, 'content': node}
|
|
137 return {'type': 'dir', 'path': path, 'content': node}
|
|
138
|
|
139 def _getChildren(self, node):
|
|
140 if node['type'] != 'dir':
|
|
141 raise Exception("'%s' is not a directory." % node['path'])
|
|
142 for name in node['content']:
|
|
143 child_path = os.path.join(node['path'], name)
|
|
144 child = node['content'][name]
|
|
145 if isinstance(child, types.StringTypes):
|
|
146 yield {
|
|
147 'type': 'file',
|
|
148 'path': child_path,
|
|
149 'content': child
|
|
150 }
|
|
151 else:
|
|
152 for c in self._getChildren({
|
|
153 'type': 'dir',
|
|
154 'path': child_path,
|
|
155 'content': child
|
|
156 }):
|
|
157 yield c
|
|
158
|
|
159 def _getPath(self, url, is_file):
|
|
160 path = ''
|
|
161 current = self.structure
|
|
162 parts = unicode(url).lower().split('/')
|
|
163 for i, part in enumerate(parts):
|
|
164 for name in current:
|
|
165 name_slug = self.slugify(name)
|
|
166 if is_file and i == len(parts) - 1:
|
|
167 if re.match(r"%s\.[a-z]+" % re.escape(part), name_slug):
|
|
168 current = current[name]
|
|
169 path = os.path.join(path, name)
|
|
170 break
|
|
171 else:
|
|
172 if name_slug == part:
|
|
173 current = current[name]
|
|
174 path = os.path.join(path, name)
|
|
175 break
|
|
176 else:
|
|
177 # Failed to find a part of the URL.
|
|
178 raise PageNotFoundError("No such page: " + url)
|
|
179 return path
|
|
180
|
|
181 @staticmethod
|
|
182 def save_structure(path, structure):
|
|
183 if not os.path.isdir(path):
|
|
184 os.makedirs(path)
|
|
185 for node in structure:
|
|
186 node_path = os.path.join(path, node)
|
|
187 if isinstance(structure[node], types.StringTypes):
|
|
188 with codecs.open(node_path, 'w', encoding='utf-8') as f:
|
|
189 f.write(structure[node])
|
|
190 else:
|
|
191 MockFileSystem.save_structure(node_path, structure[node])
|
|
192
|
|
193
|
|
194 class MockWikiIndex(WikiIndex):
|
|
195 def __init__(self, logger=None):
|
|
196 WikiIndex.__init__(self, logger)
|
|
197
|
|
198 def initIndex(self):
|
|
199 pass
|
|
200
|
|
201 def reset(self, pages):
|
|
202 pass
|
|
203
|
|
204 def update(self, pages):
|
|
205 pass
|
|
206
|
|
207 def search(self, query):
|
|
208 # url, title, content_highlights
|
|
209 return None
|
|
210
|
|
211
|
|
212 class MockSourceControl(SourceControl):
|
|
213 def __init__(self, logger=None):
|
|
214 SourceControl.__init__(self, logger)
|
|
215
|
|
216 def initRepo(self):
|
|
217 pass
|
|
218
|
|
219 def getSpecialFilenames(self):
|
|
220 return []
|
|
221
|
|
222 def getHistory(self, path=None):
|
|
223 return []
|
|
224
|
|
225 def getState(self, path):
|
|
226 raise NotImplementedError()
|
|
227
|
|
228 def getRevision(self, path, rev):
|
|
229 raise NotImplementedError()
|
|
230
|
|
231 def diff(self, path, rev1, rev2):
|
|
232 raise NotImplementedError()
|
|
233
|
|
234 def commit(self, paths, op_meta):
|
|
235 raise NotImplementedError()
|
|
236
|
|
237 def revert(self, paths=None):
|
|
238 raise NotImplementedError()
|