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