~bzr-pqm/bzr/bzr.dev

4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
1
# Copyright (C) 2009 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
"""Tools for dealing with the Launchpad API."""
18
19
import os
20
21
from bzrlib import (
22
    errors,
23
    trace,
24
    )
25
from bzrlib.plugins.launchpad.lp_registration import (
26
    InvalidLaunchpadInstance,
27
    NotLaunchpadBranch,
28
    )
29
30
from launchpadlib.credentials import Credentials
31
from launchpadlib.launchpad import (
32
    EDGE_SERVICE_ROOT,
33
    STAGING_SERVICE_ROOT,
34
    Launchpad,
35
    )
36
from lazr.uri import URI
37
38
4505.6.9 by Jonathan Lange
Add some XXX comments based on the review.
39
# XXX: Not the right value for Windows
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
40
CACHE_DIRECTORY = os.path.expanduser('~/.launchpadlib/cache')
41
42
43
LAUNCHPAD_API_URLS = {
44
    'production': EDGE_SERVICE_ROOT,
45
    'edge': EDGE_SERVICE_ROOT,
46
    'staging': STAGING_SERVICE_ROOT,
47
    'dev': 'https://api.launchpad.dev/beta/',
48
    }
49
50
51
def _get_api_url(service):
52
    """Return the root URL of the Launchpad API.
53
54
    e.g. For the 'edge' Launchpad service, this function returns
55
    launchpadlib.launchpad.EDGE_SERVICE_ROOT.
56
57
    :param service: A `LaunchpadService` object.
58
    :return: A URL as a string.
59
    """
60
    if service._lp_instance is None:
61
        lp_instance = service.DEFAULT_INSTANCE
62
    else:
63
        lp_instance = service._lp_instance
64
    try:
65
        return LAUNCHPAD_API_URLS[lp_instance]
66
    except KeyError:
67
        raise InvalidLaunchpadInstance(lp_instance)
68
69
70
def _get_credential_path(service):
71
    """Return the path to cached credentials for 'service'.
72
73
    :param service: A `LaunchpadService` object.
74
    :return: The path to a cached credentials file, which might not exist.
75
    """
76
    web_root_uri = URI(_get_api_url(service))
77
    credential_name = 'creds-%s-bzr' % (web_root_uri.host)
78
    return os.path.join(CACHE_DIRECTORY, credential_name)
79
80
81
def _login_from_cache(consumer_name, service_root, cache_dir,
82
                      credential_cache, timeout=None, proxy_info=None):
83
    """Use cached credentials if they exist, log in otherwise."""
84
    try:
85
        credentials = Credentials.load_from_path(credential_cache)
86
    except (OSError, IOError):
87
        launchpad = Launchpad.get_token_and_login(
88
            consumer_name, service_root, cache_dir, timeout, proxy_info)
89
        launchpad.credentials.save_to_path(credential_cache)
90
    else:
91
        access_key = credentials.access_token.key
92
        access_secret = credentials.access_token.secret
93
        launchpad = Launchpad.login(
94
            consumer_name, access_key, access_secret, service_root,
95
            cache_dir, timeout, proxy_info)
96
    return launchpad
97
98
99
def login(service, timeout=None, proxy_info=None):
100
    """Log in to the Launchpad API.
101
102
    :return: The root `Launchpad` object from launchpadlib.
103
    """
104
    credential_path = _get_credential_path(service)
105
    launchpad = _login_from_cache(
106
        'bzr', _get_api_url(service), CACHE_DIRECTORY, credential_path,
107
        timeout, proxy_info)
4505.6.9 by Jonathan Lange
Add some XXX comments based on the review.
108
    # XXX: Why does this set the private member of a class?
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
109
    launchpad._service = service
110
    return launchpad
111
112
113
def load_branch(launchpad, branch):
114
    """Return the launchpadlib Branch object corresponding to 'branch'.
115
116
    :param launchpad: The root `Launchpad` object from launchpadlib.
117
    :param branch: A `bzrlib.branch.Branch`.
118
    :raise NotLaunchpadBranch: If we cannot determine the Launchpad URL of
119
        `branch`.
120
    :return: A launchpadlib Branch object.
121
    """
4505.6.9 by Jonathan Lange
Add some XXX comments based on the review.
122
    # XXX: Why does this need service and _guess_branch_path?
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
123
    service = launchpad._service
124
    for url in branch.get_public_branch(), branch.get_push_location():
125
        if url is None:
126
            continue
127
        try:
128
            path = service._guess_branch_path(url)
129
        except (errors.InvalidURL, NotLaunchpadBranch):
130
            pass
131
        else:
132
            trace.mutter('Guessing path: %s', path)
133
            uri = launchpad._root_uri.append(path)
134
            uri_str = str(uri)
135
            trace.mutter('Guessing url: %s', uri_str)
136
            return launchpad.load(uri_str)
137
    raise NotLaunchpadBranch(url)