Example #1
0
def _filerevision(web, req, tmpl, fctx):
    f = fctx.path()
    text = fctx.data()
    parity = paritygen(web.stripecount)

    if util.binary(text):
        mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
        text = '(binary:%s)' % mt

    def lines():
        for lineno, t in enumerate(text.splitlines(True)):
            yield {"line": t,
                   "lineid": "l%d" % (lineno + 1),
                   "linenumber": "% 6d" % (lineno + 1),
                   "parity": parity.next()}

    return tmpl("filerevision",
                file=f,
                path=webutil.up(f),
                text=lines(),
                rev=fctx.rev(),
                symrev=webutil.symrevorshortnode(req, fctx),
                node=fctx.hex(),
                author=fctx.user(),
                date=fctx.date(),
                desc=fctx.description(),
                extra=fctx.extra(),
                branch=webutil.nodebranchnodefault(fctx),
                parent=webutil.parents(fctx),
                child=webutil.children(fctx),
                rename=webutil.renamelink(fctx),
                tags=webutil.nodetagsdict(web.repo, fctx.node()),
                bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
                permissions=fctx.manifest().flags(f))
Example #2
0
def _filerevision(web, req, tmpl, fctx):
    f = fctx.path()
    text = fctx.data()
    parity = paritygen(web.stripecount)

    if util.binary(text):
        mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
        text = '(binary:%s)' % mt

    def lines():
        for lineno, t in enumerate(text.splitlines(True)):
            yield {"line": t,
                   "lineid": "l%d" % (lineno + 1),
                   "linenumber": "% 6d" % (lineno + 1),
                   "parity": parity.next()}

    return tmpl("filerevision",
                file=f,
                path=webutil.up(f),
                text=lines(),
                rev=fctx.rev(),
                symrev=webutil.symrevorshortnode(req, fctx),
                node=fctx.hex(),
                author=fctx.user(),
                date=fctx.date(),
                desc=fctx.description(),
                extra=fctx.extra(),
                branch=webutil.nodebranchnodefault(fctx),
                parent=webutil.parents(fctx),
                child=webutil.children(fctx),
                rename=webutil.renamelink(fctx),
                tags=webutil.nodetagsdict(web.repo, fctx.node()),
                bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
                permissions=fctx.manifest().flags(f))
Example #3
0
def filediff(web, req, tmpl):
    """
    /diff/{revision}/{path}
    -----------------------

    Show how a file changed in a particular commit.

    The ``filediff`` template is rendered.

    This hander is registered under both the ``/diff`` and ``/filediff``
    paths. ``/diff`` is used in modern code.
    """
    fctx, ctx = None, None
    try:
        fctx = webutil.filectx(web.repo, req)
    except LookupError:
        ctx = webutil.changectx(web.repo, req)
        path = webutil.cleanpath(web.repo, req.form['file'][0])
        if path not in ctx.files():
            raise

    if fctx is not None:
        n = fctx.node()
        path = fctx.path()
        ctx = fctx.changectx()
    else:
        n = ctx.node()
        # path already defined in except clause

    parity = paritygen(web.stripecount)
    style = web.config('web', 'style', 'paper')
    if 'style' in req.form:
        style = req.form['style'][0]

    diffs = webutil.diffs(web.repo, tmpl, ctx, None, [path], parity, style)
    if fctx:
        rename = webutil.renamelink(fctx)
        ctx = fctx
    else:
        rename = []
        ctx = ctx
    return tmpl("filediff",
                file=path,
                node=hex(n),
                rev=ctx.rev(),
                symrev=webutil.symrevorshortnode(req, ctx),
                date=ctx.date(),
                desc=ctx.description(),
                extra=ctx.extra(),
                author=ctx.user(),
                rename=rename,
                branch=webutil.nodebranchnodefault(ctx),
                parent=webutil.parents(ctx),
                child=webutil.children(ctx),
                tags=webutil.nodetagsdict(web.repo, n),
                bookmarks=webutil.nodebookmarksdict(web.repo, n),
                diff=diffs)
Example #4
0
def filediff(web, req, tmpl):
    """
    /diff/{revision}/{path}
    -----------------------

    Show how a file changed in a particular commit.

    The ``filediff`` template is rendered.

    This hander is registered under both the ``/diff`` and ``/filediff``
    paths. ``/diff`` is used in modern code.
    """
    fctx, ctx = None, None
    try:
        fctx = webutil.filectx(web.repo, req)
    except LookupError:
        ctx = webutil.changectx(web.repo, req)
        path = webutil.cleanpath(web.repo, req.form['file'][0])
        if path not in ctx.files():
            raise

    if fctx is not None:
        n = fctx.node()
        path = fctx.path()
        ctx = fctx.changectx()
    else:
        n = ctx.node()
        # path already defined in except clause

    parity = paritygen(web.stripecount)
    style = web.config('web', 'style', 'paper')
    if 'style' in req.form:
        style = req.form['style'][0]

    diffs = webutil.diffs(web.repo, tmpl, ctx, None, [path], parity, style)
    if fctx:
        rename = webutil.renamelink(fctx)
        ctx = fctx
    else:
        rename = []
        ctx = ctx
    return tmpl("filediff",
                file=path,
                node=hex(n),
                rev=ctx.rev(),
                symrev=webutil.symrevorshortnode(req, ctx),
                date=ctx.date(),
                desc=ctx.description(),
                extra=ctx.extra(),
                author=ctx.user(),
                rename=rename,
                branch=webutil.nodebranchnodefault(ctx),
                parent=webutil.parents(ctx),
                child=webutil.children(ctx),
                tags=webutil.nodetagsdict(web.repo, n),
                bookmarks=webutil.nodebookmarksdict(web.repo, n),
                diff=diffs)
Example #5
0
def filelog(web, req, tmpl):
    """
    /filelog/{revision}/{path}
    --------------------------

    Show information about the history of a file in the repository.

    The ``revcount`` query string argument can be defined to control the
    maximum number of entries to show.

    The ``filelog`` template will be rendered.
    """

    try:
        fctx = webutil.filectx(web.repo, req)
        f = fctx.path()
        fl = fctx.filelog()
    except error.LookupError:
        f = webutil.cleanpath(web.repo, req.form['file'][0])
        fl = web.repo.file(f)
        numrevs = len(fl)
        if not numrevs:  # file doesn't exist at all
            raise
        rev = webutil.changectx(web.repo, req).rev()
        first = fl.linkrev(0)
        if rev < first:  # current rev is from before file existed
            raise
        frev = numrevs - 1
        while fl.linkrev(frev) > rev:
            frev -= 1
        fctx = web.repo.filectx(f, fl.linkrev(frev))

    revcount = web.maxshortchanges
    if 'revcount' in req.form:
        try:
            revcount = int(req.form.get('revcount', [revcount])[0])
            revcount = max(revcount, 1)
            tmpl.defaults['sessionvars']['revcount'] = revcount
        except ValueError:
            pass

    lessvars = copy.copy(tmpl.defaults['sessionvars'])
    lessvars['revcount'] = max(revcount / 2, 1)
    morevars = copy.copy(tmpl.defaults['sessionvars'])
    morevars['revcount'] = revcount * 2

    count = fctx.filerev() + 1
    start = max(0, fctx.filerev() - revcount + 1)  # first rev on this page
    end = min(count, start + revcount)  # last rev on this page
    parity = paritygen(web.stripecount, offset=start - end)

    def entries():
        l = []

        repo = web.repo
        revs = fctx.filelog().revs(start, end - 1)
        for i in revs:
            iterfctx = fctx.filectx(i)

            l.append({
                "parity":
                parity.next(),
                "filerev":
                i,
                "file":
                f,
                "node":
                iterfctx.hex(),
                "author":
                iterfctx.user(),
                "date":
                iterfctx.date(),
                "rename":
                webutil.renamelink(iterfctx),
                "parent":
                webutil.parents(iterfctx),
                "child":
                webutil.children(iterfctx),
                "desc":
                iterfctx.description(),
                "extra":
                iterfctx.extra(),
                "tags":
                webutil.nodetagsdict(repo, iterfctx.node()),
                "bookmarks":
                webutil.nodebookmarksdict(repo, iterfctx.node()),
                "branch":
                webutil.nodebranchnodefault(iterfctx),
                "inbranch":
                webutil.nodeinbranch(repo, iterfctx),
                "branches":
                webutil.nodebranchdict(repo, iterfctx)
            })
        for e in reversed(l):
            yield e

    entries = list(entries())
    latestentry = entries[:1]

    revnav = webutil.filerevnav(web.repo, fctx.path())
    nav = revnav.gen(end - 1, revcount, count)
    return tmpl("filelog",
                file=f,
                node=fctx.hex(),
                nav=nav,
                symrev=webutil.symrevorshortnode(req, fctx),
                entries=entries,
                latestentry=latestentry,
                revcount=revcount,
                morevars=morevars,
                lessvars=lessvars)
Example #6
0
def annotate(web, req, tmpl):
    """
    /annotate/{revision}/{path}
    ---------------------------

    Show changeset information for each line in a file.

    The ``fileannotate`` template is rendered.
    """
    fctx = webutil.filectx(web.repo, req)
    f = fctx.path()
    parity = paritygen(web.stripecount)
    diffopts = patch.difffeatureopts(web.repo.ui,
                                     untrusted=True,
                                     section='annotate',
                                     whitespace=True)

    def annotate(**map):
        last = None
        if util.binary(fctx.data()):
            mt = (mimetypes.guess_type(fctx.path())[0]
                  or 'application/octet-stream')
            lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
                                '(binary:%s)' % mt)])
        else:
            lines = enumerate(
                fctx.annotate(follow=True, linenumber=True, diffopts=diffopts))
        for lineno, ((f, targetline), l) in lines:
            fnode = f.filenode()

            if last != fnode:
                last = fnode

            yield {
                "parity": parity.next(),
                "node": f.hex(),
                "rev": f.rev(),
                "author": f.user(),
                "desc": f.description(),
                "extra": f.extra(),
                "file": f.path(),
                "targetline": targetline,
                "line": l,
                "lineno": lineno + 1,
                "lineid": "l%d" % (lineno + 1),
                "linenumber": "% 6d" % (lineno + 1),
                "revdate": f.date()
            }

    return tmpl("fileannotate",
                file=f,
                annotate=annotate,
                path=webutil.up(f),
                rev=fctx.rev(),
                symrev=webutil.symrevorshortnode(req, fctx),
                node=fctx.hex(),
                author=fctx.user(),
                date=fctx.date(),
                desc=fctx.description(),
                extra=fctx.extra(),
                rename=webutil.renamelink(fctx),
                branch=webutil.nodebranchnodefault(fctx),
                parent=webutil.parents(fctx),
                child=webutil.children(fctx),
                tags=webutil.nodetagsdict(web.repo, fctx.node()),
                bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
                permissions=fctx.manifest().flags(f))
Example #7
0
def comparison(web, req, tmpl):
    """
    /comparison/{revision}/{path}
    -----------------------------

    Show a comparison between the old and new versions of a file from changes
    made on a particular revision.

    This is similar to the ``diff`` handler. However, this form features
    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
    context in the diff.

    The ``filecomparison`` template is rendered.
    """
    ctx = webutil.changectx(web.repo, req)
    if 'file' not in req.form:
        raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
    path = webutil.cleanpath(web.repo, req.form['file'][0])
    rename = path in ctx and webutil.renamelink(ctx[path]) or []

    parsecontext = lambda v: v == 'full' and -1 or int(v)
    if 'context' in req.form:
        context = parsecontext(req.form['context'][0])
    else:
        context = parsecontext(web.config('web', 'comparisoncontext', '5'))

    def filelines(f):
        if util.binary(f.data()):
            mt = mimetypes.guess_type(f.path())[0]
            if not mt:
                mt = 'application/octet-stream'
            return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
        return f.data().splitlines()

    parent = ctx.p1()
    leftrev = parent.rev()
    leftnode = parent.node()
    rightrev = ctx.rev()
    rightnode = ctx.node()
    if path in ctx:
        fctx = ctx[path]
        rightlines = filelines(fctx)
        if path not in parent:
            leftlines = ()
        else:
            pfctx = parent[path]
            leftlines = filelines(pfctx)
    else:
        rightlines = ()
        fctx = ctx.parents()[0][path]
        leftlines = filelines(fctx)

    comparison = webutil.compare(tmpl, context, leftlines, rightlines)
    return tmpl('filecomparison',
                file=path,
                node=hex(ctx.node()),
                rev=ctx.rev(),
                symrev=webutil.symrevorshortnode(req, ctx),
                date=ctx.date(),
                desc=ctx.description(),
                extra=ctx.extra(),
                author=ctx.user(),
                rename=rename,
                branch=webutil.nodebranchnodefault(ctx),
                parent=webutil.parents(fctx),
                child=webutil.children(fctx),
                tags=webutil.nodetagsdict(web.repo, ctx.node()),
                bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
                leftrev=leftrev,
                leftnode=hex(leftnode),
                rightrev=rightrev,
                rightnode=hex(rightnode),
                comparison=comparison)
Example #8
0
def manifest(web, req, tmpl):
    """
    /manifest[/{revision}[/{path}]]
    -------------------------------

    Show information about a directory.

    If the URL path arguments are omitted, information about the root
    directory for the ``tip`` changeset will be shown.

    Because this handler can only show information for directories, it
    is recommended to use the ``file`` handler instead, as it can handle both
    directories and files.

    The ``manifest`` template will be rendered for this handler.
    """
    if 'node' in req.form:
        ctx = webutil.changectx(web.repo, req)
        symrev = webutil.symrevorshortnode(req, ctx)
    else:
        ctx = web.repo['tip']
        symrev = 'tip'
    path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
    mf = ctx.manifest()
    node = ctx.node()

    files = {}
    dirs = {}
    parity = paritygen(web.stripecount)

    if path and path[-1] != "/":
        path += "/"
    l = len(path)
    abspath = "/" + path

    for full, n in mf.iteritems():
        # the virtual path (working copy path) used for the full
        # (repository) path
        f = decodepath(full)

        if f[:l] != path:
            continue
        remain = f[l:]
        elements = remain.split('/')
        if len(elements) == 1:
            files[remain] = full
        else:
            h = dirs  # need to retain ref to dirs (root)
            for elem in elements[0:-1]:
                if elem not in h:
                    h[elem] = {}
                h = h[elem]
                if len(h) > 1:
                    break
            h[None] = None  # denotes files present

    if mf and not files and not dirs:
        raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)

    def filelist(**map):
        for f in sorted(files):
            full = files[f]

            fctx = ctx.filectx(full)
            yield {
                "file": full,
                "parity": parity.next(),
                "basename": f,
                "date": fctx.date(),
                "size": fctx.size(),
                "permissions": mf.flags(full)
            }

    def dirlist(**map):
        for d in sorted(dirs):

            emptydirs = []
            h = dirs[d]
            while isinstance(h, dict) and len(h) == 1:
                k, v = h.items()[0]
                if v:
                    emptydirs.append(k)
                h = v

            path = "%s%s" % (abspath, d)
            yield {
                "parity": parity.next(),
                "path": path,
                "emptydirs": "/".join(emptydirs),
                "basename": d
            }

    return tmpl("manifest",
                rev=ctx.rev(),
                symrev=symrev,
                node=hex(node),
                path=abspath,
                up=webutil.up(abspath),
                upparity=parity.next(),
                fentries=filelist,
                dentries=dirlist,
                archives=web.archivelist(hex(node)),
                tags=webutil.nodetagsdict(web.repo, node),
                bookmarks=webutil.nodebookmarksdict(web.repo, node),
                branch=webutil.nodebranchnodefault(ctx),
                inbranch=webutil.nodeinbranch(web.repo, ctx),
                branches=webutil.nodebranchdict(web.repo, ctx))
Example #9
0
def changelog(web, req, tmpl, shortlog=False):
    """
    /changelog[/{revision}]
    -----------------------

    Show information about multiple changesets.

    If the optional ``revision`` URL argument is absent, information about
    all changesets starting at ``tip`` will be rendered. If the ``revision``
    argument is present, changesets will be shown starting from the specified
    revision.

    If ``revision`` is absent, the ``rev`` query string argument may be
    defined. This will perform a search for changesets.

    The argument for ``rev`` can be a single revision, a revision set,
    or a literal keyword to search for in changeset data (equivalent to
    :hg:`log -k`).

    The ``revcount`` query string argument defines the maximum numbers of
    changesets to render.

    For non-searches, the ``changelog`` template will be rendered.
    """

    query = ''
    if 'node' in req.form:
        ctx = webutil.changectx(web.repo, req)
        symrev = webutil.symrevorshortnode(req, ctx)
    elif 'rev' in req.form:
        return _search(web, req, tmpl)
    else:
        ctx = web.repo['tip']
        symrev = 'tip'

    def changelist():
        revs = []
        if pos != -1:
            revs = web.repo.changelog.revs(pos, 0)
        curcount = 0
        for rev in revs:
            curcount += 1
            if curcount > revcount + 1:
                break

            entry = webutil.changelistentry(web, web.repo[rev], tmpl)
            entry['parity'] = parity.next()
            yield entry

    if shortlog:
        revcount = web.maxshortchanges
    else:
        revcount = web.maxchanges

    if 'revcount' in req.form:
        try:
            revcount = int(req.form.get('revcount', [revcount])[0])
            revcount = max(revcount, 1)
            tmpl.defaults['sessionvars']['revcount'] = revcount
        except ValueError:
            pass

    lessvars = copy.copy(tmpl.defaults['sessionvars'])
    lessvars['revcount'] = max(revcount / 2, 1)
    morevars = copy.copy(tmpl.defaults['sessionvars'])
    morevars['revcount'] = revcount * 2

    count = len(web.repo)
    pos = ctx.rev()
    parity = paritygen(web.stripecount)

    changenav = webutil.revnav(web.repo).gen(pos, revcount, count)

    entries = list(changelist())
    latestentry = entries[:1]
    if len(entries) > revcount:
        nextentry = entries[-1:]
        entries = entries[:-1]
    else:
        nextentry = []

    return tmpl(shortlog and 'shortlog' or 'changelog',
                changenav=changenav,
                node=ctx.hex(),
                rev=pos,
                symrev=symrev,
                changesets=count,
                entries=entries,
                latestentry=latestentry,
                nextentry=nextentry,
                archives=web.archivelist("tip"),
                revcount=revcount,
                morevars=morevars,
                lessvars=lessvars,
                query=query)
Example #10
0
def graph(web, req, tmpl):
    """
    /graph[/{revision}]
    -------------------

    Show information about the graphical topology of the repository.

    Information rendered by this handler can be used to create visual
    representations of repository topology.

    The ``revision`` URL parameter controls the starting changeset.

    The ``revcount`` query string argument can define the number of changesets
    to show information for.

    This handler will render the ``graph`` template.
    """

    if 'node' in req.form:
        ctx = webutil.changectx(web.repo, req)
        symrev = webutil.symrevorshortnode(req, ctx)
    else:
        ctx = web.repo['tip']
        symrev = 'tip'
    rev = ctx.rev()

    bg_height = 39
    revcount = web.maxshortchanges
    if 'revcount' in req.form:
        try:
            revcount = int(req.form.get('revcount', [revcount])[0])
            revcount = max(revcount, 1)
            tmpl.defaults['sessionvars']['revcount'] = revcount
        except ValueError:
            pass

    lessvars = copy.copy(tmpl.defaults['sessionvars'])
    lessvars['revcount'] = max(revcount / 2, 1)
    morevars = copy.copy(tmpl.defaults['sessionvars'])
    morevars['revcount'] = revcount * 2

    count = len(web.repo)
    pos = rev

    uprev = min(max(0, count - 1), rev + revcount)
    downrev = max(0, rev - revcount)
    changenav = webutil.revnav(web.repo).gen(pos, revcount, count)

    tree = []
    if pos != -1:
        allrevs = web.repo.changelog.revs(pos, 0)
        revs = []
        for i in allrevs:
            revs.append(i)
            if len(revs) >= revcount:
                break

        # We have to feed a baseset to dagwalker as it is expecting smartset
        # object. This does not have a big impact on hgweb performance itself
        # since hgweb graphing code is not itself lazy yet.
        dag = graphmod.dagwalker(web.repo, revset.baseset(revs))
        # As we said one line above... not lazy.
        tree = list(graphmod.colored(dag, web.repo))

    def getcolumns(tree):
        cols = 0
        for (id, type, ctx, vtx, edges) in tree:
            if type != graphmod.CHANGESET:
                continue
            cols = max(cols, max([edge[0] for edge in edges] or [0]),
                       max([edge[1] for edge in edges] or [0]))
        return cols

    def graphdata(usetuples, **map):
        data = []

        row = 0
        for (id, type, ctx, vtx, edges) in tree:
            if type != graphmod.CHANGESET:
                continue
            node = str(ctx)
            age = templatefilters.age(ctx.date())
            desc = templatefilters.firstline(ctx.description())
            desc = cgi.escape(templatefilters.nonempty(desc))
            user = cgi.escape(templatefilters.person(ctx.user()))
            branch = cgi.escape(ctx.branch())
            try:
                branchnode = web.repo.branchtip(branch)
            except error.RepoLookupError:
                branchnode = None
            branch = branch, branchnode == ctx.node()

            if usetuples:
                data.append((node, vtx, edges, desc, user, age, branch,
                             [cgi.escape(x) for x in ctx.tags()
                              ], [cgi.escape(x) for x in ctx.bookmarks()]))
            else:
                edgedata = [{
                    'col': edge[0],
                    'nextcol': edge[1],
                    'color': (edge[2] - 1) % 6 + 1,
                    'width': edge[3],
                    'bcolor': edge[4]
                } for edge in edges]

                data.append({
                    'node':
                    node,
                    'col':
                    vtx[0],
                    'color': (vtx[1] - 1) % 6 + 1,
                    'edges':
                    edgedata,
                    'row':
                    row,
                    'nextrow':
                    row + 1,
                    'desc':
                    desc,
                    'user':
                    user,
                    'age':
                    age,
                    'bookmarks':
                    webutil.nodebookmarksdict(web.repo, ctx.node()),
                    'branches':
                    webutil.nodebranchdict(web.repo, ctx),
                    'inbranch':
                    webutil.nodeinbranch(web.repo, ctx),
                    'tags':
                    webutil.nodetagsdict(web.repo, ctx.node())
                })

            row += 1

        return data

    cols = getcolumns(tree)
    rows = len(tree)
    canvasheight = (rows + 1) * bg_height - 27

    return tmpl('graph',
                rev=rev,
                symrev=symrev,
                revcount=revcount,
                uprev=uprev,
                lessvars=lessvars,
                morevars=morevars,
                downrev=downrev,
                cols=cols,
                rows=rows,
                canvaswidth=(cols + 1) * bg_height,
                truecanvasheight=rows * bg_height,
                canvasheight=canvasheight,
                bg_height=bg_height,
                jsdata=lambda **x: graphdata(True, **x),
                nodes=lambda **x: graphdata(False, **x),
                node=ctx.hex(),
                changenav=changenav)
Example #11
0
def filelog(web, req, tmpl):
    """
    /filelog/{revision}/{path}
    --------------------------

    Show information about the history of a file in the repository.

    The ``revcount`` query string argument can be defined to control the
    maximum number of entries to show.

    The ``filelog`` template will be rendered.
    """

    try:
        fctx = webutil.filectx(web.repo, req)
        f = fctx.path()
        fl = fctx.filelog()
    except error.LookupError:
        f = webutil.cleanpath(web.repo, req.form['file'][0])
        fl = web.repo.file(f)
        numrevs = len(fl)
        if not numrevs: # file doesn't exist at all
            raise
        rev = webutil.changectx(web.repo, req).rev()
        first = fl.linkrev(0)
        if rev < first: # current rev is from before file existed
            raise
        frev = numrevs - 1
        while fl.linkrev(frev) > rev:
            frev -= 1
        fctx = web.repo.filectx(f, fl.linkrev(frev))

    revcount = web.maxshortchanges
    if 'revcount' in req.form:
        try:
            revcount = int(req.form.get('revcount', [revcount])[0])
            revcount = max(revcount, 1)
            tmpl.defaults['sessionvars']['revcount'] = revcount
        except ValueError:
            pass

    lessvars = copy.copy(tmpl.defaults['sessionvars'])
    lessvars['revcount'] = max(revcount / 2, 1)
    morevars = copy.copy(tmpl.defaults['sessionvars'])
    morevars['revcount'] = revcount * 2

    count = fctx.filerev() + 1
    start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
    end = min(count, start + revcount) # last rev on this page
    parity = paritygen(web.stripecount, offset=start - end)

    def entries():
        l = []

        repo = web.repo
        revs = fctx.filelog().revs(start, end - 1)
        for i in revs:
            iterfctx = fctx.filectx(i)

            l.append({"parity": parity.next(),
                      "filerev": i,
                      "file": f,
                      "node": iterfctx.hex(),
                      "author": iterfctx.user(),
                      "date": iterfctx.date(),
                      "rename": webutil.renamelink(iterfctx),
                      "parent": webutil.parents(iterfctx),
                      "child": webutil.children(iterfctx),
                      "desc": iterfctx.description(),
                      "extra": iterfctx.extra(),
                      "tags": webutil.nodetagsdict(repo, iterfctx.node()),
                      "bookmarks": webutil.nodebookmarksdict(
                          repo, iterfctx.node()),
                      "branch": webutil.nodebranchnodefault(iterfctx),
                      "inbranch": webutil.nodeinbranch(repo, iterfctx),
                      "branches": webutil.nodebranchdict(repo, iterfctx)})
        for e in reversed(l):
            yield e

    entries = list(entries())
    latestentry = entries[:1]

    revnav = webutil.filerevnav(web.repo, fctx.path())
    nav = revnav.gen(end - 1, revcount, count)
    return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
                symrev=webutil.symrevorshortnode(req, fctx),
                entries=entries,
                latestentry=latestentry,
                revcount=revcount, morevars=morevars, lessvars=lessvars)
Example #12
0
def annotate(web, req, tmpl):
    """
    /annotate/{revision}/{path}
    ---------------------------

    Show changeset information for each line in a file.

    The ``fileannotate`` template is rendered.
    """
    fctx = webutil.filectx(web.repo, req)
    f = fctx.path()
    parity = paritygen(web.stripecount)
    diffopts = patch.difffeatureopts(web.repo.ui, untrusted=True,
                                     section='annotate', whitespace=True)

    def annotate(**map):
        last = None
        if util.binary(fctx.data()):
            mt = (mimetypes.guess_type(fctx.path())[0]
                  or 'application/octet-stream')
            lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
                                '(binary:%s)' % mt)])
        else:
            lines = enumerate(fctx.annotate(follow=True, linenumber=True,
                                            diffopts=diffopts))
        for lineno, ((f, targetline), l) in lines:
            fnode = f.filenode()

            if last != fnode:
                last = fnode

            yield {"parity": parity.next(),
                   "node": f.hex(),
                   "rev": f.rev(),
                   "author": f.user(),
                   "desc": f.description(),
                   "extra": f.extra(),
                   "file": f.path(),
                   "targetline": targetline,
                   "line": l,
                   "lineno": lineno + 1,
                   "lineid": "l%d" % (lineno + 1),
                   "linenumber": "% 6d" % (lineno + 1),
                   "revdate": f.date()}

    return tmpl("fileannotate",
                file=f,
                annotate=annotate,
                path=webutil.up(f),
                rev=fctx.rev(),
                symrev=webutil.symrevorshortnode(req, fctx),
                node=fctx.hex(),
                author=fctx.user(),
                date=fctx.date(),
                desc=fctx.description(),
                extra=fctx.extra(),
                rename=webutil.renamelink(fctx),
                branch=webutil.nodebranchnodefault(fctx),
                parent=webutil.parents(fctx),
                child=webutil.children(fctx),
                tags=webutil.nodetagsdict(web.repo, fctx.node()),
                bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
                permissions=fctx.manifest().flags(f))
Example #13
0
def comparison(web, req, tmpl):
    """
    /comparison/{revision}/{path}
    -----------------------------

    Show a comparison between the old and new versions of a file from changes
    made on a particular revision.

    This is similar to the ``diff`` handler. However, this form features
    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
    context in the diff.

    The ``filecomparison`` template is rendered.
    """
    ctx = webutil.changectx(web.repo, req)
    if 'file' not in req.form:
        raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
    path = webutil.cleanpath(web.repo, req.form['file'][0])
    rename = path in ctx and webutil.renamelink(ctx[path]) or []

    parsecontext = lambda v: v == 'full' and -1 or int(v)
    if 'context' in req.form:
        context = parsecontext(req.form['context'][0])
    else:
        context = parsecontext(web.config('web', 'comparisoncontext', '5'))

    def filelines(f):
        if util.binary(f.data()):
            mt = mimetypes.guess_type(f.path())[0]
            if not mt:
                mt = 'application/octet-stream'
            return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
        return f.data().splitlines()

    parent = ctx.p1()
    leftrev = parent.rev()
    leftnode = parent.node()
    rightrev = ctx.rev()
    rightnode = ctx.node()
    if path in ctx:
        fctx = ctx[path]
        rightlines = filelines(fctx)
        if path not in parent:
            leftlines = ()
        else:
            pfctx = parent[path]
            leftlines = filelines(pfctx)
    else:
        rightlines = ()
        fctx = ctx.parents()[0][path]
        leftlines = filelines(fctx)

    comparison = webutil.compare(tmpl, context, leftlines, rightlines)
    return tmpl('filecomparison',
                file=path,
                node=hex(ctx.node()),
                rev=ctx.rev(),
                symrev=webutil.symrevorshortnode(req, ctx),
                date=ctx.date(),
                desc=ctx.description(),
                extra=ctx.extra(),
                author=ctx.user(),
                rename=rename,
                branch=webutil.nodebranchnodefault(ctx),
                parent=webutil.parents(fctx),
                child=webutil.children(fctx),
                tags=webutil.nodetagsdict(web.repo, ctx.node()),
                bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
                leftrev=leftrev,
                leftnode=hex(leftnode),
                rightrev=rightrev,
                rightnode=hex(rightnode),
                comparison=comparison)
Example #14
0
def manifest(web, req, tmpl):
    """
    /manifest[/{revision}[/{path}]]
    -------------------------------

    Show information about a directory.

    If the URL path arguments are omitted, information about the root
    directory for the ``tip`` changeset will be shown.

    Because this handler can only show information for directories, it
    is recommended to use the ``file`` handler instead, as it can handle both
    directories and files.

    The ``manifest`` template will be rendered for this handler.
    """
    if 'node' in req.form:
        ctx = webutil.changectx(web.repo, req)
        symrev = webutil.symrevorshortnode(req, ctx)
    else:
        ctx = web.repo['tip']
        symrev = 'tip'
    path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
    mf = ctx.manifest()
    node = ctx.node()

    files = {}
    dirs = {}
    parity = paritygen(web.stripecount)

    if path and path[-1] != "/":
        path += "/"
    l = len(path)
    abspath = "/" + path

    for full, n in mf.iteritems():
        # the virtual path (working copy path) used for the full
        # (repository) path
        f = decodepath(full)

        if f[:l] != path:
            continue
        remain = f[l:]
        elements = remain.split('/')
        if len(elements) == 1:
            files[remain] = full
        else:
            h = dirs # need to retain ref to dirs (root)
            for elem in elements[0:-1]:
                if elem not in h:
                    h[elem] = {}
                h = h[elem]
                if len(h) > 1:
                    break
            h[None] = None # denotes files present

    if mf and not files and not dirs:
        raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)

    def filelist(**map):
        for f in sorted(files):
            full = files[f]

            fctx = ctx.filectx(full)
            yield {"file": full,
                   "parity": parity.next(),
                   "basename": f,
                   "date": fctx.date(),
                   "size": fctx.size(),
                   "permissions": mf.flags(full)}

    def dirlist(**map):
        for d in sorted(dirs):

            emptydirs = []
            h = dirs[d]
            while isinstance(h, dict) and len(h) == 1:
                k, v = h.items()[0]
                if v:
                    emptydirs.append(k)
                h = v

            path = "%s%s" % (abspath, d)
            yield {"parity": parity.next(),
                   "path": path,
                   "emptydirs": "/".join(emptydirs),
                   "basename": d}

    return tmpl("manifest",
                rev=ctx.rev(),
                symrev=symrev,
                node=hex(node),
                path=abspath,
                up=webutil.up(abspath),
                upparity=parity.next(),
                fentries=filelist,
                dentries=dirlist,
                archives=web.archivelist(hex(node)),
                tags=webutil.nodetagsdict(web.repo, node),
                bookmarks=webutil.nodebookmarksdict(web.repo, node),
                branch=webutil.nodebranchnodefault(ctx),
                inbranch=webutil.nodeinbranch(web.repo, ctx),
                branches=webutil.nodebranchdict(web.repo, ctx))
Example #15
0
def changelog(web, req, tmpl, shortlog=False):
    """
    /changelog[/{revision}]
    -----------------------

    Show information about multiple changesets.

    If the optional ``revision`` URL argument is absent, information about
    all changesets starting at ``tip`` will be rendered. If the ``revision``
    argument is present, changesets will be shown starting from the specified
    revision.

    If ``revision`` is absent, the ``rev`` query string argument may be
    defined. This will perform a search for changesets.

    The argument for ``rev`` can be a single revision, a revision set,
    or a literal keyword to search for in changeset data (equivalent to
    :hg:`log -k`).

    The ``revcount`` query string argument defines the maximum numbers of
    changesets to render.

    For non-searches, the ``changelog`` template will be rendered.
    """

    query = ''
    if 'node' in req.form:
        ctx = webutil.changectx(web.repo, req)
        symrev = webutil.symrevorshortnode(req, ctx)
    elif 'rev' in req.form:
        return _search(web, req, tmpl)
    else:
        ctx = web.repo['tip']
        symrev = 'tip'

    def changelist():
        revs = []
        if pos != -1:
            revs = web.repo.changelog.revs(pos, 0)
        curcount = 0
        for rev in revs:
            curcount += 1
            if curcount > revcount + 1:
                break

            entry = webutil.changelistentry(web, web.repo[rev], tmpl)
            entry['parity'] = parity.next()
            yield entry

    if shortlog:
        revcount = web.maxshortchanges
    else:
        revcount = web.maxchanges

    if 'revcount' in req.form:
        try:
            revcount = int(req.form.get('revcount', [revcount])[0])
            revcount = max(revcount, 1)
            tmpl.defaults['sessionvars']['revcount'] = revcount
        except ValueError:
            pass

    lessvars = copy.copy(tmpl.defaults['sessionvars'])
    lessvars['revcount'] = max(revcount / 2, 1)
    morevars = copy.copy(tmpl.defaults['sessionvars'])
    morevars['revcount'] = revcount * 2

    count = len(web.repo)
    pos = ctx.rev()
    parity = paritygen(web.stripecount)

    changenav = webutil.revnav(web.repo).gen(pos, revcount, count)

    entries = list(changelist())
    latestentry = entries[:1]
    if len(entries) > revcount:
        nextentry = entries[-1:]
        entries = entries[:-1]
    else:
        nextentry = []

    return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
                node=ctx.hex(), rev=pos, symrev=symrev, changesets=count,
                entries=entries,
                latestentry=latestentry, nextentry=nextentry,
                archives=web.archivelist("tip"), revcount=revcount,
                morevars=morevars, lessvars=lessvars, query=query)
Example #16
0
def graph(web, req, tmpl):
    """
    /graph[/{revision}]
    -------------------

    Show information about the graphical topology of the repository.

    Information rendered by this handler can be used to create visual
    representations of repository topology.

    The ``revision`` URL parameter controls the starting changeset.

    The ``revcount`` query string argument can define the number of changesets
    to show information for.

    This handler will render the ``graph`` template.
    """

    if 'node' in req.form:
        ctx = webutil.changectx(web.repo, req)
        symrev = webutil.symrevorshortnode(req, ctx)
    else:
        ctx = web.repo['tip']
        symrev = 'tip'
    rev = ctx.rev()

    bg_height = 39
    revcount = web.maxshortchanges
    if 'revcount' in req.form:
        try:
            revcount = int(req.form.get('revcount', [revcount])[0])
            revcount = max(revcount, 1)
            tmpl.defaults['sessionvars']['revcount'] = revcount
        except ValueError:
            pass

    lessvars = copy.copy(tmpl.defaults['sessionvars'])
    lessvars['revcount'] = max(revcount / 2, 1)
    morevars = copy.copy(tmpl.defaults['sessionvars'])
    morevars['revcount'] = revcount * 2

    count = len(web.repo)
    pos = rev

    uprev = min(max(0, count - 1), rev + revcount)
    downrev = max(0, rev - revcount)
    changenav = webutil.revnav(web.repo).gen(pos, revcount, count)

    tree = []
    if pos != -1:
        allrevs = web.repo.changelog.revs(pos, 0)
        revs = []
        for i in allrevs:
            revs.append(i)
            if len(revs) >= revcount:
                break

        # We have to feed a baseset to dagwalker as it is expecting smartset
        # object. This does not have a big impact on hgweb performance itself
        # since hgweb graphing code is not itself lazy yet.
        dag = graphmod.dagwalker(web.repo, revset.baseset(revs))
        # As we said one line above... not lazy.
        tree = list(graphmod.colored(dag, web.repo))

    def getcolumns(tree):
        cols = 0
        for (id, type, ctx, vtx, edges) in tree:
            if type != graphmod.CHANGESET:
                continue
            cols = max(cols, max([edge[0] for edge in edges] or [0]),
                             max([edge[1] for edge in edges] or [0]))
        return cols

    def graphdata(usetuples, **map):
        data = []

        row = 0
        for (id, type, ctx, vtx, edges) in tree:
            if type != graphmod.CHANGESET:
                continue
            node = str(ctx)
            age = templatefilters.age(ctx.date())
            desc = templatefilters.firstline(ctx.description())
            desc = cgi.escape(templatefilters.nonempty(desc))
            user = cgi.escape(templatefilters.person(ctx.user()))
            branch = cgi.escape(ctx.branch())
            try:
                branchnode = web.repo.branchtip(branch)
            except error.RepoLookupError:
                branchnode = None
            branch = branch, branchnode == ctx.node()

            if usetuples:
                data.append((node, vtx, edges, desc, user, age, branch,
                             [cgi.escape(x) for x in ctx.tags()],
                             [cgi.escape(x) for x in ctx.bookmarks()]))
            else:
                edgedata = [{'col': edge[0], 'nextcol': edge[1],
                             'color': (edge[2] - 1) % 6 + 1,
                             'width': edge[3], 'bcolor': edge[4]}
                            for edge in edges]

                data.append(
                    {'node': node,
                     'col': vtx[0],
                     'color': (vtx[1] - 1) % 6 + 1,
                     'edges': edgedata,
                     'row': row,
                     'nextrow': row + 1,
                     'desc': desc,
                     'user': user,
                     'age': age,
                     'bookmarks': webutil.nodebookmarksdict(
                         web.repo, ctx.node()),
                     'branches': webutil.nodebranchdict(web.repo, ctx),
                     'inbranch': webutil.nodeinbranch(web.repo, ctx),
                     'tags': webutil.nodetagsdict(web.repo, ctx.node())})

            row += 1

        return data

    cols = getcolumns(tree)
    rows = len(tree)
    canvasheight = (rows + 1) * bg_height - 27

    return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount,
                uprev=uprev,
                lessvars=lessvars, morevars=morevars, downrev=downrev,
                cols=cols, rows=rows,
                canvaswidth=(cols + 1) * bg_height,
                truecanvasheight=rows * bg_height,
                canvasheight=canvasheight, bg_height=bg_height,
                jsdata=lambda **x: graphdata(True, **x),
                nodes=lambda **x: graphdata(False, **x),
                node=ctx.hex(), changenav=changenav)