Move dirtag.xul and *.rdf generation into CherryPy.
[dirtag.git] / dirtag / __init__.py
index 406c2860225cd6cc8809bad24b04065bbe55aedf..cb69eeb9ef2c741f9774bfa4a9df8a21a2063031 100644 (file)
@@ -20,6 +20,24 @@ import os
 import os.path
 
 
+class Node (list):
+    def __init__(self, root, type, tags, *args, **kwargs):
+        list.__init__(self, *args, **kwargs)
+        self.root = root
+        self.type = type
+        self.tags = tags
+
+    def pre_extend(self, a):
+        """
+        >>> n = Node(None, None, None, ['a', 'b', 'c'])
+        >>> n.pre_extend([1, 2, 3])
+        >>> print n
+        [1, 2, 3, 'a', 'b', 'c']
+        """
+        for i,element in enumerate(a):
+            self.insert(i, element)
+
+
 class Tree (list):
     """
     >>> t = Tree('a')
@@ -36,25 +54,26 @@ class Tree (list):
     z|a|1
     z|a|1|A
     z|a|2
-    >>> print '\\n'.join(['|'.join(x) for x in t.traverse(depth=1)])
-    1
-    1|A
-    2
     """
-    def __init__(self, data=None, *args, **kwargs):
+    def __init__(self, data=None, root=None, *args, **kwargs):
         self.data = data
+        self.root = root
         list.__init__(self, *args, **kwargs)
 
-    def traverse(self, prefix=[], depth=0):
+    def traverse(self, prefix=[], depth=0, type='both', dirtag=None):
         p = prefix + [self.data]
-        if depth < len(p):
-            yield p[depth:]
+        if depth < len(p) and type in ['both', 'dirs']:
+            yield Node(self.root, 'dir', [], p[depth:])
         for child in self:
             if hasattr(child, 'traverse'):
-                for grandchild in child.traverse(p, depth=depth):
+                for grandchild in child.traverse(
+                    p, depth=depth, type=type, dirtag=dirtag):
                     yield grandchild
-            elif depth <= len(p):
-                yield (p + [child])[depth:]
+            elif depth <= len(p) and type in ['both', 'files']:
+                n = Node(self.root, 'file', [], (p + [child])[depth:])
+                if dirtag != None:
+                    n.tags = dirtag.node_tags(n)
+                yield n
 
 
 def dir_tree(root_dir):
@@ -70,6 +89,16 @@ def dir_tree(root_dir):
     x|y|b1.dat
     x|a2.dat
     x|b3.dat
+    >>> print '\\n'.join(['|'.join(x) for x in t.traverse(depth=1, type='files')])
+    1|a1.dat
+    1|b1.dat
+    x|y|b1.dat
+    x|a2.dat
+    x|b3.dat
+    >>> print '\\n'.join(['|'.join(x) for x in t.traverse(depth=1, type='dirs')])
+    1
+    x
+    x|y
     """
     if not os.path.exists(root_dir):
         raise ValueError(root_dir)
@@ -77,11 +106,11 @@ def dir_tree(root_dir):
     for dirpath,dirnames,filenames in os.walk(root_dir, followlinks=True):
         t = trees.get(
             dirpath,
-            Tree(os.path.basename(dirpath)))
+            Tree(os.path.basename(dirpath), root=root_dir))
         if dirpath == root_dir:
             root = t
         for d in sorted(dirnames):
-            t2 = Tree(d)
+            t2 = Tree(d, root=root_dir)
             trees[os.path.join(dirpath, d)] = t2
             t.append(t2)
         t.extend(sorted(filenames))
@@ -91,15 +120,18 @@ def dir_tree(root_dir):
 class Dirtag (object):
     """
     >>> d = Dirtag('test/raw', 'test/tag')
-    >>> print '\\n'.join(['|'.join(x) for x in d.elements()])
-    a
-    a|a1.dat
-    a|a2.dat
-    a|a3.dat
-    b
-    b|b1.dat
-    b|b2.dat
-    b|b3.dat
+    >>> print '\\n'.join(['\t'.join([x.type, x.root, '|'.join(x),
+    ...                              ','.join(['/'.join(t) for t in x.tags])])
+    ...                   for x in d.elements()]
+    ...                 )  # doctest: +NORMALIZE_WHITESPACE
+    dir       test/raw      a      
+    file      test/raw      a|a1.dat      1
+    file      test/raw      a|a2.dat      x
+    file      test/raw      a|a3.dat      
+    dir       test/raw      b      
+    file      test/raw      b|b1.dat      1,x/y
+    file      test/raw      b|b2.dat      
+    file      test/raw      b|b3.dat      x
     >>> print '\\n'.join(['|'.join(x) for x in d.elements(['x'])])
     x|y
     x|y|b1.dat
@@ -131,13 +163,14 @@ class Dirtag (object):
     def elements(self, tag=None):
         if tag == None:
             tag = []
-            nodes = dir_tree(self.raw_dir).traverse(depth=1)
+            nodes = dir_tree(self.raw_dir).traverse(depth=1, dirtag=self)
         else:
             p = [self.tag_dir]+tag
             nodes = dir_tree(os.path.join(*p)).traverse(
-                prefix=p[:-1], depth=len(p))
+                prefix=p[:-1], depth=len(p), dirtag=self)
         for node in nodes:
-            yield tag+node
+            node.pre_extend(tag)
+            yield node
 
     def tags(self, target):
         for node in dir_tree(self.tag_dir).traverse(depth=1):
@@ -170,6 +203,21 @@ class Dirtag (object):
         finally:
             os.chdir(cwd)
 
+    def raw_node(self, node):
+        """Return a node for the real file linked to by node.
+        """
+        if node.root == self.raw_dir:
+            return node
+        path = os.path.realpath(os.path.join(node.root, *node))
+        raw_path = os.path.relpath(path, self.raw_dir)
+        return raw_path.split(os.path.sep)
+
+    def node_tags(self, node):
+        """Return a list of tags for a particular node.
+        """
+        return self.tags(self.raw_node(node))
+
+
 if __name__ == '__main__':
     import doctest
     doctest.testmod()