Skip to content

Commit

Permalink
Fixed matching Windows paths.
Browse files Browse the repository at this point in the history
  • Loading branch information
cpburnz committed Nov 7, 2014
1 parent 3e0eaaf commit 45829da
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 20 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
Change History
==============

0.3.2 (TBD)
-----------

- Issue #6: Fixed matching Windows paths.


0.3.1 (2014-09-17)
------------------

Expand Down
6 changes: 3 additions & 3 deletions pathspec/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# encoding: utf-8
"""
The *pathspec* package provides pattern matching for file paths. So far
this only includes gitignore style pattern matching.
Expand All @@ -18,8 +18,8 @@
__license__ = "MPL 2.0"
__project__ = "pathspec"
__status__ = "Development"
__updated__ = "2014-09-17"
__version__ = "0.3.1"
__updated__ = "2014-11-07"
__version__ = "0.3.2b1"

from .gitignore import GitIgnorePattern
from .pathspec import PathSpec
Expand Down
17 changes: 14 additions & 3 deletions pathspec/compat.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
# coding: utf-8
# encoding: utf-8
"""
This module provides compatibility between Python 2 and 3. Hardly
anything is used by this project to constitute including `six`_.
.. _`six`: http://pythonhosted.org/six
"""

try:
import sys

if sys.version_info[0] < 3:
# Python 2.
string_types = (basestring,)
except NameError:

def viewkeys(mapping):
return mapping.viewkeys()

else:
# Python 3.
string_types = (str,)

def viewkeys(mapping):
return mapping.keys()
2 changes: 1 addition & 1 deletion pathspec/gitignore.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# encoding: utf-8
"""
This module implements gitignore style pattern matching which
incorporates POSIX glob patterns.
Expand Down
23 changes: 17 additions & 6 deletions pathspec/pathspec.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# encoding: utf-8
"""
This module provides an object oriented interface for pattern matching
of files.
Expand All @@ -7,7 +7,7 @@
import collections

from . import util
from .compat import string_types
from .compat import string_types, viewkeys


class PathSpec(object):
Expand Down Expand Up @@ -63,16 +63,27 @@ def from_lines(cls, pattern_factory, lines):
lines = [pattern_factory(line) for line in lines if line]
return cls(lines)

def match_files(self, files):
def match_files(self, files, separators=None):
"""
Matches the files to this path-spec.
*files* (``Iterable`` of ``str``) contains the files to be matched
against *patterns*.
Returns the matched files (``set`` of ``str``).
*separators* (``Container`` of ``str``) optionally contains the path
separators to normalize. This does not need to include the POSIX
path separator (`/`), but including it will not affect the results.
Default is ``None`` to determine the separators based upon the
current operating system by examining `os.sep` and `os.altsep`. To
prevent normalization, pass an empty container (e.g., an empty tuple
`()`).
Returns the matched files (``Iterable`` of ``str``).
"""
return util.match_files(self.patterns, files)
file_map = util.normalize_files(files, separators=separators)
matched_files = util.match_files(self.patterns, viewkeys(file_map))
for path in matched_files:
yield file_map[path]

def match_tree(self, root):
"""
Expand All @@ -81,7 +92,7 @@ def match_tree(self, root):
*root* (``str``) is the root directory to search for files.
Returns the matched files (``set`` of ``str``).
Returns the matched files (``Iterable`` of ``str``).
"""
files = util.iter_tree(root)
return self.match_files(files)
2 changes: 1 addition & 1 deletion pathspec/pattern.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# encoding: utf-8
"""
This module provides the base definition for patterns.
"""
Expand Down
7 changes: 7 additions & 0 deletions pathspec/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# encoding: utf-8
"""
This package provides tests.
"""

from .test_pathspec import PathSpecTest
from .test_gitignore import GitIgnoreTest
2 changes: 1 addition & 1 deletion pathspec/tests/test_gitignore.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# encoding: utf-8
"""
This script tests ``GitIgnorePattern``.
"""
Expand Down
35 changes: 35 additions & 0 deletions pathspec/tests/test_pathspec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# encoding: utf-8
"""
This script tests ``PathSpec``.
"""

import unittest

import pathspec

class PathSpecTest(unittest.TestCase):
"""
The ``PathSpecTest`` class tests the ``PathSpec`` class.
"""

def test_01_windows_paths(self):
"""
Tests that Windows paths will be properly normalized and matched.
"""
spec = pathspec.PathSpec.from_lines('gitignore', [
'*.txt',
'!test1/',
])
results = set(spec.match_files([
'src\\test1\\a.txt',
'src\\test1\\b.txt',
'src\\test1\\c\\c.txt',
'src\\test2\\a.txt',
'src\\test2\\b.txt',
'src\\test2\\c\\c.txt',
], separators=('\\',)))
self.assertEquals(results, {
'src\\test2\\a.txt',
'src\\test2\\b.txt',
'src\\test2\\c\\c.txt',
})
36 changes: 33 additions & 3 deletions pathspec/util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# encoding: utf-8
"""
This module provides utility methods for dealing with path-specs.
"""
Expand All @@ -9,6 +9,13 @@

from .compat import string_types

NORMALIZE_PATH_SEPS = [sep for sep in [os.sep, os.altsep] if sep and sep != '/']
"""
*NORMALIZE_PATH_SEPS* (``list`` of ``str``) contains the path separators
that need to be normalized to the POSIX separator for the current
operating system.
"""

_registered_patterns = {}
"""
*_registered_patterns* (``dict``) maps a name (``str``) to the
Expand Down Expand Up @@ -66,8 +73,8 @@ def match_files(patterns, files):
*patterns* (``Iterable`` of ``pathspec.Pattern``) contains the
patterns to use.
*files* (``Iterable`` of ``str``) contains the files to be matched
against *patterns*.
*files* (``Iterable`` of ``str``) contains the normalized files to be
matched against *patterns*.
Returns the matched files (``set`` of ``str``).
"""
Expand All @@ -82,6 +89,29 @@ def match_files(patterns, files):
return_files.difference_update(result_files)
return return_files

def normalize_files(files, separators=None):
"""
Normalizes the file paths to use the POSIX path separator (i.e., `/`).
*files* (``Iterable`` of ``str``) contains the file paths to be
normalized.
*separators* (``Container`` of ``str``) optionally contains the path
separators to normalize.
Returns a ``dict`` mapping the normalized file path (``str``) to the
original file path (``str``)
"""
if separators is None:
separators = NORMALIZE_PATH_SEPS
file_map = {}
for path in files:
norm = path
for sep in separators:
norm = norm.replace(sep, '/')
file_map[norm] = path
return file_map

def register_pattern(name, pattern_factory, override=None):
"""
Registers the specified pattern factory.
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding: utf-8
# encoding: utf-8

import io
from setuptools import setup, find_packages
Expand Down Expand Up @@ -33,5 +33,5 @@
],
license=__license__,
packages=find_packages(),
test_suite='pathspec.tests.test_gitignore.GitIgnoreTest',
test_suite='pathspec.tests',
)

0 comments on commit 45829da

Please sign in to comment.