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

« back to all changes in this revision

Viewing changes to 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
 
                   }