##// END OF EJS Templates
wireproto: fix check-code.py breakage introduced by 6d97dd630d79
Patrick Mezard -
r17567:2ee7281e default
parent child Browse files
Show More
@@ -1,632 +1,637 b''
1 # wireproto.py - generic wire protocol support functions
1 # wireproto.py - generic wire protocol support functions
2 #
2 #
3 # Copyright 2005-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import urllib, tempfile, os, sys
8 import urllib, tempfile, os, sys
9 from i18n import _
9 from i18n import _
10 from node import bin, hex
10 from node import bin, hex
11 import changegroup as changegroupmod
11 import changegroup as changegroupmod
12 import peer, error, encoding, util, store
12 import peer, error, encoding, util, store
13 import discovery, phases
13 import discovery, phases
14
14
15 # abstract batching support
15 # abstract batching support
16
16
17 class future(object):
17 class future(object):
18 '''placeholder for a value to be set later'''
18 '''placeholder for a value to be set later'''
19 def set(self, value):
19 def set(self, value):
20 if util.safehasattr(self, 'value'):
20 if util.safehasattr(self, 'value'):
21 raise error.RepoError("future is already set")
21 raise error.RepoError("future is already set")
22 self.value = value
22 self.value = value
23
23
24 class batcher(object):
24 class batcher(object):
25 '''base class for batches of commands submittable in a single request
25 '''base class for batches of commands submittable in a single request
26
26
27 All methods invoked on instances of this class are simply queued and
27 All methods invoked on instances of this class are simply queued and
28 return a a future for the result. Once you call submit(), all the queued
28 return a a future for the result. Once you call submit(), all the queued
29 calls are performed and the results set in their respective futures.
29 calls are performed and the results set in their respective futures.
30 '''
30 '''
31 def __init__(self):
31 def __init__(self):
32 self.calls = []
32 self.calls = []
33 def __getattr__(self, name):
33 def __getattr__(self, name):
34 def call(*args, **opts):
34 def call(*args, **opts):
35 resref = future()
35 resref = future()
36 self.calls.append((name, args, opts, resref,))
36 self.calls.append((name, args, opts, resref,))
37 return resref
37 return resref
38 return call
38 return call
39 def submit(self):
39 def submit(self):
40 pass
40 pass
41
41
42 class localbatch(batcher):
42 class localbatch(batcher):
43 '''performs the queued calls directly'''
43 '''performs the queued calls directly'''
44 def __init__(self, local):
44 def __init__(self, local):
45 batcher.__init__(self)
45 batcher.__init__(self)
46 self.local = local
46 self.local = local
47 def submit(self):
47 def submit(self):
48 for name, args, opts, resref in self.calls:
48 for name, args, opts, resref in self.calls:
49 resref.set(getattr(self.local, name)(*args, **opts))
49 resref.set(getattr(self.local, name)(*args, **opts))
50
50
51 class remotebatch(batcher):
51 class remotebatch(batcher):
52 '''batches the queued calls; uses as few roundtrips as possible'''
52 '''batches the queued calls; uses as few roundtrips as possible'''
53 def __init__(self, remote):
53 def __init__(self, remote):
54 '''remote must support _submitbatch(encbatch) and
54 '''remote must support _submitbatch(encbatch) and
55 _submitone(op, encargs)'''
55 _submitone(op, encargs)'''
56 batcher.__init__(self)
56 batcher.__init__(self)
57 self.remote = remote
57 self.remote = remote
58 def submit(self):
58 def submit(self):
59 req, rsp = [], []
59 req, rsp = [], []
60 for name, args, opts, resref in self.calls:
60 for name, args, opts, resref in self.calls:
61 mtd = getattr(self.remote, name)
61 mtd = getattr(self.remote, name)
62 batchablefn = getattr(mtd, 'batchable', None)
62 batchablefn = getattr(mtd, 'batchable', None)
63 if batchablefn is not None:
63 if batchablefn is not None:
64 batchable = batchablefn(mtd.im_self, *args, **opts)
64 batchable = batchablefn(mtd.im_self, *args, **opts)
65 encargsorres, encresref = batchable.next()
65 encargsorres, encresref = batchable.next()
66 if encresref:
66 if encresref:
67 req.append((name, encargsorres,))
67 req.append((name, encargsorres,))
68 rsp.append((batchable, encresref, resref,))
68 rsp.append((batchable, encresref, resref,))
69 else:
69 else:
70 resref.set(encargsorres)
70 resref.set(encargsorres)
71 else:
71 else:
72 if req:
72 if req:
73 self._submitreq(req, rsp)
73 self._submitreq(req, rsp)
74 req, rsp = [], []
74 req, rsp = [], []
75 resref.set(mtd(*args, **opts))
75 resref.set(mtd(*args, **opts))
76 if req:
76 if req:
77 self._submitreq(req, rsp)
77 self._submitreq(req, rsp)
78 def _submitreq(self, req, rsp):
78 def _submitreq(self, req, rsp):
79 encresults = self.remote._submitbatch(req)
79 encresults = self.remote._submitbatch(req)
80 for encres, r in zip(encresults, rsp):
80 for encres, r in zip(encresults, rsp):
81 batchable, encresref, resref = r
81 batchable, encresref, resref = r
82 encresref.set(encres)
82 encresref.set(encres)
83 resref.set(batchable.next())
83 resref.set(batchable.next())
84
84
85 def batchable(f):
85 def batchable(f):
86 '''annotation for batchable methods
86 '''annotation for batchable methods
87
87
88 Such methods must implement a coroutine as follows:
88 Such methods must implement a coroutine as follows:
89
89
90 @batchable
90 @batchable
91 def sample(self, one, two=None):
91 def sample(self, one, two=None):
92 # Handle locally computable results first:
92 # Handle locally computable results first:
93 if not one:
93 if not one:
94 yield "a local result", None
94 yield "a local result", None
95 # Build list of encoded arguments suitable for your wire protocol:
95 # Build list of encoded arguments suitable for your wire protocol:
96 encargs = [('one', encode(one),), ('two', encode(two),)]
96 encargs = [('one', encode(one),), ('two', encode(two),)]
97 # Create future for injection of encoded result:
97 # Create future for injection of encoded result:
98 encresref = future()
98 encresref = future()
99 # Return encoded arguments and future:
99 # Return encoded arguments and future:
100 yield encargs, encresref
100 yield encargs, encresref
101 # Assuming the future to be filled with the result from the batched
101 # Assuming the future to be filled with the result from the batched
102 # request now. Decode it:
102 # request now. Decode it:
103 yield decode(encresref.value)
103 yield decode(encresref.value)
104
104
105 The decorator returns a function which wraps this coroutine as a plain
105 The decorator returns a function which wraps this coroutine as a plain
106 method, but adds the original method as an attribute called "batchable",
106 method, but adds the original method as an attribute called "batchable",
107 which is used by remotebatch to split the call into separate encoding and
107 which is used by remotebatch to split the call into separate encoding and
108 decoding phases.
108 decoding phases.
109 '''
109 '''
110 def plain(*args, **opts):
110 def plain(*args, **opts):
111 batchable = f(*args, **opts)
111 batchable = f(*args, **opts)
112 encargsorres, encresref = batchable.next()
112 encargsorres, encresref = batchable.next()
113 if not encresref:
113 if not encresref:
114 return encargsorres # a local result in this case
114 return encargsorres # a local result in this case
115 self = args[0]
115 self = args[0]
116 encresref.set(self._submitone(f.func_name, encargsorres))
116 encresref.set(self._submitone(f.func_name, encargsorres))
117 return batchable.next()
117 return batchable.next()
118 setattr(plain, 'batchable', f)
118 setattr(plain, 'batchable', f)
119 return plain
119 return plain
120
120
121 # list of nodes encoding / decoding
121 # list of nodes encoding / decoding
122
122
123 def decodelist(l, sep=' '):
123 def decodelist(l, sep=' '):
124 if l:
124 if l:
125 return map(bin, l.split(sep))
125 return map(bin, l.split(sep))
126 return []
126 return []
127
127
128 def encodelist(l, sep=' '):
128 def encodelist(l, sep=' '):
129 return sep.join(map(hex, l))
129 return sep.join(map(hex, l))
130
130
131 # batched call argument encoding
131 # batched call argument encoding
132
132
133 def escapearg(plain):
133 def escapearg(plain):
134 return (plain
134 return (plain
135 .replace(':', '::')
135 .replace(':', '::')
136 .replace(',', ':,')
136 .replace(',', ':,')
137 .replace(';', ':;')
137 .replace(';', ':;')
138 .replace('=', ':='))
138 .replace('=', ':='))
139
139
140 def unescapearg(escaped):
140 def unescapearg(escaped):
141 return (escaped
141 return (escaped
142 .replace(':=', '=')
142 .replace(':=', '=')
143 .replace(':;', ';')
143 .replace(':;', ';')
144 .replace(':,', ',')
144 .replace(':,', ',')
145 .replace('::', ':'))
145 .replace('::', ':'))
146
146
147 # client side
147 # client side
148
148
149 def todict(**args):
149 def todict(**args):
150 return args
150 return args
151
151
152 class wirepeer(peer.peerrepository):
152 class wirepeer(peer.peerrepository):
153
153
154 def batch(self):
154 def batch(self):
155 return remotebatch(self)
155 return remotebatch(self)
156 def _submitbatch(self, req):
156 def _submitbatch(self, req):
157 cmds = []
157 cmds = []
158 for op, argsdict in req:
158 for op, argsdict in req:
159 args = ','.join('%s=%s' % p for p in argsdict.iteritems())
159 args = ','.join('%s=%s' % p for p in argsdict.iteritems())
160 cmds.append('%s %s' % (op, args))
160 cmds.append('%s %s' % (op, args))
161 rsp = self._call("batch", cmds=';'.join(cmds))
161 rsp = self._call("batch", cmds=';'.join(cmds))
162 return rsp.split(';')
162 return rsp.split(';')
163 def _submitone(self, op, args):
163 def _submitone(self, op, args):
164 return self._call(op, **args)
164 return self._call(op, **args)
165
165
166 @batchable
166 @batchable
167 def lookup(self, key):
167 def lookup(self, key):
168 self.requirecap('lookup', _('look up remote revision'))
168 self.requirecap('lookup', _('look up remote revision'))
169 f = future()
169 f = future()
170 yield todict(key=encoding.fromlocal(key)), f
170 yield todict(key=encoding.fromlocal(key)), f
171 d = f.value
171 d = f.value
172 success, data = d[:-1].split(" ", 1)
172 success, data = d[:-1].split(" ", 1)
173 if int(success):
173 if int(success):
174 yield bin(data)
174 yield bin(data)
175 self._abort(error.RepoError(data))
175 self._abort(error.RepoError(data))
176
176
177 @batchable
177 @batchable
178 def heads(self):
178 def heads(self):
179 f = future()
179 f = future()
180 yield {}, f
180 yield {}, f
181 d = f.value
181 d = f.value
182 try:
182 try:
183 yield decodelist(d[:-1])
183 yield decodelist(d[:-1])
184 except ValueError:
184 except ValueError:
185 self._abort(error.ResponseError(_("unexpected response:"), d))
185 self._abort(error.ResponseError(_("unexpected response:"), d))
186
186
187 @batchable
187 @batchable
188 def known(self, nodes):
188 def known(self, nodes):
189 f = future()
189 f = future()
190 yield todict(nodes=encodelist(nodes)), f
190 yield todict(nodes=encodelist(nodes)), f
191 d = f.value
191 d = f.value
192 try:
192 try:
193 yield [bool(int(f)) for f in d]
193 yield [bool(int(f)) for f in d]
194 except ValueError:
194 except ValueError:
195 self._abort(error.ResponseError(_("unexpected response:"), d))
195 self._abort(error.ResponseError(_("unexpected response:"), d))
196
196
197 @batchable
197 @batchable
198 def branchmap(self):
198 def branchmap(self):
199 f = future()
199 f = future()
200 yield {}, f
200 yield {}, f
201 d = f.value
201 d = f.value
202 try:
202 try:
203 branchmap = {}
203 branchmap = {}
204 for branchpart in d.splitlines():
204 for branchpart in d.splitlines():
205 branchname, branchheads = branchpart.split(' ', 1)
205 branchname, branchheads = branchpart.split(' ', 1)
206 branchname = encoding.tolocal(urllib.unquote(branchname))
206 branchname = encoding.tolocal(urllib.unquote(branchname))
207 branchheads = decodelist(branchheads)
207 branchheads = decodelist(branchheads)
208 branchmap[branchname] = branchheads
208 branchmap[branchname] = branchheads
209 yield branchmap
209 yield branchmap
210 except TypeError:
210 except TypeError:
211 self._abort(error.ResponseError(_("unexpected response:"), d))
211 self._abort(error.ResponseError(_("unexpected response:"), d))
212
212
213 def branches(self, nodes):
213 def branches(self, nodes):
214 n = encodelist(nodes)
214 n = encodelist(nodes)
215 d = self._call("branches", nodes=n)
215 d = self._call("branches", nodes=n)
216 try:
216 try:
217 br = [tuple(decodelist(b)) for b in d.splitlines()]
217 br = [tuple(decodelist(b)) for b in d.splitlines()]
218 return br
218 return br
219 except ValueError:
219 except ValueError:
220 self._abort(error.ResponseError(_("unexpected response:"), d))
220 self._abort(error.ResponseError(_("unexpected response:"), d))
221
221
222 def between(self, pairs):
222 def between(self, pairs):
223 batch = 8 # avoid giant requests
223 batch = 8 # avoid giant requests
224 r = []
224 r = []
225 for i in xrange(0, len(pairs), batch):
225 for i in xrange(0, len(pairs), batch):
226 n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
226 n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
227 d = self._call("between", pairs=n)
227 d = self._call("between", pairs=n)
228 try:
228 try:
229 r.extend(l and decodelist(l) or [] for l in d.splitlines())
229 r.extend(l and decodelist(l) or [] for l in d.splitlines())
230 except ValueError:
230 except ValueError:
231 self._abort(error.ResponseError(_("unexpected response:"), d))
231 self._abort(error.ResponseError(_("unexpected response:"), d))
232 return r
232 return r
233
233
234 @batchable
234 @batchable
235 def pushkey(self, namespace, key, old, new):
235 def pushkey(self, namespace, key, old, new):
236 if not self.capable('pushkey'):
236 if not self.capable('pushkey'):
237 yield False, None
237 yield False, None
238 f = future()
238 f = future()
239 self.ui.debug('preparing pushkey for "%s:%s"\n' % (namespace, key))
239 self.ui.debug('preparing pushkey for "%s:%s"\n' % (namespace, key))
240 yield todict(namespace=encoding.fromlocal(namespace),
240 yield todict(namespace=encoding.fromlocal(namespace),
241 key=encoding.fromlocal(key),
241 key=encoding.fromlocal(key),
242 old=encoding.fromlocal(old),
242 old=encoding.fromlocal(old),
243 new=encoding.fromlocal(new)), f
243 new=encoding.fromlocal(new)), f
244 d = f.value
244 d = f.value
245 d, output = d.split('\n', 1)
245 d, output = d.split('\n', 1)
246 try:
246 try:
247 d = bool(int(d))
247 d = bool(int(d))
248 except ValueError:
248 except ValueError:
249 raise error.ResponseError(
249 raise error.ResponseError(
250 _('push failed (unexpected response):'), d)
250 _('push failed (unexpected response):'), d)
251 for l in output.splitlines(True):
251 for l in output.splitlines(True):
252 self.ui.status(_('remote: '), l)
252 self.ui.status(_('remote: '), l)
253 yield d
253 yield d
254
254
255 @batchable
255 @batchable
256 def listkeys(self, namespace):
256 def listkeys(self, namespace):
257 if not self.capable('pushkey'):
257 if not self.capable('pushkey'):
258 yield {}, None
258 yield {}, None
259 f = future()
259 f = future()
260 self.ui.debug('preparing listkeys for "%s"\n' % namespace)
260 self.ui.debug('preparing listkeys for "%s"\n' % namespace)
261 yield todict(namespace=encoding.fromlocal(namespace)), f
261 yield todict(namespace=encoding.fromlocal(namespace)), f
262 d = f.value
262 d = f.value
263 r = {}
263 r = {}
264 for l in d.splitlines():
264 for l in d.splitlines():
265 k, v = l.split('\t')
265 k, v = l.split('\t')
266 r[encoding.tolocal(k)] = encoding.tolocal(v)
266 r[encoding.tolocal(k)] = encoding.tolocal(v)
267 yield r
267 yield r
268
268
269 def stream_out(self):
269 def stream_out(self):
270 return self._callstream('stream_out')
270 return self._callstream('stream_out')
271
271
272 def changegroup(self, nodes, kind):
272 def changegroup(self, nodes, kind):
273 n = encodelist(nodes)
273 n = encodelist(nodes)
274 f = self._callstream("changegroup", roots=n)
274 f = self._callstream("changegroup", roots=n)
275 return changegroupmod.unbundle10(self._decompress(f), 'UN')
275 return changegroupmod.unbundle10(self._decompress(f), 'UN')
276
276
277 def changegroupsubset(self, bases, heads, kind):
277 def changegroupsubset(self, bases, heads, kind):
278 self.requirecap('changegroupsubset', _('look up remote changes'))
278 self.requirecap('changegroupsubset', _('look up remote changes'))
279 bases = encodelist(bases)
279 bases = encodelist(bases)
280 heads = encodelist(heads)
280 heads = encodelist(heads)
281 f = self._callstream("changegroupsubset",
281 f = self._callstream("changegroupsubset",
282 bases=bases, heads=heads)
282 bases=bases, heads=heads)
283 return changegroupmod.unbundle10(self._decompress(f), 'UN')
283 return changegroupmod.unbundle10(self._decompress(f), 'UN')
284
284
285 def getbundle(self, source, heads=None, common=None):
285 def getbundle(self, source, heads=None, common=None):
286 self.requirecap('getbundle', _('look up remote changes'))
286 self.requirecap('getbundle', _('look up remote changes'))
287 opts = {}
287 opts = {}
288 if heads is not None:
288 if heads is not None:
289 opts['heads'] = encodelist(heads)
289 opts['heads'] = encodelist(heads)
290 if common is not None:
290 if common is not None:
291 opts['common'] = encodelist(common)
291 opts['common'] = encodelist(common)
292 f = self._callstream("getbundle", **opts)
292 f = self._callstream("getbundle", **opts)
293 return changegroupmod.unbundle10(self._decompress(f), 'UN')
293 return changegroupmod.unbundle10(self._decompress(f), 'UN')
294
294
295 def unbundle(self, cg, heads, source):
295 def unbundle(self, cg, heads, source):
296 '''Send cg (a readable file-like object representing the
296 '''Send cg (a readable file-like object representing the
297 changegroup to push, typically a chunkbuffer object) to the
297 changegroup to push, typically a chunkbuffer object) to the
298 remote server as a bundle. Return an integer indicating the
298 remote server as a bundle. Return an integer indicating the
299 result of the push (see localrepository.addchangegroup()).'''
299 result of the push (see localrepository.addchangegroup()).'''
300
300
301 if heads != ['force'] and self.capable('unbundlehash'):
301 if heads != ['force'] and self.capable('unbundlehash'):
302 heads = encodelist(['hashed',
302 heads = encodelist(['hashed',
303 util.sha1(''.join(sorted(heads))).digest()])
303 util.sha1(''.join(sorted(heads))).digest()])
304 else:
304 else:
305 heads = encodelist(heads)
305 heads = encodelist(heads)
306
306
307 ret, output = self._callpush("unbundle", cg, heads=heads)
307 ret, output = self._callpush("unbundle", cg, heads=heads)
308 if ret == "":
308 if ret == "":
309 raise error.ResponseError(
309 raise error.ResponseError(
310 _('push failed:'), output)
310 _('push failed:'), output)
311 try:
311 try:
312 ret = int(ret)
312 ret = int(ret)
313 except ValueError:
313 except ValueError:
314 raise error.ResponseError(
314 raise error.ResponseError(
315 _('push failed (unexpected response):'), ret)
315 _('push failed (unexpected response):'), ret)
316
316
317 for l in output.splitlines(True):
317 for l in output.splitlines(True):
318 self.ui.status(_('remote: '), l)
318 self.ui.status(_('remote: '), l)
319 return ret
319 return ret
320
320
321 def debugwireargs(self, one, two, three=None, four=None, five=None):
321 def debugwireargs(self, one, two, three=None, four=None, five=None):
322 # don't pass optional arguments left at their default value
322 # don't pass optional arguments left at their default value
323 opts = {}
323 opts = {}
324 if three is not None:
324 if three is not None:
325 opts['three'] = three
325 opts['three'] = three
326 if four is not None:
326 if four is not None:
327 opts['four'] = four
327 opts['four'] = four
328 return self._call('debugwireargs', one=one, two=two, **opts)
328 return self._call('debugwireargs', one=one, two=two, **opts)
329
329
330 # server side
330 # server side
331
331
332 class streamres(object):
332 class streamres(object):
333 def __init__(self, gen):
333 def __init__(self, gen):
334 self.gen = gen
334 self.gen = gen
335
335
336 class pushres(object):
336 class pushres(object):
337 def __init__(self, res):
337 def __init__(self, res):
338 self.res = res
338 self.res = res
339
339
340 class pusherr(object):
340 class pusherr(object):
341 def __init__(self, res):
341 def __init__(self, res):
342 self.res = res
342 self.res = res
343
343
344 class ooberror(object):
344 class ooberror(object):
345 def __init__(self, message):
345 def __init__(self, message):
346 self.message = message
346 self.message = message
347
347
348 def dispatch(repo, proto, command):
348 def dispatch(repo, proto, command):
349 func, spec = commands[command]
349 func, spec = commands[command]
350 args = proto.getargs(spec)
350 args = proto.getargs(spec)
351 return func(repo, proto, *args)
351 return func(repo, proto, *args)
352
352
353 def options(cmd, keys, others):
353 def options(cmd, keys, others):
354 opts = {}
354 opts = {}
355 for k in keys:
355 for k in keys:
356 if k in others:
356 if k in others:
357 opts[k] = others[k]
357 opts[k] = others[k]
358 del others[k]
358 del others[k]
359 if others:
359 if others:
360 sys.stderr.write("abort: %s got unexpected arguments %s\n"
360 sys.stderr.write("abort: %s got unexpected arguments %s\n"
361 % (cmd, ",".join(others)))
361 % (cmd, ",".join(others)))
362 return opts
362 return opts
363
363
364 def batch(repo, proto, cmds, others):
364 def batch(repo, proto, cmds, others):
365 res = []
365 res = []
366 for pair in cmds.split(';'):
366 for pair in cmds.split(';'):
367 op, args = pair.split(' ', 1)
367 op, args = pair.split(' ', 1)
368 vals = {}
368 vals = {}
369 for a in args.split(','):
369 for a in args.split(','):
370 if a:
370 if a:
371 n, v = a.split('=')
371 n, v = a.split('=')
372 vals[n] = unescapearg(v)
372 vals[n] = unescapearg(v)
373 func, spec = commands[op]
373 func, spec = commands[op]
374 if spec:
374 if spec:
375 keys = spec.split()
375 keys = spec.split()
376 data = {}
376 data = {}
377 for k in keys:
377 for k in keys:
378 if k == '*':
378 if k == '*':
379 star = {}
379 star = {}
380 for key in vals.keys():
380 for key in vals.keys():
381 if key not in keys:
381 if key not in keys:
382 star[key] = vals[key]
382 star[key] = vals[key]
383 data['*'] = star
383 data['*'] = star
384 else:
384 else:
385 data[k] = vals[k]
385 data[k] = vals[k]
386 result = func(repo, proto, *[data[k] for k in keys])
386 result = func(repo, proto, *[data[k] for k in keys])
387 else:
387 else:
388 result = func(repo, proto)
388 result = func(repo, proto)
389 if isinstance(result, ooberror):
389 if isinstance(result, ooberror):
390 return result
390 return result
391 res.append(escapearg(result))
391 res.append(escapearg(result))
392 return ';'.join(res)
392 return ';'.join(res)
393
393
394 def between(repo, proto, pairs):
394 def between(repo, proto, pairs):
395 pairs = [decodelist(p, '-') for p in pairs.split(" ")]
395 pairs = [decodelist(p, '-') for p in pairs.split(" ")]
396 r = []
396 r = []
397 for b in repo.between(pairs):
397 for b in repo.between(pairs):
398 r.append(encodelist(b) + "\n")
398 r.append(encodelist(b) + "\n")
399 return "".join(r)
399 return "".join(r)
400
400
401 def branchmap(repo, proto):
401 def branchmap(repo, proto):
402 branchmap = discovery.visiblebranchmap(repo)
402 branchmap = discovery.visiblebranchmap(repo)
403 heads = []
403 heads = []
404 for branch, nodes in branchmap.iteritems():
404 for branch, nodes in branchmap.iteritems():
405 branchname = urllib.quote(encoding.fromlocal(branch))
405 branchname = urllib.quote(encoding.fromlocal(branch))
406 branchnodes = encodelist(nodes)
406 branchnodes = encodelist(nodes)
407 heads.append('%s %s' % (branchname, branchnodes))
407 heads.append('%s %s' % (branchname, branchnodes))
408 return '\n'.join(heads)
408 return '\n'.join(heads)
409
409
410 def branches(repo, proto, nodes):
410 def branches(repo, proto, nodes):
411 nodes = decodelist(nodes)
411 nodes = decodelist(nodes)
412 r = []
412 r = []
413 for b in repo.branches(nodes):
413 for b in repo.branches(nodes):
414 r.append(encodelist(b) + "\n")
414 r.append(encodelist(b) + "\n")
415 return "".join(r)
415 return "".join(r)
416
416
417 def capabilities(repo, proto):
417 def capabilities(repo, proto):
418 caps = ('lookup changegroupsubset branchmap pushkey known getbundle '
418 caps = ('lookup changegroupsubset branchmap pushkey known getbundle '
419 'unbundlehash batch').split()
419 'unbundlehash batch').split()
420 if _allowstream(repo.ui):
420 if _allowstream(repo.ui):
421 if repo.ui.configbool('server', 'preferuncompressed', False):
421 if repo.ui.configbool('server', 'preferuncompressed', False):
422 caps.append('stream-preferred')
422 caps.append('stream-preferred')
423 requiredformats = repo.requirements & repo.supportedformats
423 requiredformats = repo.requirements & repo.supportedformats
424 # if our local revlogs are just revlogv1, add 'stream' cap
424 # if our local revlogs are just revlogv1, add 'stream' cap
425 if not requiredformats - set(('revlogv1',)):
425 if not requiredformats - set(('revlogv1',)):
426 caps.append('stream')
426 caps.append('stream')
427 # otherwise, add 'streamreqs' detailing our local revlog format
427 # otherwise, add 'streamreqs' detailing our local revlog format
428 else:
428 else:
429 caps.append('streamreqs=%s' % ','.join(requiredformats))
429 caps.append('streamreqs=%s' % ','.join(requiredformats))
430 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
430 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
431 caps.append('httpheader=1024')
431 caps.append('httpheader=1024')
432 return ' '.join(caps)
432 return ' '.join(caps)
433
433
434 def changegroup(repo, proto, roots):
434 def changegroup(repo, proto, roots):
435 nodes = decodelist(roots)
435 nodes = decodelist(roots)
436 cg = repo.changegroup(nodes, 'serve')
436 cg = repo.changegroup(nodes, 'serve')
437 return streamres(proto.groupchunks(cg))
437 return streamres(proto.groupchunks(cg))
438
438
439 def changegroupsubset(repo, proto, bases, heads):
439 def changegroupsubset(repo, proto, bases, heads):
440 bases = decodelist(bases)
440 bases = decodelist(bases)
441 heads = decodelist(heads)
441 heads = decodelist(heads)
442 cg = repo.changegroupsubset(bases, heads, 'serve')
442 cg = repo.changegroupsubset(bases, heads, 'serve')
443 return streamres(proto.groupchunks(cg))
443 return streamres(proto.groupchunks(cg))
444
444
445 def debugwireargs(repo, proto, one, two, others):
445 def debugwireargs(repo, proto, one, two, others):
446 # only accept optional args from the known set
446 # only accept optional args from the known set
447 opts = options('debugwireargs', ['three', 'four'], others)
447 opts = options('debugwireargs', ['three', 'four'], others)
448 return repo.debugwireargs(one, two, **opts)
448 return repo.debugwireargs(one, two, **opts)
449
449
450 def getbundle(repo, proto, others):
450 def getbundle(repo, proto, others):
451 opts = options('getbundle', ['heads', 'common'], others)
451 opts = options('getbundle', ['heads', 'common'], others)
452 for k, v in opts.iteritems():
452 for k, v in opts.iteritems():
453 opts[k] = decodelist(v)
453 opts[k] = decodelist(v)
454 cg = repo.getbundle('serve', **opts)
454 cg = repo.getbundle('serve', **opts)
455 return streamres(proto.groupchunks(cg))
455 return streamres(proto.groupchunks(cg))
456
456
457 def heads(repo, proto):
457 def heads(repo, proto):
458 h = discovery.visibleheads(repo)
458 h = discovery.visibleheads(repo)
459 return encodelist(h) + "\n"
459 return encodelist(h) + "\n"
460
460
461 def hello(repo, proto):
461 def hello(repo, proto):
462 '''the hello command returns a set of lines describing various
462 '''the hello command returns a set of lines describing various
463 interesting things about the server, in an RFC822-like format.
463 interesting things about the server, in an RFC822-like format.
464 Currently the only one defined is "capabilities", which
464 Currently the only one defined is "capabilities", which
465 consists of a line in the form:
465 consists of a line in the form:
466
466
467 capabilities: space separated list of tokens
467 capabilities: space separated list of tokens
468 '''
468 '''
469 return "capabilities: %s\n" % (capabilities(repo, proto))
469 return "capabilities: %s\n" % (capabilities(repo, proto))
470
470
471 def listkeys(repo, proto, namespace):
471 def listkeys(repo, proto, namespace):
472 d = repo.listkeys(encoding.tolocal(namespace)).items()
472 d = repo.listkeys(encoding.tolocal(namespace)).items()
473 t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v))
473 t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v))
474 for k, v in d])
474 for k, v in d])
475 return t
475 return t
476
476
477 def lookup(repo, proto, key):
477 def lookup(repo, proto, key):
478 try:
478 try:
479 k = encoding.tolocal(key)
479 k = encoding.tolocal(key)
480 c = repo[k]
480 c = repo[k]
481 if c.phase() == phases.secret:
481 if c.phase() == phases.secret:
482 raise error.RepoLookupError(_("unknown revision '%s'") % k)
482 raise error.RepoLookupError(_("unknown revision '%s'") % k)
483 r = c.hex()
483 r = c.hex()
484 success = 1
484 success = 1
485 except Exception, inst:
485 except Exception, inst:
486 r = str(inst)
486 r = str(inst)
487 success = 0
487 success = 0
488 return "%s %s\n" % (success, r)
488 return "%s %s\n" % (success, r)
489
489
490 def known(repo, proto, nodes, others):
490 def known(repo, proto, nodes, others):
491 return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes)))
491 return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes)))
492
492
493 def pushkey(repo, proto, namespace, key, old, new):
493 def pushkey(repo, proto, namespace, key, old, new):
494 # compatibility with pre-1.8 clients which were accidentally
494 # compatibility with pre-1.8 clients which were accidentally
495 # sending raw binary nodes rather than utf-8-encoded hex
495 # sending raw binary nodes rather than utf-8-encoded hex
496 if len(new) == 20 and new.encode('string-escape') != new:
496 if len(new) == 20 and new.encode('string-escape') != new:
497 # looks like it could be a binary node
497 # looks like it could be a binary node
498 try:
498 try:
499 new.decode('utf-8')
499 new.decode('utf-8')
500 new = encoding.tolocal(new) # but cleanly decodes as UTF-8
500 new = encoding.tolocal(new) # but cleanly decodes as UTF-8
501 except UnicodeDecodeError:
501 except UnicodeDecodeError:
502 pass # binary, leave unmodified
502 pass # binary, leave unmodified
503 else:
503 else:
504 new = encoding.tolocal(new) # normal path
504 new = encoding.tolocal(new) # normal path
505
505
506 r = repo.pushkey(encoding.tolocal(namespace), encoding.tolocal(key),
506 r = repo.pushkey(encoding.tolocal(namespace), encoding.tolocal(key),
507 encoding.tolocal(old), new)
507 encoding.tolocal(old), new)
508 return '%s\n' % int(r)
508 return '%s\n' % int(r)
509
509
510 def _allowstream(ui):
510 def _allowstream(ui):
511 return ui.configbool('server', 'uncompressed', True, untrusted=True)
511 return ui.configbool('server', 'uncompressed', True, untrusted=True)
512
512
513 def stream(repo, proto):
513 def stream(repo, proto):
514 '''If the server supports streaming clone, it advertises the "stream"
514 '''If the server supports streaming clone, it advertises the "stream"
515 capability with a value representing the version and flags of the repo
515 capability with a value representing the version and flags of the repo
516 it is serving. Client checks to see if it understands the format.
516 it is serving. Client checks to see if it understands the format.
517
517
518 The format is simple: the server writes out a line with the amount
518 The format is simple: the server writes out a line with the amount
519 of files, then the total amount of bytes to be transferred (separated
519 of files, then the total amount of bytes to be transferred (separated
520 by a space). Then, for each file, the server first writes the filename
520 by a space). Then, for each file, the server first writes the filename
521 and filesize (separated by the null character), then the file contents.
521 and filesize (separated by the null character), then the file contents.
522 '''
522 '''
523
523
524 if not _allowstream(repo.ui):
524 if not _allowstream(repo.ui):
525 return '1\n'
525 return '1\n'
526
526
527 entries = []
527 entries = []
528 total_bytes = 0
528 total_bytes = 0
529 try:
529 try:
530 # get consistent snapshot of repo, lock during scan
530 # get consistent snapshot of repo, lock during scan
531 lock = repo.lock()
531 lock = repo.lock()
532 try:
532 try:
533 repo.ui.debug('scanning\n')
533 repo.ui.debug('scanning\n')
534 for name, ename, size in repo.store.walk():
534 for name, ename, size in repo.store.walk():
535 entries.append((name, size))
535 entries.append((name, size))
536 total_bytes += size
536 total_bytes += size
537 finally:
537 finally:
538 lock.release()
538 lock.release()
539 except error.LockError:
539 except error.LockError:
540 return '2\n' # error: 2
540 return '2\n' # error: 2
541
541
542 def streamer(repo, entries, total):
542 def streamer(repo, entries, total):
543 '''stream out all metadata files in repository.'''
543 '''stream out all metadata files in repository.'''
544 yield '0\n' # success
544 yield '0\n' # success
545 repo.ui.debug('%d files, %d bytes to transfer\n' %
545 repo.ui.debug('%d files, %d bytes to transfer\n' %
546 (len(entries), total_bytes))
546 (len(entries), total_bytes))
547 yield '%d %d\n' % (len(entries), total_bytes)
547 yield '%d %d\n' % (len(entries), total_bytes)
548
548
549 sopener = repo.sopener
549 sopener = repo.sopener
550 oldaudit = sopener.mustaudit
550 oldaudit = sopener.mustaudit
551 debugflag = repo.ui.debugflag
551 debugflag = repo.ui.debugflag
552 sopener.mustaudit = False
552 sopener.mustaudit = False
553
553
554 try:
554 try:
555 for name, size in entries:
555 for name, size in entries:
556 if debugflag:
556 if debugflag:
557 repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
557 repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
558 # partially encode name over the wire for backwards compat
558 # partially encode name over the wire for backwards compat
559 yield '%s\0%d\n' % (store.encodedir(name), size)
559 yield '%s\0%d\n' % (store.encodedir(name), size)
560 if size <= 65536:
560 if size <= 65536:
561 yield sopener(name).read(size)
561 fp = sopener(name)
562 try:
563 data = fp.read(size)
564 finally:
565 fp.close()
566 yield data
562 else:
567 else:
563 for chunk in util.filechunkiter(sopener(name), limit=size):
568 for chunk in util.filechunkiter(sopener(name), limit=size):
564 yield chunk
569 yield chunk
565 finally:
570 finally:
566 sopener.mustaudit = oldaudit
571 sopener.mustaudit = oldaudit
567
572
568 return streamres(streamer(repo, entries, total_bytes))
573 return streamres(streamer(repo, entries, total_bytes))
569
574
570 def unbundle(repo, proto, heads):
575 def unbundle(repo, proto, heads):
571 their_heads = decodelist(heads)
576 their_heads = decodelist(heads)
572
577
573 def check_heads():
578 def check_heads():
574 heads = discovery.visibleheads(repo)
579 heads = discovery.visibleheads(repo)
575 heads_hash = util.sha1(''.join(sorted(heads))).digest()
580 heads_hash = util.sha1(''.join(sorted(heads))).digest()
576 return (their_heads == ['force'] or their_heads == heads or
581 return (their_heads == ['force'] or their_heads == heads or
577 their_heads == ['hashed', heads_hash])
582 their_heads == ['hashed', heads_hash])
578
583
579 proto.redirect()
584 proto.redirect()
580
585
581 # fail early if possible
586 # fail early if possible
582 if not check_heads():
587 if not check_heads():
583 return pusherr('unsynced changes')
588 return pusherr('unsynced changes')
584
589
585 # write bundle data to temporary file because it can be big
590 # write bundle data to temporary file because it can be big
586 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
591 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
587 fp = os.fdopen(fd, 'wb+')
592 fp = os.fdopen(fd, 'wb+')
588 r = 0
593 r = 0
589 try:
594 try:
590 proto.getfile(fp)
595 proto.getfile(fp)
591 lock = repo.lock()
596 lock = repo.lock()
592 try:
597 try:
593 if not check_heads():
598 if not check_heads():
594 # someone else committed/pushed/unbundled while we
599 # someone else committed/pushed/unbundled while we
595 # were transferring data
600 # were transferring data
596 return pusherr('unsynced changes')
601 return pusherr('unsynced changes')
597
602
598 # push can proceed
603 # push can proceed
599 fp.seek(0)
604 fp.seek(0)
600 gen = changegroupmod.readbundle(fp, None)
605 gen = changegroupmod.readbundle(fp, None)
601
606
602 try:
607 try:
603 r = repo.addchangegroup(gen, 'serve', proto._client())
608 r = repo.addchangegroup(gen, 'serve', proto._client())
604 except util.Abort, inst:
609 except util.Abort, inst:
605 sys.stderr.write("abort: %s\n" % inst)
610 sys.stderr.write("abort: %s\n" % inst)
606 finally:
611 finally:
607 lock.release()
612 lock.release()
608 return pushres(r)
613 return pushres(r)
609
614
610 finally:
615 finally:
611 fp.close()
616 fp.close()
612 os.unlink(tempname)
617 os.unlink(tempname)
613
618
614 commands = {
619 commands = {
615 'batch': (batch, 'cmds *'),
620 'batch': (batch, 'cmds *'),
616 'between': (between, 'pairs'),
621 'between': (between, 'pairs'),
617 'branchmap': (branchmap, ''),
622 'branchmap': (branchmap, ''),
618 'branches': (branches, 'nodes'),
623 'branches': (branches, 'nodes'),
619 'capabilities': (capabilities, ''),
624 'capabilities': (capabilities, ''),
620 'changegroup': (changegroup, 'roots'),
625 'changegroup': (changegroup, 'roots'),
621 'changegroupsubset': (changegroupsubset, 'bases heads'),
626 'changegroupsubset': (changegroupsubset, 'bases heads'),
622 'debugwireargs': (debugwireargs, 'one two *'),
627 'debugwireargs': (debugwireargs, 'one two *'),
623 'getbundle': (getbundle, '*'),
628 'getbundle': (getbundle, '*'),
624 'heads': (heads, ''),
629 'heads': (heads, ''),
625 'hello': (hello, ''),
630 'hello': (hello, ''),
626 'known': (known, 'nodes *'),
631 'known': (known, 'nodes *'),
627 'listkeys': (listkeys, 'namespace'),
632 'listkeys': (listkeys, 'namespace'),
628 'lookup': (lookup, 'key'),
633 'lookup': (lookup, 'key'),
629 'pushkey': (pushkey, 'namespace key old new'),
634 'pushkey': (pushkey, 'namespace key old new'),
630 'stream_out': (stream, ''),
635 'stream_out': (stream, ''),
631 'unbundle': (unbundle, 'heads'),
636 'unbundle': (unbundle, 'heads'),
632 }
637 }
@@ -1,190 +1,183 b''
1 $ check_code="$TESTDIR"/../contrib/check-code.py
1 $ check_code="$TESTDIR"/../contrib/check-code.py
2 $ cd "$TESTDIR"/..
2 $ cd "$TESTDIR"/..
3 $ if hg identify -q > /dev/null; then :
3 $ if hg identify -q > /dev/null; then :
4 > else
4 > else
5 > echo "skipped: not a Mercurial working dir" >&2
5 > echo "skipped: not a Mercurial working dir" >&2
6 > exit 80
6 > exit 80
7 > fi
7 > fi
8 $ hg manifest | xargs "$check_code" || echo 'FAILURE IS NOT AN OPTION!!!'
8 $ hg manifest | xargs "$check_code" || echo 'FAILURE IS NOT AN OPTION!!!'
9 mercurial/wireproto.py:562:
10 > yield sopener(name).read(size)
11 use opener.read() instead
12 FAILURE IS NOT AN OPTION!!!
13
9
14 $ hg manifest | xargs "$check_code" --warnings --nolineno --per-file=0 || true
10 $ hg manifest | xargs "$check_code" --warnings --nolineno --per-file=0 || true
15 hgext/convert/cvsps.py:0:
11 hgext/convert/cvsps.py:0:
16 > ui.write('Ancestors: %s\n' % (','.join(r)))
12 > ui.write('Ancestors: %s\n' % (','.join(r)))
17 warning: unwrapped ui message
13 warning: unwrapped ui message
18 hgext/convert/cvsps.py:0:
14 hgext/convert/cvsps.py:0:
19 > ui.write('Parent: %d\n' % cs.parents[0].id)
15 > ui.write('Parent: %d\n' % cs.parents[0].id)
20 warning: unwrapped ui message
16 warning: unwrapped ui message
21 hgext/convert/cvsps.py:0:
17 hgext/convert/cvsps.py:0:
22 > ui.write('Parents: %s\n' %
18 > ui.write('Parents: %s\n' %
23 warning: unwrapped ui message
19 warning: unwrapped ui message
24 hgext/convert/cvsps.py:0:
20 hgext/convert/cvsps.py:0:
25 > ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
21 > ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
26 warning: unwrapped ui message
22 warning: unwrapped ui message
27 hgext/convert/cvsps.py:0:
23 hgext/convert/cvsps.py:0:
28 > ui.write('Author: %s\n' % cs.author)
24 > ui.write('Author: %s\n' % cs.author)
29 warning: unwrapped ui message
25 warning: unwrapped ui message
30 hgext/convert/cvsps.py:0:
26 hgext/convert/cvsps.py:0:
31 > ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
27 > ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
32 warning: unwrapped ui message
28 warning: unwrapped ui message
33 hgext/convert/cvsps.py:0:
29 hgext/convert/cvsps.py:0:
34 > ui.write('Date: %s\n' % util.datestr(cs.date,
30 > ui.write('Date: %s\n' % util.datestr(cs.date,
35 warning: unwrapped ui message
31 warning: unwrapped ui message
36 hgext/convert/cvsps.py:0:
32 hgext/convert/cvsps.py:0:
37 > ui.write('Log:\n')
33 > ui.write('Log:\n')
38 warning: unwrapped ui message
34 warning: unwrapped ui message
39 hgext/convert/cvsps.py:0:
35 hgext/convert/cvsps.py:0:
40 > ui.write('Members: \n')
36 > ui.write('Members: \n')
41 warning: unwrapped ui message
37 warning: unwrapped ui message
42 hgext/convert/cvsps.py:0:
38 hgext/convert/cvsps.py:0:
43 > ui.write('PatchSet %d \n' % cs.id)
39 > ui.write('PatchSet %d \n' % cs.id)
44 warning: unwrapped ui message
40 warning: unwrapped ui message
45 hgext/convert/cvsps.py:0:
41 hgext/convert/cvsps.py:0:
46 > ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1],
42 > ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1],
47 warning: unwrapped ui message
43 warning: unwrapped ui message
48 hgext/hgk.py:0:
44 hgext/hgk.py:0:
49 > ui.write("parent %s\n" % p)
45 > ui.write("parent %s\n" % p)
50 warning: unwrapped ui message
46 warning: unwrapped ui message
51 hgext/hgk.py:0:
47 hgext/hgk.py:0:
52 > ui.write('k=%s\nv=%s\n' % (name, value))
48 > ui.write('k=%s\nv=%s\n' % (name, value))
53 warning: unwrapped ui message
49 warning: unwrapped ui message
54 hgext/hgk.py:0:
50 hgext/hgk.py:0:
55 > ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
51 > ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
56 warning: unwrapped ui message
52 warning: unwrapped ui message
57 hgext/hgk.py:0:
53 hgext/hgk.py:0:
58 > ui.write("branch %s\n\n" % ctx.branch())
54 > ui.write("branch %s\n\n" % ctx.branch())
59 warning: unwrapped ui message
55 warning: unwrapped ui message
60 hgext/hgk.py:0:
56 hgext/hgk.py:0:
61 > ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
57 > ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
62 warning: unwrapped ui message
58 warning: unwrapped ui message
63 hgext/hgk.py:0:
59 hgext/hgk.py:0:
64 > ui.write("revision %d\n" % ctx.rev())
60 > ui.write("revision %d\n" % ctx.rev())
65 warning: unwrapped ui message
61 warning: unwrapped ui message
66 hgext/hgk.py:0:
62 hgext/hgk.py:0:
67 > ui.write("tree %s\n" % short(ctx.changeset()[0]))
63 > ui.write("tree %s\n" % short(ctx.changeset()[0]))
68 warning: unwrapped ui message
64 warning: unwrapped ui message
69 hgext/mq.py:0:
65 hgext/mq.py:0:
70 > ui.write("mq: %s\n" % ', '.join(m))
66 > ui.write("mq: %s\n" % ', '.join(m))
71 warning: unwrapped ui message
67 warning: unwrapped ui message
72 hgext/patchbomb.py:0:
68 hgext/patchbomb.py:0:
73 > ui.write('Subject: %s\n' % subj)
69 > ui.write('Subject: %s\n' % subj)
74 warning: unwrapped ui message
70 warning: unwrapped ui message
75 hgext/patchbomb.py:0:
71 hgext/patchbomb.py:0:
76 > ui.write('From: %s\n' % sender)
72 > ui.write('From: %s\n' % sender)
77 warning: unwrapped ui message
73 warning: unwrapped ui message
78 mercurial/commands.py:0:
74 mercurial/commands.py:0:
79 > ui.note('branch %s\n' % data)
75 > ui.note('branch %s\n' % data)
80 warning: unwrapped ui message
76 warning: unwrapped ui message
81 mercurial/commands.py:0:
77 mercurial/commands.py:0:
82 > ui.note('node %s\n' % str(data))
78 > ui.note('node %s\n' % str(data))
83 warning: unwrapped ui message
79 warning: unwrapped ui message
84 mercurial/commands.py:0:
80 mercurial/commands.py:0:
85 > ui.note('tag %s\n' % name)
81 > ui.note('tag %s\n' % name)
86 warning: unwrapped ui message
82 warning: unwrapped ui message
87 mercurial/commands.py:0:
83 mercurial/commands.py:0:
88 > ui.write("unpruned common: %s\n" % " ".join([short(n)
84 > ui.write("unpruned common: %s\n" % " ".join([short(n)
89 warning: unwrapped ui message
85 warning: unwrapped ui message
90 mercurial/commands.py:0:
86 mercurial/commands.py:0:
91 > ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
87 > ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
92 warning: unwrapped ui message
88 warning: unwrapped ui message
93 mercurial/commands.py:0:
89 mercurial/commands.py:0:
94 > ui.write("local is subset\n")
90 > ui.write("local is subset\n")
95 warning: unwrapped ui message
91 warning: unwrapped ui message
96 mercurial/commands.py:0:
92 mercurial/commands.py:0:
97 > ui.write("remote is subset\n")
93 > ui.write("remote is subset\n")
98 warning: unwrapped ui message
94 warning: unwrapped ui message
99 mercurial/commands.py:0:
95 mercurial/commands.py:0:
100 > ui.write('deltas against other : ' + fmt % pcfmt(numother,
96 > ui.write('deltas against other : ' + fmt % pcfmt(numother,
101 warning: unwrapped ui message
97 warning: unwrapped ui message
102 mercurial/commands.py:0:
98 mercurial/commands.py:0:
103 > ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
99 > ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
104 warning: unwrapped ui message
100 warning: unwrapped ui message
105 mercurial/commands.py:0:
101 mercurial/commands.py:0:
106 > ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
102 > ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
107 warning: unwrapped ui message
103 warning: unwrapped ui message
108 mercurial/commands.py:0:
104 mercurial/commands.py:0:
109 > ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
105 > ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
110 warning: unwrapped ui message
106 warning: unwrapped ui message
111 mercurial/commands.py:0:
107 mercurial/commands.py:0:
112 > ui.write("match: %s\n" % m(d[0]))
108 > ui.write("match: %s\n" % m(d[0]))
113 warning: unwrapped ui message
109 warning: unwrapped ui message
114 mercurial/commands.py:0:
110 mercurial/commands.py:0:
115 > ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
111 > ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
116 warning: unwrapped ui message
112 warning: unwrapped ui message
117 mercurial/commands.py:0:
113 mercurial/commands.py:0:
118 > ui.write('path %s\n' % k)
114 > ui.write('path %s\n' % k)
119 warning: unwrapped ui message
115 warning: unwrapped ui message
120 mercurial/commands.py:0:
116 mercurial/commands.py:0:
121 > ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
117 > ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
122 warning: unwrapped ui message
118 warning: unwrapped ui message
123 mercurial/commands.py:0:
119 mercurial/commands.py:0:
124 > ui.write("digraph G {\n")
120 > ui.write("digraph G {\n")
125 warning: unwrapped ui message
121 warning: unwrapped ui message
126 mercurial/commands.py:0:
122 mercurial/commands.py:0:
127 > ui.write("internal: %s %s\n" % d)
123 > ui.write("internal: %s %s\n" % d)
128 warning: unwrapped ui message
124 warning: unwrapped ui message
129 mercurial/commands.py:0:
125 mercurial/commands.py:0:
130 > ui.write("standard: %s\n" % util.datestr(d))
126 > ui.write("standard: %s\n" % util.datestr(d))
131 warning: unwrapped ui message
127 warning: unwrapped ui message
132 mercurial/commands.py:0:
128 mercurial/commands.py:0:
133 > ui.write('avg chain length : ' + fmt % avgchainlen)
129 > ui.write('avg chain length : ' + fmt % avgchainlen)
134 warning: unwrapped ui message
130 warning: unwrapped ui message
135 mercurial/commands.py:0:
131 mercurial/commands.py:0:
136 > ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
132 > ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
137 warning: unwrapped ui message
133 warning: unwrapped ui message
138 mercurial/commands.py:0:
134 mercurial/commands.py:0:
139 > ui.write('compression ratio : ' + fmt % compratio)
135 > ui.write('compression ratio : ' + fmt % compratio)
140 warning: unwrapped ui message
136 warning: unwrapped ui message
141 mercurial/commands.py:0:
137 mercurial/commands.py:0:
142 > ui.write('delta size (min/max/avg) : %d / %d / %d\n'
138 > ui.write('delta size (min/max/avg) : %d / %d / %d\n'
143 warning: unwrapped ui message
139 warning: unwrapped ui message
144 mercurial/commands.py:0:
140 mercurial/commands.py:0:
145 > ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
141 > ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
146 warning: unwrapped ui message
142 warning: unwrapped ui message
147 mercurial/commands.py:0:
143 mercurial/commands.py:0:
148 > ui.write('flags : %s\n' % ', '.join(flags))
144 > ui.write('flags : %s\n' % ', '.join(flags))
149 warning: unwrapped ui message
145 warning: unwrapped ui message
150 mercurial/commands.py:0:
146 mercurial/commands.py:0:
151 > ui.write('format : %d\n' % format)
147 > ui.write('format : %d\n' % format)
152 warning: unwrapped ui message
148 warning: unwrapped ui message
153 mercurial/commands.py:0:
149 mercurial/commands.py:0:
154 > ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
150 > ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
155 warning: unwrapped ui message
151 warning: unwrapped ui message
156 mercurial/commands.py:0:
152 mercurial/commands.py:0:
157 > ui.write('revision size : ' + fmt2 % totalsize)
153 > ui.write('revision size : ' + fmt2 % totalsize)
158 warning: unwrapped ui message
154 warning: unwrapped ui message
159 mercurial/commands.py:0:
155 mercurial/commands.py:0:
160 > ui.write('revisions : ' + fmt2 % numrevs)
156 > ui.write('revisions : ' + fmt2 % numrevs)
161 warning: unwrapped ui message
157 warning: unwrapped ui message
162 warning: unwrapped ui message
158 warning: unwrapped ui message
163 mercurial/commands.py:0:
159 mercurial/commands.py:0:
164 > ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
160 > ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
165 warning: unwrapped ui message
161 warning: unwrapped ui message
166 mercurial/wireproto.py:0:
167 > yield sopener(name).read(size)
168 use opener.read() instead
169 tests/autodiff.py:0:
162 tests/autodiff.py:0:
170 > ui.write('data lost for: %s\n' % fn)
163 > ui.write('data lost for: %s\n' % fn)
171 warning: unwrapped ui message
164 warning: unwrapped ui message
172 tests/test-convert-mtn.t:0:
165 tests/test-convert-mtn.t:0:
173 > > function get_passphrase(keypair_id)
166 > > function get_passphrase(keypair_id)
174 don't use 'function', use old style
167 don't use 'function', use old style
175 tests/test-import-git.t:0:
168 tests/test-import-git.t:0:
176 > > Mc\${NkU|\`?^000jF3jhEB
169 > > Mc\${NkU|\`?^000jF3jhEB
177 ^ must be quoted
170 ^ must be quoted
178 tests/test-import.t:0:
171 tests/test-import.t:0:
179 > > diff -Naur proj-orig/foo proj-new/foo
172 > > diff -Naur proj-orig/foo proj-new/foo
180 don't use 'diff -N'
173 don't use 'diff -N'
181 don't use 'diff -N'
174 don't use 'diff -N'
182 tests/test-schemes.t:0:
175 tests/test-schemes.t:0:
183 > > z = file:\$PWD/
176 > > z = file:\$PWD/
184 don't use $PWD, use `pwd`
177 don't use $PWD, use `pwd`
185 tests/test-ui-color.py:0:
178 tests/test-ui-color.py:0:
186 > testui.warn('warning\n')
179 > testui.warn('warning\n')
187 warning: unwrapped ui message
180 warning: unwrapped ui message
188 tests/test-ui-color.py:0:
181 tests/test-ui-color.py:0:
189 > testui.write('buffered\n')
182 > testui.write('buffered\n')
190 warning: unwrapped ui message
183 warning: unwrapped ui message
General Comments 0
You need to be logged in to leave comments. Login now