#!/usr/bin/python # author: Martin Michel # created: February 2008 import os import glob import codecs def getrelfolders(srcfolder, subfolders=True, followlinks=False, pkgfolders=False, warnlevel=None, nodefolder=None): """I am returning the names of all folders contained in the given source folder. If the option is set to true, then I am also listing the names of existing subfolders. The scheme for subfolder names is as follows: 'parentdirname/subfolder/subfolder'. You can also choose to follow links and to include package folders. If the option is set, I will return an error message if the count of processed folders exceeds the limit. This is to avoid problems which can occur when the user accidently selected a folder containing a large amount of (sub)folders, e.g. the hard disk at '/'.""" relfolders = [] folderitems = glob.glob(os.path.join(srcfolder, '*')) warnexit = False for folderitem in folderitems: if os.path.isdir(folderitem): # ignnore symboli links/aliases? if os.path.islink(folderitem) and followlinks == False: continue foldername = os.path.split(folderitem) [1] # ignore package folders/apps? if foldername[-4:] in ['.app', '.pkg'] and pkgfolders == False: continue # too many folders? if warnlevel: if len(relfolders) > warnlevel: warnexit = True break if foldername not in relfolders: if nodefolder: foldername = os.path.join(nodefolder, foldername) relfolders.append(foldername) # process subfolders? if subfolders: subrelfolders = getrelfolders(folderitem, subfolders, followlinks, pkgfolders, foldername) for subrelfolder in subrelfolders: relfolders.append(subrelfolder) if not warnexit: return relfolders # too many folders! else: errmsg = u"<> The chosen source folder '%s' contains more than %s folders." % (srcfolder, warnlevel) return [errmsg] class Error(Exception): """Base class for FolderSetsDB exceptions.""" def __init__(self, msg=''): self.message = msg Exception.__init__(self, msg) def __repr__(self): return self.message __str__ = __repr__ class FileError(Error): """Raised when a read/write error occurs.""" def __init__(self, filepath): errmsg = u"Could not read/write to/from file: '%s'" % (filepath) Error.__init__(self, errmsg) self.filepath = filepath class MissingFSetNameError(Error): """Raised when the given folder set name is not found in the database.""" def __init__(self, fsetname): errmsg = u"The folder set name '%s' does not exist in the database." % (fsetname) Error.__init__(self, errmsg) self.fsetname = fsetname class FSetNameExistsError(Error): """Raised when the given folder set name is already used in the database.""" def __init__(self, fsetname): errmsg = u"The folder set name '%s' does already exist in the database." % (fsetname) Error.__init__(self, errmsg) self.fsetname = fsetname class FolderSetsDB: """I am managing the folder sets located in the database file.""" def __init__(self): self._db = {} def read(self, filepath): """I am reading and parsing the given database file.""" try: fileobj = open(filepath, 'r') except IOError: raise FileError(filepath) self._parse(fileobj) fileobj.close() def _parse(self, fileobj): """I am parsing the content of a given database file object.""" curfsetname = None while True: line = unicode(fileobj.readline(), 'utf-8') if not line: break line = line.strip() # ignoring blank lines, comments if line == '' or line[0] in [u'#']: continue if line[0] == '[' and line[-1] == ']': curfsetname = line[1:-1] if curfsetname not in self._db.keys(): self._db[curfsetname] = [] else: if curfsetname: if not u':' in line: if line not in self._db[curfsetname]: self._db[curfsetname].append(line) def save(self, filepath): """I am saving the current folder set database to the given file path.""" try: fileobj = open(filepath, 'w') except IOError: raise FileError(filepath) fileobj.write(codecs.BOM_UTF8) header = u'# This database file must always be saved as UTF-8!\n\n' fileobj.write(header) fsetnames = self.getfsetnames() for fsetname in fsetnames: line = u'[%s]\n' % (fsetname) fileobj.write(line.encode('utf-8')) relfolders = self.getfset(fsetname) for relfolder in relfolders: line = u'%s\n' % (relfolder) fileobj.write(line.encode('utf-8')) fileobj.write('\n') fileobj.close() def getfsetnames(self): """I am returning the names of all available folder sets.""" return self._db.keys() def hasfsetname(self, fsetname): """I am indicating if a given folder set name exists in the database.""" return fsetname in self._db.keys() def getfset(self, fsetname): """I am returning the relative folders saved in a given folder set.""" if not self.hasfsetname(fsetname): raise MissingFSetNameError(fsetname) else: fset = self._db[fsetname] return fset def addfset(self, fsetname, relfolders): """I am adding a given folder set to the database.""" if self.hasfsetname(fsetname): raise FSetNameExistsError(fsetname) else: self._db[fsetname] = relfolders def delfset(self, fsetname): """I am deleting a given folder set from the database.""" if self.hasfsetname(fsetname): del self._db[fsetname] def addrelfolders(self, fsetname, relfolders): """I am adding folders to an existing folder set.""" if not self.hasfsetname(fsetname): raise MissingFSetNameError(fsetname) else: for relfolder in relfolders: if relfolder not in self._db[fsetname]: self._db[fsetname].append(relfolder) def delrelfolders(self, fsetname, relfolders): """I am deleting folders from an existing folder set.""" if not self.hasfsetname(fsetname): raise MissingFSetNameError(fsetname) else: for relfolder in relfolders: if relfolder in self._db[fsetname]: self._db[fsetname].remove(relfolder)