mercurial/ignore.py
author Matt Mackall <mpm@selenic.com>
Fri, 15 May 2015 09:56:43 -0500
changeset 25084 7046c7e7fcb4
parent 25066 e91b32d3c67b
child 25163 3139900f31b1
permissions -rw-r--r--
hooks: use try/except/finally
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
25066
e91b32d3c67b ignore: refactor syntax concatenation
Durham Goode <durham@fb.com>
parents: 25065
diff changeset
    43
e91b32d3c67b ignore: refactor syntax concatenation
Durham Goode <durham@fb.com>
parents: 25065
diff changeset
    44
        linesyntax = syntax
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    45
        for s, rels in syntaxes.iteritems():
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    46
            if line.startswith(rels):
25066
e91b32d3c67b ignore: refactor syntax concatenation
Durham Goode <durham@fb.com>
parents: 25065
diff changeset
    47
                linesyntax = rels
e91b32d3c67b ignore: refactor syntax concatenation
Durham Goode <durham@fb.com>
parents: 25065
diff changeset
    48
                line = line[len(rels):]
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    49
                break
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    50
            elif line.startswith(s+':'):
25066
e91b32d3c67b ignore: refactor syntax concatenation
Durham Goode <durham@fb.com>
parents: 25065
diff changeset
    51
                linesyntax = rels
e91b32d3c67b ignore: refactor syntax concatenation
Durham Goode <durham@fb.com>
parents: 25065
diff changeset
    52
                line = line[len(s) + 1:]
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    53
                break
25066
e91b32d3c67b ignore: refactor syntax concatenation
Durham Goode <durham@fb.com>
parents: 25065
diff changeset
    54
        patterns.append(linesyntax + line)
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    55
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    56
    return patterns, warnings
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    57
25065
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    58
def readignorefile(filepath, warn, skipwarning=False):
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    59
    try:
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    60
        pats = []
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    61
        fp = open(filepath)
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    62
        pats, warnings = ignorepats(fp)
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    63
        fp.close()
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    64
        for warning in warnings:
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    65
            warn("%s: %s\n" % (filepath, warning))
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    66
    except IOError, inst:
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    67
        if not skipwarning:
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    68
            warn(_("skipping unreadable ignore file '%s': %s\n") %
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    69
                 (filepath, inst.strerror))
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    70
    return pats
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    71
18087
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
    72
def readpats(root, files, warn):
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
    73
    '''return a dict mapping ignore-file-name to list-of-patterns'''
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
    74
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
    75
    pats = {}
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
    76
    for f in files:
18088
52620e5db2f6 ignore: only read an ignore file once
Bryan O'Sullivan <bryano@fb.com>
parents: 18087
diff changeset
    77
        if f in pats:
52620e5db2f6 ignore: only read an ignore file once
Bryan O'Sullivan <bryano@fb.com>
parents: 18087
diff changeset
    78
            continue
25065
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    79
        skipwarning = f == files[0]
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    80
        pats[f] = readignorefile(f, warn, skipwarning=skipwarning)
8cf7f0c4cb14 ignore: refactor file read into a function
Durham Goode <durham@fb.com>
parents: 18089
diff changeset
    81
18089
0127366df8fe ignore: process hgignore files in deterministic order
Bryan O'Sullivan <bryano@fb.com>
parents: 18088
diff changeset
    82
    return [(f, pats[f]) for f in files if f in pats]
18087
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
    83
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    84
def ignore(root, files, warn):
9091
79a886bcf461 ignore: separate pattern extraction from match compilation
Brendan Cully <brendan@kublai.com>
parents: 8567
diff changeset
    85
    '''return matcher covering patterns in 'files'.
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    86
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    87
    the files parsed for patterns include:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    88
    .hgignore in the repository root
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    89
    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
    90
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    91
    trailing white space is dropped.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    92
    the escape character is backslash.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    93
    comments start with #.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    94
    empty lines are skipped.
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    95
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    96
    lines can be of the following formats:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    97
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    98
    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
    99
    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
   100
    re:pattern     # non-rooted regular expression
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   101
    glob:pattern   # non-rooted glob
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   102
    pattern        # pattern of the current default type'''
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   103
18087
5712e3b12274 ignore: refactor ignore into two functions
Bryan O'Sullivan <bryano@fb.com>
parents: 18054
diff changeset
   104
    pats = readpats(root, files, warn)
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   105
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   106
    allpats = []
18089
0127366df8fe ignore: process hgignore files in deterministic order
Bryan O'Sullivan <bryano@fb.com>
parents: 18088
diff changeset
   107
    for f, patlist in pats:
13412
58c497d0e44d remove unnecessary list comprehensions
Martin Geisler <mg@aragost.com>
parents: 10263
diff changeset
   108
        allpats.extend(patlist)
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   109
    if not allpats:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   110
        return util.never
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   111
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   112
    try:
8567
fea40a677d43 match: add some default args
Matt Mackall <mpm@selenic.com>
parents: 8566
diff changeset
   113
        ignorefunc = match.match(root, '', [], allpats)
4609
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   114
    except util.Abort:
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   115
        # Re-raise an exception where the src is the right file
18089
0127366df8fe ignore: process hgignore files in deterministic order
Bryan O'Sullivan <bryano@fb.com>
parents: 18088
diff changeset
   116
        for f, patlist in pats:
8566
744d6322b05b match: change all users of util.matcher to match.match
Matt Mackall <mpm@selenic.com>
parents: 8312
diff changeset
   117
            try:
8567
fea40a677d43 match: add some default args
Matt Mackall <mpm@selenic.com>
parents: 8566
diff changeset
   118
                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
   119
            except util.Abort, inst:
744d6322b05b match: change all users of util.matcher to match.match
Matt Mackall <mpm@selenic.com>
parents: 8312
diff changeset
   120
                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
   121
b43f17691ae6 dirstate: move ignore to its own file
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   122
    return ignorefunc