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.
54
decoded_revision_id = revision_id.decode('utf8')
55
if not decoded_revision_id:
56
decoded_revision_id = None
60
revision_graph = repository.get_revision_graph(decoded_revision_id)
61
except errors.NoSuchRevision:
62
# Note that we return an empty body, rather than omitting the body.
63
# This way the client knows that it can always expect to find a body
64
# in the response for this method, even in the error case.
65
return SmartServerResponse(('nosuchrevision', revision_id), '')
67
for revision, parents in revision_graph.items():
68
lines.append(' '.join([revision,] + parents))
70
return SmartServerResponse(('ok', ), '\n'.join(lines).encode('utf8'))
73
class SmartServerRequestHasRevision(SmartServerRepositoryRequest):
75
def do_repository_request(self, repository, revision_id):
76
"""Return ok if a specific revision is in the repository at path.
78
:param repository: The repository to query in.
79
:param revision_id: The utf8 encoded revision_id to lookup.
80
:return: A smart server response of ('ok', ) if the revision is
83
decoded_revision_id = revision_id.decode('utf8')
84
if repository.has_revision(decoded_revision_id):
85
return SmartServerResponse(('ok', ))
87
return SmartServerResponse(('no', ))
90
class SmartServerRepositoryGatherStats(SmartServerRepositoryRequest):
92
def do_repository_request(self, repository, revid, committers):
93
"""Return the result of repository.gather_stats().
95
:param repository: The repository to query in.
96
:param revid: utf8 encoded rev id or an empty string to indicate None
97
:param committers: 'yes' or 'no'.
99
:return: A SmartServerResponse ('ok',), a encoded body looking like
102
latestrev: 345.700 3600
106
But containing only fields returned by the gather_stats() call
109
decoded_revision_id = None
111
decoded_revision_id = revid.decode('utf8')
112
if committers == 'yes':
113
decoded_committers = True
115
decoded_committers = None
116
stats = repository.gather_stats(decoded_revision_id, decoded_committers)
119
if stats.has_key('committers'):
120
body += 'committers: %d\n' % stats['committers']
121
if stats.has_key('firstrev'):
122
body += 'firstrev: %.3f %d\n' % stats['firstrev']
123
if stats.has_key('latestrev'):
124
body += 'latestrev: %.3f %d\n' % stats['latestrev']
125
if stats.has_key('revisions'):
126
body += 'revisions: %d\n' % stats['revisions']
127
if stats.has_key('size'):
128
body += 'size: %d\n' % stats['size']
130
return SmartServerResponse(('ok', ), body)
133
class SmartServerRepositoryIsShared(SmartServerRepositoryRequest):
135
def do_repository_request(self, repository):
136
"""Return the result of repository.is_shared().
138
:param repository: The repository to query in.
139
:return: A smart server response of ('yes', ) if the repository is
140
shared, and ('no', ) if it is not.
142
if repository.is_shared():
143
return SmartServerResponse(('yes', ))
145
return SmartServerResponse(('no', ))
148
class SmartServerRepositoryLockWrite(SmartServerRepositoryRequest):
150
def do_repository_request(self, repository, token=''):
151
# XXX: this probably should not have a token.
155
token = repository.lock_write(token=token)
156
except errors.LockContention, e:
157
return SmartServerResponse(('LockContention',))
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',))