##// END OF EJS Templates
wireproto: add batching support to wirerepository...
Peter Arrenbrecht -
r14622:bd88561a default
parent child Browse files
Show More
@@ -0,0 +1,45 b''
1 from mercurial import wireproto
2
3 class proto():
4 def __init__(self, args):
5 self.args = args
6 def getargs(self, spec):
7 args = self.args
8 args.setdefault('*', {})
9 names = spec.split()
10 return [args[n] for n in names]
11
12 class clientrepo(wireproto.wirerepository):
13 def __init__(self, serverrepo):
14 self.serverrepo = serverrepo
15 def _call(self, cmd, **args):
16 return wireproto.dispatch(self.serverrepo, proto(args), cmd)
17
18 @wireproto.batchable
19 def greet(self, name):
20 f = wireproto.future()
21 yield wireproto.todict(name=mangle(name)), f
22 yield unmangle(f.value)
23
24 class serverrepo():
25 def greet(self, name):
26 return "Hello, " + name
27
28 def mangle(s):
29 return ''.join(chr(ord(c) + 1) for c in s)
30 def unmangle(s):
31 return ''.join(chr(ord(c) - 1) for c in s)
32
33 def greet(repo, proto, name):
34 return mangle(repo.greet(unmangle(name)))
35
36 wireproto.commands['greet'] = (greet, 'name',)
37
38 srv = serverrepo()
39 clt = clientrepo(srv)
40
41 print clt.greet("Foobar")
42 b = clt.batch()
43 fs = [b.greet(s) for s in ["Fo, =;o", "Bar"]]
44 b.submit()
45 print [f.value for f in fs]
@@ -0,0 +1,2 b''
1 Hello, Foobar
2 ['Hello, Fo, =;o', 'Hello, Bar']
@@ -1,525 +1,586 b''
1 1 # wireproto.py - generic wire protocol support functions
2 2 #
3 3 # Copyright 2005-2010 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import urllib, tempfile, os, sys
9 9 from i18n import _
10 10 from node import bin, hex
11 11 import changegroup as changegroupmod
12 12 import repo, error, encoding, util, store
13 13 import pushkey as pushkeymod
14 14
15 15 # abstract batching support
16 16
17 17 class future(object):
18 18 '''placeholder for a value to be set later'''
19 19 def set(self, value):
20 20 if hasattr(self, 'value'):
21 21 raise error.RepoError("future is already set")
22 22 self.value = value
23 23
24 24 class batcher(object):
25 25 '''base class for batches of commands submittable in a single request
26 26
27 27 All methods invoked on instances of this class are simply queued and return a
28 28 a future for the result. Once you call submit(), all the queued calls are
29 29 performed and the results set in their respective futures.
30 30 '''
31 31 def __init__(self):
32 32 self.calls = []
33 33 def __getattr__(self, name):
34 34 def call(*args, **opts):
35 35 resref = future()
36 36 self.calls.append((name, args, opts, resref,))
37 37 return resref
38 38 return call
39 39 def submit(self):
40 40 pass
41 41
42 42 class localbatch(batcher):
43 43 '''performs the queued calls directly'''
44 44 def __init__(self, local):
45 45 batcher.__init__(self)
46 46 self.local = local
47 47 def submit(self):
48 48 for name, args, opts, resref in self.calls:
49 49 resref.set(getattr(self.local, name)(*args, **opts))
50 50
51 51 class remotebatch(batcher):
52 52 '''batches the queued calls; uses as few roundtrips as possible'''
53 53 def __init__(self, remote):
54 54 '''remote must support _submitbatch(encbatch) and _submitone(op, encargs)'''
55 55 batcher.__init__(self)
56 56 self.remote = remote
57 57 def submit(self):
58 58 req, rsp = [], []
59 59 for name, args, opts, resref in self.calls:
60 60 mtd = getattr(self.remote, name)
61 61 if hasattr(mtd, 'batchable'):
62 62 batchable = getattr(mtd, 'batchable')(mtd.im_self, *args, **opts)
63 63 encargsorres, encresref = batchable.next()
64 64 if encresref:
65 65 req.append((name, encargsorres,))
66 66 rsp.append((batchable, encresref, resref,))
67 67 else:
68 68 resref.set(encargsorres)
69 69 else:
70 70 if req:
71 71 self._submitreq(req, rsp)
72 72 req, rsp = [], []
73 73 resref.set(mtd(*args, **opts))
74 74 if req:
75 75 self._submitreq(req, rsp)
76 76 def _submitreq(self, req, rsp):
77 77 encresults = self.remote._submitbatch(req)
78 78 for encres, r in zip(encresults, rsp):
79 79 batchable, encresref, resref = r
80 80 encresref.set(encres)
81 81 resref.set(batchable.next())
82 82
83 83 def batchable(f):
84 84 '''annotation for batchable methods
85 85
86 86 Such methods must implement a coroutine as follows:
87 87
88 88 @batchable
89 89 def sample(self, one, two=None):
90 90 # Handle locally computable results first:
91 91 if not one:
92 92 yield "a local result", None
93 93 # Build list of encoded arguments suitable for your wire protocol:
94 94 encargs = [('one', encode(one),), ('two', encode(two),)]
95 95 # Create future for injection of encoded result:
96 96 encresref = future()
97 97 # Return encoded arguments and future:
98 98 yield encargs, encresref
99 99 # Assuming the future to be filled with the result from the batched request
100 100 # now. Decode it:
101 101 yield decode(encresref.value)
102 102
103 103 The decorator returns a function which wraps this coroutine as a plain method,
104 104 but adds the original method as an attribute called "batchable", which is
105 105 used by remotebatch to split the call into separate encoding and decoding
106 106 phases.
107 107 '''
108 108 def plain(*args, **opts):
109 109 batchable = f(*args, **opts)
110 110 encargsorres, encresref = batchable.next()
111 111 if not encresref:
112 112 return encargsorres # a local result in this case
113 113 self = args[0]
114 114 encresref.set(self._submitone(f.func_name, encargsorres))
115 115 return batchable.next()
116 116 setattr(plain, 'batchable', f)
117 117 return plain
118 118
119 119 # list of nodes encoding / decoding
120 120
121 121 def decodelist(l, sep=' '):
122 122 if l:
123 123 return map(bin, l.split(sep))
124 124 return []
125 125
126 126 def encodelist(l, sep=' '):
127 127 return sep.join(map(hex, l))
128 128
129 # batched call argument encoding
130
131 def escapearg(plain):
132 return (plain
133 .replace(':', '::')
134 .replace(',', ':,')
135 .replace(';', ':;')
136 .replace('=', ':='))
137
138 def unescapearg(escaped):
139 return (escaped
140 .replace(':=', '=')
141 .replace(':;', ';')
142 .replace(':,', ',')
143 .replace('::', ':'))
144
129 145 # client side
130 146
147 def todict(**args):
148 return args
149
131 150 class wirerepository(repo.repository):
151
152 def batch(self):
153 return remotebatch(self)
154 def _submitbatch(self, req):
155 cmds = []
156 for op, argsdict in req:
157 args = ','.join('%s=%s' % p for p in argsdict.iteritems())
158 cmds.append('%s %s' % (op, args))
159 rsp = self._call("batch", cmds=';'.join(cmds))
160 return rsp.split(';')
161 def _submitone(self, op, args):
162 return self._call(op, **args)
163
132 164 def lookup(self, key):
133 165 self.requirecap('lookup', _('look up remote revision'))
134 166 d = self._call("lookup", key=encoding.fromlocal(key))
135 167 success, data = d[:-1].split(" ", 1)
136 168 if int(success):
137 169 return bin(data)
138 170 self._abort(error.RepoError(data))
139 171
140 172 def heads(self):
141 173 d = self._call("heads")
142 174 try:
143 175 return decodelist(d[:-1])
144 176 except ValueError:
145 177 self._abort(error.ResponseError(_("unexpected response:"), d))
146 178
147 179 def known(self, nodes):
148 180 n = encodelist(nodes)
149 181 d = self._call("known", nodes=n)
150 182 try:
151 183 return [bool(int(f)) for f in d]
152 184 except ValueError:
153 185 self._abort(error.ResponseError(_("unexpected response:"), d))
154 186
155 187 def branchmap(self):
156 188 d = self._call("branchmap")
157 189 try:
158 190 branchmap = {}
159 191 for branchpart in d.splitlines():
160 192 branchname, branchheads = branchpart.split(' ', 1)
161 193 branchname = encoding.tolocal(urllib.unquote(branchname))
162 194 branchheads = decodelist(branchheads)
163 195 branchmap[branchname] = branchheads
164 196 return branchmap
165 197 except TypeError:
166 198 self._abort(error.ResponseError(_("unexpected response:"), d))
167 199
168 200 def branches(self, nodes):
169 201 n = encodelist(nodes)
170 202 d = self._call("branches", nodes=n)
171 203 try:
172 204 br = [tuple(decodelist(b)) for b in d.splitlines()]
173 205 return br
174 206 except ValueError:
175 207 self._abort(error.ResponseError(_("unexpected response:"), d))
176 208
177 209 def between(self, pairs):
178 210 batch = 8 # avoid giant requests
179 211 r = []
180 212 for i in xrange(0, len(pairs), batch):
181 213 n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
182 214 d = self._call("between", pairs=n)
183 215 try:
184 216 r.extend(l and decodelist(l) or [] for l in d.splitlines())
185 217 except ValueError:
186 218 self._abort(error.ResponseError(_("unexpected response:"), d))
187 219 return r
188 220
189 221 def pushkey(self, namespace, key, old, new):
190 222 if not self.capable('pushkey'):
191 223 return False
192 224 d = self._call("pushkey",
193 225 namespace=encoding.fromlocal(namespace),
194 226 key=encoding.fromlocal(key),
195 227 old=encoding.fromlocal(old),
196 228 new=encoding.fromlocal(new))
197 229 try:
198 230 d = bool(int(d))
199 231 except ValueError:
200 232 raise error.ResponseError(
201 233 _('push failed (unexpected response):'), d)
202 234 return d
203 235
204 236 def listkeys(self, namespace):
205 237 if not self.capable('pushkey'):
206 238 return {}
207 239 d = self._call("listkeys", namespace=encoding.fromlocal(namespace))
208 240 r = {}
209 241 for l in d.splitlines():
210 242 k, v = l.split('\t')
211 243 r[encoding.tolocal(k)] = encoding.tolocal(v)
212 244 return r
213 245
214 246 def stream_out(self):
215 247 return self._callstream('stream_out')
216 248
217 249 def changegroup(self, nodes, kind):
218 250 n = encodelist(nodes)
219 251 f = self._callstream("changegroup", roots=n)
220 252 return changegroupmod.unbundle10(self._decompress(f), 'UN')
221 253
222 254 def changegroupsubset(self, bases, heads, kind):
223 255 self.requirecap('changegroupsubset', _('look up remote changes'))
224 256 bases = encodelist(bases)
225 257 heads = encodelist(heads)
226 258 f = self._callstream("changegroupsubset",
227 259 bases=bases, heads=heads)
228 260 return changegroupmod.unbundle10(self._decompress(f), 'UN')
229 261
230 262 def getbundle(self, source, heads=None, common=None):
231 263 self.requirecap('getbundle', _('look up remote changes'))
232 264 opts = {}
233 265 if heads is not None:
234 266 opts['heads'] = encodelist(heads)
235 267 if common is not None:
236 268 opts['common'] = encodelist(common)
237 269 f = self._callstream("getbundle", **opts)
238 270 return changegroupmod.unbundle10(self._decompress(f), 'UN')
239 271
240 272 def unbundle(self, cg, heads, source):
241 273 '''Send cg (a readable file-like object representing the
242 274 changegroup to push, typically a chunkbuffer object) to the
243 275 remote server as a bundle. Return an integer indicating the
244 276 result of the push (see localrepository.addchangegroup()).'''
245 277
246 278 if heads != ['force'] and self.capable('unbundlehash'):
247 279 heads = encodelist(['hashed',
248 280 util.sha1(''.join(sorted(heads))).digest()])
249 281 else:
250 282 heads = encodelist(heads)
251 283
252 284 ret, output = self._callpush("unbundle", cg, heads=heads)
253 285 if ret == "":
254 286 raise error.ResponseError(
255 287 _('push failed:'), output)
256 288 try:
257 289 ret = int(ret)
258 290 except ValueError:
259 291 raise error.ResponseError(
260 292 _('push failed (unexpected response):'), ret)
261 293
262 294 for l in output.splitlines(True):
263 295 self.ui.status(_('remote: '), l)
264 296 return ret
265 297
266 298 def debugwireargs(self, one, two, three=None, four=None, five=None):
267 299 # don't pass optional arguments left at their default value
268 300 opts = {}
269 301 if three is not None:
270 302 opts['three'] = three
271 303 if four is not None:
272 304 opts['four'] = four
273 305 return self._call('debugwireargs', one=one, two=two, **opts)
274 306
275 307 # server side
276 308
277 309 class streamres(object):
278 310 def __init__(self, gen):
279 311 self.gen = gen
280 312
281 313 class pushres(object):
282 314 def __init__(self, res):
283 315 self.res = res
284 316
285 317 class pusherr(object):
286 318 def __init__(self, res):
287 319 self.res = res
288 320
289 321 def dispatch(repo, proto, command):
290 322 func, spec = commands[command]
291 323 args = proto.getargs(spec)
292 324 return func(repo, proto, *args)
293 325
294 326 def options(cmd, keys, others):
295 327 opts = {}
296 328 for k in keys:
297 329 if k in others:
298 330 opts[k] = others[k]
299 331 del others[k]
300 332 if others:
301 333 sys.stderr.write("abort: %s got unexpected arguments %s\n"
302 334 % (cmd, ",".join(others)))
303 335 return opts
304 336
337 def batch(repo, proto, cmds, others):
338 res = []
339 for pair in cmds.split(';'):
340 op, args = pair.split(' ', 1)
341 vals = {}
342 for a in args.split(','):
343 if a:
344 n, v = a.split('=')
345 vals[n] = unescapearg(v)
346 func, spec = commands[op]
347 if spec:
348 keys = spec.split()
349 data = {}
350 for k in keys:
351 if k == '*':
352 star = {}
353 for key in vals.keys():
354 if key not in keys:
355 star[key] = vals[key]
356 data['*'] = star
357 else:
358 data[k] = vals[k]
359 result = func(repo, proto, *[data[k] for k in keys])
360 else:
361 result = func(repo, proto)
362 res.append(escapearg(result))
363 return ';'.join(res)
364
305 365 def between(repo, proto, pairs):
306 366 pairs = [decodelist(p, '-') for p in pairs.split(" ")]
307 367 r = []
308 368 for b in repo.between(pairs):
309 369 r.append(encodelist(b) + "\n")
310 370 return "".join(r)
311 371
312 372 def branchmap(repo, proto):
313 373 branchmap = repo.branchmap()
314 374 heads = []
315 375 for branch, nodes in branchmap.iteritems():
316 376 branchname = urllib.quote(encoding.fromlocal(branch))
317 377 branchnodes = encodelist(nodes)
318 378 heads.append('%s %s' % (branchname, branchnodes))
319 379 return '\n'.join(heads)
320 380
321 381 def branches(repo, proto, nodes):
322 382 nodes = decodelist(nodes)
323 383 r = []
324 384 for b in repo.branches(nodes):
325 385 r.append(encodelist(b) + "\n")
326 386 return "".join(r)
327 387
328 388 def capabilities(repo, proto):
329 389 caps = ('lookup changegroupsubset branchmap pushkey known getbundle '
330 'unbundlehash').split()
390 'unbundlehash batch').split()
331 391 if _allowstream(repo.ui):
332 392 requiredformats = repo.requirements & repo.supportedformats
333 393 # if our local revlogs are just revlogv1, add 'stream' cap
334 394 if not requiredformats - set(('revlogv1',)):
335 395 caps.append('stream')
336 396 # otherwise, add 'streamreqs' detailing our local revlog format
337 397 else:
338 398 caps.append('streamreqs=%s' % ','.join(requiredformats))
339 399 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
340 400 caps.append('httpheader=1024')
341 401 return ' '.join(caps)
342 402
343 403 def changegroup(repo, proto, roots):
344 404 nodes = decodelist(roots)
345 405 cg = repo.changegroup(nodes, 'serve')
346 406 return streamres(proto.groupchunks(cg))
347 407
348 408 def changegroupsubset(repo, proto, bases, heads):
349 409 bases = decodelist(bases)
350 410 heads = decodelist(heads)
351 411 cg = repo.changegroupsubset(bases, heads, 'serve')
352 412 return streamres(proto.groupchunks(cg))
353 413
354 414 def debugwireargs(repo, proto, one, two, others):
355 415 # only accept optional args from the known set
356 416 opts = options('debugwireargs', ['three', 'four'], others)
357 417 return repo.debugwireargs(one, two, **opts)
358 418
359 419 def getbundle(repo, proto, others):
360 420 opts = options('getbundle', ['heads', 'common'], others)
361 421 for k, v in opts.iteritems():
362 422 opts[k] = decodelist(v)
363 423 cg = repo.getbundle('serve', **opts)
364 424 return streamres(proto.groupchunks(cg))
365 425
366 426 def heads(repo, proto):
367 427 h = repo.heads()
368 428 return encodelist(h) + "\n"
369 429
370 430 def hello(repo, proto):
371 431 '''the hello command returns a set of lines describing various
372 432 interesting things about the server, in an RFC822-like format.
373 433 Currently the only one defined is "capabilities", which
374 434 consists of a line in the form:
375 435
376 436 capabilities: space separated list of tokens
377 437 '''
378 438 return "capabilities: %s\n" % (capabilities(repo, proto))
379 439
380 440 def listkeys(repo, proto, namespace):
381 441 d = pushkeymod.list(repo, encoding.tolocal(namespace)).items()
382 442 t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v))
383 443 for k, v in d])
384 444 return t
385 445
386 446 def lookup(repo, proto, key):
387 447 try:
388 448 r = hex(repo.lookup(encoding.tolocal(key)))
389 449 success = 1
390 450 except Exception, inst:
391 451 r = str(inst)
392 452 success = 0
393 453 return "%s %s\n" % (success, r)
394 454
395 455 def known(repo, proto, nodes, others):
396 456 return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes)))
397 457
398 458 def pushkey(repo, proto, namespace, key, old, new):
399 459 # compatibility with pre-1.8 clients which were accidentally
400 460 # sending raw binary nodes rather than utf-8-encoded hex
401 461 if len(new) == 20 and new.encode('string-escape') != new:
402 462 # looks like it could be a binary node
403 463 try:
404 464 new.decode('utf-8')
405 465 new = encoding.tolocal(new) # but cleanly decodes as UTF-8
406 466 except UnicodeDecodeError:
407 467 pass # binary, leave unmodified
408 468 else:
409 469 new = encoding.tolocal(new) # normal path
410 470
411 471 r = pushkeymod.push(repo,
412 472 encoding.tolocal(namespace), encoding.tolocal(key),
413 473 encoding.tolocal(old), new)
414 474 return '%s\n' % int(r)
415 475
416 476 def _allowstream(ui):
417 477 return ui.configbool('server', 'uncompressed', True, untrusted=True)
418 478
419 479 def stream(repo, proto):
420 480 '''If the server supports streaming clone, it advertises the "stream"
421 481 capability with a value representing the version and flags of the repo
422 482 it is serving. Client checks to see if it understands the format.
423 483
424 484 The format is simple: the server writes out a line with the amount
425 485 of files, then the total amount of bytes to be transfered (separated
426 486 by a space). Then, for each file, the server first writes the filename
427 487 and filesize (separated by the null character), then the file contents.
428 488 '''
429 489
430 490 if not _allowstream(repo.ui):
431 491 return '1\n'
432 492
433 493 entries = []
434 494 total_bytes = 0
435 495 try:
436 496 # get consistent snapshot of repo, lock during scan
437 497 lock = repo.lock()
438 498 try:
439 499 repo.ui.debug('scanning\n')
440 500 for name, ename, size in repo.store.walk():
441 501 entries.append((name, size))
442 502 total_bytes += size
443 503 finally:
444 504 lock.release()
445 505 except error.LockError:
446 506 return '2\n' # error: 2
447 507
448 508 def streamer(repo, entries, total):
449 509 '''stream out all metadata files in repository.'''
450 510 yield '0\n' # success
451 511 repo.ui.debug('%d files, %d bytes to transfer\n' %
452 512 (len(entries), total_bytes))
453 513 yield '%d %d\n' % (len(entries), total_bytes)
454 514 for name, size in entries:
455 515 repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
456 516 # partially encode name over the wire for backwards compat
457 517 yield '%s\0%d\n' % (store.encodedir(name), size)
458 518 for chunk in util.filechunkiter(repo.sopener(name), limit=size):
459 519 yield chunk
460 520
461 521 return streamres(streamer(repo, entries, total_bytes))
462 522
463 523 def unbundle(repo, proto, heads):
464 524 their_heads = decodelist(heads)
465 525
466 526 def check_heads():
467 527 heads = repo.heads()
468 528 heads_hash = util.sha1(''.join(sorted(heads))).digest()
469 529 return (their_heads == ['force'] or their_heads == heads or
470 530 their_heads == ['hashed', heads_hash])
471 531
472 532 proto.redirect()
473 533
474 534 # fail early if possible
475 535 if not check_heads():
476 536 return pusherr('unsynced changes')
477 537
478 538 # write bundle data to temporary file because it can be big
479 539 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
480 540 fp = os.fdopen(fd, 'wb+')
481 541 r = 0
482 542 try:
483 543 proto.getfile(fp)
484 544 lock = repo.lock()
485 545 try:
486 546 if not check_heads():
487 547 # someone else committed/pushed/unbundled while we
488 548 # were transferring data
489 549 return pusherr('unsynced changes')
490 550
491 551 # push can proceed
492 552 fp.seek(0)
493 553 gen = changegroupmod.readbundle(fp, None)
494 554
495 555 try:
496 556 r = repo.addchangegroup(gen, 'serve', proto._client(),
497 557 lock=lock)
498 558 except util.Abort, inst:
499 559 sys.stderr.write("abort: %s\n" % inst)
500 560 finally:
501 561 lock.release()
502 562 return pushres(r)
503 563
504 564 finally:
505 565 fp.close()
506 566 os.unlink(tempname)
507 567
508 568 commands = {
569 'batch': (batch, 'cmds *'),
509 570 'between': (between, 'pairs'),
510 571 'branchmap': (branchmap, ''),
511 572 'branches': (branches, 'nodes'),
512 573 'capabilities': (capabilities, ''),
513 574 'changegroup': (changegroup, 'roots'),
514 575 'changegroupsubset': (changegroupsubset, 'bases heads'),
515 576 'debugwireargs': (debugwireargs, 'one two *'),
516 577 'getbundle': (getbundle, '*'),
517 578 'heads': (heads, ''),
518 579 'hello': (hello, ''),
519 580 'known': (known, 'nodes *'),
520 581 'listkeys': (listkeys, 'namespace'),
521 582 'lookup': (lookup, 'key'),
522 583 'pushkey': (pushkey, 'namespace key old new'),
523 584 'stream_out': (stream, ''),
524 585 'unbundle': (unbundle, 'heads'),
525 586 }
@@ -1,1157 +1,1157 b''
1 1 An attempt at more fully testing the hgweb web interface.
2 2 The following things are tested elsewhere and are therefore omitted:
3 3 - archive, tested in test-archive
4 4 - unbundle, tested in test-push-http
5 5 - changegroupsubset, tested in test-pull
6 6
7 7 Set up the repo
8 8
9 9 $ hg init test
10 10 $ cd test
11 11 $ mkdir da
12 12 $ echo foo > da/foo
13 13 $ echo foo > foo
14 14 $ hg ci -Ambase
15 15 adding da/foo
16 16 adding foo
17 17 $ hg tag 1.0
18 18 $ hg bookmark something
19 19 $ hg bookmark -r0 anotherthing
20 20 $ echo another > foo
21 21 $ hg branch stable
22 22 marked working directory as branch stable
23 23 $ hg ci -Ambranch
24 24 $ hg serve --config server.uncompressed=False -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
25 25 $ cat hg.pid >> $DAEMON_PIDS
26 26
27 27 Logs and changes
28 28
29 29 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/log/?style=atom'
30 30 200 Script output follows
31 31
32 32 <?xml version="1.0" encoding="ascii"?>
33 33 <feed xmlns="http://www.w3.org/2005/Atom">
34 34 <!-- Changelog -->
35 35 <id>http://*:$HGPORT/</id> (glob)
36 36 <link rel="self" href="http://*:$HGPORT/atom-log"/> (glob)
37 37 <link rel="alternate" href="http://*:$HGPORT/"/> (glob)
38 38 <title>test Changelog</title>
39 39 <updated>1970-01-01T00:00:00+00:00</updated>
40 40
41 41 <entry>
42 42 <title>branch</title>
43 43 <id>http://*:$HGPORT/#changeset-1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe</id> (glob)
44 44 <link href="http://*:$HGPORT/rev/1d22e65f027e"/> (glob)
45 45 <author>
46 46 <name>test</name>
47 47 <email>&#116;&#101;&#115;&#116;</email>
48 48 </author>
49 49 <updated>1970-01-01T00:00:00+00:00</updated>
50 50 <published>1970-01-01T00:00:00+00:00</published>
51 51 <content type="xhtml">
52 52 <div xmlns="http://www.w3.org/1999/xhtml">
53 53 <pre xml:space="preserve">branch</pre>
54 54 </div>
55 55 </content>
56 56 </entry>
57 57 <entry>
58 58 <title>Added tag 1.0 for changeset 2ef0ac749a14</title>
59 59 <id>http://*:$HGPORT/#changeset-a4f92ed23982be056b9852de5dfe873eaac7f0de</id> (glob)
60 60 <link href="http://*:$HGPORT/rev/a4f92ed23982"/> (glob)
61 61 <author>
62 62 <name>test</name>
63 63 <email>&#116;&#101;&#115;&#116;</email>
64 64 </author>
65 65 <updated>1970-01-01T00:00:00+00:00</updated>
66 66 <published>1970-01-01T00:00:00+00:00</published>
67 67 <content type="xhtml">
68 68 <div xmlns="http://www.w3.org/1999/xhtml">
69 69 <pre xml:space="preserve">Added tag 1.0 for changeset 2ef0ac749a14</pre>
70 70 </div>
71 71 </content>
72 72 </entry>
73 73 <entry>
74 74 <title>base</title>
75 75 <id>http://*:$HGPORT/#changeset-2ef0ac749a14e4f57a5a822464a0902c6f7f448f</id> (glob)
76 76 <link href="http://*:$HGPORT/rev/2ef0ac749a14"/> (glob)
77 77 <author>
78 78 <name>test</name>
79 79 <email>&#116;&#101;&#115;&#116;</email>
80 80 </author>
81 81 <updated>1970-01-01T00:00:00+00:00</updated>
82 82 <published>1970-01-01T00:00:00+00:00</published>
83 83 <content type="xhtml">
84 84 <div xmlns="http://www.w3.org/1999/xhtml">
85 85 <pre xml:space="preserve">base</pre>
86 86 </div>
87 87 </content>
88 88 </entry>
89 89
90 90 </feed>
91 91 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/log/1/?style=atom'
92 92 200 Script output follows
93 93
94 94 <?xml version="1.0" encoding="ascii"?>
95 95 <feed xmlns="http://www.w3.org/2005/Atom">
96 96 <!-- Changelog -->
97 97 <id>http://*:$HGPORT/</id> (glob)
98 98 <link rel="self" href="http://*:$HGPORT/atom-log"/> (glob)
99 99 <link rel="alternate" href="http://*:$HGPORT/"/> (glob)
100 100 <title>test Changelog</title>
101 101 <updated>1970-01-01T00:00:00+00:00</updated>
102 102
103 103 <entry>
104 104 <title>branch</title>
105 105 <id>http://*:$HGPORT/#changeset-1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe</id> (glob)
106 106 <link href="http://*:$HGPORT/rev/1d22e65f027e"/> (glob)
107 107 <author>
108 108 <name>test</name>
109 109 <email>&#116;&#101;&#115;&#116;</email>
110 110 </author>
111 111 <updated>1970-01-01T00:00:00+00:00</updated>
112 112 <published>1970-01-01T00:00:00+00:00</published>
113 113 <content type="xhtml">
114 114 <div xmlns="http://www.w3.org/1999/xhtml">
115 115 <pre xml:space="preserve">branch</pre>
116 116 </div>
117 117 </content>
118 118 </entry>
119 119 <entry>
120 120 <title>Added tag 1.0 for changeset 2ef0ac749a14</title>
121 121 <id>http://*:$HGPORT/#changeset-a4f92ed23982be056b9852de5dfe873eaac7f0de</id> (glob)
122 122 <link href="http://*:$HGPORT/rev/a4f92ed23982"/> (glob)
123 123 <author>
124 124 <name>test</name>
125 125 <email>&#116;&#101;&#115;&#116;</email>
126 126 </author>
127 127 <updated>1970-01-01T00:00:00+00:00</updated>
128 128 <published>1970-01-01T00:00:00+00:00</published>
129 129 <content type="xhtml">
130 130 <div xmlns="http://www.w3.org/1999/xhtml">
131 131 <pre xml:space="preserve">Added tag 1.0 for changeset 2ef0ac749a14</pre>
132 132 </div>
133 133 </content>
134 134 </entry>
135 135 <entry>
136 136 <title>base</title>
137 137 <id>http://*:$HGPORT/#changeset-2ef0ac749a14e4f57a5a822464a0902c6f7f448f</id> (glob)
138 138 <link href="http://*:$HGPORT/rev/2ef0ac749a14"/> (glob)
139 139 <author>
140 140 <name>test</name>
141 141 <email>&#116;&#101;&#115;&#116;</email>
142 142 </author>
143 143 <updated>1970-01-01T00:00:00+00:00</updated>
144 144 <published>1970-01-01T00:00:00+00:00</published>
145 145 <content type="xhtml">
146 146 <div xmlns="http://www.w3.org/1999/xhtml">
147 147 <pre xml:space="preserve">base</pre>
148 148 </div>
149 149 </content>
150 150 </entry>
151 151
152 152 </feed>
153 153 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/log/1/foo/?style=atom'
154 154 200 Script output follows
155 155
156 156 <?xml version="1.0" encoding="ascii"?>
157 157 <feed xmlns="http://www.w3.org/2005/Atom">
158 158 <id>http://*:$HGPORT/atom-log/tip/foo</id> (glob)
159 159 <link rel="self" href="http://*:$HGPORT/atom-log/tip/foo"/> (glob)
160 160 <title>test: foo history</title>
161 161 <updated>1970-01-01T00:00:00+00:00</updated>
162 162
163 163 <entry>
164 164 <title>base</title>
165 165 <id>http://*:$HGPORT/#changeset-2ef0ac749a14e4f57a5a822464a0902c6f7f448f</id> (glob)
166 166 <link href="http://*:$HGPORT/rev/2ef0ac749a14"/> (glob)
167 167 <author>
168 168 <name>test</name>
169 169 <email>&#116;&#101;&#115;&#116;</email>
170 170 </author>
171 171 <updated>1970-01-01T00:00:00+00:00</updated>
172 172 <published>1970-01-01T00:00:00+00:00</published>
173 173 <content type="xhtml">
174 174 <div xmlns="http://www.w3.org/1999/xhtml">
175 175 <pre xml:space="preserve">base</pre>
176 176 </div>
177 177 </content>
178 178 </entry>
179 179
180 180 </feed>
181 181 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/shortlog/'
182 182 200 Script output follows
183 183
184 184 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
185 185 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
186 186 <head>
187 187 <link rel="icon" href="/static/hgicon.png" type="image/png" />
188 188 <meta name="robots" content="index, nofollow" />
189 189 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
190 190 <script type="text/javascript" src="/static/mercurial.js"></script>
191 191
192 192 <title>test: log</title>
193 193 <link rel="alternate" type="application/atom+xml"
194 194 href="/atom-log" title="Atom feed for test" />
195 195 <link rel="alternate" type="application/rss+xml"
196 196 href="/rss-log" title="RSS feed for test" />
197 197 </head>
198 198 <body>
199 199
200 200 <div class="container">
201 201 <div class="menu">
202 202 <div class="logo">
203 203 <a href="http://mercurial.selenic.com/">
204 204 <img src="/static/hglogo.png" alt="mercurial" /></a>
205 205 </div>
206 206 <ul>
207 207 <li class="active">log</li>
208 208 <li><a href="/graph/1d22e65f027e">graph</a></li>
209 209 <li><a href="/tags">tags</a></li>
210 210 <li><a href="/bookmarks">bookmarks</a></li>
211 211 <li><a href="/branches">branches</a></li>
212 212 </ul>
213 213 <ul>
214 214 <li><a href="/rev/1d22e65f027e">changeset</a></li>
215 215 <li><a href="/file/1d22e65f027e">browse</a></li>
216 216 </ul>
217 217 <ul>
218 218
219 219 </ul>
220 220 <ul>
221 221 <li><a href="/help">help</a></li>
222 222 </ul>
223 223 </div>
224 224
225 225 <div class="main">
226 226 <h2><a href="/">test</a></h2>
227 227 <h3>log</h3>
228 228
229 229 <form class="search" action="/log">
230 230
231 231 <p><input name="rev" id="search1" type="text" size="30" /></p>
232 232 <div id="hint">find changesets by author, revision,
233 233 files, or words in the commit message</div>
234 234 </form>
235 235
236 236 <div class="navigate">
237 237 <a href="/shortlog/2?revcount=30">less</a>
238 238 <a href="/shortlog/2?revcount=120">more</a>
239 239 | rev 2: <a href="/shortlog/2ef0ac749a14">(0)</a> <a href="/shortlog/tip">tip</a>
240 240 </div>
241 241
242 242 <table class="bigtable">
243 243 <tr>
244 244 <th class="age">age</th>
245 245 <th class="author">author</th>
246 246 <th class="description">description</th>
247 247 </tr>
248 248 <tr class="parity0">
249 249 <td class="age">Thu Jan 01 00:00:00 1970 +0000</td>
250 250 <td class="author">test</td>
251 251 <td class="description"><a href="/rev/1d22e65f027e">branch</a><span class="branchhead">stable</span> <span class="tag">tip</span> <span class="tag">something</span> </td>
252 252 </tr>
253 253 <tr class="parity1">
254 254 <td class="age">Thu Jan 01 00:00:00 1970 +0000</td>
255 255 <td class="author">test</td>
256 256 <td class="description"><a href="/rev/a4f92ed23982">Added tag 1.0 for changeset 2ef0ac749a14</a><span class="branchhead">default</span> </td>
257 257 </tr>
258 258 <tr class="parity0">
259 259 <td class="age">Thu Jan 01 00:00:00 1970 +0000</td>
260 260 <td class="author">test</td>
261 261 <td class="description"><a href="/rev/2ef0ac749a14">base</a><span class="tag">1.0</span> <span class="tag">anotherthing</span> </td>
262 262 </tr>
263 263
264 264 </table>
265 265
266 266 <div class="navigate">
267 267 <a href="/shortlog/2?revcount=30">less</a>
268 268 <a href="/shortlog/2?revcount=120">more</a>
269 269 | rev 2: <a href="/shortlog/2ef0ac749a14">(0)</a> <a href="/shortlog/tip">tip</a>
270 270 </div>
271 271
272 272 </div>
273 273 </div>
274 274
275 275 <script type="text/javascript">process_dates()</script>
276 276
277 277
278 278 </body>
279 279 </html>
280 280
281 281 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/rev/0/'
282 282 200 Script output follows
283 283
284 284 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
285 285 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
286 286 <head>
287 287 <link rel="icon" href="/static/hgicon.png" type="image/png" />
288 288 <meta name="robots" content="index, nofollow" />
289 289 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
290 290 <script type="text/javascript" src="/static/mercurial.js"></script>
291 291
292 292 <title>test: 2ef0ac749a14</title>
293 293 </head>
294 294 <body>
295 295 <div class="container">
296 296 <div class="menu">
297 297 <div class="logo">
298 298 <a href="http://mercurial.selenic.com/">
299 299 <img src="/static/hglogo.png" alt="mercurial" /></a>
300 300 </div>
301 301 <ul>
302 302 <li><a href="/shortlog/2ef0ac749a14">log</a></li>
303 303 <li><a href="/graph/2ef0ac749a14">graph</a></li>
304 304 <li><a href="/tags">tags</a></li>
305 305 <li><a href="/bookmarks">bookmarks</a></li>
306 306 <li><a href="/branches">branches</a></li>
307 307 </ul>
308 308 <ul>
309 309 <li class="active">changeset</li>
310 310 <li><a href="/raw-rev/2ef0ac749a14">raw</a></li>
311 311 <li><a href="/file/2ef0ac749a14">browse</a></li>
312 312 </ul>
313 313 <ul>
314 314
315 315 </ul>
316 316 <ul>
317 317 <li><a href="/help">help</a></li>
318 318 </ul>
319 319 </div>
320 320
321 321 <div class="main">
322 322
323 323 <h2><a href="/">test</a></h2>
324 324 <h3>changeset 0:2ef0ac749a14 <span class="tag">1.0</span> <span class="tag">anotherthing</span> </h3>
325 325
326 326 <form class="search" action="/log">
327 327
328 328 <p><input name="rev" id="search1" type="text" size="30" /></p>
329 329 <div id="hint">find changesets by author, revision,
330 330 files, or words in the commit message</div>
331 331 </form>
332 332
333 333 <div class="description">base</div>
334 334
335 335 <table id="changesetEntry">
336 336 <tr>
337 337 <th class="author">author</th>
338 338 <td class="author">&#116;&#101;&#115;&#116;</td>
339 339 </tr>
340 340 <tr>
341 341 <th class="date">date</th>
342 342 <td class="date age">Thu Jan 01 00:00:00 1970 +0000</td></tr>
343 343 <tr>
344 344 <th class="author">parents</th>
345 345 <td class="author"></td>
346 346 </tr>
347 347 <tr>
348 348 <th class="author">children</th>
349 349 <td class="author"> <a href="/rev/a4f92ed23982">a4f92ed23982</a></td>
350 350 </tr>
351 351 <tr>
352 352 <th class="files">files</th>
353 353 <td class="files"><a href="/file/2ef0ac749a14/da/foo">da/foo</a> <a href="/file/2ef0ac749a14/foo">foo</a> </td>
354 354 </tr>
355 355 <tr>
356 356 <th class="diffstat">diffstat</th>
357 357 <td class="diffstat">
358 358 2 files changed, 2 insertions(+), 0 deletions(-)
359 359
360 360 <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
361 361 <div id="diffstatdetails" style="display:none;">
362 362 <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
363 363 <p>
364 364 <table> <tr class="parity0">
365 365 <td class="diffstat-file"><a href="#l1.1">da/foo</a></td>
366 366 <td class="diffstat-total" align="right">1</td>
367 367 <td class="diffstat-graph">
368 368 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
369 369 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
370 370 </td>
371 371 </tr>
372 372 <tr class="parity1">
373 373 <td class="diffstat-file"><a href="#l2.1">foo</a></td>
374 374 <td class="diffstat-total" align="right">1</td>
375 375 <td class="diffstat-graph">
376 376 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
377 377 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
378 378 </td>
379 379 </tr>
380 380 </table>
381 381 </div>
382 382 </td>
383 383 </tr>
384 384 </table>
385 385
386 386 <div class="overflow">
387 387 <div class="sourcefirst"> line diff</div>
388 388
389 389 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
390 390 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/da/foo Thu Jan 01 00:00:00 1970 +0000
391 391 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
392 392 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+foo
393 393 </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
394 394 </span><a href="#l2.2" id="l2.2"> 2.2</a> <span class="plusline">+++ b/foo Thu Jan 01 00:00:00 1970 +0000
395 395 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="atline">@@ -0,0 +1,1 @@
396 396 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="plusline">+foo
397 397 </span></pre></div>
398 398 </div>
399 399
400 400 </div>
401 401 </div>
402 402 <script type="text/javascript">process_dates()</script>
403 403
404 404
405 405 </body>
406 406 </html>
407 407
408 408 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/rev/1/?style=raw'
409 409 200 Script output follows
410 410
411 411
412 412 # HG changeset patch
413 413 # User test
414 414 # Date 0 0
415 415 # Node ID a4f92ed23982be056b9852de5dfe873eaac7f0de
416 416 # Parent 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
417 417 Added tag 1.0 for changeset 2ef0ac749a14
418 418
419 419 diff -r 2ef0ac749a14 -r a4f92ed23982 .hgtags
420 420 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
421 421 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
422 422 @@ -0,0 +1,1 @@
423 423 +2ef0ac749a14e4f57a5a822464a0902c6f7f448f 1.0
424 424
425 425 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/log?rev=base'
426 426 200 Script output follows
427 427
428 428 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
429 429 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
430 430 <head>
431 431 <link rel="icon" href="/static/hgicon.png" type="image/png" />
432 432 <meta name="robots" content="index, nofollow" />
433 433 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
434 434 <script type="text/javascript" src="/static/mercurial.js"></script>
435 435
436 436 <title>test: searching for base</title>
437 437 </head>
438 438 <body>
439 439
440 440 <div class="container">
441 441 <div class="menu">
442 442 <div class="logo">
443 443 <a href="http://mercurial.selenic.com/">
444 444 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
445 445 </div>
446 446 <ul>
447 447 <li><a href="/shortlog">log</a></li>
448 448 <li><a href="/graph">graph</a></li>
449 449 <li><a href="/tags">tags</a></li>
450 450 <li><a href="/bookmarks">bookmarks</a></li>
451 451 <li><a href="/branches">branches</a></li>
452 452 <li><a href="/help">help</a></li>
453 453 </ul>
454 454 </div>
455 455
456 456 <div class="main">
457 457 <h2><a href="/">test</a></h2>
458 458 <h3>searching for 'base'</h3>
459 459
460 460 <form class="search" action="/log">
461 461
462 462 <p><input name="rev" id="search1" type="text" size="30"></p>
463 463 <div id="hint">find changesets by author, revision,
464 464 files, or words in the commit message</div>
465 465 </form>
466 466
467 467 <div class="navigate">
468 468 <a href="/search/?rev=base&revcount=5">less</a>
469 469 <a href="/search/?rev=base&revcount=20">more</a>
470 470 </div>
471 471
472 472 <table class="bigtable">
473 473 <tr>
474 474 <th class="age">age</th>
475 475 <th class="author">author</th>
476 476 <th class="description">description</th>
477 477 </tr>
478 478 <tr class="parity0">
479 479 <td class="age">Thu Jan 01 00:00:00 1970 +0000</td>
480 480 <td class="author">test</td>
481 481 <td class="description"><a href="/rev/2ef0ac749a14">base</a><span class="tag">1.0</span> <span class="tag">anotherthing</span> </td>
482 482 </tr>
483 483
484 484 </table>
485 485
486 486 <div class="navigate">
487 487 <a href="/search/?rev=base&revcount=5">less</a>
488 488 <a href="/search/?rev=base&revcount=20">more</a>
489 489 </div>
490 490
491 491 </div>
492 492 </div>
493 493
494 494 <script type="text/javascript">process_dates()</script>
495 495
496 496
497 497 </body>
498 498 </html>
499 499
500 500
501 501 File-related
502 502
503 503 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/1/foo/?style=raw'
504 504 200 Script output follows
505 505
506 506 foo
507 507 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/annotate/1/foo/?style=raw'
508 508 200 Script output follows
509 509
510 510
511 511 test@0: foo
512 512
513 513
514 514
515 515
516 516 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/1/?style=raw'
517 517 200 Script output follows
518 518
519 519
520 520 drwxr-xr-x da
521 521 -rw-r--r-- 45 .hgtags
522 522 -rw-r--r-- 4 foo
523 523
524 524
525 525 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/1/foo'
526 526 200 Script output follows
527 527
528 528 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
529 529 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
530 530 <head>
531 531 <link rel="icon" href="/static/hgicon.png" type="image/png" />
532 532 <meta name="robots" content="index, nofollow" />
533 533 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
534 534 <script type="text/javascript" src="/static/mercurial.js"></script>
535 535
536 536 <title>test: a4f92ed23982 foo</title>
537 537 </head>
538 538 <body>
539 539
540 540 <div class="container">
541 541 <div class="menu">
542 542 <div class="logo">
543 543 <a href="http://mercurial.selenic.com/">
544 544 <img src="/static/hglogo.png" alt="mercurial" /></a>
545 545 </div>
546 546 <ul>
547 547 <li><a href="/shortlog/a4f92ed23982">log</a></li>
548 548 <li><a href="/graph/a4f92ed23982">graph</a></li>
549 549 <li><a href="/tags">tags</a></li>
550 550 <li><a href="/branches">branches</a></li>
551 551 </ul>
552 552 <ul>
553 553 <li><a href="/rev/a4f92ed23982">changeset</a></li>
554 554 <li><a href="/file/a4f92ed23982/">browse</a></li>
555 555 </ul>
556 556 <ul>
557 557 <li class="active">file</li>
558 558 <li><a href="/file/tip/foo">latest</a></li>
559 559 <li><a href="/diff/a4f92ed23982/foo">diff</a></li>
560 560 <li><a href="/annotate/a4f92ed23982/foo">annotate</a></li>
561 561 <li><a href="/log/a4f92ed23982/foo">file log</a></li>
562 562 <li><a href="/raw-file/a4f92ed23982/foo">raw</a></li>
563 563 </ul>
564 564 <ul>
565 565 <li><a href="/help">help</a></li>
566 566 </ul>
567 567 </div>
568 568
569 569 <div class="main">
570 570 <h2><a href="/">test</a></h2>
571 571 <h3>view foo @ 1:a4f92ed23982</h3>
572 572
573 573 <form class="search" action="/log">
574 574
575 575 <p><input name="rev" id="search1" type="text" size="30" /></p>
576 576 <div id="hint">find changesets by author, revision,
577 577 files, or words in the commit message</div>
578 578 </form>
579 579
580 580 <div class="description">Added tag 1.0 for changeset 2ef0ac749a14</div>
581 581
582 582 <table id="changesetEntry">
583 583 <tr>
584 584 <th class="author">author</th>
585 585 <td class="author">&#116;&#101;&#115;&#116;</td>
586 586 </tr>
587 587 <tr>
588 588 <th class="date">date</th>
589 589 <td class="date age">Thu Jan 01 00:00:00 1970 +0000</td>
590 590 </tr>
591 591 <tr>
592 592 <th class="author">parents</th>
593 593 <td class="author"></td>
594 594 </tr>
595 595 <tr>
596 596 <th class="author">children</th>
597 597 <td class="author"><a href="/file/1d22e65f027e/foo">1d22e65f027e</a> </td>
598 598 </tr>
599 599
600 600 </table>
601 601
602 602 <div class="overflow">
603 603 <div class="sourcefirst"> line source</div>
604 604
605 605 <div class="parity0 source"><a href="#l1" id="l1"> 1</a> foo
606 606 </div>
607 607 <div class="sourcelast"></div>
608 608 </div>
609 609 </div>
610 610 </div>
611 611
612 612 <script type="text/javascript">process_dates()</script>
613 613
614 614
615 615 </body>
616 616 </html>
617 617
618 618 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/filediff/1/foo/?style=raw'
619 619 200 Script output follows
620 620
621 621
622 622 diff -r 000000000000 -r a4f92ed23982 foo
623 623 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
624 624 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
625 625 @@ -0,0 +1,1 @@
626 626 +foo
627 627
628 628
629 629
630 630
631 631
632 632 Overviews
633 633
634 634 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/raw-tags'
635 635 200 Script output follows
636 636
637 637 tip 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
638 638 1.0 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
639 639 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/raw-branches'
640 640 200 Script output follows
641 641
642 642 stable 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe open
643 643 default a4f92ed23982be056b9852de5dfe873eaac7f0de inactive
644 644 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/raw-bookmarks'
645 645 200 Script output follows
646 646
647 647 anotherthing 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
648 648 something 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
649 649 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/summary/?style=gitweb'
650 650 200 Script output follows
651 651
652 652 <?xml version="1.0" encoding="ascii"?>
653 653 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
654 654 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
655 655 <head>
656 656 <link rel="icon" href="/static/hgicon.png" type="image/png" />
657 657 <meta name="robots" content="index, nofollow"/>
658 658 <link rel="stylesheet" href="/static/style-gitweb.css" type="text/css" />
659 659 <script type="text/javascript" src="/static/mercurial.js"></script>
660 660
661 661 <title>test: Summary</title>
662 662 <link rel="alternate" type="application/atom+xml"
663 663 href="/atom-log" title="Atom feed for test"/>
664 664 <link rel="alternate" type="application/rss+xml"
665 665 href="/rss-log" title="RSS feed for test"/>
666 666 </head>
667 667 <body>
668 668
669 669 <div class="page_header">
670 670 <a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="/summary?style=gitweb">test</a> / summary
671 671
672 672 <form action="/log">
673 673 <input type="hidden" name="style" value="gitweb" />
674 674 <div class="search">
675 675 <input type="text" name="rev" />
676 676 </div>
677 677 </form>
678 678 </div>
679 679
680 680 <div class="page_nav">
681 681 summary |
682 682 <a href="/shortlog?style=gitweb">shortlog</a> |
683 683 <a href="/log?style=gitweb">changelog</a> |
684 684 <a href="/graph?style=gitweb">graph</a> |
685 685 <a href="/tags?style=gitweb">tags</a> |
686 686 <a href="/bookmarks?style=gitweb">bookmarks</a> |
687 687 <a href="/branches?style=gitweb">branches</a> |
688 688 <a href="/file/1d22e65f027e?style=gitweb">files</a> |
689 689 <a href="/help?style=gitweb">help</a>
690 690 <br/>
691 691 </div>
692 692
693 693 <div class="title">&nbsp;</div>
694 694 <table cellspacing="0">
695 695 <tr><td>description</td><td>unknown</td></tr>
696 696 <tr><td>owner</td><td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td></tr>
697 697 <tr><td>last change</td><td>Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
698 698 </table>
699 699
700 700 <div><a class="title" href="/shortlog?style=gitweb">changes</a></div>
701 701 <table cellspacing="0">
702 702
703 703 <tr class="parity0">
704 704 <td class="age"><i class="age">Thu Jan 01 00:00:00 1970 +0000</i></td>
705 705 <td><i>test</i></td>
706 706 <td>
707 707 <a class="list" href="/rev/1d22e65f027e?style=gitweb">
708 708 <b>branch</b>
709 709 <span class="logtags"><span class="branchtag" title="stable">stable</span> <span class="tagtag" title="tip">tip</span> <span class="bookmarktag" title="something">something</span> </span>
710 710 </a>
711 711 </td>
712 712 <td class="link" nowrap>
713 713 <a href="/rev/1d22e65f027e?style=gitweb">changeset</a> |
714 714 <a href="/file/1d22e65f027e?style=gitweb">files</a>
715 715 </td>
716 716 </tr>
717 717 <tr class="parity1">
718 718 <td class="age"><i class="age">Thu Jan 01 00:00:00 1970 +0000</i></td>
719 719 <td><i>test</i></td>
720 720 <td>
721 721 <a class="list" href="/rev/a4f92ed23982?style=gitweb">
722 722 <b>Added tag 1.0 for changeset 2ef0ac749a14</b>
723 723 <span class="logtags"><span class="branchtag" title="default">default</span> </span>
724 724 </a>
725 725 </td>
726 726 <td class="link" nowrap>
727 727 <a href="/rev/a4f92ed23982?style=gitweb">changeset</a> |
728 728 <a href="/file/a4f92ed23982?style=gitweb">files</a>
729 729 </td>
730 730 </tr>
731 731 <tr class="parity0">
732 732 <td class="age"><i class="age">Thu Jan 01 00:00:00 1970 +0000</i></td>
733 733 <td><i>test</i></td>
734 734 <td>
735 735 <a class="list" href="/rev/2ef0ac749a14?style=gitweb">
736 736 <b>base</b>
737 737 <span class="logtags"><span class="tagtag" title="1.0">1.0</span> <span class="bookmarktag" title="anotherthing">anotherthing</span> </span>
738 738 </a>
739 739 </td>
740 740 <td class="link" nowrap>
741 741 <a href="/rev/2ef0ac749a14?style=gitweb">changeset</a> |
742 742 <a href="/file/2ef0ac749a14?style=gitweb">files</a>
743 743 </td>
744 744 </tr>
745 745 <tr class="light"><td colspan="4"><a class="list" href="/shortlog?style=gitweb">...</a></td></tr>
746 746 </table>
747 747
748 748 <div><a class="title" href="/tags?style=gitweb">tags</a></div>
749 749 <table cellspacing="0">
750 750
751 751 <tr class="parity0">
752 752 <td class="age"><i class="age">Thu Jan 01 00:00:00 1970 +0000</i></td>
753 753 <td><a class="list" href="/rev/2ef0ac749a14?style=gitweb"><b>1.0</b></a></td>
754 754 <td class="link">
755 755 <a href="/rev/2ef0ac749a14?style=gitweb">changeset</a> |
756 756 <a href="/log/2ef0ac749a14?style=gitweb">changelog</a> |
757 757 <a href="/file/2ef0ac749a14?style=gitweb">files</a>
758 758 </td>
759 759 </tr>
760 760 <tr class="light"><td colspan="3"><a class="list" href="/tags?style=gitweb">...</a></td></tr>
761 761 </table>
762 762
763 763 <div><a class="title" href="/bookmarks?style=gitweb">bookmarks</a></div>
764 764 <table cellspacing="0">
765 765
766 766 <tr class="parity0">
767 767 <td class="age"><i class="age">Thu Jan 01 00:00:00 1970 +0000</i></td>
768 768 <td><a class="list" href="/rev/2ef0ac749a14?style=gitweb"><b>anotherthing</b></a></td>
769 769 <td class="link">
770 770 <a href="/rev/2ef0ac749a14?style=gitweb">changeset</a> |
771 771 <a href="/log/2ef0ac749a14?style=gitweb">changelog</a> |
772 772 <a href="/file/2ef0ac749a14?style=gitweb">files</a>
773 773 </td>
774 774 </tr>
775 775 <tr class="parity1">
776 776 <td class="age"><i class="age">Thu Jan 01 00:00:00 1970 +0000</i></td>
777 777 <td><a class="list" href="/rev/1d22e65f027e?style=gitweb"><b>something</b></a></td>
778 778 <td class="link">
779 779 <a href="/rev/1d22e65f027e?style=gitweb">changeset</a> |
780 780 <a href="/log/1d22e65f027e?style=gitweb">changelog</a> |
781 781 <a href="/file/1d22e65f027e?style=gitweb">files</a>
782 782 </td>
783 783 </tr>
784 784 <tr class="light"><td colspan="3"><a class="list" href="/bookmarks?style=gitweb">...</a></td></tr>
785 785 </table>
786 786
787 787 <div><a class="title" href="#">branches</a></div>
788 788 <table cellspacing="0">
789 789
790 790 <tr class="parity0">
791 791 <td class="age"><i class="age">Thu Jan 01 00:00:00 1970 +0000</i></td>
792 792 <td><a class="list" href="/shortlog/1d22e65f027e?style=gitweb"><b>1d22e65f027e</b></a></td>
793 793 <td class="">stable</td>
794 794 <td class="link">
795 795 <a href="/changeset/1d22e65f027e?style=gitweb">changeset</a> |
796 796 <a href="/log/1d22e65f027e?style=gitweb">changelog</a> |
797 797 <a href="/file/1d22e65f027e?style=gitweb">files</a>
798 798 </td>
799 799 </tr>
800 800 <tr class="parity1">
801 801 <td class="age"><i class="age">Thu Jan 01 00:00:00 1970 +0000</i></td>
802 802 <td><a class="list" href="/shortlog/a4f92ed23982?style=gitweb"><b>a4f92ed23982</b></a></td>
803 803 <td class="">default</td>
804 804 <td class="link">
805 805 <a href="/changeset/a4f92ed23982?style=gitweb">changeset</a> |
806 806 <a href="/log/a4f92ed23982?style=gitweb">changelog</a> |
807 807 <a href="/file/a4f92ed23982?style=gitweb">files</a>
808 808 </td>
809 809 </tr>
810 810 <tr class="light">
811 811 <td colspan="4"><a class="list" href="#">...</a></td>
812 812 </tr>
813 813 </table>
814 814 <script type="text/javascript">process_dates()</script>
815 815 <div class="page_footer">
816 816 <div class="page_footer_text">test</div>
817 817 <div class="rss_logo">
818 818 <a href="/rss-log">RSS</a>
819 819 <a href="/atom-log">Atom</a>
820 820 </div>
821 821 <br />
822 822
823 823 </div>
824 824 </body>
825 825 </html>
826 826
827 827 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/graph/?style=gitweb'
828 828 200 Script output follows
829 829
830 830 <?xml version="1.0" encoding="ascii"?>
831 831 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
832 832 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
833 833 <head>
834 834 <link rel="icon" href="/static/hgicon.png" type="image/png" />
835 835 <meta name="robots" content="index, nofollow"/>
836 836 <link rel="stylesheet" href="/static/style-gitweb.css" type="text/css" />
837 837 <script type="text/javascript" src="/static/mercurial.js"></script>
838 838
839 839 <title>test: Graph</title>
840 840 <link rel="alternate" type="application/atom+xml"
841 841 href="/atom-log" title="Atom feed for test"/>
842 842 <link rel="alternate" type="application/rss+xml"
843 843 href="/rss-log" title="RSS feed for test"/>
844 844 <!--[if IE]><script type="text/javascript" src="/static/excanvas.js"></script><![endif]-->
845 845 </head>
846 846 <body>
847 847
848 848 <div class="page_header">
849 849 <a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="/summary?style=gitweb">test</a> / graph
850 850 </div>
851 851
852 852 <form action="/log">
853 853 <input type="hidden" name="style" value="gitweb" />
854 854 <div class="search">
855 855 <input type="text" name="rev" />
856 856 </div>
857 857 </form>
858 858 <div class="page_nav">
859 859 <a href="/summary?style=gitweb">summary</a> |
860 860 <a href="/shortlog?style=gitweb">shortlog</a> |
861 861 <a href="/log/2?style=gitweb">changelog</a> |
862 862 graph |
863 863 <a href="/tags?style=gitweb">tags</a> |
864 864 <a href="/bookmarks?style=gitweb">bookmarks</a> |
865 865 <a href="/branches?style=gitweb">branches</a> |
866 866 <a href="/file/1d22e65f027e?style=gitweb">files</a> |
867 867 <a href="/help?style=gitweb">help</a>
868 868 <br/>
869 869 <a href="/graph/2?style=gitweb&revcount=30">less</a>
870 870 <a href="/graph/2?style=gitweb&revcount=120">more</a>
871 871 | <a href="/graph/2ef0ac749a14?style=gitweb">(0)</a> <a href="/graph/2ef0ac749a14?style=gitweb">-2</a> <a href="/graph/tip?style=gitweb">tip</a> <br/>
872 872 </div>
873 873
874 874 <div class="title">&nbsp;</div>
875 875
876 876 <noscript>The revision graph only works with JavaScript-enabled browsers.</noscript>
877 877
878 878 <div id="wrapper">
879 879 <ul id="nodebgs"></ul>
880 880 <canvas id="graph" width="480" height="129"></canvas>
881 881 <ul id="graphnodes"></ul>
882 882 </div>
883 883
884 884 <script>
885 885 <!-- hide script content
886 886
887 887 var data = [["1d22e65f027e", [0, 1], [[0, 0, 1]], "branch", "test", "1970-01-01", ["stable", true], ["tip"], ["something"]], ["a4f92ed23982", [0, 1], [[0, 0, 1]], "Added tag 1.0 for changeset 2ef0ac749a14", "test", "1970-01-01", ["default", true], [], []], ["2ef0ac749a14", [0, 1], [], "base", "test", "1970-01-01", ["default", false], ["1.0"], ["anotherthing"]]];
888 888 var graph = new Graph();
889 889 graph.scale(39);
890 890
891 891 graph.edge = function(x0, y0, x1, y1, color) {
892 892
893 893 this.setColor(color, 0.0, 0.65);
894 894 this.ctx.beginPath();
895 895 this.ctx.moveTo(x0, y0);
896 896 this.ctx.lineTo(x1, y1);
897 897 this.ctx.stroke();
898 898
899 899 }
900 900
901 901 var revlink = '<li style="_STYLE"><span class="desc">';
902 902 revlink += '<a class="list" href="/rev/_NODEID?style=gitweb" title="_NODEID"><b>_DESC</b></a>';
903 903 revlink += '</span> _TAGS';
904 904 revlink += '<span class="info">_DATE, by _USER</span></li>';
905 905
906 906 graph.vertex = function(x, y, color, parity, cur) {
907 907
908 908 this.ctx.beginPath();
909 909 color = this.setColor(color, 0.25, 0.75);
910 910 this.ctx.arc(x, y, radius, 0, Math.PI * 2, true);
911 911 this.ctx.fill();
912 912
913 913 var bg = '<li class="bg parity' + parity + '"></li>';
914 914 var left = (this.columns + 1) * this.bg_height;
915 915 var nstyle = 'padding-left: ' + left + 'px;';
916 916 var item = revlink.replace(/_STYLE/, nstyle);
917 917 item = item.replace(/_PARITY/, 'parity' + parity);
918 918 item = item.replace(/_NODEID/, cur[0]);
919 919 item = item.replace(/_NODEID/, cur[0]);
920 920 item = item.replace(/_DESC/, cur[3]);
921 921 item = item.replace(/_USER/, cur[4]);
922 922 item = item.replace(/_DATE/, cur[5]);
923 923
924 924 var tagspan = '';
925 925 if (cur[7].length || cur[8].length || (cur[6][0] != 'default' || cur[6][1])) {
926 926 tagspan = '<span class="logtags">';
927 927 if (cur[6][1]) {
928 928 tagspan += '<span class="branchtag" title="' + cur[6][0] + '">';
929 929 tagspan += cur[6][0] + '</span> ';
930 930 } else if (!cur[6][1] && cur[6][0] != 'default') {
931 931 tagspan += '<span class="inbranchtag" title="' + cur[6][0] + '">';
932 932 tagspan += cur[6][0] + '</span> ';
933 933 }
934 934 if (cur[7].length) {
935 935 for (var t in cur[7]) {
936 936 var tag = cur[7][t];
937 937 tagspan += '<span class="tagtag">' + tag + '</span> ';
938 938 }
939 939 }
940 940 if (cur[8].length) {
941 941 for (var t in cur[8]) {
942 942 var bookmark = cur[8][t];
943 943 tagspan += '<span class="bookmarktag">' + bookmark + '</span> ';
944 944 }
945 945 }
946 946 tagspan += '</span>';
947 947 }
948 948
949 949 item = item.replace(/_TAGS/, tagspan);
950 950 return [bg, item];
951 951
952 952 }
953 953
954 954 graph.render(data);
955 955
956 956 // stop hiding script -->
957 957 </script>
958 958
959 959 <div class="page_nav">
960 960 <a href="/graph/2?style=gitweb&revcount=30">less</a>
961 961 <a href="/graph/2?style=gitweb&revcount=120">more</a>
962 962 | <a href="/graph/2ef0ac749a14?style=gitweb">(0)</a> <a href="/graph/2ef0ac749a14?style=gitweb">-2</a> <a href="/graph/tip?style=gitweb">tip</a>
963 963 </div>
964 964
965 965 <script type="text/javascript">process_dates()</script>
966 966 <div class="page_footer">
967 967 <div class="page_footer_text">test</div>
968 968 <div class="rss_logo">
969 969 <a href="/rss-log">RSS</a>
970 970 <a href="/atom-log">Atom</a>
971 971 </div>
972 972 <br />
973 973
974 974 </div>
975 975 </body>
976 976 </html>
977 977
978 978
979 979 capabilities
980 980
981 981 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities'; echo
982 982 200 Script output follows
983 983
984 lookup changegroupsubset branchmap pushkey known getbundle unbundlehash unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
984 lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
985 985
986 986 heads
987 987
988 988 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=heads'
989 989 200 Script output follows
990 990
991 991 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
992 992
993 993 branches
994 994
995 995 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=branches&nodes=0000000000000000000000000000000000000000'
996 996 200 Script output follows
997 997
998 998 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
999 999
1000 1000 changegroup
1001 1001
1002 1002 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=changegroup&roots=0000000000000000000000000000000000000000'
1003 1003 200 Script output follows
1004 1004
1005 1005 x\x9c\xbdTMHUA\x14\xbe\xa8\xf9\xec\xda&\x10\x11*\xb8\x88\x81\x99\xbef\xe6\xce\xbdw\xc6\xf2a\x16E\x1b\x11[%\x98\xcc\xaf\x8f\x8c\xf7\xc0\xf7\x82 (esc)
1006 1006 4\x11KP2m\x95\xad*\xabE\x05AP\xd0\xc22Z\x14\xf9\x03\xb9j\xa3\x9b$\xa4MJ\xb4\x90\xc0\x9a\x9bO0\x10\xdf\x13\xa2\x81\x0f\x869g\xe6|\xe7\x9c\xef\x8ceY\xf7\xa2KO\xd2\xb7K\x16~\\n\xe9\xad\x90w\x86\xab\x93W\x8e\xdf\xb0r\\Y\xee6(\xa2)\xf6\x95\xc6\x01\xe4\x1az\x80R\xe8kN\x98\xe7R\xa4\xa9K@\xe0!A\xb4k\xa7U*m\x03\x07\xd8\x92\x1d\xd2\xc9\xa4\x1d\xc2\xe6,\xa5\xcc+\x1f\xef\xafDgi\xef\xab\x1d\x1d\xb7\x9a\xe7[W\xfbc\x8f\xde-\xcd\xe7\xcaz\xb3\xbb\x19\xd3\x81\x10>c>\x08\x00"X\x11\xc2\x84@\xd2\xe7B*L\x00\x01P\x04R\xc3@\xbaB0\xdb8#\x83:\x83\xa2h\xbc=\xcd\xdaS\xe1Y,L\xd3\xa0\xf2\xa8\x94J:\xe6\xd8\x81Q\xe0\xe8d\xa7#\xe2,\xd1\xaeR*\xed \xa5\x01\x13\x01\xa6\x0cb\xe3;\xbe\xaf\xfcK[^wK\xe1N\xaf\xbbk\xe8B\xd1\xf4\xc1\x07\xb3\xab[\x10\xfdkmvwcB\xa6\xa4\xd4G\xc4D\xc2\x141\xad\x91\x10\x00\x08J\x81\xcb}\xee \xee+W\xba\x8a\x80\x90|\xd4\xa0\xd6\xa0\xd4T\xde\xe1\x9d,!\xe2\xb5\xa94\xe3\xe7\xd5\x9f\x06\x18\xcba\x03aP\xb8f\xcd\x04\x1a_\\9\xf1\xed\xe4\x9e\xe5\xa6\xd1\xd2\x9f\x03\xa7o\xae\x90H\xf3\xfb\xef\xffH3\xadk (esc)
1007 1007 \xb0\x90\x92\x88\xb9\x14"\x068\xc2\x1e@\x00\xbb\x8a)\xd3'\x859 (esc)
1008 1008 \xa8\x80\x84S \xa5\xbd-g\x13`\xe4\xdc\xc3H^\xdf\xe2\xc0TM\xc7\xf4BO\xcf\xde\xae\xe5\xae#\x1frM(K\x97`F\x19\x16s\x05GD\xb9\x01\xc1\x00+\x8c|\x9fp\xc11\xf0\x14\x00\x9cJ\x82<\xe0\x12\x9f\xc1\x90\xd0\xf5\xc8\x19>Pr\xaa\xeaW\xf5\xc4\xae\xd1\xfc\x17\xcf'\x13u\xb1\x9e\xcdHnC\x0e\xcc`\xc8\xa0&\xac\x0e\xf1|\x8c\x10$\xc4\x8c\xa2p\x05`\xdc\x08 \x80\xc4\xd7Rr-\x94\x10\x102\xedi;\xf3f\xf1z\x16\x86\xdb\xd8d\xe5\xe7\x8b\xf5\x8d\rzp\xb2\xfe\xac\xf5\xf2\xd3\xfe\xfckws\xedt\x96b\xd5l\x1c\x0b\x85\xb5\x170\x8f\x11\x84\xb0\x8f\x19\xa0\x00 _\x07\x1ac\xa2\xc3\x89Z\xe7\x96\xf9 \xccNFg\xc7F\xaa\x8a+\x9a\x9cc_\x17\x1b\x17\x9e]z38<\x97+\xb5,",\xc8\xc8?\\\x91\xff\x17.~U\x96\x97\xf5%\xdeN<\x8e\xf5\x97%\xe7^\xcfL\xed~\xda\x96k\xdc->\x86\x02\x83"\x96H\xa6\xe3\xaas=-\xeb7\xe5\xda\x8f\xbc (no-eol) (esc)
1009 1009
1010 1010 stream_out
1011 1011
1012 1012 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=stream_out'
1013 1013 200 Script output follows
1014 1014
1015 1015 1
1016 1016
1017 1017 failing unbundle, requires POST request
1018 1018
1019 1019 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=unbundle'
1020 1020 405 push requires POST request
1021 1021
1022 1022 0
1023 1023 push requires POST request
1024 1024 [1]
1025 1025
1026 1026 Static files
1027 1027
1028 1028 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/static/style.css'
1029 1029 200 Script output follows
1030 1030
1031 1031 a { text-decoration:none; }
1032 1032 .age { white-space:nowrap; }
1033 1033 .date { white-space:nowrap; }
1034 1034 .indexlinks { white-space:nowrap; }
1035 1035 .parity0 { background-color: #ddd; }
1036 1036 .parity1 { background-color: #eee; }
1037 1037 .lineno { width: 60px; color: #aaa; font-size: smaller;
1038 1038 text-align: right; }
1039 1039 .plusline { color: green; }
1040 1040 .minusline { color: red; }
1041 1041 .atline { color: purple; }
1042 1042 .annotate { font-size: smaller; text-align: right; padding-right: 1em; }
1043 1043 .buttons a {
1044 1044 background-color: #666;
1045 1045 padding: 2pt;
1046 1046 color: white;
1047 1047 font-family: sans;
1048 1048 font-weight: bold;
1049 1049 }
1050 1050 .navigate a {
1051 1051 background-color: #ccc;
1052 1052 padding: 2pt;
1053 1053 font-family: sans;
1054 1054 color: black;
1055 1055 }
1056 1056
1057 1057 .metatag {
1058 1058 background-color: #888;
1059 1059 color: white;
1060 1060 text-align: right;
1061 1061 }
1062 1062
1063 1063 /* Common */
1064 1064 pre { margin: 0; }
1065 1065
1066 1066 .logo {
1067 1067 float: right;
1068 1068 clear: right;
1069 1069 }
1070 1070
1071 1071 /* Changelog/Filelog entries */
1072 1072 .logEntry { width: 100%; }
1073 1073 .logEntry .age { width: 15%; }
1074 1074 .logEntry th { font-weight: normal; text-align: right; vertical-align: top; }
1075 1075 .logEntry th.age, .logEntry th.firstline { font-weight: bold; }
1076 1076 .logEntry th.firstline { text-align: left; width: inherit; }
1077 1077
1078 1078 /* Shortlog entries */
1079 1079 .slogEntry { width: 100%; }
1080 1080 .slogEntry .age { width: 8em; }
1081 1081 .slogEntry td { font-weight: normal; text-align: left; vertical-align: top; }
1082 1082 .slogEntry td.author { width: 15em; }
1083 1083
1084 1084 /* Tag entries */
1085 1085 #tagEntries { list-style: none; margin: 0; padding: 0; }
1086 1086 #tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; }
1087 1087
1088 1088 /* Changeset entry */
1089 1089 #changesetEntry { }
1090 1090 #changesetEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
1091 1091 #changesetEntry th.files, #changesetEntry th.description { vertical-align: top; }
1092 1092
1093 1093 /* File diff view */
1094 1094 #filediffEntry { }
1095 1095 #filediffEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
1096 1096
1097 1097 /* Graph */
1098 1098 div#wrapper {
1099 1099 position: relative;
1100 1100 margin: 0;
1101 1101 padding: 0;
1102 1102 }
1103 1103
1104 1104 canvas {
1105 1105 position: absolute;
1106 1106 z-index: 5;
1107 1107 top: -0.6em;
1108 1108 margin: 0;
1109 1109 }
1110 1110
1111 1111 ul#nodebgs {
1112 1112 list-style: none inside none;
1113 1113 padding: 0;
1114 1114 margin: 0;
1115 1115 top: -0.7em;
1116 1116 }
1117 1117
1118 1118 ul#graphnodes li, ul#nodebgs li {
1119 1119 height: 39px;
1120 1120 }
1121 1121
1122 1122 ul#graphnodes {
1123 1123 position: absolute;
1124 1124 z-index: 10;
1125 1125 top: -0.85em;
1126 1126 list-style: none inside none;
1127 1127 padding: 0;
1128 1128 }
1129 1129
1130 1130 ul#graphnodes li .info {
1131 1131 display: block;
1132 1132 font-size: 70%;
1133 1133 position: relative;
1134 1134 top: -1px;
1135 1135 }
1136 1136
1137 1137 Stop and restart with HGENCODING=cp932
1138 1138
1139 1139 $ "$TESTDIR/killdaemons.py"
1140 1140 $ HGENCODING=cp932 hg serve --config server.uncompressed=False -n test \
1141 1141 > -p $HGPORT -d --pid-file=hg.pid -E errors.log
1142 1142 $ cat hg.pid >> $DAEMON_PIDS
1143 1143
1144 1144 commit message with Japanese Kanji 'Noh', which ends with '\x5c'
1145 1145
1146 1146 $ echo foo >> foo
1147 1147 $ HGENCODING=cp932 hg ci -m `python -c 'print("\x94\x5c")'`
1148 1148
1149 1149 Graph json escape of multibyte character
1150 1150
1151 1151 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/graph/' \
1152 1152 > | grep '^var data ='
1153 1153 var data = [["40b4d6888e92", [0, 1], [[0, 0, 1]], "\u80fd", "test", "1970-01-01", ["stable", true], ["tip"], ["something"]], ["1d22e65f027e", [0, 1], [[0, 0, 1]], "branch", "test", "1970-01-01", ["stable", false], [], []], ["a4f92ed23982", [0, 1], [[0, 0, 1]], "Added tag 1.0 for changeset 2ef0ac749a14", "test", "1970-01-01", ["default", true], [], []], ["2ef0ac749a14", [0, 1], [], "base", "test", "1970-01-01", ["default", false], ["1.0"], ["anotherthing"]]];
1154 1154
1155 1155 ERRORS ENCOUNTERED
1156 1156
1157 1157 $ cat errors.log
General Comments 0
You need to be logged in to leave comments. Login now