X-Git-Url: https://v.licheni.net/stack/code/dboxswitch.git/blobdiff_plain/4ccfdabe53cd795fe1e74b704c15da311986ecaf..957fc59fe85f6c3ad18fe279699db2e614a1d036:/dboxswitch/profhandler.py diff --git a/dboxswitch/profhandler.py b/dboxswitch/profhandler.py new file mode 100644 index 0000000..f2be538 --- /dev/null +++ b/dboxswitch/profhandler.py @@ -0,0 +1,213 @@ +# -*- coding: utf-8 -*- + +""" +Dboxswitch dropbox profile switcher + +license: Modified BSD License + +Copyright (c) 2012, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +import platform +import re +import shutil +import os +import errno +import signal + +from apperror import AppError +from settings import appconf + +class ProfHandler(): + + def __init__(self): + + #create profile directory if not exists + try: + os.makedirs(self.getProfileFolder()) + except OSError, e: + if e.errno != errno.EEXIST: + raise + + #compile regular expression for validating profile names + self.reg = re.compile("[a-zA-Z0-9_-]+") + + #patch symlink on windows + if platform.system() is 'Windows': + os.symlink = winsymlink + + def getProfilesList(self): + """ Generate and returns the profiles + it assumes that self.pdir is defined """ + #this is generated every time to handle the case of the user renaming the directories by hand + return sorted([os.path.join(self.pdir, f) for f in os.listdir(self.pdir)]) + + def getProfileFolder(self): + """ Generates, in a os dependant way, the local folder where all profiles are stored """ + try: + #directory path is cached + return self.pdir + except AttributeError: + pl = platform.system() + if pl == "Linux": + try: + from xdg.BaseDirectory import xdf_data_home + self.pdir = os.path.join(xdg_data_home, appconf.appname) + except: + self.pdir = os.path.join(os.path.expanduser('~'),".local/share",appconf.appname) + elif pl == 'Windows': + self.pdir = os.path.join(os.getenv("APPDATA"), appconf.appname) + elif pl == 'Darwin': + self.pdir = os.path.join(os.path.expanduser('~'),"."+appconf.appname) + elif pl == None: + raise AppError('Operative system NOT supported.') + + return self.pdir + + def addProfile(self, profileName): + """ Create a profile """ + + print("Creating a new profile") + if self.isValidProfileName(profileName): + try: + os.makedirs(os.path.join(self.getProfileFolder(), profileName)) + except OSError,e: + if e.errno == errno.EEXIST: + raise AppError("Profile exists.") + else: + raise AppError(str(e)) + else: + raise AppError('Profile Name not valid.\nAllowed only ascii characters.') + print("Profile "+profileName+" created.") + + def delProfile(self, profileName): + """ Delete a profile """ + + print("Deleting profile") + if self.isValidProfileName(profileName): + try: + #recursively delete the profile directory + shutil.rmtree(os.path.join(self.pdir, profileName)) + except: + raise AppError('Profile Name does not exists') + else: + raise AppError('Profile Name not valid') + print("Profile "+profileName+" deleted.") + + def isCurrentProfile(self, ppath): + """ Returns true if the current profile path is currently activated """ + + pl = platform.system() + if pl in ('Linux','Darwin'): + if os.path.exists(self.getDropboxDirectory()): + return True if os.readlink(self.getDropboxDirectory()) == ppath else False + else: + return False + + def isValidProfileName(self, pname): + + if self.reg.match(pname) is not None: + return True + else: + return False + + def activateProfile(self, ppath): + pl = platform.system() + if ppath in self.getProfilesList(): + self.stopDropbox() + try: + if pl in ('Linux','Darwin'): + if os.path.exists(self.getDropboxDirectory()): + os.unlink(self.getDropboxDirectory()) + os.symlink(ppath, self.getDropboxDirectory()) + else: + raise NotImplementedError, "Not implemented yet." + except IOError as e: + raise AppError('Error on activating Profile: '+ self.getBaseProfileName(ppath)) + self.startDropbox() + else: + raise AppError("Trying to acrivate non existant profile") + + def getBaseProfileName(self, ppath): + """ Returns the base name given a profile returned by getProfilesList """ + + return os.path.basename(ppath) + + def getDropboxDirectory(self): + pl = platform.system() + if pl in ('Linux', 'Darwin'): + return os.path.join(os.path.expanduser('~'),".dropbox") + elif pl == 'Windows': + assert os.environ.has_key('APPDATA'), Exception('APPDATA env variable not found') + return os.path.join(os.environ['APPDATA'],'Dropbox') + else: + raise NotImplementedError, "Not implemented yet." + + def stopDropbox(self): + """ Stop dropbox Daemon """ + pl = platform.system() + if pl == 'Linux': + os.system("dropbox stop") + if pl in ('Linux','Darwin'): + pidfile = os.path.expanduser("~/.dropbox/dropbox.pid") + try: + with open(pidfile, "r") as f: + pid = int(f.read()) + os.kill(pid, signal.SIGTERM) + except: + pass + + def startDropbox(self): + """ Sart dropbox Daemon """ + + pl = platform.system() + if pl == 'Linux': + try: + os.system("dropbox start -i") + except: + raise AppError(u"Could not start dropbox.") + elif pl == 'Darwin': + os.system("/Applications/Dropbox.app/Contents/MacOS/Dropbox &") + + +__CSL = None +def winsymlink(source, link_name): + '''symlink(source, link_name) + Creates a symbolic link pointing to source named link_name. + Used to patch the nonexistant version on windows for python 2.6''' + global __CSL + if __CSL is None: + import ctypes + csl = ctypes.windll.kernel32.CreateSymbolicLinkW + csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32) + csl.restype = ctypes.c_ubyte + __CSL = csl + flags = 0 + if source is not None and os.path.isdir(source): + flags = 1 + if __CSL(link_name, source, flags) == 0: + raise ctypes.WinError() +