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')
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):
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)
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))
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
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):
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()