~ubuntu-branches/ubuntu/quantal/enigmail/quantal-security

« back to all changes in this revision

Viewing changes to mozilla/testing/mozbase/mozprofile/mozprofile/profile.py

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2013-09-13 16:02:15 UTC
  • mfrom: (0.12.16)
  • Revision ID: package-import@ubuntu.com-20130913160215-u3g8nmwa0pdwagwc
Tags: 2:1.5.2-0ubuntu0.12.10.1
* New upstream release v1.5.2 for Thunderbird 24

* Build enigmail using a stripped down Thunderbird 17 build system, as it's
  now quite difficult to build the way we were doing previously, with the
  latest Firefox build system
* Add debian/patches/no_libxpcom.patch - Don't link against libxpcom, as it
  doesn't exist anymore (but exists in the build system)
* Add debian/patches/use_sdk.patch - Use the SDK version of xpt.py and
  friends
* Drop debian/patches/ipc-pipe_rename.diff (not needed anymore)
* Drop debian/patches/makefile_depth.diff (not needed anymore)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# This Source Code Form is subject to the terms of the Mozilla Public
 
2
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
 
3
# You can obtain one at http://mozilla.org/MPL/2.0/.
 
4
 
 
5
__all__ = ['Profile', 'FirefoxProfile', 'ThunderbirdProfile']
 
6
 
 
7
import os
 
8
import time
 
9
import tempfile
 
10
import uuid
 
11
from addons import AddonManager
 
12
from permissions import Permissions
 
13
from shutil import rmtree
 
14
 
 
15
try:
 
16
    import simplejson
 
17
except ImportError:
 
18
    import json as simplejson
 
19
 
 
20
class Profile(object):
 
21
    """Handles all operations regarding profile. Created new profiles, installs extensions,
 
22
    sets preferences and handles cleanup."""
 
23
 
 
24
    def __init__(self,
 
25
                 profile=None, # Path to the profile
 
26
                 addons=None,  # String of one or list of addons to install
 
27
                 addon_manifests=None,  # Manifest for addons, see http://ahal.ca/blog/2011/bulk-installing-fx-addons/
 
28
                 preferences=None, # Dictionary or class of preferences
 
29
                 locations=None, # locations to proxy
 
30
                 proxy=None, # setup a proxy - dict of server-loc,server-port,ssl-port
 
31
                 restore=True # If true remove all installed addons preferences when cleaning up
 
32
                 ):
 
33
 
 
34
        # if true, remove installed addons/prefs afterwards
 
35
        self.restore = restore
 
36
 
 
37
        # prefs files written to
 
38
        self.written_prefs = set()
 
39
 
 
40
        # our magic markers
 
41
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
 
42
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,'#MozRunner Prefs End %s' % nonce)
 
43
 
 
44
        # Handle profile creation
 
45
        self.create_new = not profile
 
46
        if profile:
 
47
            # Ensure we have a full path to the profile
 
48
            self.profile = os.path.abspath(os.path.expanduser(profile))
 
49
            if not os.path.exists(self.profile):
 
50
                os.makedirs(self.profile)
 
51
        else:
 
52
            self.profile = self.create_new_profile()
 
53
 
 
54
        # set preferences
 
55
        if hasattr(self.__class__, 'preferences'):
 
56
            # class preferences
 
57
            self.set_preferences(self.__class__.preferences)
 
58
        self._preferences = preferences
 
59
        if preferences:
 
60
            # supplied preferences
 
61
            if isinstance(preferences, dict):
 
62
                # unordered
 
63
                preferences = preferences.items()
 
64
            # sanity check
 
65
            assert not [i for i in preferences
 
66
                        if len(i) != 2]
 
67
        else:
 
68
            preferences = []
 
69
        self.set_preferences(preferences)
 
70
 
 
71
        # set permissions
 
72
        self._locations = locations # store this for reconstruction
 
73
        self._proxy = proxy
 
74
        self.permissions = Permissions(self.profile, locations)
 
75
        prefs_js, user_js = self.permissions.network_prefs(proxy)
 
76
        self.set_preferences(prefs_js, 'prefs.js')
 
77
        self.set_preferences(user_js)
 
78
 
 
79
        # handle addon installation
 
80
        self.addon_manager = AddonManager(self.profile)
 
81
        self.addon_manager.install_addons(addons, addon_manifests)
 
82
 
 
83
    def exists(self):
 
84
        """returns whether the profile exists or not"""
 
85
        return os.path.exists(self.profile)
 
86
 
 
87
    def reset(self):
 
88
        """
 
89
        reset the profile to the beginning state
 
90
        """
 
91
        self.cleanup()
 
92
        if self.create_new:
 
93
            profile = None
 
94
        else:
 
95
            profile = self.profile
 
96
        self.__init__(profile=profile,
 
97
                      addons=self.addon_manager.installed_addons,
 
98
                      addon_manifests=self.addon_manager.installed_manifests,
 
99
                      preferences=self._preferences,
 
100
                      locations=self._locations,
 
101
                      proxy = self._proxy)
 
102
 
 
103
    def create_new_profile(self):
 
104
        """Create a new clean profile in tmp which is a simple empty folder"""
 
105
        profile = tempfile.mkdtemp(suffix='.mozrunner')
 
106
        return profile
 
107
 
 
108
 
 
109
    ### methods for preferences
 
110
 
 
111
    def set_preferences(self, preferences, filename='user.js'):
 
112
        """Adds preferences dict to profile preferences"""
 
113
 
 
114
 
 
115
        # append to the file
 
116
        prefs_file = os.path.join(self.profile, filename)
 
117
        f = open(prefs_file, 'a')
 
118
 
 
119
        if preferences:
 
120
 
 
121
            # note what files we've touched
 
122
            self.written_prefs.add(filename)
 
123
 
 
124
 
 
125
            if isinstance(preferences, dict):
 
126
                # order doesn't matter
 
127
                preferences = preferences.items()
 
128
 
 
129
            # write the preferences
 
130
            f.write('\n%s\n' % self.delimeters[0])
 
131
            _prefs = [(simplejson.dumps(k), simplejson.dumps(v) )
 
132
                      for k, v in preferences]
 
133
            for _pref in _prefs:
 
134
                f.write('user_pref(%s, %s);\n' % _pref)
 
135
            f.write('%s\n' % self.delimeters[1])
 
136
        f.close()
 
137
 
 
138
    def pop_preferences(self, filename):
 
139
        """
 
140
        pop the last set of preferences added
 
141
        returns True if popped
 
142
        """
 
143
 
 
144
        lines = file(os.path.join(self.profile, filename)).read().splitlines()
 
145
        def last_index(_list, value):
 
146
            """
 
147
            returns the last index of an item;
 
148
            this should actually be part of python code but it isn't
 
149
            """
 
150
            for index in reversed(range(len(_list))):
 
151
                if _list[index] == value:
 
152
                    return index
 
153
        s = last_index(lines, self.delimeters[0])
 
154
        e = last_index(lines, self.delimeters[1])
 
155
 
 
156
        # ensure both markers are found
 
157
        if s is None:
 
158
            assert e is None, '%s found without %s' % (self.delimeters[1], self.delimeters[0])
 
159
            return False # no preferences found
 
160
        elif e is None:
 
161
            assert s is None, '%s found without %s' % (self.delimeters[0], self.delimeters[1])
 
162
 
 
163
        # ensure the markers are in the proper order
 
164
        assert e > s, '%s found at %s, while %s found at %s' % (self.delimeters[1], e, self.delimeters[0], s)
 
165
 
 
166
        # write the prefs
 
167
        cleaned_prefs = '\n'.join(lines[:s] + lines[e+1:])
 
168
        f = file(os.path.join(self.profile, 'user.js'), 'w')
 
169
        f.write(cleaned_prefs)
 
170
        f.close()
 
171
        return True
 
172
 
 
173
    def clean_preferences(self):
 
174
        """Removed preferences added by mozrunner."""
 
175
        for filename in self.written_prefs:
 
176
            if not os.path.exists(os.path.join(self.profile, filename)):
 
177
                # file has been deleted
 
178
                break
 
179
            while True:
 
180
                if not self.pop_preferences(filename):
 
181
                    break
 
182
 
 
183
    ### cleanup
 
184
 
 
185
    def _cleanup_error(self, function, path, excinfo):
 
186
        """ Specifically for windows we need to handle the case where the windows
 
187
            process has not yet relinquished handles on files, so we do a wait/try
 
188
            construct and timeout if we can't get a clear road to deletion
 
189
        """
 
190
 
 
191
        try:
 
192
            from exceptions import WindowsError
 
193
            from time import sleep
 
194
            def is_file_locked():
 
195
                return excinfo[0] is WindowsError and excinfo[1].winerror == 32
 
196
 
 
197
            if excinfo[0] is WindowsError and excinfo[1].winerror == 32:
 
198
                # Then we're on windows, wait to see if the file gets unlocked
 
199
                # we wait 10s
 
200
                count = 0
 
201
                while count < 10:
 
202
                    sleep(1)
 
203
                    try:
 
204
                        function(path)
 
205
                        break
 
206
                    except:
 
207
                        count += 1
 
208
        except ImportError:
 
209
            # We can't re-raise an error, so we'll hope the stuff above us will throw
 
210
            pass
 
211
 
 
212
    def cleanup(self):
 
213
        """Cleanup operations for the profile."""
 
214
        if self.restore:
 
215
            if self.create_new:
 
216
                if os.path.exists(self.profile):
 
217
                    rmtree(self.profile, onerror=self._cleanup_error)
 
218
            else:
 
219
                self.clean_preferences()
 
220
                self.addon_manager.clean_addons()
 
221
                self.permissions.clean_db()
 
222
 
 
223
    __del__ = cleanup
 
224
 
 
225
class FirefoxProfile(Profile):
 
226
    """Specialized Profile subclass for Firefox"""
 
227
    preferences = {# Don't automatically update the application
 
228
                   'app.update.enabled' : False,
 
229
                   # Don't restore the last open set of tabs if the browser has crashed
 
230
                   'browser.sessionstore.resume_from_crash': False,
 
231
                   # Don't check for the default web browser
 
232
                   'browser.shell.checkDefaultBrowser' : False,
 
233
                   # Don't warn on exit when multiple tabs are open
 
234
                   'browser.tabs.warnOnClose' : False,
 
235
                   # Don't warn when exiting the browser
 
236
                   'browser.warnOnQuit': False,
 
237
                   # Only install add-ons from the profile and the application scope
 
238
                   # Also ensure that those are not getting disabled.
 
239
                   # see: https://developer.mozilla.org/en/Installing_extensions
 
240
                   'extensions.enabledScopes' : 5,
 
241
                   'extensions.autoDisableScopes' : 10,
 
242
                   # Don't install distribution add-ons from the app folder
 
243
                   'extensions.installDistroAddons' : False,
 
244
                   # Dont' run the add-on compatibility check during start-up
 
245
                   'extensions.showMismatchUI' : False,
 
246
                   # Don't automatically update add-ons
 
247
                   'extensions.update.enabled'    : False,
 
248
                   # Don't open a dialog to show available add-on updates
 
249
                   'extensions.update.notifyUser' : False,
 
250
                   # Suppress automatic safe mode after crashes
 
251
                   'toolkit.startup.max_resumed_crashes' : -1,
 
252
                   # Enable test mode to run multiple tests in parallel
 
253
                   'focusmanager.testmode' : True,
 
254
                   }
 
255
 
 
256
class ThunderbirdProfile(Profile):
 
257
    preferences = {'extensions.update.enabled'    : False,
 
258
                   'extensions.update.notifyUser' : False,
 
259
                   'browser.shell.checkDefaultBrowser' : False,
 
260
                   'browser.tabs.warnOnClose' : False,
 
261
                   'browser.warnOnQuit': False,
 
262
                   'browser.sessionstore.resume_from_crash': False,
 
263
                   # prevents the 'new e-mail address' wizard on new profile
 
264
                   'mail.provider.enabled': False,
 
265
                   }