allow loading module from working copy if osc is not installed
[opensuse:osc.git] / fuse / fuseosc
1 #!/usr/bin/python
2
3 # Copyright (c) 2008-2009 Pavol Rusnak <prusnak@suse.cz>
4 #
5 # Permission is hereby granted, free of charge, to any person
6 # obtaining a copy of this software and associated documentation
7 # files (the "Software"), to deal in the Software without
8 # restriction, including without limitation the rights to use,
9 # copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the
11 # Software is furnished to do so, subject to the following
12 # conditions:
13
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
16
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 # OTHER DEALINGS IN THE SOFTWARE.
25
26 import sys
27 import os
28 try:
29     import osc
30     import osc.conf
31     import osc.core
32 except:
33     # allow loading module from working copy if osc is not installed
34     sys.path.append(os.path.abspath(os.path.dirname(sys.argv[0]) + '/../osc'))
35     import osc
36     import osc.conf
37     import osc.core
38 import fuse
39 import stat
40 import errno
41 import tempfile
42
43 fuse.fuse_python_api = (0, 2)
44
45 projects = []
46 cache = {}
47
48 class EmptyStat(fuse.Stat):
49     def __init__(self):
50         self.st_mode = 0
51         self.st_ino = 0
52         self.st_dev = 0
53         self.st_nlink = 0
54         self.st_uid = 0
55         self.st_gid = 0
56         self.st_size = 0
57         self.st_atime = 0
58         self.st_mtime = 0
59         self.st_ctime = 0
60
61 class CacheEntry(object):
62     def __init__(self):
63         self.stat = None
64         self.handle = None
65         self.tmpname = None
66
67 class oscFS(fuse.Fuse):
68
69     def __init__(self, *args, **kw):
70         fuse.Fuse.__init__(self, *args, **kw)
71         print 'OK'
72
73     def getattr(self, path):
74         st = EmptyStat()
75         # path is project
76         if path == '/' or path in projects or len(filter(lambda x: x.startswith(path), projects)) > 0:
77             st.st_mode = stat.S_IFDIR | 0555
78             st.st_nlink = 2
79             return st
80         # path is package
81         if os.path.dirname(path) in projects:
82             st.st_mode = stat.S_IFDIR | 0555
83             st.st_nlink = 2
84             return st
85         # path is file
86         if cache.has_key(path):
87             return cache[path].stat
88         else:
89             return -errno.ENOENT
90
91     def readdir(self, path, offset):
92         yield fuse.Direntry('.')
93         yield fuse.Direntry('..')
94
95         if os.path.dirname(path) in projects: # path is package
96             prj = os.path.dirname(path).replace('/','')
97             pkg = os.path.basename(path)
98             for f in osc.core.meta_get_filelist(osc.conf.config['apiurl'], prj, pkg, verbose=True):
99                 st = EmptyStat()
100                 st.st_mode = stat.S_IFREG | 0444
101                 st.st_size = f.size
102                 st.st_atime = f.mtime
103                 st.st_ctime = f.mtime
104                 st.st_mtime = f.mtime
105                 cache[path + '/' + f.name] = CacheEntry()
106                 cache[path + '/' + f.name].stat = st
107                 yield fuse.Direntry(f.name)
108             return
109
110         if path in projects: # path is project
111             prj = path.replace('/','')
112             for p in osc.core.meta_get_packagelist(osc.conf.config['apiurl'], prj):
113                 yield fuse.Direntry(p)
114
115         else: # path is project structure
116             if (path != '/'):
117                 path += '/'
118             l = len(path)
119             for d in set( map(lambda x: x[l:].split('/')[0], filter(lambda x: x.startswith(path), projects) ) ) :
120                 yield fuse.Direntry(d)
121
122     def mythread ( self ):
123         print '*** mythread'
124         return -errno.ENOSYS
125
126     def chmod ( self, path, mode ):
127         print '*** chmod', path, oct(mode)
128         return -errno.ENOSYS
129
130     def chown ( self, path, uid, gid ):
131         print '*** chown', path, uid, gid
132         return -errno.ENOSYS
133
134     def fsync ( self, path, isFsyncFile ):
135         print '*** fsync', path, isFsyncFile
136         return -errno.ENOSYS
137
138     def link ( self, targetPath, linkPath ):
139         print '*** link', targetPath, linkPath
140         return -errno.ENOSYS
141
142     def mkdir ( self, path, mode ):
143         print '*** mkdir', path, oct(mode)
144         return -errno.ENOSYS
145
146     def mknod ( self, path, mode, dev ):
147         print '*** mknod', path, oct(mode), dev
148         return -errno.ENOSYS
149
150     def open ( self, path, flags ):
151         file = os.path.basename(path)
152         d = os.path.dirname(path)
153         pkg = os.path.basename(d)
154         prj = os.path.dirname(d).replace('/','')
155         if not cache.has_key(path):
156             return -errno.ENOENT
157         if cache[path].stat == None:
158             return -errno.ENOENT
159         tmp = tempfile.mktemp(prefix = 'oscfs_')
160         osc.core.get_source_file(osc.conf.config['apiurl'], prj, pkg, file, tmp)
161         cache[path].handle = open(tmp, 'r')
162         cache[path].tmpname = tmp
163
164     def read ( self, path, length, offset ):
165         if not cache.has_key(path):
166             return -errno.EACCES
167         f = cache[path].handle
168         f.seek(offset)
169         return f.read(length)
170
171     def readlink ( self, path ):
172         print '*** readlink', path
173         return -errno.ENOSYS
174
175     def release ( self, path, flags ):
176         if cache.has_key(path):
177             cache[path].handle.close()
178             cache[path].handle = None
179             os.unlink(f.cache[path].tmpname)
180             cache[path].tmpname = None
181
182     def rename ( self, oldPath, newPath ):
183         print '*** rename', oldPath, newPath
184         return -errno.ENOSYS
185
186     def rmdir ( self, path ):
187         print '*** rmdir', path
188         return -errno.ENOSYS
189
190     def statfs ( self ):
191         print '*** statfs'
192         return -errno.ENOSYS
193
194     def symlink ( self, targetPath, linkPath ):
195         print '*** symlink', targetPath, linkPath
196         return -errno.ENOSYS
197
198     def truncate ( self, path, size ):
199         print '*** truncate', path, size
200         return -errno.ENOSYS
201
202     def unlink ( self, path ):
203         print '*** unlink', path
204         return -errno.ENOSYS
205
206     def utime ( self, path, times ):
207         print '*** utime', path, times
208         return -errno.ENOSYS
209
210     def write ( self, path, buf, offset ):
211         print '*** write', path, buf, offset
212         return -errno.ENOSYS
213
214 def fill_projects():
215     try:
216         for prj in osc.core.meta_get_project_list(osc.conf.config['apiurl']):
217             projects.append( '/' + prj.replace(':', ':/') )
218     except:
219         print 'failed'
220         sys.exit(1)
221
222 if __name__ == '__main__':
223     print 'Loading config ...',
224     osc.conf.get_config()
225     print 'OK'
226     print 'Getting projects list ...',
227     fill_projects()
228     print 'OK'
229     print 'Starting FUSE ...',
230     oscfs = oscFS( version = '%prog ' + fuse.__version__, usage = '', dash_s_do = 'setsingle')
231     oscfs.flags = 0
232     oscfs.multithreaded = 0
233     oscfs.parse(values = oscfs, errex = 1)
234     oscfs.main()