Index: third_party/mozprofile/mozprofile/profile.py |
=================================================================== |
--- third_party/mozprofile/mozprofile/profile.py (revision 0) |
+++ third_party/mozprofile/mozprofile/profile.py (revision 0) |
@@ -0,0 +1,265 @@ |
+# This Source Code Form is subject to the terms of the Mozilla Public |
+# License, v. 2.0. If a copy of the MPL was not distributed with this file, |
+# You can obtain one at http://mozilla.org/MPL/2.0/. |
+ |
+__all__ = ['Profile', 'FirefoxProfile', 'ThunderbirdProfile'] |
+ |
+import os |
+import time |
+import tempfile |
+import uuid |
+from addons import AddonManager |
+from permissions import Permissions |
+from shutil import rmtree |
+ |
+try: |
+ import simplejson |
+except ImportError: |
+ import json as simplejson |
+ |
+class Profile(object): |
+ """Handles all operations regarding profile. Created new profiles, installs extensions, |
+ sets preferences and handles cleanup.""" |
+ |
+ def __init__(self, |
+ profile=None, # Path to the profile |
+ addons=None, # String of one or list of addons to install |
+ addon_manifests=None, # Manifest for addons, see http://ahal.ca/blog/2011/bulk-installing-fx-addons/ |
+ preferences=None, # Dictionary or class of preferences |
+ locations=None, # locations to proxy |
+ proxy=None, # setup a proxy - dict of server-loc,server-port,ssl-port |
+ restore=True # If true remove all installed addons preferences when cleaning up |
+ ): |
+ |
+ # if true, remove installed addons/prefs afterwards |
+ self.restore = restore |
+ |
+ # prefs files written to |
+ self.written_prefs = set() |
+ |
+ # our magic markers |
+ nonce = '%s %s' % (str(time.time()), uuid.uuid4()) |
+ self.delimeters = ('#MozRunner Prefs Start %s' % nonce,'#MozRunner Prefs End %s' % nonce) |
+ |
+ # 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)) |
+ if not os.path.exists(self.profile): |
+ os.makedirs(self.profile) |
+ else: |
+ self.profile = self.create_new_profile() |
+ |
+ # set preferences |
+ if hasattr(self.__class__, 'preferences'): |
+ # class preferences |
+ self.set_preferences(self.__class__.preferences) |
+ self._preferences = preferences |
+ if preferences: |
+ # supplied 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.set_preferences(preferences) |
+ |
+ # set permissions |
+ self._locations = locations # store this for reconstruction |
+ self._proxy = proxy |
+ self.permissions = Permissions(self.profile, locations) |
+ prefs_js, user_js = self.permissions.network_prefs(proxy) |
+ self.set_preferences(prefs_js, 'prefs.js') |
+ self.set_preferences(user_js) |
+ |
+ # handle addon installation |
+ self.addon_manager = AddonManager(self.profile) |
+ self.addon_manager.install_addons(addons, addon_manifests) |
+ |
+ def exists(self): |
+ """returns whether the profile exists or not""" |
+ return os.path.exists(self.profile) |
+ |
+ def reset(self): |
+ """ |
+ reset the profile to the beginning state |
+ """ |
+ self.cleanup() |
+ if self.create_new: |
+ profile = None |
+ else: |
+ profile = self.profile |
+ self.__init__(profile=profile, |
+ addons=self.addon_manager.installed_addons, |
+ addon_manifests=self.addon_manager.installed_manifests, |
+ preferences=self._preferences, |
+ locations=self._locations, |
+ proxy = self._proxy) |
+ |
+ def create_new_profile(self): |
+ """Create a new clean profile in tmp which is a simple empty folder""" |
+ profile = tempfile.mkdtemp(suffix='.mozrunner') |
+ return profile |
+ |
+ |
+ ### methods for preferences |
+ |
+ def set_preferences(self, preferences, filename='user.js'): |
+ """Adds preferences dict to profile preferences""" |
+ |
+ |
+ # append to the file |
+ prefs_file = os.path.join(self.profile, filename) |
+ f = open(prefs_file, 'a') |
+ |
+ if preferences: |
+ |
+ # note what files we've touched |
+ self.written_prefs.add(filename) |
+ |
+ |
+ if isinstance(preferences, dict): |
+ # order doesn't matter |
+ preferences = preferences.items() |
+ |
+ # write the preferences |
+ f.write('\n%s\n' % self.delimeters[0]) |
+ _prefs = [(simplejson.dumps(k), simplejson.dumps(v) ) |
+ for k, v in preferences] |
+ for _pref in _prefs: |
+ f.write('user_pref(%s, %s);\n' % _pref) |
+ f.write('%s\n' % self.delimeters[1]) |
+ f.close() |
+ |
+ def pop_preferences(self, filename): |
+ """ |
+ pop the last set of preferences added |
+ returns True if popped |
+ """ |
+ |
+ lines = file(os.path.join(self.profile, filename)).read().splitlines() |
+ def last_index(_list, value): |
+ """ |
+ returns the last index of an item; |
+ this should actually be part of python code but it isn't |
+ """ |
+ for index in reversed(range(len(_list))): |
+ if _list[index] == value: |
+ return index |
+ s = last_index(lines, self.delimeters[0]) |
+ e = last_index(lines, self.delimeters[1]) |
+ |
+ # ensure both markers are found |
+ if s is None: |
+ assert e is None, '%s found without %s' % (self.delimeters[1], self.delimeters[0]) |
+ return False # no preferences found |
+ elif e is None: |
+ assert s is None, '%s found without %s' % (self.delimeters[0], self.delimeters[1]) |
+ |
+ # ensure the markers are in the proper order |
+ assert e > s, '%s found at %s, while %s found at %s' % (self.delimeters[1], e, self.delimeters[0], s) |
+ |
+ # write the prefs |
+ cleaned_prefs = '\n'.join(lines[:s] + lines[e+1:]) |
+ f = file(os.path.join(self.profile, 'user.js'), 'w') |
+ f.write(cleaned_prefs) |
+ f.close() |
+ return True |
+ |
+ def clean_preferences(self): |
+ """Removed preferences added by mozrunner.""" |
+ for filename in self.written_prefs: |
+ if not os.path.exists(os.path.join(self.profile, filename)): |
+ # file has been deleted |
+ break |
+ while True: |
+ if not self.pop_preferences(filename): |
+ break |
+ |
+ ### cleanup |
+ |
+ def _cleanup_error(self, function, path, excinfo): |
+ """ Specifically for windows we need to handle the case where the windows |
+ process has not yet relinquished handles on files, so we do a wait/try |
+ construct and timeout if we can't get a clear road to deletion |
+ """ |
+ |
+ try: |
+ from exceptions import WindowsError |
+ from time import sleep |
+ def is_file_locked(): |
+ return excinfo[0] is WindowsError and excinfo[1].winerror == 32 |
+ |
+ if excinfo[0] is WindowsError and excinfo[1].winerror == 32: |
+ # Then we're on windows, wait to see if the file gets unlocked |
+ # we wait 10s |
+ count = 0 |
+ while count < 10: |
+ sleep(1) |
+ try: |
+ function(path) |
+ break |
+ except: |
+ count += 1 |
+ except ImportError: |
+ # We can't re-raise an error, so we'll hope the stuff above us will throw |
+ pass |
+ |
+ def cleanup(self): |
+ """Cleanup operations for the profile.""" |
+ if self.restore: |
+ if self.create_new: |
+ if os.path.exists(self.profile): |
+ rmtree(self.profile, onerror=self._cleanup_error) |
+ else: |
+ self.clean_preferences() |
+ self.addon_manager.clean_addons() |
+ self.permissions.clean_db() |
+ |
+ __del__ = cleanup |
+ |
+class FirefoxProfile(Profile): |
+ """Specialized Profile subclass for Firefox""" |
+ preferences = {# Don't automatically update the application |
+ 'app.update.enabled' : False, |
+ # Don't restore the last open set of tabs if the browser has crashed |
+ 'browser.sessionstore.resume_from_crash': False, |
+ # Don't check for the default web browser |
+ 'browser.shell.checkDefaultBrowser' : False, |
+ # Don't warn on exit when multiple tabs are open |
+ 'browser.tabs.warnOnClose' : False, |
+ # Don't warn when exiting the browser |
+ 'browser.warnOnQuit': False, |
+ # Only install add-ons from the profile and the application scope |
+ # Also ensure that those are not getting disabled. |
+ # see: https://developer.mozilla.org/en/Installing_extensions |
+ 'extensions.enabledScopes' : 5, |
+ 'extensions.autoDisableScopes' : 10, |
+ # Don't install distribution add-ons from the app folder |
+ 'extensions.installDistroAddons' : False, |
+ # Dont' run the add-on compatibility check during start-up |
+ 'extensions.showMismatchUI' : False, |
+ # Don't automatically update add-ons |
+ 'extensions.update.enabled' : False, |
+ # Don't open a dialog to show available add-on updates |
+ 'extensions.update.notifyUser' : False, |
+ # Suppress automatic safe mode after crashes |
+ 'toolkit.startup.max_resumed_crashes' : -1, |
+ # Enable test mode to run multiple tests in parallel |
+ 'focusmanager.testmode' : True, |
+ } |
+ |
+class ThunderbirdProfile(Profile): |
+ preferences = {'extensions.update.enabled' : False, |
+ 'extensions.update.notifyUser' : False, |
+ 'browser.shell.checkDefaultBrowser' : False, |
+ 'browser.tabs.warnOnClose' : False, |
+ 'browser.warnOnQuit': False, |
+ 'browser.sessionstore.resume_from_crash': False, |
+ # prevents the 'new e-mail address' wizard on new profile |
+ 'mail.provider.enabled': False, |
+ } |
Property changes on: third_party/mozprofile/mozprofile/profile.py |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |