~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/codehosting/bzrutils.py

  • Committer: Gary Poster
  • Date: 2011-07-27 15:25:32 UTC
  • mto: This revision was merged to the branch mainline in revision 13541.
  • Revision ID: gary.poster@canonical.com-20110727152532-50akr19c7mgcj5qu
add config option for timeout value

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
    'read_locked',
23
23
    'remove_exception_logging_hook',
24
24
    'safe_open',
 
25
    'UnsafeUrlSeen',
25
26
    ]
26
27
 
27
28
from contextlib import contextmanager
28
29
import os
29
30
import sys
 
31
import threading
30
32
 
31
33
from bzrlib import (
32
34
    config,
33
35
    trace,
34
36
    )
 
37
from bzrlib.branch import Branch
 
38
from bzrlib.bzrdir import BzrDir
35
39
from bzrlib.errors import (
36
40
    NotStacked,
37
41
    UnstackableBranchFormat,
288
292
            get_vfs_format_classes(branch_two))
289
293
 
290
294
 
 
295
checked_open_data = threading.local()
 
296
 
 
297
 
 
298
def _install_checked_open_hook():
 
299
    """Install `_checked_open_pre_open_hook` as a ``pre_open`` hook.
 
300
 
 
301
    This is done at module import time, but _checked_open_pre_open_hook
 
302
    doesn't do anything unless the `checked_open_data` threading.Local object
 
303
    has a 'checked_opener' attribute in this thread.
 
304
 
 
305
    This is in a module-level function rather than performed at module level
 
306
    so that it can be called in setUp for testing `checked_open` as
 
307
    bzrlib.tests.TestCase.setUp clears hooks.
 
308
    """
 
309
    BzrDir.hooks.install_named_hook(
 
310
        'pre_open', _checked_open_pre_open_hook, 'safe open')
 
311
 
 
312
 
 
313
def _checked_open_pre_open_hook(transport):
 
314
    """If a checked_open validate function is present in this thread, call it.
 
315
    """
 
316
    if not getattr(checked_open_data, 'validate', False):
 
317
        return
 
318
    checked_open_data.validate(transport.base)
 
319
 
 
320
 
 
321
_install_checked_open_hook()
 
322
 
 
323
 
 
324
def checked_open(validation_function, url, possible_transports=None):
 
325
    """Open a branch, calling `validation_function` with any URL thus found.
 
326
 
 
327
    This is intended to be used to open a branch ensuring that it's not
 
328
    stacked or a reference to something unexpected.
 
329
    """
 
330
    if hasattr(checked_open_data, 'validate'):
 
331
        raise AssertionError("checked_open called recursively")
 
332
    checked_open_data.validate = validation_function
 
333
    try:
 
334
        return Branch.open(url, possible_transports=possible_transports)
 
335
    finally:
 
336
        del checked_open_data.validate
 
337
 
 
338
 
 
339
class UnsafeUrlSeen(Exception):
 
340
    """`safe_open` found a URL that was not on the configured scheme."""
 
341
 
 
342
 
 
343
def makeURLChecker(allowed_scheme):
 
344
    """Make a callable that rejects URLs not on the given scheme."""
 
345
 
 
346
    def checkURL(url):
 
347
        """Check that `url` is safe to open."""
 
348
        if URI(url).scheme != allowed_scheme:
 
349
            raise UnsafeUrlSeen(
 
350
                "Attempt to open %r which is not a %s URL" % (
 
351
                    url, allowed_scheme))
 
352
    return checkURL
 
353
 
 
354
 
 
355
def safe_open(allowed_scheme, url, possible_transports=None):
 
356
    """Open the branch at `url`, only accessing URLs on `allowed_scheme`.
 
357
 
 
358
    :raises UnsafeUrlSeen: An attempt was made to open a URL that was not on
 
359
        `allowed_scheme`.
 
360
    """
 
361
    return checked_open(
 
362
        makeURLChecker(allowed_scheme), url, possible_transports)
 
363
 
 
364
 
291
365
def get_stacked_on_url(branch):
292
366
    """Get the stacked-on URL for 'branch', or `None` if not stacked."""
293
367
    try: