Mercurial > wikked
annotate wikked/fs.py @ 124:6c261cb94631
Fixed wiki history page and API endpoint.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sat, 23 Nov 2013 13:35:37 -0800 |
parents | 827e236aa7c6 |
children | 72e5f588f989 |
rev | line source |
---|---|
0 | 1 import os |
2 import os.path | |
3 import re | |
4 import string | |
24
8a83b0e91633
The wiki `fs` only scans known file extensions.
Ludovic Chabant <ludovic@chabant.com>
parents:
18
diff
changeset
|
5 import codecs |
49 | 6 import logging |
124
6c261cb94631
Fixed wiki history page and API endpoint.
Ludovic Chabant <ludovic@chabant.com>
parents:
110
diff
changeset
|
7 from utils import PageNotFoundError, title_to_url, path_to_url |
0 | 8 |
9 | |
82
9afe4a1dbd1e
Refactoring of core wiki classes:
Ludovic Chabant <ludovic@chabant.com>
parents:
65
diff
changeset
|
10 class PageInfo(object): |
101
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
11 def __init__(self, url, path): |
82
9afe4a1dbd1e
Refactoring of core wiki classes:
Ludovic Chabant <ludovic@chabant.com>
parents:
65
diff
changeset
|
12 self.url = url |
9afe4a1dbd1e
Refactoring of core wiki classes:
Ludovic Chabant <ludovic@chabant.com>
parents:
65
diff
changeset
|
13 self.path = path |
101
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
14 self._content = None |
82
9afe4a1dbd1e
Refactoring of core wiki classes:
Ludovic Chabant <ludovic@chabant.com>
parents:
65
diff
changeset
|
15 |
9afe4a1dbd1e
Refactoring of core wiki classes:
Ludovic Chabant <ludovic@chabant.com>
parents:
65
diff
changeset
|
16 @property |
101
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
17 def content(self): |
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
18 if self._content is None: |
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
19 with codecs.open(self.path, 'r', encoding='utf-8') as f: |
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
20 self._content = f.read() |
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
21 return self._content |
82
9afe4a1dbd1e
Refactoring of core wiki classes:
Ludovic Chabant <ludovic@chabant.com>
parents:
65
diff
changeset
|
22 |
9afe4a1dbd1e
Refactoring of core wiki classes:
Ludovic Chabant <ludovic@chabant.com>
parents:
65
diff
changeset
|
23 |
0 | 24 class FileSystem(object): |
25 """ A class responsible for mapping page URLs to | |
26 file-system paths, and for scanning the file-system | |
27 to list existing pages. | |
28 """ | |
100
fd6eccb24882
Refactoring to get rid of `slugify` callbacks.
Ludovic Chabant <ludovic@chabant.com>
parents:
82
diff
changeset
|
29 def __init__(self, root, logger=None): |
35
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
30 self.root = unicode(root) |
49 | 31 |
32 if logger is None: | |
33 logger = logging.getLogger('wikked.fs') | |
34 self.logger = logger | |
35 | |
0 | 36 self.excluded = [] |
24
8a83b0e91633
The wiki `fs` only scans known file extensions.
Ludovic Chabant <ludovic@chabant.com>
parents:
18
diff
changeset
|
37 self.page_extensions = None |
0 | 38 |
3
59cad6ce1a1c
Added support for history and diffing.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
39 def getPageInfos(self, subdir=None): |
0 | 40 basepath = self.root |
41 if subdir is not None: | |
42 basepath = self.getPhysicalNamespacePath(subdir) | |
43 | |
44 for dirpath, dirnames, filenames in os.walk(basepath): | |
45 dirnames[:] = [d for d in dirnames if os.path.join(dirpath, d) not in self.excluded] | |
46 for filename in filenames: | |
47 path = os.path.join(dirpath, filename) | |
8
793234411100
Fixed Mercurial files incorrectly included as pages.
Ludovic Chabant <ludovic@chabant.com>
parents:
3
diff
changeset
|
48 if path in self.excluded: |
793234411100
Fixed Mercurial files incorrectly included as pages.
Ludovic Chabant <ludovic@chabant.com>
parents:
3
diff
changeset
|
49 continue |
18
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
50 page_info = self.getPageInfo(path) |
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
51 if page_info is not None: |
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
52 yield page_info |
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
53 |
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
54 def getPageInfo(self, path): |
35
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
55 if not isinstance(path, unicode): |
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
56 path = unicode(path) |
18
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
57 for e in self.excluded: |
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
58 if path.startswith(e): |
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
59 return None |
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
60 return self._getPageInfo(path) |
0 | 61 |
62 def getPage(self, url): | |
63 path = self.getPhysicalPagePath(url) | |
101
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
64 return PageInfo(url, path) |
0 | 65 |
101
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
66 def setPage(self, url, content): |
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
67 path = self.getPhysicalPagePath(url) |
49 | 68 with codecs.open(path, 'w', encoding='utf-8') as f: |
69 f.write(content) | |
101
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
70 return PageInfo(url, path) |
49 | 71 |
3
59cad6ce1a1c
Added support for history and diffing.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
72 def pageExists(self, url): |
59cad6ce1a1c
Added support for history and diffing.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
73 try: |
59cad6ce1a1c
Added support for history and diffing.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
74 self.getPhysicalPagePath(url) |
59cad6ce1a1c
Added support for history and diffing.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
75 return True |
59cad6ce1a1c
Added support for history and diffing.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
76 except PageNotFoundError: |
59cad6ce1a1c
Added support for history and diffing.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
77 return False |
59cad6ce1a1c
Added support for history and diffing.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
78 |
49 | 79 def getPhysicalPagePath(self, url): |
80 return self._getPhysicalPath(url, True) | |
81 | |
0 | 82 def getPhysicalNamespacePath(self, url): |
83 return self._getPhysicalPath(url, False) | |
84 | |
18
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
85 def _getPageInfo(self, path): |
35
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
86 rel_path = os.path.relpath(path, self.root) |
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
87 rel_path_split = os.path.splitext(rel_path) |
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
88 ext = rel_path_split[1].lstrip('.') |
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
89 name = rel_path_split[0] |
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
90 if len(ext) == 0: |
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
91 return None |
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
92 if self.page_extensions is not None and ext not in self.page_extensions: |
2b35d719f342
Handle wiki and page permissions for read/write access.
Ludovic Chabant <ludovic@chabant.com>
parents:
24
diff
changeset
|
93 return None |
65
c6dcf6716d26
Fixed slugification bug on Windows.
Ludovic Chabant <ludovic@chabant.com>
parents:
49
diff
changeset
|
94 |
124
6c261cb94631
Fixed wiki history page and API endpoint.
Ludovic Chabant <ludovic@chabant.com>
parents:
110
diff
changeset
|
95 url = path_to_url(unicode(name), strip_ext=True) |
101
13249e5ca51c
Big refactor for better database caching:
Ludovic Chabant <ludovic@chabant.com>
parents:
100
diff
changeset
|
96 return PageInfo(url, path) |
18
67c150d5ed53
Added ability to get a single page's info from the file-system.
Ludovic Chabant <ludovic@chabant.com>
parents:
8
diff
changeset
|
97 |
0 | 98 def _getPhysicalPath(self, url, is_file): |
110
827e236aa7c6
Various front-end fixes:
Ludovic Chabant <ludovic@chabant.com>
parents:
101
diff
changeset
|
99 if url[0] != '/': |
827e236aa7c6
Various front-end fixes:
Ludovic Chabant <ludovic@chabant.com>
parents:
101
diff
changeset
|
100 raise ValueError("Page URLs need to be absolute: " + url) |
0 | 101 if string.find(url, '..') >= 0: |
102 raise ValueError("Page URLs can't contain '..': " + url) | |
103 | |
104 # For each "part" in the given URL, find the first | |
105 # file-system entry that would get slugified to an | |
106 # equal string. | |
107 current = self.root | |
110
827e236aa7c6
Various front-end fixes:
Ludovic Chabant <ludovic@chabant.com>
parents:
101
diff
changeset
|
108 parts = unicode(url[1:]).lower().split('/') |
0 | 109 for i, part in enumerate(parts): |
110 names = os.listdir(current) | |
111 for name in names: | |
100
fd6eccb24882
Refactoring to get rid of `slugify` callbacks.
Ludovic Chabant <ludovic@chabant.com>
parents:
82
diff
changeset
|
112 name_formatted = title_to_url(name) |
0 | 113 if is_file and i == len(parts) - 1: |
114 # If we're looking for a file and this is the last part, | |
115 # look for something similar but with an extension. | |
49 | 116 if re.match(r"%s\.[a-z]+" % re.escape(part), name_formatted): |
0 | 117 current = os.path.join(current, name) |
118 break | |
119 else: | |
120 if name_formatted == part: | |
121 current = os.path.join(current, name) | |
122 break | |
123 else: | |
124 # Failed to find a part of the URL. | |
125 raise PageNotFoundError("No such page: " + url) | |
126 return current | |
110
827e236aa7c6
Various front-end fixes:
Ludovic Chabant <ludovic@chabant.com>
parents:
101
diff
changeset
|
127 |