lib/filesystem/page_tree.py
branchsites
changeset 34 09196d5b2a39
parent 33 19ea04f4b0cd
child 35 79ea0e2a6cc2
equal deleted inserted replaced
33:19ea04f4b0cd 34:09196d5b2a39
     1 """
       
     2     Implements the tree containing pages and their metadata
       
     3 """
       
     4 
       
     5 from lib import tree_parse
       
     6 
       
     7 class PageTreeError (Exception) :
       
     8     """
       
     9         Error parsing/loading the page tree
       
    10     """
       
    11 
       
    12     pass
       
    13 
       
    14 class PageInfo (object) :
       
    15     """
       
    16         Contains metainformation about a page
       
    17     """
       
    18 
       
    19     def __init__ (self, parent, name, title, children=None) :
       
    20         """
       
    21             Initialize, children defaults to empty list
       
    22         """
       
    23 
       
    24         # store
       
    25         self.parent = parent
       
    26         self.name = name
       
    27         self.title = title
       
    28         self.children = children if children else []
       
    29 
       
    30         # no url get
       
    31         self._url = None
       
    32     
       
    33     def set_parent (self, parent) :
       
    34         """
       
    35             Set a parent where non was set before
       
    36         """
       
    37 
       
    38         assert self.parent is None
       
    39 
       
    40         self.parent = parent
       
    41 
       
    42     def add_child (self, child) :
       
    43         """
       
    44             Add a PageInfo child
       
    45         """
       
    46 
       
    47         self.children.append(child)
       
    48     
       
    49     def get_child (self, name) :
       
    50         """
       
    51             Look up a child by name, returning None if not found
       
    52         """
       
    53 
       
    54         return dict((c.name, c) for c in self.children).get(name)
       
    55 
       
    56     def get_ancestry (self) :
       
    57         """
       
    58             Returns a list of this page's parents and the page itself, but not root
       
    59         """
       
    60         
       
    61         # collect in reverse order
       
    62         ancestry = []
       
    63         
       
    64         # starting from self
       
    65         item = self
       
    66         
       
    67         # add all items, but not root
       
    68         while item and item.parent :
       
    69             ancestry.append(item)
       
    70 
       
    71             item = item.parent
       
    72 
       
    73         # reverse
       
    74         ancestry.reverse()
       
    75         
       
    76         # done
       
    77         return ancestry
       
    78 
       
    79     @property
       
    80     def url (self) :
       
    81         """
       
    82             Build this page's URL
       
    83         """
       
    84 
       
    85         # cached?
       
    86         if self._url :
       
    87             return self._url
       
    88 
       
    89         segments = [item.name for item in self.get_ancestry()]
       
    90         
       
    91         # add empty segment if dir
       
    92         if self.children :
       
    93             segments.append('')
       
    94         
       
    95         # join
       
    96         url = '/'.join(segments)
       
    97         
       
    98         # cache
       
    99         self._url = url
       
   100         
       
   101         # done
       
   102         return url
       
   103 
       
   104 class PageTree (object) :
       
   105     """
       
   106         The tree of pages, rooted at .root.
       
   107 
       
   108         Use load_page_tree to initialize the global page_tree instance, and then use that
       
   109     """
       
   110 
       
   111     def __init__ (self, path) :
       
   112         """
       
   113             Loads the PageTree root from the given file
       
   114         """
       
   115         
       
   116         # store
       
   117         self.path = path
       
   118         
       
   119         # load
       
   120         self._load(path)
       
   121 
       
   122     def _load (self, path) :
       
   123         """
       
   124             Processes the lines in the given file
       
   125         """
       
   126         
       
   127         # parse tree
       
   128         tree = tree_parse.parse(path, ':')
       
   129 
       
   130         if not tree :
       
   131             raise PageTreeError("No root node found")
       
   132 
       
   133         def _create_node (parent, item) :
       
   134             """
       
   135                 Creates and returns a PageInfo from the given parent node and (line_number, line, children) tuple item
       
   136             """
       
   137 
       
   138             # unpack
       
   139             line_number, line, children = item
       
   140             
       
   141             # parse line
       
   142             url = title = None
       
   143             
       
   144             try :
       
   145                 url, title = line.split(':')
       
   146 
       
   147             except :
       
   148                 raise PageTreeError("Invalid line: %s:%d: %r" % (path, line_number, line))
       
   149 
       
   150             # remove whitespace
       
   151             url = url.strip()
       
   152             title = title.strip()
       
   153             
       
   154             # create PageInfo
       
   155             node = PageInfo(parent, url, title)
       
   156             
       
   157             # set node children
       
   158             node.children = [
       
   159                 _create_node(node, child_item) for child_item in children
       
   160             ]
       
   161 
       
   162             # return
       
   163             return node
       
   164         
       
   165         # translate
       
   166         self.root = _create_node(None, tree)
       
   167             
       
   168         # *evil cackle*
       
   169         self.root.children.insert(0, self.root)
       
   170         
       
   171     def get_page (self, url) :
       
   172         """
       
   173             Lookup the given page URL, and return the matching PageInfo object, or None, if not found
       
   174         """
       
   175         
       
   176         # start from root
       
   177         node = self.root
       
   178         
       
   179         # traverse the object tree
       
   180         for segment in url.split('/') :
       
   181             if segment :
       
   182                 node = node.get_child(segment)
       
   183 
       
   184             if not node :
       
   185                 return None
       
   186         
       
   187         # return
       
   188         return node
       
   189     
       
   190     def get_siblings (self, url) :
       
   191         """
       
   192             Get the list of siblings for the given url, including the given page itself
       
   193         """
       
   194         
       
   195         # look up the page itself
       
   196         page = self.get_page(url)
       
   197         
       
   198         # specialcase root/unknown node
       
   199         if page and page.parent :
       
   200             return page.parent.children
       
   201 
       
   202         else :
       
   203             return self.root.children
       
   204     
       
   205     def dump (self) :
       
   206         """
       
   207             Returns a string representation of the tree
       
   208         """
       
   209         
       
   210         def _print_node (indent, node) :
       
   211             return '\n'.join('%s%s' % (' '*indent, line) for line in [
       
   212                 "%-15s : %s" % (node.name, node.title)
       
   213             ] + [
       
   214                 _print_node(indent + 4, child) for child in node.children if child != node
       
   215             ])
       
   216 
       
   217         return _print_node(0, self.root)
       
   218