1
# Copyright (C) 2006 Canonical Ltd
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""Server-side repository related request implmentations."""
20
from bzrlib import errors
21
from bzrlib.bzrdir import BzrDir
22
from bzrlib.smart.request import SmartServerRequest, SmartServerResponse
25
class SmartServerRepositoryRequest(SmartServerRequest):
26
"""Common base class for Repository requests."""
28
def do(self, path, *args):
29
"""Execute a repository request.
31
The repository must be at the exact path - no searching is done.
33
The actual logic is delegated to self.do_repository_request.
35
:param path: The path for the repository.
36
:return: A smart server from self.do_repository_request().
38
transport = self._backing_transport.clone(path)
39
bzrdir = BzrDir.open_from_transport(transport)
40
repository = bzrdir.open_repository()
41
return self.do_repository_request(repository, *args)
44
class SmartServerRepositoryGetRevisionGraph(SmartServerRepositoryRequest):
46
def do_repository_request(self, repository, revision_id):
47
"""Return the result of repository.get_revision_graph(revision_id).
49
:param repository: The repository to query in.
50
:param revision_id: The utf8 encoded revision_id to get a graph from.
51
:return: A smart server response where the body contains an utf8
52
encoded flattened list of the revision graph.
59
revision_graph = repository.get_revision_graph(revision_id)
60
except errors.NoSuchRevision:
61
# Note that we return an empty body, rather than omitting the body.
62
# This way the client knows that it can always expect to find a body
63
# in the response for this method, even in the error case.
64
return SmartServerResponse(('nosuchrevision', revision_id), '')
66
for revision, parents in revision_graph.items():
67
lines.append(' '.join([revision,] + parents))
69
return SmartServerResponse(('ok', ), '\n'.join(lines))
72
class SmartServerRequestHasRevision(SmartServerRepositoryRequest):
74
def do_repository_request(self, repository, revision_id):
75
"""Return ok if a specific revision is in the repository at path.
77
:param repository: The repository to query in.
78
:param revision_id: The utf8 encoded revision_id to lookup.
79
:return: A smart server response of ('ok', ) if the revision is
82
if repository.has_revision(revision_id):
83
return SmartServerResponse(('yes', ))
85
return SmartServerResponse(('no', ))
88
class SmartServerRepositoryGatherStats(SmartServerRepositoryRequest):
90
def do_repository_request(self, repository, revid, committers):
91
"""Return the result of repository.gather_stats().
93
:param repository: The repository to query in.
94
:param revid: utf8 encoded rev id or an empty string to indicate None
95
:param committers: 'yes' or 'no'.
97
:return: A SmartServerResponse ('ok',), a encoded body looking like
100
latestrev: 345.700 3600
104
But containing only fields returned by the gather_stats() call
107
decoded_revision_id = None
109
decoded_revision_id = revid
110
if committers == 'yes':
111
decoded_committers = True
113
decoded_committers = None
114
stats = repository.gather_stats(decoded_revision_id, decoded_committers)
117
if stats.has_key('committers'):
118
body += 'committers: %d\n' % stats['committers']
119
if stats.has_key('firstrev'):
120
body += 'firstrev: %.3f %d\n' % stats['firstrev']
121
if stats.has_key('latestrev'):
122
body += 'latestrev: %.3f %d\n' % stats['latestrev']
123
if stats.has_key('revisions'):
124
body += 'revisions: %d\n' % stats['revisions']
125
if stats.has_key('size'):
126
body += 'size: %d\n' % stats['size']
128
return SmartServerResponse(('ok', ), body)
131
class SmartServerRepositoryIsShared(SmartServerRepositoryRequest):
133
def do_repository_request(self, repository):
134
"""Return the result of repository.is_shared().
136
:param repository: The repository to query in.
137
:return: A smart server response of ('yes', ) if the repository is
138
shared, and ('no', ) if it is not.
140
if repository.is_shared():
141
return SmartServerResponse(('yes', ))
143
return SmartServerResponse(('no', ))
146
class SmartServerRepositoryLockWrite(SmartServerRepositoryRequest):
148
def do_repository_request(self, repository, token=''):
149
# XXX: this probably should not have a token.
153
token = repository.lock_write(token=token)
154
except errors.LockContention, e:
155
return SmartServerResponse(('LockContention',))
156
except errors.UnlockableTransport:
157
return SmartServerResponse(('UnlockableTransport',))
158
repository.leave_lock_in_place()
162
return SmartServerResponse(('ok', token))
165
class SmartServerRepositoryUnlock(SmartServerRepositoryRequest):
167
def do_repository_request(self, repository, token):
169
repository.lock_write(token=token)
170
except errors.TokenMismatch, e:
171
return SmartServerResponse(('TokenMismatch',))
172
repository.dont_leave_lock_in_place()
174
return SmartServerResponse(('ok',))