author Matt Mackall <>
Mon, 26 Apr 2010 11:03:40 -0500
changeset 11000 3381677351243e1de05f840a9341fe92bf607e4a
parent 10263 25e572394f5c3bae9c4706b5529cb78555295a85
child 13412 58c497d0e44db1f5bd0c5301effdb4e47dc3102c
permissions -rw-r--r--
hgweb: simplify hgweb.cgi, add help pointer - move important config to the top - add help pointer - drop encoding hack comment (use web.encoding) - simplify imports - use unified hgweb interface

# - ignored file handling for mercurial
# Copyright 2007 Matt Mackall <>
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

from i18n import _
import util, match
import re

_commentre = None

def ignorepats(lines):
    '''parse lines (iterable) of .hgignore text, returning a tuple of
    (patterns, parse errors). These patterns should be given to compile()
    to be validated and converted into a match function.'''
    syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
    syntax = 'relre:'
    patterns = []
    warnings = []

    for line in lines:
        if "#" in line:
            global _commentre
            if not _commentre:
                _commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
            # remove comments prefixed by an even number of escapes
            line = _commentre.sub(r'\1', line)
            # fixup properly escaped comments that survived the above
            line = line.replace("\\#", "#")
        line = line.rstrip()
        if not line:

        if line.startswith('syntax:'):
            s = line[7:].strip()
                syntax = syntaxes[s]
            except KeyError:
                warnings.append(_("ignoring invalid syntax '%s'") % s)
        pat = syntax + line
        for s, rels in syntaxes.iteritems():
            if line.startswith(rels):
                pat = line
            elif line.startswith(s+':'):
                pat = rels + line[len(s)+1:]

    return patterns, warnings

def ignore(root, files, warn):
    '''return matcher covering patterns in 'files'.

    the files parsed for patterns include:
    .hgignore in the repository root
    any additional files specified in the [ui] section of ~/.hgrc

    trailing white space is dropped.
    the escape character is backslash.
    comments start with #.
    empty lines are skipped.

    lines can be of the following formats:

    syntax: regexp # defaults following lines to non-rooted regexps
    syntax: glob   # defaults following lines to non-rooted globs
    re:pattern     # non-rooted regular expression
    glob:pattern   # non-rooted glob
    pattern        # pattern of the current default type'''

    pats = {}
    for f in files:
            pats[f] = []
            fp = open(f)
            pats[f], warnings = ignorepats(fp)
            for warning in warnings:
                warn("%s: %s\n" % (f, warning))
        except IOError, inst:
            if f != files[0]:
                warn(_("skipping unreadable ignore file '%s': %s\n") %
                     (f, inst.strerror))

    allpats = []
    [allpats.extend(patlist) for patlist in pats.values()]
    if not allpats:
        return util.never

        ignorefunc = match.match(root, '', [], allpats)
    except util.Abort:
        # Re-raise an exception where the src is the right file
        for f, patlist in pats.iteritems():
                match.match(root, '', [], patlist)
            except util.Abort, inst:
                raise util.Abort('%s: %s' % (f, inst[0]))

    return ignorefunc