Our march towards killing wsgirequest continues.
.. api::
Various functions in hgweb.webutil now take a modern request object instead of ``wsgirequest``.
| durin42 |
| hg-reviewers |
Our march towards killing wsgirequest continues.
.. api::
Various functions in hgweb.webutil now take a modern request object instead of ``wsgirequest``.
| Automatic diff as part of commit; lint not applicable. |
| Automatic diff as part of commit; unit tests not applicable. |
| Path | Packages | |||
|---|---|---|---|---|
| M | hgext/highlight/__init__.py (2 lines) | |||
| M | mercurial/hgweb/webcommands.py (50 lines) | |||
| M | mercurial/hgweb/webutil.py (42 lines) |
| if 'html' in mt: | if 'html' in mt: | ||||
| pygmentize(web, 'fileline', fctx, web.tmpl) | pygmentize(web, 'fileline', fctx, web.tmpl) | ||||
| return orig(web, req, fctx) | return orig(web, req, fctx) | ||||
| def annotate_highlight(orig, web, req, tmpl): | def annotate_highlight(orig, web, req, tmpl): | ||||
| mt = ''.join(web.tmpl('mimetype', encoding=encoding.encoding)) | mt = ''.join(web.tmpl('mimetype', encoding=encoding.encoding)) | ||||
| if 'html' in mt: | if 'html' in mt: | ||||
| fctx = webutil.filectx(web.repo, req) | fctx = webutil.filectx(web.repo, web.req) | ||||
| pygmentize(web, 'annotateline', fctx, web.tmpl) | pygmentize(web, 'annotateline', fctx, web.tmpl) | ||||
| return orig(web, req, web.tmpl) | return orig(web, req, web.tmpl) | ||||
| def generate_css(web, req, tmpl): | def generate_css(web, req, tmpl): | ||||
| pg_style = web.config('web', 'pygments_style', 'colorful') | pg_style = web.config('web', 'pygments_style', 'colorful') | ||||
| fmter = highlight.HtmlFormatter(style=pg_style) | fmter = highlight.HtmlFormatter(style=pg_style) | ||||
| web.res.headers['Content-Type'] = 'text/css' | web.res.headers['Content-Type'] = 'text/css' | ||||
| def rawfile(web, req, tmpl): | def rawfile(web, req, tmpl): | ||||
| guessmime = web.configbool('web', 'guessmime') | guessmime = web.configbool('web', 'guessmime') | ||||
| path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | ||||
| if not path: | if not path: | ||||
| return manifest(web, req, None) | return manifest(web, req, None) | ||||
| try: | try: | ||||
| fctx = webutil.filectx(web.repo, req) | fctx = webutil.filectx(web.repo, web.req) | ||||
| except error.LookupError as inst: | except error.LookupError as inst: | ||||
| try: | try: | ||||
| return manifest(web, req, None) | return manifest(web, req, None) | ||||
| except ErrorResponse: | except ErrorResponse: | ||||
| raise inst | raise inst | ||||
| path = fctx.path() | path = fctx.path() | ||||
| text = fctx.data() | text = fctx.data() | ||||
| "linenumber": "% 6d" % (lineno + 1), | "linenumber": "% 6d" % (lineno + 1), | ||||
| "parity": next(parity)} | "parity": next(parity)} | ||||
| return web.sendtemplate( | return web.sendtemplate( | ||||
| 'filerevision', | 'filerevision', | ||||
| file=f, | file=f, | ||||
| path=webutil.up(f), | path=webutil.up(f), | ||||
| text=lines(), | text=lines(), | ||||
| symrev=webutil.symrevorshortnode(req, fctx), | symrev=webutil.symrevorshortnode(web.req, fctx), | ||||
| rename=webutil.renamelink(fctx), | rename=webutil.renamelink(fctx), | ||||
| permissions=fctx.manifest().flags(f), | permissions=fctx.manifest().flags(f), | ||||
| ishead=int(ishead), | ishead=int(ishead), | ||||
| **pycompat.strkwargs(webutil.commonentry(web.repo, fctx))) | **pycompat.strkwargs(webutil.commonentry(web.repo, fctx))) | ||||
| @webcommand('file') | @webcommand('file') | ||||
| def file(web, req, tmpl): | def file(web, req, tmpl): | ||||
| """ | """ | ||||
| """ | """ | ||||
| if web.req.qsparams.get('style') == 'raw': | if web.req.qsparams.get('style') == 'raw': | ||||
| return rawfile(web, req, None) | return rawfile(web, req, None) | ||||
| path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | ||||
| if not path: | if not path: | ||||
| return manifest(web, req, None) | return manifest(web, req, None) | ||||
| try: | try: | ||||
| return _filerevision(web, req, webutil.filectx(web.repo, req)) | return _filerevision(web, req, webutil.filectx(web.repo, web.req)) | ||||
| except error.LookupError as inst: | except error.LookupError as inst: | ||||
| try: | try: | ||||
| return manifest(web, req, None) | return manifest(web, req, None) | ||||
| except ErrorResponse: | except ErrorResponse: | ||||
| raise inst | raise inst | ||||
| def _search(web): | def _search(web): | ||||
| MODE_REVISION = 'rev' | MODE_REVISION = 'rev' | ||||
| The ``revcount`` query string argument defines the maximum numbers of | The ``revcount`` query string argument defines the maximum numbers of | ||||
| changesets to render. | changesets to render. | ||||
| For non-searches, the ``changelog`` template will be rendered. | For non-searches, the ``changelog`` template will be rendered. | ||||
| """ | """ | ||||
| query = '' | query = '' | ||||
| if 'node' in web.req.qsparams: | if 'node' in web.req.qsparams: | ||||
| ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
| symrev = webutil.symrevorshortnode(req, ctx) | symrev = webutil.symrevorshortnode(web.req, ctx) | ||||
| elif 'rev' in web.req.qsparams: | elif 'rev' in web.req.qsparams: | ||||
| return _search(web) | return _search(web) | ||||
| else: | else: | ||||
| ctx = web.repo['tip'] | ctx = web.repo['tip'] | ||||
| symrev = 'tip' | symrev = 'tip' | ||||
| def changelist(): | def changelist(): | ||||
| revs = [] | revs = [] | ||||
| A URL path argument is the changeset identifier to show. See ``hg help | A URL path argument is the changeset identifier to show. See ``hg help | ||||
| revisions`` for possible values. If not defined, the ``tip`` changeset | revisions`` for possible values. If not defined, the ``tip`` changeset | ||||
| will be shown. | will be shown. | ||||
| The ``changeset`` template is rendered. Contents of the ``changesettag``, | The ``changeset`` template is rendered. Contents of the ``changesettag``, | ||||
| ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many | ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many | ||||
| templates related to diffs may all be used to produce the output. | templates related to diffs may all be used to produce the output. | ||||
| """ | """ | ||||
| ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
| return web.sendtemplate( | return web.sendtemplate( | ||||
| 'changeset', | 'changeset', | ||||
| **webutil.changesetentry(web, req, ctx)) | **webutil.changesetentry(web, ctx)) | ||||
| rev = webcommand('rev')(changeset) | rev = webcommand('rev')(changeset) | ||||
| def decodepath(path): | def decodepath(path): | ||||
| """Hook for mapping a path in the repository to a path in the | """Hook for mapping a path in the repository to a path in the | ||||
| working copy. | working copy. | ||||
| Extensions (e.g., largefiles) can override this to remap files in | Extensions (e.g., largefiles) can override this to remap files in | ||||
| Because this handler can only show information for directories, it | Because this handler can only show information for directories, it | ||||
| is recommended to use the ``file`` handler instead, as it can handle both | is recommended to use the ``file`` handler instead, as it can handle both | ||||
| directories and files. | directories and files. | ||||
| The ``manifest`` template will be rendered for this handler. | The ``manifest`` template will be rendered for this handler. | ||||
| """ | """ | ||||
| if 'node' in web.req.qsparams: | if 'node' in web.req.qsparams: | ||||
| ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
| symrev = webutil.symrevorshortnode(req, ctx) | symrev = webutil.symrevorshortnode(web.req, ctx) | ||||
| else: | else: | ||||
| ctx = web.repo['tip'] | ctx = web.repo['tip'] | ||||
| symrev = 'tip' | symrev = 'tip' | ||||
| path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | ||||
| mf = ctx.manifest() | mf = ctx.manifest() | ||||
| node = ctx.node() | node = ctx.node() | ||||
| files = {} | files = {} | ||||
| The ``filediff`` template is rendered. | The ``filediff`` template is rendered. | ||||
| This handler is registered under both the ``/diff`` and ``/filediff`` | This handler is registered under both the ``/diff`` and ``/filediff`` | ||||
| paths. ``/diff`` is used in modern code. | paths. ``/diff`` is used in modern code. | ||||
| """ | """ | ||||
| fctx, ctx = None, None | fctx, ctx = None, None | ||||
| try: | try: | ||||
| fctx = webutil.filectx(web.repo, req) | fctx = webutil.filectx(web.repo, web.req) | ||||
| except LookupError: | except LookupError: | ||||
| ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
| path = webutil.cleanpath(web.repo, web.req.qsparams['file']) | path = webutil.cleanpath(web.repo, web.req.qsparams['file']) | ||||
| if path not in ctx.files(): | if path not in ctx.files(): | ||||
| raise | raise | ||||
| if fctx is not None: | if fctx is not None: | ||||
| path = fctx.path() | path = fctx.path() | ||||
| ctx = fctx.changectx() | ctx = fctx.changectx() | ||||
| basectx = ctx.p1() | basectx = ctx.p1() | ||||
| style = web.config('web', 'style') | style = web.config('web', 'style') | ||||
| if 'style' in web.req.qsparams: | if 'style' in web.req.qsparams: | ||||
| style = web.req.qsparams['style'] | style = web.req.qsparams['style'] | ||||
| diffs = webutil.diffs(web, ctx, basectx, [path], style) | diffs = webutil.diffs(web, ctx, basectx, [path], style) | ||||
| if fctx is not None: | if fctx is not None: | ||||
| rename = webutil.renamelink(fctx) | rename = webutil.renamelink(fctx) | ||||
| ctx = fctx | ctx = fctx | ||||
| else: | else: | ||||
| rename = [] | rename = [] | ||||
| ctx = ctx | ctx = ctx | ||||
| return web.sendtemplate( | return web.sendtemplate( | ||||
| 'filediff', | 'filediff', | ||||
| file=path, | file=path, | ||||
| symrev=webutil.symrevorshortnode(req, ctx), | symrev=webutil.symrevorshortnode(web.req, ctx), | ||||
| rename=rename, | rename=rename, | ||||
| diff=diffs, | diff=diffs, | ||||
| **pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) | **pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) | ||||
| diff = webcommand('diff')(filediff) | diff = webcommand('diff')(filediff) | ||||
| @webcommand('comparison') | @webcommand('comparison') | ||||
| def comparison(web, req, tmpl): | def comparison(web, req, tmpl): | ||||
| """ | """ | ||||
| /comparison/{revision}/{path} | /comparison/{revision}/{path} | ||||
| ----------------------------- | ----------------------------- | ||||
| Show a comparison between the old and new versions of a file from changes | Show a comparison between the old and new versions of a file from changes | ||||
| made on a particular revision. | made on a particular revision. | ||||
| This is similar to the ``diff`` handler. However, this form features | This is similar to the ``diff`` handler. However, this form features | ||||
| a split or side-by-side diff rather than a unified diff. | a split or side-by-side diff rather than a unified diff. | ||||
| The ``context`` query string argument can be used to control the lines of | The ``context`` query string argument can be used to control the lines of | ||||
| context in the diff. | context in the diff. | ||||
| The ``filecomparison`` template is rendered. | The ``filecomparison`` template is rendered. | ||||
| """ | """ | ||||
| ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
| if 'file' not in web.req.qsparams: | if 'file' not in web.req.qsparams: | ||||
| raise ErrorResponse(HTTP_NOT_FOUND, 'file not given') | raise ErrorResponse(HTTP_NOT_FOUND, 'file not given') | ||||
| path = webutil.cleanpath(web.repo, web.req.qsparams['file']) | path = webutil.cleanpath(web.repo, web.req.qsparams['file']) | ||||
| parsecontext = lambda v: v == 'full' and -1 or int(v) | parsecontext = lambda v: v == 'full' and -1 or int(v) | ||||
| if 'context' in web.req.qsparams: | if 'context' in web.req.qsparams: | ||||
| context = parsecontext(web.req.qsparams['context']) | context = parsecontext(web.req.qsparams['context']) | ||||
| else: | else: | ||||
| ctx = fctx | ctx = fctx | ||||
| else: | else: | ||||
| rename = [] | rename = [] | ||||
| ctx = ctx | ctx = ctx | ||||
| return web.sendtemplate( | return web.sendtemplate( | ||||
| 'filecomparison', | 'filecomparison', | ||||
| file=path, | file=path, | ||||
| symrev=webutil.symrevorshortnode(req, ctx), | symrev=webutil.symrevorshortnode(web.req, ctx), | ||||
| rename=rename, | rename=rename, | ||||
| leftrev=leftrev, | leftrev=leftrev, | ||||
| leftnode=hex(leftnode), | leftnode=hex(leftnode), | ||||
| rightrev=rightrev, | rightrev=rightrev, | ||||
| rightnode=hex(rightnode), | rightnode=hex(rightnode), | ||||
| comparison=comparison, | comparison=comparison, | ||||
| **pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) | **pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) | ||||
| ``ignoreblanklines`` query string arguments have the same meaning as | ``ignoreblanklines`` query string arguments have the same meaning as | ||||
| their ``[annotate]`` config equivalents. It uses the hgrc boolean | their ``[annotate]`` config equivalents. It uses the hgrc boolean | ||||
| parsing logic to interpret the value. e.g. ``0`` and ``false`` are | parsing logic to interpret the value. e.g. ``0`` and ``false`` are | ||||
| false and ``1`` and ``true`` are true. If not defined, the server | false and ``1`` and ``true`` are true. If not defined, the server | ||||
| default settings are used. | default settings are used. | ||||
| The ``fileannotate`` template is rendered. | The ``fileannotate`` template is rendered. | ||||
| """ | """ | ||||
| fctx = webutil.filectx(web.repo, req) | fctx = webutil.filectx(web.repo, web.req) | ||||
| f = fctx.path() | f = fctx.path() | ||||
| parity = paritygen(web.stripecount) | parity = paritygen(web.stripecount) | ||||
| ishead = fctx.filerev() in fctx.filelog().headrevs() | ishead = fctx.filerev() in fctx.filelog().headrevs() | ||||
| # parents() is called once per line and several lines likely belong to | # parents() is called once per line and several lines likely belong to | ||||
| # same revision. So it is worth caching. | # same revision. So it is worth caching. | ||||
| # TODO there are still redundant operations within basefilectx.parents() | # TODO there are still redundant operations within basefilectx.parents() | ||||
| # and from the fctx.annotate() call itself that could be cached. | # and from the fctx.annotate() call itself that could be cached. | ||||
| yield p | yield p | ||||
| def annotate(**map): | def annotate(**map): | ||||
| if fctx.isbinary(): | if fctx.isbinary(): | ||||
| mt = (mimetypes.guess_type(fctx.path())[0] | mt = (mimetypes.guess_type(fctx.path())[0] | ||||
| or 'application/octet-stream') | or 'application/octet-stream') | ||||
| lines = [((fctx.filectx(fctx.filerev()), 1), '(binary:%s)' % mt)] | lines = [((fctx.filectx(fctx.filerev()), 1), '(binary:%s)' % mt)] | ||||
| else: | else: | ||||
| lines = webutil.annotate(req, fctx, web.repo.ui) | lines = webutil.annotate(web.req, fctx, web.repo.ui) | ||||
| previousrev = None | previousrev = None | ||||
| blockparitygen = paritygen(1) | blockparitygen = paritygen(1) | ||||
| for lineno, (aline, l) in enumerate(lines): | for lineno, (aline, l) in enumerate(lines): | ||||
| f = aline.fctx | f = aline.fctx | ||||
| rev = f.rev() | rev = f.rev() | ||||
| if rev != previousrev: | if rev != previousrev: | ||||
| blockhead = True | blockhead = True | ||||
| "blockparity": blockparity, | "blockparity": blockparity, | ||||
| "targetline": aline.lineno, | "targetline": aline.lineno, | ||||
| "line": l, | "line": l, | ||||
| "lineno": lineno + 1, | "lineno": lineno + 1, | ||||
| "lineid": "l%d" % (lineno + 1), | "lineid": "l%d" % (lineno + 1), | ||||
| "linenumber": "% 6d" % (lineno + 1), | "linenumber": "% 6d" % (lineno + 1), | ||||
| "revdate": f.date()} | "revdate": f.date()} | ||||
| diffopts = webutil.difffeatureopts(req, web.repo.ui, 'annotate') | diffopts = webutil.difffeatureopts(web.req, web.repo.ui, 'annotate') | ||||
| diffopts = {k: getattr(diffopts, k) for k in diffopts.defaults} | diffopts = {k: getattr(diffopts, k) for k in diffopts.defaults} | ||||
| return web.sendtemplate( | return web.sendtemplate( | ||||
| 'fileannotate', | 'fileannotate', | ||||
| file=f, | file=f, | ||||
| annotate=annotate, | annotate=annotate, | ||||
| path=webutil.up(f), | path=webutil.up(f), | ||||
| symrev=webutil.symrevorshortnode(req, fctx), | symrev=webutil.symrevorshortnode(web.req, fctx), | ||||
| rename=webutil.renamelink(fctx), | rename=webutil.renamelink(fctx), | ||||
| permissions=fctx.manifest().flags(f), | permissions=fctx.manifest().flags(f), | ||||
| ishead=int(ishead), | ishead=int(ishead), | ||||
| diffopts=diffopts, | diffopts=diffopts, | ||||
| **pycompat.strkwargs(webutil.commonentry(web.repo, fctx))) | **pycompat.strkwargs(webutil.commonentry(web.repo, fctx))) | ||||
| @webcommand('filelog') | @webcommand('filelog') | ||||
| def filelog(web, req, tmpl): | def filelog(web, req, tmpl): | ||||
| """ | """ | ||||
| /filelog/{revision}/{path} | /filelog/{revision}/{path} | ||||
| -------------------------- | -------------------------- | ||||
| Show information about the history of a file in the repository. | Show information about the history of a file in the repository. | ||||
| The ``revcount`` query string argument can be defined to control the | The ``revcount`` query string argument can be defined to control the | ||||
| maximum number of entries to show. | maximum number of entries to show. | ||||
| The ``filelog`` template will be rendered. | The ``filelog`` template will be rendered. | ||||
| """ | """ | ||||
| try: | try: | ||||
| fctx = webutil.filectx(web.repo, req) | fctx = webutil.filectx(web.repo, web.req) | ||||
| f = fctx.path() | f = fctx.path() | ||||
| fl = fctx.filelog() | fl = fctx.filelog() | ||||
| except error.LookupError: | except error.LookupError: | ||||
| f = webutil.cleanpath(web.repo, web.req.qsparams['file']) | f = webutil.cleanpath(web.repo, web.req.qsparams['file']) | ||||
| fl = web.repo.file(f) | fl = web.repo.file(f) | ||||
| numrevs = len(fl) | numrevs = len(fl) | ||||
| if not numrevs: # file doesn't exist at all | if not numrevs: # file doesn't exist at all | ||||
| raise | raise | ||||
| rev = webutil.changectx(web.repo, req).rev() | rev = webutil.changectx(web.repo, web.req).rev() | ||||
| first = fl.linkrev(0) | first = fl.linkrev(0) | ||||
| if rev < first: # current rev is from before file existed | if rev < first: # current rev is from before file existed | ||||
| raise | raise | ||||
| frev = numrevs - 1 | frev = numrevs - 1 | ||||
| while fl.linkrev(frev) > rev: | while fl.linkrev(frev) > rev: | ||||
| frev -= 1 | frev -= 1 | ||||
| fctx = web.repo.filectx(f, fl.linkrev(frev)) | fctx = web.repo.filectx(f, fl.linkrev(frev)) | ||||
| revcount = web.maxshortchanges | revcount = web.maxshortchanges | ||||
| if 'revcount' in web.req.qsparams: | if 'revcount' in web.req.qsparams: | ||||
| try: | try: | ||||
| revcount = int(web.req.qsparams.get('revcount', revcount)) | revcount = int(web.req.qsparams.get('revcount', revcount)) | ||||
| revcount = max(revcount, 1) | revcount = max(revcount, 1) | ||||
| web.tmpl.defaults['sessionvars']['revcount'] = revcount | web.tmpl.defaults['sessionvars']['revcount'] = revcount | ||||
| except ValueError: | except ValueError: | ||||
| pass | pass | ||||
| lrange = webutil.linerange(req) | lrange = webutil.linerange(web.req) | ||||
| lessvars = copy.copy(web.tmpl.defaults['sessionvars']) | lessvars = copy.copy(web.tmpl.defaults['sessionvars']) | ||||
| lessvars['revcount'] = max(revcount // 2, 1) | lessvars['revcount'] = max(revcount // 2, 1) | ||||
| morevars = copy.copy(web.tmpl.defaults['sessionvars']) | morevars = copy.copy(web.tmpl.defaults['sessionvars']) | ||||
| morevars['revcount'] = revcount * 2 | morevars['revcount'] = revcount * 2 | ||||
| patch = 'patch' in web.req.qsparams | patch = 'patch' in web.req.qsparams | ||||
| if patch: | if patch: | ||||
| nav = revnav.gen(end - 1, revcount, count) | nav = revnav.gen(end - 1, revcount, count) | ||||
| latestentry = entries[:1] | latestentry = entries[:1] | ||||
| return web.sendtemplate( | return web.sendtemplate( | ||||
| 'filelog', | 'filelog', | ||||
| file=f, | file=f, | ||||
| nav=nav, | nav=nav, | ||||
| symrev=webutil.symrevorshortnode(req, fctx), | symrev=webutil.symrevorshortnode(web.req, fctx), | ||||
| entries=entries, | entries=entries, | ||||
| descend=descend, | descend=descend, | ||||
| patch=patch, | patch=patch, | ||||
| latestentry=latestentry, | latestentry=latestentry, | ||||
| linerange=linerange, | linerange=linerange, | ||||
| revcount=revcount, | revcount=revcount, | ||||
| morevars=morevars, | morevars=morevars, | ||||
| lessvars=lessvars, | lessvars=lessvars, | ||||
| reponame = re.sub(br"\W+", "-", os.path.basename(web.reponame)) | reponame = re.sub(br"\W+", "-", os.path.basename(web.reponame)) | ||||
| cnode = web.repo.lookup(key) | cnode = web.repo.lookup(key) | ||||
| arch_version = key | arch_version = key | ||||
| if cnode == key or key == 'tip': | if cnode == key or key == 'tip': | ||||
| arch_version = short(cnode) | arch_version = short(cnode) | ||||
| name = "%s-%s" % (reponame, arch_version) | name = "%s-%s" % (reponame, arch_version) | ||||
| ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
| pats = [] | pats = [] | ||||
| match = scmutil.match(ctx, []) | match = scmutil.match(ctx, []) | ||||
| file = web.req.qsparams.get('file') | file = web.req.qsparams.get('file') | ||||
| if file: | if file: | ||||
| pats = ['path:' + file] | pats = ['path:' + file] | ||||
| match = scmutil.match(ctx, pats, default='path') | match = scmutil.match(ctx, pats, default='path') | ||||
| if pats: | if pats: | ||||
| files = [f for f in ctx.manifest().keys() if match(f)] | files = [f for f in ctx.manifest().keys() if match(f)] | ||||
| The ``graphtop`` query string argument can specify the starting changeset | The ``graphtop`` query string argument can specify the starting changeset | ||||
| for producing ``jsdata`` variable that is used for rendering graph in | for producing ``jsdata`` variable that is used for rendering graph in | ||||
| JavaScript. By default it has the same value as ``revision``. | JavaScript. By default it has the same value as ``revision``. | ||||
| This handler will render the ``graph`` template. | This handler will render the ``graph`` template. | ||||
| """ | """ | ||||
| if 'node' in web.req.qsparams: | if 'node' in web.req.qsparams: | ||||
| ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
| symrev = webutil.symrevorshortnode(req, ctx) | symrev = webutil.symrevorshortnode(web.req, ctx) | ||||
| else: | else: | ||||
| ctx = web.repo['tip'] | ctx = web.repo['tip'] | ||||
| symrev = 'tip' | symrev = 'tip' | ||||
| rev = ctx.rev() | rev = ctx.rev() | ||||
| bg_height = 39 | bg_height = 39 | ||||
| revcount = web.maxshortchanges | revcount = web.maxshortchanges | ||||
| if 'revcount' in web.req.qsparams: | if 'revcount' in web.req.qsparams: | ||||
| def __len__(self): | def __len__(self): | ||||
| return len(self.siblings) | return len(self.siblings) | ||||
| def difffeatureopts(req, ui, section): | def difffeatureopts(req, ui, section): | ||||
| diffopts = patch.difffeatureopts(ui, untrusted=True, | diffopts = patch.difffeatureopts(ui, untrusted=True, | ||||
| section=section, whitespace=True) | section=section, whitespace=True) | ||||
| for k in ('ignorews', 'ignorewsamount', 'ignorewseol', 'ignoreblanklines'): | for k in ('ignorews', 'ignorewsamount', 'ignorewseol', 'ignoreblanklines'): | ||||
| v = req.req.qsparams.get(k) | v = req.qsparams.get(k) | ||||
| if v is not None: | if v is not None: | ||||
| v = util.parsebool(v) | v = util.parsebool(v) | ||||
| setattr(diffopts, k, v if v is not None else True) | setattr(diffopts, k, v if v is not None else True) | ||||
| return diffopts | return diffopts | ||||
| def annotate(req, fctx, ui): | def annotate(req, fctx, ui): | ||||
| diffopts = difffeatureopts(req, ui, 'annotate') | diffopts = difffeatureopts(req, ui, 'annotate') | ||||
| except error.RepoError: | except error.RepoError: | ||||
| man = repo.manifestlog._revlog | man = repo.manifestlog._revlog | ||||
| ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))] | ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))] | ||||
| return ctx | return ctx | ||||
| def changectx(repo, req): | def changectx(repo, req): | ||||
| changeid = "tip" | changeid = "tip" | ||||
| if 'node' in req.req.qsparams: | if 'node' in req.qsparams: | ||||
| changeid = req.req.qsparams['node'] | changeid = req.qsparams['node'] | ||||
| ipos = changeid.find(':') | ipos = changeid.find(':') | ||||
| if ipos != -1: | if ipos != -1: | ||||
| changeid = changeid[(ipos + 1):] | changeid = changeid[(ipos + 1):] | ||||
| elif 'manifest' in req.req.qsparams: | elif 'manifest' in req.qsparams: | ||||
| changeid = req.req.qsparams['manifest'] | changeid = req.qsparams['manifest'] | ||||
| return changeidctx(repo, changeid) | return changeidctx(repo, changeid) | ||||
| def basechangectx(repo, req): | def basechangectx(repo, req): | ||||
| if 'node' in req.req.qsparams: | if 'node' in req.qsparams: | ||||
| changeid = req.req.qsparams['node'] | changeid = req.qsparams['node'] | ||||
| ipos = changeid.find(':') | ipos = changeid.find(':') | ||||
| if ipos != -1: | if ipos != -1: | ||||
| changeid = changeid[:ipos] | changeid = changeid[:ipos] | ||||
| return changeidctx(repo, changeid) | return changeidctx(repo, changeid) | ||||
| return None | return None | ||||
| def filectx(repo, req): | def filectx(repo, req): | ||||
| if 'file' not in req.req.qsparams: | if 'file' not in req.qsparams: | ||||
| raise ErrorResponse(HTTP_NOT_FOUND, 'file not given') | raise ErrorResponse(HTTP_NOT_FOUND, 'file not given') | ||||
| path = cleanpath(repo, req.req.qsparams['file']) | path = cleanpath(repo, req.qsparams['file']) | ||||
| if 'node' in req.req.qsparams: | if 'node' in req.qsparams: | ||||
| changeid = req.req.qsparams['node'] | changeid = req.qsparams['node'] | ||||
| elif 'filenode' in req.req.qsparams: | elif 'filenode' in req.qsparams: | ||||
| changeid = req.req.qsparams['filenode'] | changeid = req.qsparams['filenode'] | ||||
| else: | else: | ||||
| raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given') | raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given') | ||||
| try: | try: | ||||
| fctx = repo[changeid][path] | fctx = repo[changeid][path] | ||||
| except error.RepoError: | except error.RepoError: | ||||
| fctx = repo.filectx(path, fileid=changeid) | fctx = repo.filectx(path, fileid=changeid) | ||||
| return fctx | return fctx | ||||
| def linerange(req): | def linerange(req): | ||||
| linerange = req.req.qsparams.getall('linerange') | linerange = req.qsparams.getall('linerange') | ||||
| if not linerange: | if not linerange: | ||||
| return None | return None | ||||
| if len(linerange) > 1: | if len(linerange) > 1: | ||||
| raise ErrorResponse(HTTP_BAD_REQUEST, | raise ErrorResponse(HTTP_BAD_REQUEST, | ||||
| 'redundant linerange parameter') | 'redundant linerange parameter') | ||||
| try: | try: | ||||
| fromline, toline = map(int, linerange[0].split(':', 1)) | fromline, toline = map(int, linerange[0].split(':', 1)) | ||||
| except ValueError: | except ValueError: | ||||
| parent=lambda **x: parents(ctx, rev - 1), | parent=lambda **x: parents(ctx, rev - 1), | ||||
| child=lambda **x: children(ctx, rev + 1), | child=lambda **x: children(ctx, rev + 1), | ||||
| changelogtag=showtags, | changelogtag=showtags, | ||||
| files=files, | files=files, | ||||
| ) | ) | ||||
| return entry | return entry | ||||
| def symrevorshortnode(req, ctx): | def symrevorshortnode(req, ctx): | ||||
| if 'node' in req.req.qsparams: | if 'node' in req.qsparams: | ||||
| return templatefilters.revescape(req.req.qsparams['node']) | return templatefilters.revescape(req.qsparams['node']) | ||||
| else: | else: | ||||
| return short(ctx.node()) | return short(ctx.node()) | ||||
| def changesetentry(web, req, ctx): | def changesetentry(web, ctx): | ||||
| '''Obtain a dictionary to be used to render the "changeset" template.''' | '''Obtain a dictionary to be used to render the "changeset" template.''' | ||||
| showtags = showtag(web.repo, web.tmpl, 'changesettag', ctx.node()) | showtags = showtag(web.repo, web.tmpl, 'changesettag', ctx.node()) | ||||
| showbookmarks = showbookmark(web.repo, web.tmpl, 'changesetbookmark', | showbookmarks = showbookmark(web.repo, web.tmpl, 'changesetbookmark', | ||||
| ctx.node()) | ctx.node()) | ||||
| showbranch = nodebranchnodefault(ctx) | showbranch = nodebranchnodefault(ctx) | ||||
| files = [] | files = [] | ||||
| parity = paritygen(web.stripecount) | parity = paritygen(web.stripecount) | ||||
| for blockno, f in enumerate(ctx.files()): | for blockno, f in enumerate(ctx.files()): | ||||
| template = 'filenodelink' if f in ctx else 'filenolink' | template = 'filenodelink' if f in ctx else 'filenolink' | ||||
| files.append(web.tmpl(template, | files.append(web.tmpl(template, | ||||
| node=ctx.hex(), file=f, blockno=blockno + 1, | node=ctx.hex(), file=f, blockno=blockno + 1, | ||||
| parity=next(parity))) | parity=next(parity))) | ||||
| basectx = basechangectx(web.repo, req) | basectx = basechangectx(web.repo, web.req) | ||||
| if basectx is None: | if basectx is None: | ||||
| basectx = ctx.p1() | basectx = ctx.p1() | ||||
| style = web.config('web', 'style') | style = web.config('web', 'style') | ||||
| if 'style' in req.req.qsparams: | if 'style' in web.req.qsparams: | ||||
| style = req.req.qsparams['style'] | style = web.req.qsparams['style'] | ||||
| diff = diffs(web, ctx, basectx, None, style) | diff = diffs(web, ctx, basectx, None, style) | ||||
| parity = paritygen(web.stripecount) | parity = paritygen(web.stripecount) | ||||
| diffstatsgen = diffstatgen(ctx, basectx) | diffstatsgen = diffstatgen(ctx, basectx) | ||||
| diffstats = diffstat(web.tmpl, ctx, diffstatsgen, parity) | diffstats = diffstat(web.tmpl, ctx, diffstatsgen, parity) | ||||
| return dict( | return dict( | ||||
| diff=diff, | diff=diff, | ||||
| symrev=symrevorshortnode(req, ctx), | symrev=symrevorshortnode(web.req, ctx), | ||||
| basenode=basectx.hex(), | basenode=basectx.hex(), | ||||
| changesettag=showtags, | changesettag=showtags, | ||||
| changesetbookmark=showbookmarks, | changesetbookmark=showbookmarks, | ||||
| changesetbranch=showbranch, | changesetbranch=showbranch, | ||||
| files=files, | files=files, | ||||
| diffsummary=lambda **x: diffsummary(diffstatsgen), | diffsummary=lambda **x: diffsummary(diffstatsgen), | ||||
| diffstat=diffstats, | diffstat=diffstats, | ||||
| archives=web.archivelist(ctx.hex()), | archives=web.archivelist(ctx.hex()), | ||||