~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
4505.6.11 by Jonathan Lange
Flag lp_api as a difficult import.
19
# Importing this module will be expensive, since it imports launchpadlib and
20
# its dependencies. However, our plan is to only load this module when it is
21
# needed by a command that uses it.
22
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
23
import os
4505.6.16 by Jonathan Lange
Work on Windows, I think.
24
import sys
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
25
26
from bzrlib import (
27
    errors,
4505.6.16 by Jonathan Lange
Work on Windows, I think.
28
    osutils,
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
29
    trace,
4505.6.16 by Jonathan Lange
Work on Windows, I think.
30
    win32utils,
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
31
    )
32
from bzrlib.plugins.launchpad.lp_registration import (
33
    InvalidLaunchpadInstance,
34
    NotLaunchpadBranch,
35
    )
36
37
from launchpadlib.credentials import Credentials
38
from launchpadlib.launchpad import (
39
    EDGE_SERVICE_ROOT,
40
    STAGING_SERVICE_ROOT,
41
    Launchpad,
42
    )
43
from lazr.uri import URI
44
45
4505.6.15 by Jonathan Lange
Baby steps: Move the cache directory stuff into a function.
46
def get_cache_directory():
47
    """Return the directory to cache launchpadlib objects in."""
4505.6.16 by Jonathan Lange
Work on Windows, I think.
48
    if sys.platform == 'win32':
49
        base = win32utils.get_appdata_location_unicode()
50
        if base is None:
51
            base = os.environ.get('HOME', None)
52
        if base is None:
53
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
54
                                  ' or HOME set')
55
    else:
56
        base = os.path.expanduser('~/.cache')
57
    return osutils.pathjoin(base, 'launchpadlib')
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
58
59
60
LAUNCHPAD_API_URLS = {
61
    'production': EDGE_SERVICE_ROOT,
62
    'edge': EDGE_SERVICE_ROOT,
63
    'staging': STAGING_SERVICE_ROOT,
64
    'dev': 'https://api.launchpad.dev/beta/',
65
    }
66
67
68
def _get_api_url(service):
69
    """Return the root URL of the Launchpad API.
70
71
    e.g. For the 'edge' Launchpad service, this function returns
72
    launchpadlib.launchpad.EDGE_SERVICE_ROOT.
73
74
    :param service: A `LaunchpadService` object.
75
    :return: A URL as a string.
76
    """
77
    if service._lp_instance is None:
78
        lp_instance = service.DEFAULT_INSTANCE
79
    else:
80
        lp_instance = service._lp_instance
81
    try:
82
        return LAUNCHPAD_API_URLS[lp_instance]
83
    except KeyError:
84
        raise InvalidLaunchpadInstance(lp_instance)
85
86
87
def _get_credential_path(service):
88
    """Return the path to cached credentials for 'service'.
89
90
    :param service: A `LaunchpadService` object.
91
    :return: The path to a cached credentials file, which might not exist.
92
    """
93
    web_root_uri = URI(_get_api_url(service))
94
    credential_name = 'creds-%s-bzr' % (web_root_uri.host)
4505.6.15 by Jonathan Lange
Baby steps: Move the cache directory stuff into a function.
95
    return os.path.join(get_cache_directory(), credential_name)
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
96
97
98
def _login_from_cache(consumer_name, service_root, cache_dir,
99
                      credential_cache, timeout=None, proxy_info=None):
100
    """Use cached credentials if they exist, log in otherwise."""
4505.6.12 by Jonathan Lange
Add some comments
101
    # XXX: make sure credentials are private
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
102
    try:
103
        credentials = Credentials.load_from_path(credential_cache)
104
    except (OSError, IOError):
105
        launchpad = Launchpad.get_token_and_login(
106
            consumer_name, service_root, cache_dir, timeout, proxy_info)
107
        launchpad.credentials.save_to_path(credential_cache)
108
    else:
109
        access_key = credentials.access_token.key
110
        access_secret = credentials.access_token.secret
111
        launchpad = Launchpad.login(
112
            consumer_name, access_key, access_secret, service_root,
113
            cache_dir, timeout, proxy_info)
114
    return launchpad
115
116
117
def login(service, timeout=None, proxy_info=None):
118
    """Log in to the Launchpad API.
119
120
    :return: The root `Launchpad` object from launchpadlib.
121
    """
122
    credential_path = _get_credential_path(service)
123
    launchpad = _login_from_cache(
124
        'bzr', _get_api_url(service), CACHE_DIRECTORY, credential_path,
125
        timeout, proxy_info)
4505.6.9 by Jonathan Lange
Add some XXX comments based on the review.
126
    # 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.
127
    launchpad._service = service
128
    return launchpad
129
130
131
def load_branch(launchpad, branch):
132
    """Return the launchpadlib Branch object corresponding to 'branch'.
133
134
    :param launchpad: The root `Launchpad` object from launchpadlib.
135
    :param branch: A `bzrlib.branch.Branch`.
136
    :raise NotLaunchpadBranch: If we cannot determine the Launchpad URL of
137
        `branch`.
138
    :return: A launchpadlib Branch object.
139
    """
4505.6.9 by Jonathan Lange
Add some XXX comments based on the review.
140
    # XXX: Why does this need service and _guess_branch_path?
4505.6.6 by Jonathan Lange
Add a command to mirror Launchpad branches now.
141
    service = launchpad._service
142
    for url in branch.get_public_branch(), branch.get_push_location():
143
        if url is None:
144
            continue
145
        try:
146
            path = service._guess_branch_path(url)
147
        except (errors.InvalidURL, NotLaunchpadBranch):
148
            pass
149
        else:
150
            trace.mutter('Guessing path: %s', path)
151
            uri = launchpad._root_uri.append(path)
152
            uri_str = str(uri)
153
            trace.mutter('Guessing url: %s', uri_str)
154
            return launchpad.load(uri_str)
155
    raise NotLaunchpadBranch(url)