Bug 1445944 - [mozprofile] Pull functionality out of Profile and into an abstract 'BaseProfile' class r=rwood

In addition to Profile, this will be implemented by the ChromeProfile class in
the next commit. This way we can test for 'isinstance(profile, BaseProfile)'
when we just want to test for a profile regardless of application.

Ideally I would have preferred 'Profile' itself to be the base class (and co-opt
FirefoxProfile to be the new defacto class for firefox profiles), but this would
break backwards compatibility.

MozReview-Commit-ID: 6TTFq2PQOGM

--HG--
extra : rebase_source : 57651887061ec52b176729109271ee2e23552cdb
This commit is contained in:
Andrew Halberstadt 2018-04-13 13:26:41 -04:00
parent 198dd77c3a
commit e29aebf0d9
2 changed files with 96 additions and 78 deletions

View File

@ -6,23 +6,103 @@ from __future__ import absolute_import
import os
import platform
import time
import tempfile
import time
import uuid
from .addons import AddonManager
import mozfile
from .permissions import Permissions
from .prefs import Preferences
from abc import ABCMeta, abstractmethod
from shutil import copytree
__all__ = ['Profile',
import mozfile
from .addons import AddonManager
from .permissions import Permissions
from .prefs import Preferences
__all__ = ['BaseProfile',
'Profile',
'FirefoxProfile',
'ThunderbirdProfile',
'create_profile']
class Profile(object):
class BaseProfile(object):
__metaclass__ = ABCMeta
def __init__(self, profile=None, addons=None, preferences=None, restore=True):
self._addons = addons
# Prepare additional preferences
if preferences:
if isinstance(preferences, dict):
# unordered
preferences = preferences.items()
# sanity check
assert not [i for i in preferences if len(i) != 2]
else:
preferences = []
self._preferences = preferences
# Handle profile creation
self.restore = restore
self.create_new = not profile
if profile:
# Ensure we have a full path to the profile
self.profile = os.path.abspath(os.path.expanduser(profile))
else:
self.profile = tempfile.mkdtemp(suffix='.mozrunner')
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.cleanup()
def __del__(self):
self.cleanup()
def cleanup(self):
"""Cleanup operations for the profile."""
if self.restore:
# If it's a temporary profile we have to remove it
if self.create_new:
mozfile.remove(self.profile)
@abstractmethod
def _reset(self):
pass
def reset(self):
"""
reset the profile to the beginning state
"""
self.cleanup()
self._reset()
@classmethod
def clone(cls, path_from, path_to=None, ignore=None, **kwargs):
"""Instantiate a temporary profile via cloning
- path: path of the basis to clone
- ignore: callable passed to shutil.copytree
- kwargs: arguments to the profile constructor
"""
if not path_to:
tempdir = tempfile.mkdtemp() # need an unused temp dir name
mozfile.remove(tempdir) # copytree requires that dest does not exist
path_to = tempdir
copytree(path_from, path_to, ignore=ignore)
c = cls(path_to, **kwargs)
c.create_new = True # deletes a cloned profile when restore is True
return c
def exists(self):
"""returns whether the profile exists or not"""
return os.path.exists(self.profile)
class Profile(BaseProfile):
"""Handles all operations regarding profile.
Creating new profiles, installing add-ons, setting preferences and
@ -58,37 +138,17 @@ class Profile(object):
:param whitelistpaths: List of paths to pass to Firefox to allow read
access to from the content process sandbox.
"""
self._addons = addons
super(Profile, self).__init__(
profile=profile, addons=addons, preferences=preferences, restore=restore)
self._locations = locations
self._proxy = proxy
# Prepare additional preferences
if preferences:
if isinstance(preferences, dict):
# unordered
preferences = preferences.items()
# sanity check
assert not [i for i in preferences if len(i) != 2]
else:
preferences = []
self._preferences = preferences
self._whitelistpaths = whitelistpaths
# Handle profile creation
self.create_new = not profile
if profile:
# Ensure we have a full path to the profile
self.profile = os.path.abspath(os.path.expanduser(profile))
else:
self.profile = tempfile.mkdtemp(suffix='.mozrunner')
self.restore = restore
# Initialize all class members
self._internal_init()
self._reset()
def _internal_init(self):
def _reset(self):
"""Internal: Initialize all class members to their default value"""
if not os.path.exists(self.profile):
@ -136,17 +196,6 @@ class Profile(object):
self.addons = AddonManager(self.profile, restore=self.restore)
self.addons.install(self._addons)
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.cleanup()
def __del__(self):
self.cleanup()
# cleanup
def cleanup(self):
"""Cleanup operations for the profile."""
@ -158,18 +207,7 @@ class Profile(object):
self.addons.clean()
if getattr(self, 'permissions', None) is not None:
self.permissions.clean_db()
# If it's a temporary profile we have to remove it
if self.create_new:
mozfile.remove(self.profile)
def reset(self):
"""
reset the profile to the beginning state
"""
self.cleanup()
self._internal_init()
super(Profile, self).cleanup()
def clean_preferences(self):
"""Removed preferences added by mozrunner."""
@ -181,27 +219,6 @@ class Profile(object):
if not self.pop_preferences(filename):
break
@classmethod
def clone(cls, path_from, path_to=None, ignore=None, **kwargs):
"""Instantiate a temporary profile via cloning
- path: path of the basis to clone
- ignore: callable passed to shutil.copytree
- kwargs: arguments to the profile constructor
"""
if not path_to:
tempdir = tempfile.mkdtemp() # need an unused temp dir name
mozfile.remove(tempdir) # copytree requires that dest does not exist
path_to = tempdir
copytree(path_from, path_to, ignore=ignore)
c = cls(path_to, **kwargs)
c.create_new = True # deletes a cloned profile when restore is True
return c
def exists(self):
"""returns whether the profile exists or not"""
return os.path.exists(self.profile)
# methods for preferences
def set_preferences(self, preferences, filename='user.js'):

View File

@ -12,6 +12,7 @@ import mozunit
import pytest
from mozprofile import (
BaseProfile,
Profile,
FirefoxProfile,
ThunderbirdProfile,
@ -51,7 +52,7 @@ def test_create_profile(tmpdir, app, cls):
return
profile = create_profile(app, profile=path)
assert isinstance(profile, Profile)
assert isinstance(profile, BaseProfile)
assert profile.__class__ == cls
assert profile.profile == path