#!/usr/bin/python # Copyright (c) 2008-2009 Pavol Rusnak # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. import sys import os try: import osc import osc.conf import osc.core except: # allow loading module from working copy if osc is not installed sys.path.append(os.path.abspath(os.path.dirname(sys.argv[0]) + '/../osc')) import osc import osc.conf import osc.core import fuse import stat import errno import tempfile fuse.fuse_python_api = (0, 2) projects = [] cache = {} class EmptyStat(fuse.Stat): def __init__(self): self.st_mode = 0 self.st_ino = 0 self.st_dev = 0 self.st_nlink = 0 self.st_uid = 0 self.st_gid = 0 self.st_size = 0 self.st_atime = 0 self.st_mtime = 0 self.st_ctime = 0 class CacheEntry(object): def __init__(self): self.stat = None self.handle = None self.tmpname = None class oscFS(fuse.Fuse): def __init__(self, *args, **kw): fuse.Fuse.__init__(self, *args, **kw) print 'OK' def getattr(self, path): st = EmptyStat() # path is project if path == '/' or path in projects or len(filter(lambda x: x.startswith(path), projects)) > 0: st.st_mode = stat.S_IFDIR | 0555 st.st_nlink = 2 return st # path is package if os.path.dirname(path) in projects: st.st_mode = stat.S_IFDIR | 0555 st.st_nlink = 2 return st # path is file if cache.has_key(path): return cache[path].stat else: return -errno.ENOENT def readdir(self, path, offset): yield fuse.Direntry('.') yield fuse.Direntry('..') if os.path.dirname(path) in projects: # path is package prj = os.path.dirname(path).replace('/','') pkg = os.path.basename(path) for f in osc.core.meta_get_filelist(osc.conf.config['apiurl'], prj, pkg, verbose=True): st = EmptyStat() st.st_mode = stat.S_IFREG | 0444 st.st_size = f.size st.st_atime = f.mtime st.st_ctime = f.mtime st.st_mtime = f.mtime cache[path + '/' + f.name] = CacheEntry() cache[path + '/' + f.name].stat = st yield fuse.Direntry(f.name) return if path in projects: # path is project prj = path.replace('/','') for p in osc.core.meta_get_packagelist(osc.conf.config['apiurl'], prj): yield fuse.Direntry(p) else: # path is project structure if (path != '/'): path += '/' l = len(path) for d in set( map(lambda x: x[l:].split('/')[0], filter(lambda x: x.startswith(path), projects) ) ) : yield fuse.Direntry(d) def mythread ( self ): print '*** mythread' return -errno.ENOSYS def chmod ( self, path, mode ): print '*** chmod', path, oct(mode) return -errno.ENOSYS def chown ( self, path, uid, gid ): print '*** chown', path, uid, gid return -errno.ENOSYS def fsync ( self, path, isFsyncFile ): print '*** fsync', path, isFsyncFile return -errno.ENOSYS def link ( self, targetPath, linkPath ): print '*** link', targetPath, linkPath return -errno.ENOSYS def mkdir ( self, path, mode ): print '*** mkdir', path, oct(mode) return -errno.ENOSYS def mknod ( self, path, mode, dev ): print '*** mknod', path, oct(mode), dev return -errno.ENOSYS def open ( self, path, flags ): file = os.path.basename(path) d = os.path.dirname(path) pkg = os.path.basename(d) prj = os.path.dirname(d).replace('/','') if not cache.has_key(path): return -errno.ENOENT if cache[path].stat == None: return -errno.ENOENT tmp = tempfile.mktemp(prefix = 'oscfs_') osc.core.get_source_file(osc.conf.config['apiurl'], prj, pkg, file, tmp) cache[path].handle = open(tmp, 'r') cache[path].tmpname = tmp def read ( self, path, length, offset ): if not cache.has_key(path): return -errno.EACCES f = cache[path].handle f.seek(offset) return f.read(length) def readlink ( self, path ): print '*** readlink', path return -errno.ENOSYS def release ( self, path, flags ): if cache.has_key(path): cache[path].handle.close() cache[path].handle = None os.unlink(f.cache[path].tmpname) cache[path].tmpname = None def rename ( self, oldPath, newPath ): print '*** rename', oldPath, newPath return -errno.ENOSYS def rmdir ( self, path ): print '*** rmdir', path return -errno.ENOSYS def statfs ( self ): print '*** statfs' return -errno.ENOSYS def symlink ( self, targetPath, linkPath ): print '*** symlink', targetPath, linkPath return -errno.ENOSYS def truncate ( self, path, size ): print '*** truncate', path, size return -errno.ENOSYS def unlink ( self, path ): print '*** unlink', path return -errno.ENOSYS def utime ( self, path, times ): print '*** utime', path, times return -errno.ENOSYS def write ( self, path, buf, offset ): print '*** write', path, buf, offset return -errno.ENOSYS def fill_projects(): try: for prj in osc.core.meta_get_project_list(osc.conf.config['apiurl']): projects.append( '/' + prj.replace(':', ':/') ) except: print 'failed' sys.exit(1) if __name__ == '__main__': print 'Loading config ...', osc.conf.get_config() print 'OK' print 'Getting projects list ...', fill_projects() print 'OK' print 'Starting FUSE ...', oscfs = oscFS( version = '%prog ' + fuse.__version__, usage = '', dash_s_do = 'setsingle') oscfs.flags = 0 oscfs.multithreaded = 0 oscfs.parse(values = oscfs, errex = 1) oscfs.main()