]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - contrib/fuse/impl_b/pyfuse/r_svnfs.py
add Protovis.js-based download-status timeline visualization
[tahoe-lafs/tahoe-lafs.git] / contrib / fuse / impl_b / pyfuse / r_svnfs.py
1 """
2 A read-only svn fs showing all the revisions in subdirectories.
3 """
4 from objectfs import ObjectFs, SymLink
5 from handler import Handler
6 from pysvn.ra import connect
7 from pysvn.date import decode
8 import errno, posixpath, time
9
10
11 #USE_SYMLINKS = 0      # they are wrong if the original file had another path
12
13 # use  getfattr -d filename  to see the node's attributes, which include
14 # information like the revision at which the file was last modified
15
16
17 class Root:
18     def __init__(self, svnurl):
19         self.svnurl = svnurl
20         self.ra = connect(svnurl)
21         self.head = self.ra.get_latest_rev()
22
23     def listdir(self):
24         for rev in range(1, self.head+1):
25             yield str(rev)
26         yield 'HEAD'
27
28     def join(self, name):
29         try:
30             rev = int(name)
31         except ValueError:
32             if name == 'HEAD':
33                 return SymLink(str(self.head))
34             else:
35                 raise KeyError(name)
36         return TopLevelDir(self.ra, rev, rev, '')
37
38
39 class Node:
40     def __init__(self, ra, rev, last_changed_rev, path):
41         self.ra = ra
42         self.rev = rev
43         self.last_changed_rev = last_changed_rev
44         self.path = path
45
46     def __repr__(self):
47         return '<%s %d/%s>' % (self.__class__.__name__, self.rev, self.path)
48
49 class Dir(Node):
50     def listdir(self):
51         rev, props, entries = self.ra.get_dir(self.path, self.rev,
52                                               want_props = False)
53         for key, stats in entries.items():
54             yield key, getnode(self.ra, self.rev,
55                                posixpath.join(self.path, key), stats)
56
57 class File(Node):
58     def __init__(self, ra, rev, last_changed_rev, path, size):
59         Node.__init__(self, ra, rev, last_changed_rev, path)
60         self.filesize = size
61
62     def size(self):
63         return self.filesize
64
65     def read(self):
66         checksum, rev, props, data = self.ra.get_file(self.path, self.rev,
67                                                       want_props = False)
68         return data
69
70
71 class TopLevelDir(Dir):
72     def listdir(self):
73         for item in Dir.listdir(self):
74             yield item
75         yield 'svn:log', Log(self.ra, self.rev)
76
77 class Log:
78
79     def __init__(self, ra, rev):
80         self.ra = ra
81         self.rev = rev
82
83     def getlogentry(self):
84         try:
85             return self.logentry
86         except AttributeError:
87             logentries = self.ra.log('', startrev=self.rev, endrev=self.rev)
88             try:
89                 [self.logentry] = logentries
90             except ValueError:
91                 self.logentry = None
92             return self.logentry
93
94     def size(self):
95         return len(self.read())
96
97     def read(self):
98         logentry = self.getlogentry()
99         if logentry is None:
100             return 'r%d | (no change here)\n' % (self.rev,)
101         datetuple = time.gmtime(decode(logentry.date))
102         date = time.strftime("%c", datetuple)
103         return 'r%d | %s | %s\n\n%s' % (self.rev,
104                                         logentry.author,
105                                         date,
106                                         logentry.message)
107
108
109 if 0:
110     pass
111 ##if USE_SYMLINKS:
112 ##    def getnode(ra, rev, path, stats):
113 ##        committed_rev = stats['svn:entry:committed-rev']
114 ##        if committed_rev == rev:
115 ##            kind = stats['svn:entry:kind']
116 ##            if kind == 'file':
117 ##                return File(ra, rev, path, stats['svn:entry:size'])
118 ##            elif kind == 'dir':
119 ##                return Dir(ra, rev, path)
120 ##            else:
121 ##                raise IOError(errno.EINVAL, "kind %r" % (kind,))
122 ##        else:
123 ##            depth = path.count('/')
124 ##            return SymLink('../' * depth + '../%d/%s' % (committed_rev, path))
125 else:
126     def getnode(ra, rev, path, stats):
127         last_changed_rev = stats['svn:entry:committed-rev']
128         kind = stats['svn:entry:kind']
129         if kind == 'file':
130             return File(ra, rev, last_changed_rev, path,
131                         stats['svn:entry:size'])
132         elif kind == 'dir':
133             return Dir(ra, rev, last_changed_rev, path)
134         else:
135             raise IOError(errno.EINVAL, "kind %r" % (kind,))
136
137
138 if __name__ == '__main__':
139     import sys
140     svnurl, mountpoint = sys.argv[1:]
141     handler = Handler(mountpoint, ObjectFs(Root(svnurl)))
142     handler.loop_forever()