##// END OF EJS Templates
hgweb: add phase to {changeset} template...
Gregory Szorc -
r24564:5ec4bda3 default
parent child Browse files
Show More
@@ -1,499 +1,500 b''
1 1 # hgweb/webutil.py - utility library for the web interface.
2 2 #
3 3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 import os, copy
10 10 from mercurial import match, patch, error, ui, util, pathutil, context
11 11 from mercurial.i18n import _
12 12 from mercurial.node import hex, nullid
13 13 from common import ErrorResponse, paritygen
14 14 from common import HTTP_NOT_FOUND
15 15 import difflib
16 16
17 17 def up(p):
18 18 if p[0] != "/":
19 19 p = "/" + p
20 20 if p[-1] == "/":
21 21 p = p[:-1]
22 22 up = os.path.dirname(p)
23 23 if up == "/":
24 24 return "/"
25 25 return up + "/"
26 26
27 27 def _navseq(step, firststep=None):
28 28 if firststep:
29 29 yield firststep
30 30 if firststep >= 20 and firststep <= 40:
31 31 firststep = 50
32 32 yield firststep
33 33 assert step > 0
34 34 assert firststep > 0
35 35 while step <= firststep:
36 36 step *= 10
37 37 while True:
38 38 yield 1 * step
39 39 yield 3 * step
40 40 step *= 10
41 41
42 42 class revnav(object):
43 43
44 44 def __init__(self, repo):
45 45 """Navigation generation object
46 46
47 47 :repo: repo object we generate nav for
48 48 """
49 49 # used for hex generation
50 50 self._revlog = repo.changelog
51 51
52 52 def __nonzero__(self):
53 53 """return True if any revision to navigate over"""
54 54 return self._first() is not None
55 55
56 56 def _first(self):
57 57 """return the minimum non-filtered changeset or None"""
58 58 try:
59 59 return iter(self._revlog).next()
60 60 except StopIteration:
61 61 return None
62 62
63 63 def hex(self, rev):
64 64 return hex(self._revlog.node(rev))
65 65
66 66 def gen(self, pos, pagelen, limit):
67 67 """computes label and revision id for navigation link
68 68
69 69 :pos: is the revision relative to which we generate navigation.
70 70 :pagelen: the size of each navigation page
71 71 :limit: how far shall we link
72 72
73 73 The return is:
74 74 - a single element tuple
75 75 - containing a dictionary with a `before` and `after` key
76 76 - values are generator functions taking arbitrary number of kwargs
77 77 - yield items are dictionaries with `label` and `node` keys
78 78 """
79 79 if not self:
80 80 # empty repo
81 81 return ({'before': (), 'after': ()},)
82 82
83 83 targets = []
84 84 for f in _navseq(1, pagelen):
85 85 if f > limit:
86 86 break
87 87 targets.append(pos + f)
88 88 targets.append(pos - f)
89 89 targets.sort()
90 90
91 91 first = self._first()
92 92 navbefore = [("(%i)" % first, self.hex(first))]
93 93 navafter = []
94 94 for rev in targets:
95 95 if rev not in self._revlog:
96 96 continue
97 97 if pos < rev < limit:
98 98 navafter.append(("+%d" % abs(rev - pos), self.hex(rev)))
99 99 if 0 < rev < pos:
100 100 navbefore.append(("-%d" % abs(rev - pos), self.hex(rev)))
101 101
102 102
103 103 navafter.append(("tip", "tip"))
104 104
105 105 data = lambda i: {"label": i[0], "node": i[1]}
106 106 return ({'before': lambda **map: (data(i) for i in navbefore),
107 107 'after': lambda **map: (data(i) for i in navafter)},)
108 108
109 109 class filerevnav(revnav):
110 110
111 111 def __init__(self, repo, path):
112 112 """Navigation generation object
113 113
114 114 :repo: repo object we generate nav for
115 115 :path: path of the file we generate nav for
116 116 """
117 117 # used for iteration
118 118 self._changelog = repo.unfiltered().changelog
119 119 # used for hex generation
120 120 self._revlog = repo.file(path)
121 121
122 122 def hex(self, rev):
123 123 return hex(self._changelog.node(self._revlog.linkrev(rev)))
124 124
125 125
126 126 def _siblings(siblings=[], hiderev=None):
127 127 siblings = [s for s in siblings if s.node() != nullid]
128 128 if len(siblings) == 1 and siblings[0].rev() == hiderev:
129 129 return
130 130 for s in siblings:
131 131 d = {'node': s.hex(), 'rev': s.rev()}
132 132 d['user'] = s.user()
133 133 d['date'] = s.date()
134 134 d['description'] = s.description()
135 135 d['branch'] = s.branch()
136 136 if util.safehasattr(s, 'path'):
137 137 d['file'] = s.path()
138 138 yield d
139 139
140 140 def parents(ctx, hide=None):
141 141 if isinstance(ctx, context.basefilectx):
142 142 introrev = ctx.introrev()
143 143 if ctx.changectx().rev() != introrev:
144 144 return _siblings([ctx.repo()[introrev]], hide)
145 145 return _siblings(ctx.parents(), hide)
146 146
147 147 def children(ctx, hide=None):
148 148 return _siblings(ctx.children(), hide)
149 149
150 150 def renamelink(fctx):
151 151 r = fctx.renamed()
152 152 if r:
153 153 return [{'file': r[0], 'node': hex(r[1])}]
154 154 return []
155 155
156 156 def nodetagsdict(repo, node):
157 157 return [{"name": i} for i in repo.nodetags(node)]
158 158
159 159 def nodebookmarksdict(repo, node):
160 160 return [{"name": i} for i in repo.nodebookmarks(node)]
161 161
162 162 def nodebranchdict(repo, ctx):
163 163 branches = []
164 164 branch = ctx.branch()
165 165 # If this is an empty repo, ctx.node() == nullid,
166 166 # ctx.branch() == 'default'.
167 167 try:
168 168 branchnode = repo.branchtip(branch)
169 169 except error.RepoLookupError:
170 170 branchnode = None
171 171 if branchnode == ctx.node():
172 172 branches.append({"name": branch})
173 173 return branches
174 174
175 175 def nodeinbranch(repo, ctx):
176 176 branches = []
177 177 branch = ctx.branch()
178 178 try:
179 179 branchnode = repo.branchtip(branch)
180 180 except error.RepoLookupError:
181 181 branchnode = None
182 182 if branch != 'default' and branchnode != ctx.node():
183 183 branches.append({"name": branch})
184 184 return branches
185 185
186 186 def nodebranchnodefault(ctx):
187 187 branches = []
188 188 branch = ctx.branch()
189 189 if branch != 'default':
190 190 branches.append({"name": branch})
191 191 return branches
192 192
193 193 def showtag(repo, tmpl, t1, node=nullid, **args):
194 194 for t in repo.nodetags(node):
195 195 yield tmpl(t1, tag=t, **args)
196 196
197 197 def showbookmark(repo, tmpl, t1, node=nullid, **args):
198 198 for t in repo.nodebookmarks(node):
199 199 yield tmpl(t1, bookmark=t, **args)
200 200
201 201 def cleanpath(repo, path):
202 202 path = path.lstrip('/')
203 203 return pathutil.canonpath(repo.root, '', path)
204 204
205 205 def changeidctx (repo, changeid):
206 206 try:
207 207 ctx = repo[changeid]
208 208 except error.RepoError:
209 209 man = repo.manifest
210 210 ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))]
211 211
212 212 return ctx
213 213
214 214 def changectx (repo, req):
215 215 changeid = "tip"
216 216 if 'node' in req.form:
217 217 changeid = req.form['node'][0]
218 218 ipos=changeid.find(':')
219 219 if ipos != -1:
220 220 changeid = changeid[(ipos + 1):]
221 221 elif 'manifest' in req.form:
222 222 changeid = req.form['manifest'][0]
223 223
224 224 return changeidctx(repo, changeid)
225 225
226 226 def basechangectx(repo, req):
227 227 if 'node' in req.form:
228 228 changeid = req.form['node'][0]
229 229 ipos=changeid.find(':')
230 230 if ipos != -1:
231 231 changeid = changeid[:ipos]
232 232 return changeidctx(repo, changeid)
233 233
234 234 return None
235 235
236 236 def filectx(repo, req):
237 237 if 'file' not in req.form:
238 238 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
239 239 path = cleanpath(repo, req.form['file'][0])
240 240 if 'node' in req.form:
241 241 changeid = req.form['node'][0]
242 242 elif 'filenode' in req.form:
243 243 changeid = req.form['filenode'][0]
244 244 else:
245 245 raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given')
246 246 try:
247 247 fctx = repo[changeid][path]
248 248 except error.RepoError:
249 249 fctx = repo.filectx(path, fileid=changeid)
250 250
251 251 return fctx
252 252
253 253 def changelistentry(web, ctx, tmpl):
254 254 '''Obtain a dictionary to be used for entries in a changelist.
255 255
256 256 This function is called when producing items for the "entries" list passed
257 257 to the "shortlog" and "changelog" templates.
258 258 '''
259 259 repo = web.repo
260 260 rev = ctx.rev()
261 261 n = ctx.node()
262 262 showtags = showtag(repo, tmpl, 'changelogtag', n)
263 263 files = listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
264 264
265 265 return {
266 266 "author": ctx.user(),
267 267 "parent": parents(ctx, rev - 1),
268 268 "child": children(ctx, rev + 1),
269 269 "changelogtag": showtags,
270 270 "desc": ctx.description(),
271 271 "extra": ctx.extra(),
272 272 "date": ctx.date(),
273 273 "files": files,
274 274 "rev": rev,
275 275 "node": hex(n),
276 276 "tags": nodetagsdict(repo, n),
277 277 "bookmarks": nodebookmarksdict(repo, n),
278 278 "inbranch": nodeinbranch(repo, ctx),
279 279 "branches": nodebranchdict(repo, ctx)
280 280 }
281 281
282 282 def changesetentry(web, req, tmpl, ctx):
283 283 '''Obtain a dictionary to be used to render the "changeset" template.'''
284 284
285 285 showtags = showtag(web.repo, tmpl, 'changesettag', ctx.node())
286 286 showbookmarks = showbookmark(web.repo, tmpl, 'changesetbookmark',
287 287 ctx.node())
288 288 showbranch = nodebranchnodefault(ctx)
289 289
290 290 files = []
291 291 parity = paritygen(web.stripecount)
292 292 for blockno, f in enumerate(ctx.files()):
293 293 template = f in ctx and 'filenodelink' or 'filenolink'
294 294 files.append(tmpl(template,
295 295 node=ctx.hex(), file=f, blockno=blockno + 1,
296 296 parity=parity.next()))
297 297
298 298 basectx = basechangectx(web.repo, req)
299 299 if basectx is None:
300 300 basectx = ctx.p1()
301 301
302 302 style = web.config('web', 'style', 'paper')
303 303 if 'style' in req.form:
304 304 style = req.form['style'][0]
305 305
306 306 parity = paritygen(web.stripecount)
307 307 diff = diffs(web.repo, tmpl, ctx, basectx, None, parity, style)
308 308
309 309 parity = paritygen(web.stripecount)
310 310 diffstatsgen = diffstatgen(ctx, basectx)
311 311 diffstats = diffstat(tmpl, ctx, diffstatsgen, parity)
312 312
313 313 return dict(
314 314 diff=diff,
315 315 rev=ctx.rev(),
316 316 node=ctx.hex(),
317 317 parent=tuple(parents(ctx)),
318 318 child=children(ctx),
319 319 basenode=basectx.hex(),
320 320 changesettag=showtags,
321 321 changesetbookmark=showbookmarks,
322 322 changesetbranch=showbranch,
323 323 author=ctx.user(),
324 324 desc=ctx.description(),
325 325 extra=ctx.extra(),
326 326 date=ctx.date(),
327 phase=ctx.phasestr(),
327 328 files=files,
328 329 diffsummary=lambda **x: diffsummary(diffstatsgen),
329 330 diffstat=diffstats,
330 331 archives=web.archivelist(ctx.hex()),
331 332 tags=nodetagsdict(web.repo, ctx.node()),
332 333 bookmarks=nodebookmarksdict(web.repo, ctx.node()),
333 334 branch=nodebranchnodefault(ctx),
334 335 inbranch=nodeinbranch(web.repo, ctx),
335 336 branches=nodebranchdict(web.repo, ctx))
336 337
337 338 def listfilediffs(tmpl, files, node, max):
338 339 for f in files[:max]:
339 340 yield tmpl('filedifflink', node=hex(node), file=f)
340 341 if len(files) > max:
341 342 yield tmpl('fileellipses')
342 343
343 344 def diffs(repo, tmpl, ctx, basectx, files, parity, style):
344 345
345 346 def countgen():
346 347 start = 1
347 348 while True:
348 349 yield start
349 350 start += 1
350 351
351 352 blockcount = countgen()
352 353 def prettyprintlines(diff, blockno):
353 354 for lineno, l in enumerate(diff.splitlines(True)):
354 355 lineno = "%d.%d" % (blockno, lineno + 1)
355 356 if l.startswith('+'):
356 357 ltype = "difflineplus"
357 358 elif l.startswith('-'):
358 359 ltype = "difflineminus"
359 360 elif l.startswith('@'):
360 361 ltype = "difflineat"
361 362 else:
362 363 ltype = "diffline"
363 364 yield tmpl(ltype,
364 365 line=l,
365 366 lineid="l%s" % lineno,
366 367 linenumber="% 8s" % lineno)
367 368
368 369 if files:
369 370 m = match.exact(repo.root, repo.getcwd(), files)
370 371 else:
371 372 m = match.always(repo.root, repo.getcwd())
372 373
373 374 diffopts = patch.diffopts(repo.ui, untrusted=True)
374 375 if basectx is None:
375 376 parents = ctx.parents()
376 377 if parents:
377 378 node1 = parents[0].node()
378 379 else:
379 380 node1 = nullid
380 381 else:
381 382 node1 = basectx.node()
382 383 node2 = ctx.node()
383 384
384 385 block = []
385 386 for chunk in patch.diff(repo, node1, node2, m, opts=diffopts):
386 387 if chunk.startswith('diff') and block:
387 388 blockno = blockcount.next()
388 389 yield tmpl('diffblock', parity=parity.next(), blockno=blockno,
389 390 lines=prettyprintlines(''.join(block), blockno))
390 391 block = []
391 392 if chunk.startswith('diff') and style != 'raw':
392 393 chunk = ''.join(chunk.splitlines(True)[1:])
393 394 block.append(chunk)
394 395 blockno = blockcount.next()
395 396 yield tmpl('diffblock', parity=parity.next(), blockno=blockno,
396 397 lines=prettyprintlines(''.join(block), blockno))
397 398
398 399 def compare(tmpl, context, leftlines, rightlines):
399 400 '''Generator function that provides side-by-side comparison data.'''
400 401
401 402 def compline(type, leftlineno, leftline, rightlineno, rightline):
402 403 lineid = leftlineno and ("l%s" % leftlineno) or ''
403 404 lineid += rightlineno and ("r%s" % rightlineno) or ''
404 405 return tmpl('comparisonline',
405 406 type=type,
406 407 lineid=lineid,
407 408 leftlinenumber="% 6s" % (leftlineno or ''),
408 409 leftline=leftline or '',
409 410 rightlinenumber="% 6s" % (rightlineno or ''),
410 411 rightline=rightline or '')
411 412
412 413 def getblock(opcodes):
413 414 for type, llo, lhi, rlo, rhi in opcodes:
414 415 len1 = lhi - llo
415 416 len2 = rhi - rlo
416 417 count = min(len1, len2)
417 418 for i in xrange(count):
418 419 yield compline(type=type,
419 420 leftlineno=llo + i + 1,
420 421 leftline=leftlines[llo + i],
421 422 rightlineno=rlo + i + 1,
422 423 rightline=rightlines[rlo + i])
423 424 if len1 > len2:
424 425 for i in xrange(llo + count, lhi):
425 426 yield compline(type=type,
426 427 leftlineno=i + 1,
427 428 leftline=leftlines[i],
428 429 rightlineno=None,
429 430 rightline=None)
430 431 elif len2 > len1:
431 432 for i in xrange(rlo + count, rhi):
432 433 yield compline(type=type,
433 434 leftlineno=None,
434 435 leftline=None,
435 436 rightlineno=i + 1,
436 437 rightline=rightlines[i])
437 438
438 439 s = difflib.SequenceMatcher(None, leftlines, rightlines)
439 440 if context < 0:
440 441 yield tmpl('comparisonblock', lines=getblock(s.get_opcodes()))
441 442 else:
442 443 for oc in s.get_grouped_opcodes(n=context):
443 444 yield tmpl('comparisonblock', lines=getblock(oc))
444 445
445 446 def diffstatgen(ctx, basectx):
446 447 '''Generator function that provides the diffstat data.'''
447 448
448 449 stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx)))
449 450 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
450 451 while True:
451 452 yield stats, maxname, maxtotal, addtotal, removetotal, binary
452 453
453 454 def diffsummary(statgen):
454 455 '''Return a short summary of the diff.'''
455 456
456 457 stats, maxname, maxtotal, addtotal, removetotal, binary = statgen.next()
457 458 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % (
458 459 len(stats), addtotal, removetotal)
459 460
460 461 def diffstat(tmpl, ctx, statgen, parity):
461 462 '''Return a diffstat template for each file in the diff.'''
462 463
463 464 stats, maxname, maxtotal, addtotal, removetotal, binary = statgen.next()
464 465 files = ctx.files()
465 466
466 467 def pct(i):
467 468 if maxtotal == 0:
468 469 return 0
469 470 return (float(i) / maxtotal) * 100
470 471
471 472 fileno = 0
472 473 for filename, adds, removes, isbinary in stats:
473 474 template = filename in files and 'diffstatlink' or 'diffstatnolink'
474 475 total = adds + removes
475 476 fileno += 1
476 477 yield tmpl(template, node=ctx.hex(), file=filename, fileno=fileno,
477 478 total=total, addpct=pct(adds), removepct=pct(removes),
478 479 parity=parity.next())
479 480
480 481 class sessionvars(object):
481 482 def __init__(self, vars, start='?'):
482 483 self.start = start
483 484 self.vars = vars
484 485 def __getitem__(self, key):
485 486 return self.vars[key]
486 487 def __setitem__(self, key, value):
487 488 self.vars[key] = value
488 489 def __copy__(self):
489 490 return sessionvars(copy.copy(self.vars), self.start)
490 491 def __iter__(self):
491 492 separator = self.start
492 493 for key, value in sorted(self.vars.iteritems()):
493 494 yield {'name': key, 'value': str(value), 'separator': separator}
494 495 separator = '&'
495 496
496 497 class wsgiui(ui.ui):
497 498 # default termwidth breaks under mod_wsgi
498 499 def termwidth(self):
499 500 return 80
@@ -1,57 +1,58 b''
1 1 mimetype = 'application/json'
2 2 filerevision = '"not yet implemented"'
3 3 search = '"not yet implemented"'
4 4 shortlog = '"not yet implemented"'
5 5 changelog = '"not yet implemented"'
6 6 changeset = '\{
7 7 "node": {node|json},
8 8 "date": {date|json},
9 9 "desc": {desc|json},
10 10 "branch": {if(branch, branch%changesetbranch, "default"|json)},
11 11 "bookmarks": [{join(changesetbookmark, ", ")}],
12 12 "tags": [{join(changesettag, ", ")}],
13 13 "user": {author|json},
14 "parents": [{join(parent%changesetparent, ", ")}]
14 "parents": [{join(parent%changesetparent, ", ")}],
15 "phase": {phase|json}
15 16 }'
16 17 changesetbranch = '{name|json}'
17 18 changesetbookmark = '{bookmark|json}'
18 19 changesettag = '{tag|json}'
19 20 changesetparent = '{node|json}'
20 21 manifest = '"not yet implemented"'
21 22 tags = '\{
22 23 "node": {node|json},
23 24 "tags": [{join(entriesnotip%tagentry, ", ")}]
24 25 }'
25 26 tagentry = '\{
26 27 "tag": {tag|json},
27 28 "node": {node|json},
28 29 "date": {date|json}
29 30 }'
30 31 bookmarks = '\{
31 32 "node": {node|json},
32 33 "bookmarks": [{join(entries%bookmarkentry, ", ")}]
33 34 }'
34 35 bookmarkentry = '\{
35 36 "bookmark": {bookmark|json},
36 37 "node": {node|json},
37 38 "date": {date|json}
38 39 }'
39 40 branches = '\{
40 41 "branches": [{join(entries%branchentry, ", ")}]
41 42 }'
42 43 branchentry = '\{
43 44 "branch": {branch|json},
44 45 "node": {node|json},
45 46 "date": {date|json},
46 47 "status": {status|json}
47 48 }'
48 49 summary = '"not yet implemented"'
49 50 filediff = '"not yet implemented"'
50 51 filecomparison = '"not yet implemented"'
51 52 fileannotate = '"not yet implemented"'
52 53 filelog = '"not yet implemented"'
53 54 graph = '"not yet implemented"'
54 55 helptopics = '"not yet implemented"'
55 56 help = '"not yet implemented"'
56 57 filenodelink = ''
57 58 filenolink = ''
@@ -1,385 +1,390 b''
1 1 #require json
2 2 #require serve
3 3
4 4 $ request() {
5 5 > $TESTDIR/get-with-headers.py --json localhost:$HGPORT "$1"
6 6 > }
7 7
8 8 $ hg init test
9 9 $ cd test
10 10 $ mkdir da
11 11 $ echo foo > da/foo
12 12 $ echo foo > foo
13 13 $ hg -q ci -A -m initial
14 14 $ echo bar > foo
15 15 $ hg ci -m 'modify foo'
16 16 $ echo bar > da/foo
17 17 $ hg ci -m 'modify da/foo'
18 18 $ hg bookmark bookmark1
19 19 $ hg up default
20 20 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 21 (leaving bookmark bookmark1)
22 22 $ hg mv foo foo-new
23 23 $ hg commit -m 'move foo'
24 24 $ hg tag -m 'create tag' tag1
25 $ hg phase --public -r .
25 26 $ echo baz > da/foo
26 27 $ hg commit -m 'another commit to da/foo'
27 28 $ hg tag -m 'create tag2' tag2
28 29 $ hg bookmark bookmark2
29 30 $ hg -q up -r 0
30 31 $ hg -q branch test-branch
31 32 $ echo branch > foo
32 33 $ hg commit -m 'create test branch'
33 34 $ echo branch_commit_2 > foo
34 35 $ hg commit -m 'another commit in test-branch'
35 36 $ hg -q up default
36 37 $ hg merge --tool :local test-branch
37 38 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
38 39 (branch merge, don't forget to commit)
39 40 $ hg commit -m 'merge test-branch into default'
40 41
41 42 $ hg log -G
42 43 @ changeset: 9:cc725e08502a
43 44 |\ tag: tip
44 45 | | parent: 6:ceed296fe500
45 46 | | parent: 8:ed66c30e87eb
46 47 | | user: test
47 48 | | date: Thu Jan 01 00:00:00 1970 +0000
48 49 | | summary: merge test-branch into default
49 50 | |
50 51 | o changeset: 8:ed66c30e87eb
51 52 | | branch: test-branch
52 53 | | user: test
53 54 | | date: Thu Jan 01 00:00:00 1970 +0000
54 55 | | summary: another commit in test-branch
55 56 | |
56 57 | o changeset: 7:6ab967a8ab34
57 58 | | branch: test-branch
58 59 | | parent: 0:06e557f3edf6
59 60 | | user: test
60 61 | | date: Thu Jan 01 00:00:00 1970 +0000
61 62 | | summary: create test branch
62 63 | |
63 64 o | changeset: 6:ceed296fe500
64 65 | | bookmark: bookmark2
65 66 | | user: test
66 67 | | date: Thu Jan 01 00:00:00 1970 +0000
67 68 | | summary: create tag2
68 69 | |
69 70 o | changeset: 5:f2890a05fea4
70 71 | | tag: tag2
71 72 | | user: test
72 73 | | date: Thu Jan 01 00:00:00 1970 +0000
73 74 | | summary: another commit to da/foo
74 75 | |
75 76 o | changeset: 4:93a8ce14f891
76 77 | | user: test
77 78 | | date: Thu Jan 01 00:00:00 1970 +0000
78 79 | | summary: create tag
79 80 | |
80 81 o | changeset: 3:78896eb0e102
81 82 | | tag: tag1
82 83 | | user: test
83 84 | | date: Thu Jan 01 00:00:00 1970 +0000
84 85 | | summary: move foo
85 86 | |
86 87 o | changeset: 2:8d7c456572ac
87 88 | | bookmark: bookmark1
88 89 | | user: test
89 90 | | date: Thu Jan 01 00:00:00 1970 +0000
90 91 | | summary: modify da/foo
91 92 | |
92 93 o | changeset: 1:f8bbb9024b10
93 94 |/ user: test
94 95 | date: Thu Jan 01 00:00:00 1970 +0000
95 96 | summary: modify foo
96 97 |
97 98 o changeset: 0:06e557f3edf6
98 99 user: test
99 100 date: Thu Jan 01 00:00:00 1970 +0000
100 101 summary: initial
101 102
102 103
103 104 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E error.log
104 105 $ cat hg.pid >> $DAEMON_PIDS
105 106
106 107 (Try to keep these in roughly the order they are defined in webcommands.py)
107 108
108 109 (log is handled by filelog/ and changelog/ - ignore it)
109 110
110 111 (rawfile/ doesn't use templating - nothing to test)
111 112
112 113 file/{revision}/{path} shows file revision
113 114
114 115 $ request json-file/06e557f3edf6/foo
115 116 200 Script output follows
116 117
117 118 "not yet implemented"
118 119
119 120 file/{revision} shows root directory info
120 121
121 122 $ request json-file/06e557f3edf6
122 123 200 Script output follows
123 124
124 125 "not yet implemented"
125 126
126 127 changelog/ shows information about several changesets
127 128
128 129 $ request json-changelog
129 130 200 Script output follows
130 131
131 132 "not yet implemented"
132 133
133 134 changelog/{revision} shows information about a single changeset
134 135
135 136 $ request json-changelog/06e557f3edf6
136 137 200 Script output follows
137 138
138 139 "not yet implemented"
139 140
140 141 shortlog/ shows information about a set of changesets
141 142
142 143 $ request json-shortlog
143 144 200 Script output follows
144 145
145 146 "not yet implemented"
146 147
147 148 changeset/ renders the tip changeset
148 149
149 150 $ request json-rev
150 151 200 Script output follows
151 152
152 153 {
153 154 "bookmarks": [],
154 155 "branch": "default",
155 156 "date": [
156 157 0.0,
157 158 0
158 159 ],
159 160 "desc": "merge test-branch into default",
160 161 "node": "cc725e08502a79dd1eda913760fbe06ed7a9abc7",
161 162 "parents": [
162 163 "ceed296fe500c3fac9541e31dad860cb49c89e45",
163 164 "ed66c30e87eb65337c05a4229efaa5f1d5285a90"
164 165 ],
166 "phase": "draft",
165 167 "tags": [
166 168 "tip"
167 169 ],
168 170 "user": "test"
169 171 }
170 172
171 173 changeset/{revision} shows tags
172 174
173 175 $ request json-rev/78896eb0e102
174 176 200 Script output follows
175 177
176 178 {
177 179 "bookmarks": [],
178 180 "branch": "default",
179 181 "date": [
180 182 0.0,
181 183 0
182 184 ],
183 185 "desc": "move foo",
184 186 "node": "78896eb0e102174ce9278438a95e12543e4367a7",
185 187 "parents": [
186 188 "8d7c456572acf3557e8ed8a07286b10c408bcec5"
187 189 ],
190 "phase": "public",
188 191 "tags": [
189 192 "tag1"
190 193 ],
191 194 "user": "test"
192 195 }
193 196
194 197 changeset/{revision} shows bookmarks
195 198
196 199 $ request json-rev/8d7c456572ac
197 200 200 Script output follows
198 201
199 202 {
200 203 "bookmarks": [
201 204 "bookmark1"
202 205 ],
203 206 "branch": "default",
204 207 "date": [
205 208 0.0,
206 209 0
207 210 ],
208 211 "desc": "modify da/foo",
209 212 "node": "8d7c456572acf3557e8ed8a07286b10c408bcec5",
210 213 "parents": [
211 214 "f8bbb9024b10f93cdbb8d940337398291d40dea8"
212 215 ],
216 "phase": "public",
213 217 "tags": [],
214 218 "user": "test"
215 219 }
216 220
217 221 changeset/{revision} shows branches
218 222
219 223 $ request json-rev/6ab967a8ab34
220 224 200 Script output follows
221 225
222 226 {
223 227 "bookmarks": [],
224 228 "branch": "test-branch",
225 229 "date": [
226 230 0.0,
227 231 0
228 232 ],
229 233 "desc": "create test branch",
230 234 "node": "6ab967a8ab3489227a83f80e920faa039a71819f",
231 235 "parents": [
232 236 "06e557f3edf66faa1ccaba5dd8c203c21cc79f1e"
233 237 ],
238 "phase": "draft",
234 239 "tags": [],
235 240 "user": "test"
236 241 }
237 242
238 243 manifest/{revision}/{path} shows info about a directory at a revision
239 244
240 245 $ request json-manifest/06e557f3edf6/
241 246 200 Script output follows
242 247
243 248 "not yet implemented"
244 249
245 250 tags/ shows tags info
246 251
247 252 $ request json-tags
248 253 200 Script output follows
249 254
250 255 {
251 256 "node": "cc725e08502a79dd1eda913760fbe06ed7a9abc7",
252 257 "tags": [
253 258 {
254 259 "date": [
255 260 0.0,
256 261 0
257 262 ],
258 263 "node": "f2890a05fea49bfaf9fb27ed5490894eba32da78",
259 264 "tag": "tag2"
260 265 },
261 266 {
262 267 "date": [
263 268 0.0,
264 269 0
265 270 ],
266 271 "node": "78896eb0e102174ce9278438a95e12543e4367a7",
267 272 "tag": "tag1"
268 273 }
269 274 ]
270 275 }
271 276
272 277 bookmarks/ shows bookmarks info
273 278
274 279 $ request json-bookmarks
275 280 200 Script output follows
276 281
277 282 {
278 283 "bookmarks": [
279 284 {
280 285 "bookmark": "bookmark1",
281 286 "date": [
282 287 0.0,
283 288 0
284 289 ],
285 290 "node": "8d7c456572acf3557e8ed8a07286b10c408bcec5"
286 291 },
287 292 {
288 293 "bookmark": "bookmark2",
289 294 "date": [
290 295 0.0,
291 296 0
292 297 ],
293 298 "node": "ceed296fe500c3fac9541e31dad860cb49c89e45"
294 299 }
295 300 ],
296 301 "node": "cc725e08502a79dd1eda913760fbe06ed7a9abc7"
297 302 }
298 303
299 304 branches/ shows branches info
300 305
301 306 $ request json-branches
302 307 200 Script output follows
303 308
304 309 {
305 310 "branches": [
306 311 {
307 312 "branch": "default",
308 313 "date": [
309 314 0.0,
310 315 0
311 316 ],
312 317 "node": "cc725e08502a79dd1eda913760fbe06ed7a9abc7",
313 318 "status": "open"
314 319 },
315 320 {
316 321 "branch": "test-branch",
317 322 "date": [
318 323 0.0,
319 324 0
320 325 ],
321 326 "node": "ed66c30e87eb65337c05a4229efaa5f1d5285a90",
322 327 "status": "inactive"
323 328 }
324 329 ]
325 330 }
326 331
327 332 summary/ shows a summary of repository state
328 333
329 334 $ request json-summary
330 335 200 Script output follows
331 336
332 337 "not yet implemented"
333 338
334 339 filediff/{revision}/{path} shows changes to a file in a revision
335 340
336 341 $ request json-diff/f8bbb9024b10/foo
337 342 200 Script output follows
338 343
339 344 "not yet implemented"
340 345
341 346 comparison/{revision}/{path} shows information about before and after for a file
342 347
343 348 $ request json-comparison/f8bbb9024b10/foo
344 349 200 Script output follows
345 350
346 351 "not yet implemented"
347 352
348 353 annotate/{revision}/{path} shows annotations for each line
349 354
350 355 $ request json-annotate/f8bbb9024b10/foo
351 356 200 Script output follows
352 357
353 358 "not yet implemented"
354 359
355 360 filelog/{revision}/{path} shows history of a single file
356 361
357 362 $ request json-filelog/f8bbb9024b10/foo
358 363 200 Script output follows
359 364
360 365 "not yet implemented"
361 366
362 367 (archive/ doesn't use templating, so ignore it)
363 368
364 369 (static/ doesn't use templating, so ignore it)
365 370
366 371 graph/ shows information that can be used to render a graph of the DAG
367 372
368 373 $ request json-graph
369 374 200 Script output follows
370 375
371 376 "not yet implemented"
372 377
373 378 help/ shows help topics
374 379
375 380 $ request json-help
376 381 200 Script output follows
377 382
378 383 "not yet implemented"
379 384
380 385 help/{topic} shows an individual help topic
381 386
382 387 $ request json-help/phases
383 388 200 Script output follows
384 389
385 390 "not yet implemented"
General Comments 0
You need to be logged in to leave comments. Login now