mercurial/ignore.py
author Christian Ebert <blacktrash@gmx.net>
Fri, 08 Oct 2010 18:39:46 +0100
changeset 12630 94926263b7ab
parent 10263 25e572394f5c
child 13412 58c497d0e44d
permissions -rw-r--r--
keyword: specific regular expressions depending on read mode More safeguarding against accidental (un)expansion: Reading filelog: act only on \$(kw1|kw2|..)\$ as keywords are always stored unexpanded. Reading wdir: act only on \$(kw1|kw2|..): [^$\n\r]*? \$ as we only are interested in expanded keywords in this situation. Note: we cannot use ..): [^$\n\r]+? \$ because e.g. the {branch} template might be empty. hg record is a special case as we read from the working directory and need one regex each for modified and added files. Therefore test recording an added file. This way we finally also forbid sequences like $Id: $ being treated as keywords.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     1
# ignore.py - ignored file handling for mercurial
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     2
#
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     3
# Copyright 2007 Matt Mackall <mpm@selenic.com>
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     4
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 7622
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9091
diff changeset
     6
# GNU General Public License version 2 or any later version.
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     7
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     8
from i18n import _
8566
744d6322b05b match: change all users of util.matcher to match.match
Matt Mackall <mpm@selenic.com>
parents: 8312
diff changeset
     9
import util, match
8312
b87a50b7125c separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents: 8225
diff changeset
    10
import re
5640
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    11
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    12
_commentre = None
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    13
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    14
def ignorepats(lines):
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    15
    '''parse lines (iterable) of .hgignore text, returning a tuple of
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    16
    (patterns, parse errors). These patterns should be given to compile()
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    17
    to be validated and converted into a match function.'''
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    18
    syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    19
    syntax = 'relre:'
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    20
    patterns = []
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    21
    warnings = []
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    22
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    23
    for line in lines:
5640
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    24
        if "#" in line:
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    25
            global _commentre
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    26
            if not _commentre:
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    27
                _commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    28
            # remove comments prefixed by an even number of escapes
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    29
            line = _commentre.sub(r'\1', line)
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    30
            # fixup properly escaped comments that survived the above
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    31
            line = line.replace("\\#", "#")
04c76f296ad6 ignore: fix up comment parsing
Matt Mackall <mpm@selenic.com>
parents: 5271
diff changeset
    32
        line = line.rstrip()
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    33
        if not line:
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    34
            continue
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    35
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    36
        if line.startswith('syntax:'):
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    37
            s = line[7:].strip()
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    38
            try:
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    39
                syntax = syntaxes[s]
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    40
            except KeyError:
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    41
                warnings.append(_("ignoring invalid syntax '%s'") % s)
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    42
            continue
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    43
        pat = syntax + line
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    44
        for s, rels in syntaxes.iteritems():
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    45
            if line.startswith(rels):
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    46
                pat = line
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    47
                break
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    48
            elif line.startswith(s+':'):
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    49
                pat = rels + line[len(s)+1:]
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    50
                break
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    51
        patterns.append(pat)
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    52
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    53
    return patterns, warnings
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    54
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    55
def ignore(root, files, warn):
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    56
    '''return matcher covering patterns in 'files'.
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    57
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    58
    the files parsed for patterns include:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    59
    .hgignore in the repository root
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    60
    any additional files specified in the [ui] section of ~/.hgrc
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    61
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    62
    trailing white space is dropped.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
    the escape character is backslash.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    64
    comments start with #.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    65
    empty lines are skipped.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    66
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    67
    lines can be of the following formats:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    68
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    69
    syntax: regexp # defaults following lines to non-rooted regexps
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    70
    syntax: glob   # defaults following lines to non-rooted globs
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    71
    re:pattern     # non-rooted regular expression
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    72
    glob:pattern   # non-rooted glob
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    73
    pattern        # pattern of the current default type'''
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    74
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    75
    pats = {}
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    76
    for f in files:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    77
        try:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    78
            pats[f] = []
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    79
            fp = open(f)
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    80
            pats[f], warnings = ignorepats(fp)
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    81
            for warning in warnings:
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    82
                warn("%s: %s\n" % (f, warning))
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    83
        except IOError, inst:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    84
            if f != files[0]:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    85
                warn(_("skipping unreadable ignore file '%s': %s\n") %
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    86
                     (f, inst.strerror))
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    87
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    88
    allpats = []
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    89
    [allpats.extend(patlist) for patlist in pats.values()]
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    90
    if not allpats:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    91
        return util.never
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    92
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    93
    try:
8567
fea40a677d43 match: add some default args
Matt Mackall <mpm@selenic.com>
parents: 8566
diff changeset
    94
        ignorefunc = match.match(root, '', [], allpats)
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    95
    except util.Abort:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    96
        # Re-raise an exception where the src is the right file
7622
4dd7b28003d2 use dict.iteritems() rather than dict.items()
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5640
diff changeset
    97
        for f, patlist in pats.iteritems():
8566
744d6322b05b match: change all users of util.matcher to match.match
Matt Mackall <mpm@selenic.com>
parents: 8312
diff changeset
    98
            try:
8567
fea40a677d43 match: add some default args
Matt Mackall <mpm@selenic.com>
parents: 8566
diff changeset
    99
                match.match(root, '', [], patlist)
8566
744d6322b05b match: change all users of util.matcher to match.match
Matt Mackall <mpm@selenic.com>
parents: 8312
diff changeset
   100
            except util.Abort, inst:
744d6322b05b match: change all users of util.matcher to match.match
Matt Mackall <mpm@selenic.com>
parents: 8312
diff changeset
   101
                raise util.Abort('%s: %s' % (f, inst[0]))
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   102
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   103
    return ignorefunc