Integration of Mercurial into LXR

Simon King simon at simonking.org.uk
Thu Dec 13 09:02:41 CST 2012


On Thu, Dec 13, 2012 at 1:07 PM, andre-littoz <page74010-sf at yahoo.fr> wrote:
> Hello,
>
> I am the present LXR (Linux Cross-Referencer - see
> http://lxr/sourceforge.net) administrator/developer and trying to extend LXR
> beyond plain files/CVS/Git/svn storage engine.
>
> I succeeded in implementing an experimental backend storage engine to work
> with local Mercurial repositories. Unhappily, it runs horribly slow
> (approximately 10 times slower than git or Subversion on the same test
> case). Certainly because that's my first contact with hg.
>
> One of the first LXR tasks is to display a directory view, same as hgweb
> does. To retrieve directory content, I found nothing else than the following
> command:
> hg locate -r "revision of interest" a_directory/**
>
> This implies to traverse the full repository, where I only want the present
> directory, without its subdirectories. I can't use * pattern because I want
> to build a list of the subdirectories. The command reports the complete
> sub-tree rooted at the requested directory. I must then filter out the
> sublevels. This is a double waste: first inside Mercurial to report the
> tree, next inside LXR to prune unwanted information.
>
> When it comes to compute file size, I had to
> hg cat -r "revision of interest" "a_file" | wc
>
> which means extract the file and throw it away for every line in the
> directory list.
>
> This is really inefficient.
>
> I had a look at the source of hgweb to discover it used internal templates
> names fentries and dentries which contain apparently the information needed
> by LXR.
>
>
> Is there a simple and efficient command line to
> 1- get a "standard" directory list like ls or ls -F
> 2- retrieve a file size
> or
> 3- have access to information supplied by {fentries} and {dentries}
> templates?
>
> Thanks for your help
> André Littoz
> LXR administrator
>

I'm not aware of any way of retrieving the information that you want,
so instead here's an extension based on the guts of the
mercurial.hgweb.webcommands:manifest function. If you save it as
"lxr.py" and add it to your [extensions], then you'll get an "hg ls"
command which behaves like this in the mercurial repository:

$: hg ls -r tip
dir      contrib
dir      doc
dir      hgext
dir      i18n
dir      mercurial
dir      tests
727      .hgignore
8468     .hgsigs
3530     .hgtags
1663     CONTRIBUTORS
18092    COPYING
4009     Makefile
547      README
1056     hg
1225     hgeditor
683      hgweb.cgi
19397    setup.py

$: hg ls -r 1
dir      mercurial
4        .hgignore
233      PKG-INFO
2753     README
7801     hg
6581     notes.txt
491      setup.py
45       tkmerge

$: hg ls -r 1 mercurial
0        __init__.py
16806    byterange.py
1484     fancyopts.py
17064    hg.py
1603     mdiff.py
6329     revlog.py
1804     transaction.py

Completely untested other than what you see above.

#------------------------------------------------
from mercurial import cmdutil
import mercurial.hgweb.webcommands

cmdtable = {}
command = cmdutil.command(cmdtable)

@command('ls',
         [('r', 'rev', '.',
           'revision to list')],
         'hg ls [-r REV] [path]')
def lxrls(ui, repo, path='', rev='.'):
    # largely copied from mercurial.hgweb.webcommands:manifest
    ctx = repo[rev]
    mf = ctx.manifest()
    if path and not path.endswith('/'):
        path += '/'
    l = len(path)

    files = {}
    dirs = {}

    for full, n in mf.iteritems():
        f = mercurial.hgweb.webcommands.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

            continue
        remain = f[l:]

    for d in sorted(dirs):
        ui.write('%-8s %s\n' % ('dir', d))

    for f in sorted(files):
        full = files[f]
        fctx = ctx.filectx(full)
        ui.write('%-8d %s\n' % (fctx.size(), f))

#------------------------------------------------

Hope that helps,

Simon


More information about the Mercurial-devel mailing list