view profilemanager/manager.py @ 8:7205cb6f5530

various flushing out, deleting old TODOs and making new ones
author Jeff Hammel <jhammel@mozilla.com>
date Tue, 13 Apr 2010 19:24:52 -0700
parents d3b22d086934
children b1274abd1206
line wrap: on
line source

"""
manage Mozilla/Firefox profiles
"""

import os
import shutil
from utils import format_tabular
from ConfigParser import SafeConfigParser as ConfigParser

class ProfileNotFound(Exception):
    """
    exception when a profile is specified but is not present in a given
    .ini file
    """

class ProfileManager(object):

    def __init__(self, profiles):
        """
        - profiles: filesystem path to profiles.ini file
        """
        self.profiles = profiles
        self.profile_dir = os.path.abspath(os.path.dirname(profiles))

    ### (public) API

    def list(self, directories=False):
        """
        lists the profiles available in the config file
        - directories : display the directories
        """
        parser = ConfigParser()
        parser.read(self.profiles)
        retval = []
        for section in parser.sections():
            if section == 'General':
                continue
            name = parser.get(section, 'name')
            values = [name]
            if directories:
                values.append(self.path(name))
            retval.append(values)
        return format_tabular(retval)

    def backups(self, profile=None):
        """
        list backups for a given profile, or all profiles if the
        profile is not given
        """
        # TODO

    def clone(self, source, dest, hash=True):
        """
        clones the profile `source` and output to `dest`
        """
        source_path = self.path(source)    # fs path of the `from` profile

        # dest: fs path to back up to
        relative = False
        if not os.path.isabs(dest):
            relative = True
            if not os.path.dirname(dest):
                dest = '%s.%s' % (self.hash(), dest)
            dest = os.path.join(self.profile_dir, dest)

        shutil.copytree(source_path, dest, symlinks=False)
        
        # TODO: update profiles.ini
        

    def backup(self, profile, dest=None):
        """
        backup the profile
        - profile: name of the profile to be backed up
        - dest: name of the destination (optional)
        """
        if dest is None:
            dest = '%s.%d.bak' % (profile, int(time.time()))
        self.clone(profile, dest, hash=False)
        # TODO: add something like
        # `Backup=$(profile)s.$(datestamp)s.bak`
        # to self.profiles

    def restore(self, profile, date=None, delete=False):
        """
        restore the profile from a backup
        the most recent backup is used unless `date` is given
        - date : date to restore from
        - delete : delete the backup after restoration
        """

        # get the possible backups
        # TODO

        # restore the backup over ``profile``

        if delete: # delete the backup
            pass

    def merge(self, output, *profiles):
        """merge a set of profiles (not trivial!)"""
        raise NotImplementedError

    ### internal functions

    def path(self, profile):
        """returns the path to the profile"""
        profile = self.profile_dict(profile)
        if profile.get('isrelative', None) == '1':
            return os.path.join(self.profile_dir, profile['path'])
        return profile['path']

    def profile_dict(self, profile):
        parser = ConfigParser()
        parser.read(self.profiles)
        for section in parser.sections():
            if not parser.has_option(section, 'name'):
                continue # not a profile
            if parser.get(section, 'name') == profile:
                return dict(parser.items(section))
        raise ProfileNotFound('Profile %s not found in %s' % (profile, self.profiles))

    def hash(self):
        """
        generate a random hash for a new profile
        """
        # XXX right now this is completely fake
        return 'FOO'