diff -r 19ea04f4b0cd -r 09196d5b2a39 sites/www.qmsk.net/page_tree.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sites/www.qmsk.net/page_tree.py Sat Feb 07 17:10:06 2009 +0200 @@ -0,0 +1,218 @@ +""" + Implements the tree containing pages and their metadata +""" + +from lib import tree_parse + +class PageTreeError (Exception) : + """ + Error parsing/loading the page tree + """ + + pass + +class PageInfo (object) : + """ + Contains metainformation about a page + """ + + def __init__ (self, parent, name, title, children=None) : + """ + Initialize, children defaults to empty list + """ + + # store + self.parent = parent + self.name = name + self.title = title + self.children = children if children else [] + + # no url get + self._url = None + + def set_parent (self, parent) : + """ + Set a parent where non was set before + """ + + assert self.parent is None + + self.parent = parent + + def add_child (self, child) : + """ + Add a PageInfo child + """ + + self.children.append(child) + + def get_child (self, name) : + """ + Look up a child by name, returning None if not found + """ + + return dict((c.name, c) for c in self.children).get(name) + + def get_ancestry (self) : + """ + Returns a list of this page's parents and the page itself, but not root + """ + + # collect in reverse order + ancestry = [] + + # starting from self + item = self + + # add all items, but not root + while item and item.parent : + ancestry.append(item) + + item = item.parent + + # reverse + ancestry.reverse() + + # done + return ancestry + + @property + def url (self) : + """ + Build this page's URL + """ + + # cached? + if self._url : + return self._url + + segments = [item.name for item in self.get_ancestry()] + + # add empty segment if dir + if self.children : + segments.append('') + + # join + url = '/'.join(segments) + + # cache + self._url = url + + # done + return url + +class PageTree (object) : + """ + The tree of pages, rooted at .root. + + Use load_page_tree to initialize the global page_tree instance, and then use that + """ + + def __init__ (self, path) : + """ + Loads the PageTree root from the given file + """ + + # store + self.path = path + + # load + self._load(path) + + def _load (self, path) : + """ + Processes the lines in the given file + """ + + # parse tree + tree = tree_parse.parse(path, ':') + + if not tree : + raise PageTreeError("No root node found") + + def _create_node (parent, item) : + """ + Creates and returns a PageInfo from the given parent node and (line_number, line, children) tuple item + """ + + # unpack + line_number, line, children = item + + # parse line + url = title = None + + try : + url, title = line.split(':') + + except : + raise PageTreeError("Invalid line: %s:%d: %r" % (path, line_number, line)) + + # remove whitespace + url = url.strip() + title = title.strip() + + # create PageInfo + node = PageInfo(parent, url, title) + + # set node children + node.children = [ + _create_node(node, child_item) for child_item in children + ] + + # return + return node + + # translate + self.root = _create_node(None, tree) + + # *evil cackle* + self.root.children.insert(0, self.root) + + def get_page (self, url) : + """ + Lookup the given page URL, and return the matching PageInfo object, or None, if not found + """ + + # start from root + node = self.root + + # traverse the object tree + for segment in url.split('/') : + if segment : + node = node.get_child(segment) + + if not node : + return None + + # return + return node + + def get_siblings (self, url) : + """ + Get the list of siblings for the given url, including the given page itself + """ + + # look up the page itself + page = self.get_page(url) + + # specialcase root/unknown node + if page and page.parent : + return page.parent.children + + else : + return self.root.children + + def dump (self) : + """ + Returns a string representation of the tree + """ + + def _print_node (indent, node) : + return '\n'.join('%s%s' % (' '*indent, line) for line in [ + "%-15s : %s" % (node.name, node.title) + ] + [ + _print_node(indent + 4, child) for child in node.children if child != node + ]) + + return _print_node(0, self.root) +