Ejemplo n.º 1
0
def path_matches_single_pattern(path, pattern):
    """Return True if and only if the given path matches the given pattern.

    Both arguments (path and pattern) must be in our chroot-like format, i.e.,
    start with a '/' and be normalized (no '..', etc.). A path matches a pattern    if the path is either equal to the pattern or the pattern is a directory
    and path is contained in the directory. In particular, this means that the
    path '/foobar' does not match the pattern '/foo'.
    """

    # check input convention
    if not (path.startswith(os.sep) and pattern.startswith(os.sep)):
        raise ValueError('Both file name ("{}") and pattern ("{}") must start with "{}".'.format(path, pattern, os.sep))

    utils.ensure_normalized(path)
    utils.ensure_normalized(pattern)

    # perform actual pattern matching check
    if path == pattern:
        # if pattern is a path, then only the path itself can match
        return True
    elif path.startswith(pattern + os.sep):
        # if pattern is a subdirectory of root then path must
        # start with "pattern/"
        return True
    elif pattern == os.sep:
        # if a pattern is root itself then any path matches
        return True
    else:
        # nothing else matches
        return False
Ejemplo n.º 2
0
def parse_pattern_file(f):
    """Return a list of patterns parsed from the file object f

    The patterns are returned as a list of pairs (modifier, pattern), where
    modifier is either the constant INCLUDE or the constant EXCLUDE. pattern
    is the pathname affected by the inclusion / exclusion rule. The list is
    in the same order as the pattern file f, i.e., in order of priority (later
    rules override earlier rules).

    In case of an invalid pattern, the function raises a ValueError exception.
    """
    res = []
    # Note that in the regex, {} is replaced by os.sep.
    regex = re.compile('^([+-])\W+({}.*)$'.format(re.escape(os.sep)))
    for line in f:
        line = line.rstrip()
        if line.startswith('#'):
            continue
        else:
            r = regex.match(line.rstrip())
            if not r:
                raise ValueError('Line "{}" is not a valid pattern.'.format(
                        line))
            modifier = r.groups()[0]
            pattern = r.groups()[1]
            utils.ensure_normalized(pattern)
            if modifier == '+':
                res.append((INCLUDE, pattern))
            elif modifier == '-':
                res.append((EXCLUDE, pattern))
            else:
                raise ValueError('Unknown pattern modifier "{}".'.format(
                        modifier))
    return res
Ejemplo n.º 3
0
def pattern_decision(path, patterns):
    """Compute the include / exclude decision for a given path and patterns.

    The parameter patterns is a list of patterns where each pattern is a pair
    of (decision, pattern_string) as returned by parse_pattern_file. The
    last matching pattern in the list determines the final decision.
    """
    utils.ensure_normalized(path)
    res = INCLUDE
    for p in patterns:
        utils.ensure_normalized(p[1])
        if p[0] != INCLUDE and p[0] != EXCLUDE:
            raise ValueError('Invalid pattern: unknown decision')
        if path_matches_single_pattern(path, p[1]):
            res = p[0]
    return res