fuseosc: reworked file cache
[opensuse:osc.git] / fuse / fuseosc
1 #!/usr/bin/python
2
3 import osc
4 import osc.conf
5 import osc.core
6 import sys
7 import fuse
8 from fuse import Fuse
9 import stat
10 import os
11 import errno
12 import tempfile
13
14 fuse.fuse_python_api = (0, 2)
15
16 projects = []
17 cache = {}
18
19 class EmptyStat(fuse.Stat):
20     def __init__(self):
21         self.st_mode = 0
22         self.st_ino = 0
23         self.st_dev = 0
24         self.st_nlink = 0
25         self.st_uid = 0
26         self.st_gid = 0
27         self.st_size = 0
28         self.st_atime = 0
29         self.st_mtime = 0
30         self.st_ctime = 0
31
32 class CacheEntry(object):
33     def __init__(self):
34         self.stat = None
35         self.handle = None
36         self.tmpname = None
37
38 class oscFS(Fuse):
39
40     def __init__(self, *args, **kw):
41         Fuse.__init__(self, *args, **kw)
42         print 'OK'
43
44     def getattr(self, path):
45         st = EmptyStat()
46         # path is project
47         if path == '/' or path in projects or len(filter(lambda x: x.startswith(path), projects)) > 0:
48             st.st_mode = stat.S_IFDIR | 0555
49             st.st_nlink = 2
50             return st
51         # path is package
52         if os.path.dirname(path) in projects:
53             st.st_mode = stat.S_IFDIR | 0555
54             st.st_nlink = 2
55             return st
56         # path is file
57         if cache.has_key(path):
58             return cache[path].stat
59         else:
60             return -errno.ENOENT
61
62     def readdir(self, path, offset):
63         yield fuse.Direntry('.')
64         yield fuse.Direntry('..')
65
66         if os.path.dirname(path) in projects: # path is package
67             prj = os.path.dirname(path).replace('/','')
68             pkg = os.path.basename(path)
69             for f in osc.core.meta_get_filelist(osc.conf.config['apiurl'], prj, pkg, verbose=True):
70                 st = EmptyStat()
71                 st.st_mode = stat.S_IFREG | 0444
72                 st.st_size = f.size
73                 st.st_atime = f.mtime
74                 st.st_ctime = f.mtime
75                 st.st_mtime = f.mtime
76                 cache[path + '/' + f.name] = CacheEntry()
77                 cache[path + '/' + f.name].stat = st
78                 yield fuse.Direntry(f.name)
79             return
80
81         if path in projects: # path is project
82             prj = path.replace('/','')
83             for p in osc.core.meta_get_packagelist(osc.conf.config['apiurl'], prj):
84                 yield fuse.Direntry(p)
85
86         else: # path is project structure
87             if (path != '/'):
88                 path += '/'
89             l = len(path)
90             for d in set( map(lambda x: x[l:].split('/')[0], filter(lambda x: x.startswith(path), projects) ) ) :
91                 yield fuse.Direntry(d)
92
93     def mythread ( self ):
94         print '*** mythread'
95         return -errno.ENOSYS
96
97     def chmod ( self, path, mode ):
98         print '*** chmod', path, oct(mode)
99         return -errno.ENOSYS
100
101     def chown ( self, path, uid, gid ):
102         print '*** chown', path, uid, gid
103         return -errno.ENOSYS
104
105     def fsync ( self, path, isFsyncFile ):
106         print '*** fsync', path, isFsyncFile
107         return -errno.ENOSYS
108
109     def link ( self, targetPath, linkPath ):
110         print '*** link', targetPath, linkPath
111         return -errno.ENOSYS
112
113     def mkdir ( self, path, mode ):
114         print '*** mkdir', path, oct(mode)
115         return -errno.ENOSYS
116
117     def mknod ( self, path, mode, dev ):
118         print '*** mknod', path, oct(mode), dev
119         return -errno.ENOSYS
120
121     def open ( self, path, flags ):
122         file = os.path.basename(path)
123         d = os.path.dirname(path)
124         pkg = os.path.basename(d)
125         prj = os.path.dirname(d).replace('/','')
126         if not cache.has_key(path):
127             return -errno.ENOENT
128         if cache[path].stat == None:
129             return -errno.ENOENT
130         tmp = tempfile.mktemp(prefix = 'oscfs_')
131         osc.core.get_source_file(osc.conf.config['apiurl'], prj, pkg, file, tmp)
132         cache[path].handle = open(tmp, 'r')
133         cache[path].tmpname = tmp
134
135     def read ( self, path, length, offset ):
136         if not cache.has_key(path):
137             return -errno.EACCES
138         f = cache[path].handle
139         f.seek(offset)
140         return f.read(length)
141
142     def readlink ( self, path ):
143         print '*** readlink', path
144         return -errno.ENOSYS
145
146     def release ( self, path, flags ):
147         if cache.has_key(path):
148             cache[path].handle.close()
149             cache[path].handle = None
150             os.unlink(f.cache[path].tmpname)
151             cache[path].tmpname = None
152
153     def rename ( self, oldPath, newPath ):
154         print '*** rename', oldPath, newPath
155         return -errno.ENOSYS
156
157     def rmdir ( self, path ):
158         print '*** rmdir', path
159         return -errno.ENOSYS
160
161     def statfs ( self ):
162         print '*** statfs'
163         return -errno.ENOSYS
164
165     def symlink ( self, targetPath, linkPath ):
166         print '*** symlink', targetPath, linkPath
167         return -errno.ENOSYS
168
169     def truncate ( self, path, size ):
170         print '*** truncate', path, size
171         return -errno.ENOSYS
172
173     def unlink ( self, path ):
174         print '*** unlink', path
175         return -errno.ENOSYS
176
177     def utime ( self, path, times ):
178         print '*** utime', path, times
179         return -errno.ENOSYS
180
181     def write ( self, path, buf, offset ):
182         print '*** write', path, buf, offset
183         return -errno.ENOSYS
184
185 def fill_projects():
186     for prj in osc.core.meta_get_project_list(osc.conf.config['apiurl']):
187         projects.append( '/' + prj.replace(':', ':/') )
188
189 if __name__ == '__main__':
190     print 'Loading config ...',
191     osc.conf.get_config()
192     print 'OK'
193     print 'Getting projects list ...',
194     fill_projects()
195     print 'OK'
196     print 'Starting FUSE ...',
197     oscfs = oscFS( version = '%prog ' + fuse.__version__, usage = '', dash_s_do = 'setsingle')
198     oscfs.flags = 0
199     oscfs.multithreaded = 0
200     oscfs.parse(values = oscfs, errex = 1)
201     oscfs.main()