13
13
# You should have received a copy of the GNU General Public License
 
14
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
 
18
 
"""Directory lookup that uses Launchpad."""
 
20
 
from urlparse import urlsplit
 
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 
18
"""Transport indirection that uses Launchpad as a directory lookup.
 
 
20
When the transport is opened, it immediately redirects to a url
 
 
21
on Launchpad, which can then either serve the branch itself or redirect
 
 
25
from urlparse import urlsplit, urlunsplit
 
23
28
from bzrlib import (
 
28
34
from bzrlib.transport import (
 
30
36
    register_urlparse_netloc_protocol,
 
33
40
from bzrlib.plugins.launchpad.lp_registration import (
 
 
41
48
register_urlparse_netloc_protocol('lp')
 
44
 
class LaunchpadDirectory(object):
 
 
51
class LaunchpadTransport(Transport):
 
 
52
    """lp:/// URL transport
 
 
54
    This transport redirects requests to the real branch location
 
 
55
    after resolving the URL via an XMLRPC request to Launchpad.
 
 
58
    def __init__(self, base):
 
 
59
        super(LaunchpadTransport, self).__init__(base)
 
 
60
        # We only support URLs without a netloc
 
 
61
        netloc = urlsplit(base)[1]
 
 
63
            raise errors.InvalidURL(path=base)
 
46
65
    def _requires_launchpad_login(self, scheme, netloc, path, query,
 
 
54
73
                and (netloc.endswith('launchpad.net')
 
55
74
                     or netloc.endswith('launchpad.dev')))
 
57
 
    def look_up(self, name, url):
 
58
 
        """See DirectoryService.look_up"""
 
59
 
        return self._resolve(url)
 
61
 
    def _resolve(self, url,
 
 
76
    def _resolve(self, abspath,
 
62
77
                 _request_factory=ResolveLaunchpadPathRequest,
 
64
79
        """Resolve the base URL for this transport."""
 
65
 
        service = LaunchpadService.for_url(url)
 
66
 
        result = urlsplit(url)
 
67
 
        resolve = _request_factory(result[2].strip('/'))
 
 
80
        path = urlsplit(abspath)[2].lstrip('/')
 
 
81
        # Perform an XMLRPC request to resolve the path
 
 
82
        resolve = _request_factory(path)
 
 
83
        service = LaunchpadService()
 
69
85
            result = resolve.submit(service)
 
70
86
        except xmlrpclib.Fault, fault:
 
71
87
            raise errors.InvalidURL(
 
72
 
                path=url, extra=fault.faultString)
 
 
88
                path=abspath, extra=fault.faultString)
 
74
90
        if 'launchpad' in debug.debug_flags:
 
75
 
            trace.mutter("resolve_lp_path(%r) == %r", url, result)
 
 
91
            trace.mutter("resolve_lp_path(%r) == %r", path, result)
 
77
93
        if _lp_login is None:
 
78
94
            _lp_login = get_lp_login()
 
80
95
        for url in result['urls']:
 
81
96
            scheme, netloc, path, query, fragment = urlsplit(url)
 
82
97
            if self._requires_launchpad_login(scheme, netloc, path, query,
 
84
99
                # Only accept launchpad.net bzr+ssh URLs if we know
 
85
100
                # the user's Launchpad login:
 
86
 
                if _lp_login is not None:
 
88
101
                if _lp_login is None:
 
91
 
'You have not informed bzr of your Launchpad ID, and you must do this to\n'
 
92
 
'write to Launchpad or access private data.  See "bzr help launchpad-login".')
 
 
103
                url = urlunsplit((scheme, '%s@%s' % (_lp_login, netloc),
 
 
104
                                  path, query, fragment))
 
95
107
                # Use the URL if we can create a transport for it.
 
 
103
 
            raise errors.InvalidURL(path=url, extra='no supported schemes')
 
 
115
            raise errors.InvalidURL(path=abspath,
 
 
116
                                    extra='no supported schemes')
 
 
119
    def _request_redirect(self, relpath):
 
 
120
        source = urlutils.join(self.base, relpath)
 
 
121
        # Split the source location into the branch location, and the
 
 
122
        # extra path components.
 
 
123
        pos = source.find('/.bzr/')
 
 
125
            branchpath = source[:pos]
 
 
130
        target = self._resolve(branchpath) + extra
 
 
131
        raise errors.RedirectRequested(
 
 
135
    def get(self, relpath):
 
 
136
        """See Transport.get()."""
 
 
137
        self._request_redirect(relpath)
 
 
139
    def mkdir(self, relpath, mode=None):
 
 
140
        """See Transport.mkdir()."""
 
 
141
        self._request_redirect(relpath)
 
107
144
def get_test_permutations():
 
108
145
    # Since this transport doesn't do anything once opened, it's not subjected