Skip to content

Commit

Permalink
Merge pull request #243 from couchapp/issue-204
Browse files Browse the repository at this point in the history
Improve .couchappignore
fix #204
  • Loading branch information
iblislin committed Feb 6, 2017
2 parents 5febebc + 7092799 commit c757000
Show file tree
Hide file tree
Showing 2 changed files with 220 additions and 10 deletions.
68 changes: 58 additions & 10 deletions couchapp/localdoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
import urlparse
import webbrowser

from copy import copy
from itertools import chain

try:
import desktopcouch
try:
Expand All @@ -38,11 +41,11 @@ def _replace_backslash(name):
re_comment = re.compile("((?:\/\*(?:[^*]|(?:\*+[^*\/]))*\*+\/)|(?:\/\/.*))")

DEFAULT_IGNORE = """[
// filenames matching these regexps will not be pushed to the database
// paths matching these regexps will not be pushed to the database
// uncomment to activate; separate entries with ","
// ".*~$"
// ".*\\\\.swp$"
// ".*\\\\.bak$"
// ".*~"
// ".*\\\\.swp"
// ".*\\\\.bak"
]"""


Expand Down Expand Up @@ -297,13 +300,54 @@ def doc(self, db=None, with_attachments=True, force=False):
return self._doc

def check_ignore(self, item):
for i in self.ignores:
match = re.match(i, item)
if match:
'''
:param item: the relative path which starts from ``self.docdir``
Given a path and a ignore list,
e.g. ``foo/bar/baz.json`` and ``['bar']``,
we will check
* ``foo/bar/baz.json`` vs ``bar`` -> False
* ``bar/baz.json`` vs ``bar`` -> True, then return
* ``baz.json`` vs ``bar`` -> not checked
'''
item = os.path.normpath(item)

for pattern in self.ignores:
# ('/' + item) is for abs path, some duplicated generated but work
paths = chain(self._combine_path(item),
self._combine_path('/' +item))
matches = (re.match(pattern + '$', i) for i in paths)
if any(matches):
logger.debug("ignoring %s", item)
return True
return False

@classmethod
def _combine_path(cls, p):
'''
>>> tuple(LocalDoc._combine_path('foo/bar/qaz'))
('foo', 'foo/bar', 'foo/bar/qaz', 'bar', 'bar/qaz', 'qaz')
>>> tuple(LocalDoc._combine_path('/foo/bar/qaz'))
('/foo', '/foo/bar', '/foo/bar/qaz', 'bar', 'bar/qaz', 'qaz')
'''
ls = util.split_path(p)
while ls:
for i in cls._combine_dir(copy(ls)):
yield i
ls.pop(0)

@staticmethod
def _combine_dir(ls):
'''
>>> tuple(LocalDoc._combine_dir(['foo', 'bar', 'qaz']))
('foo', 'foo/bar', 'foo/bar/qaz')
'''
ret = tuple()
while ls:
ret += (ls.pop(0),)
yield '/'.join(ret)

def dir_to_fields(self, current_dir=None, depth=0, manifest=None):
"""
Process a directory and get all members
Expand All @@ -320,7 +364,7 @@ def dir_to_fields(self, current_dir=None, depth=0, manifest=None):
self.docdir))
if name.startswith("."):
continue
elif self.check_ignore(name):
elif self.check_ignore(rel_path):
continue
elif depth == 0 and name.startswith('_'):
# files starting with "_" are always "special"
Expand Down Expand Up @@ -400,11 +444,15 @@ def _process_attachments(self, path, vendor=None):
if os.path.isdir(path):
for root, dirs, files in os.walk(path):
for dirname in dirs:
if self.check_ignore(dirname):
_relpath = util.relpath(os.path.join(root, dirname),
self.docdir)
if self.check_ignore(_relpath):
dirs.remove(dirname)
if files:
for filename in files:
if self.check_ignore(filename):
_relpath = util.relpath(os.path.join(root, filename),
self.docdir)
if self.check_ignore(_relpath):
continue
else:
filepath = os.path.join(root, filename)
Expand Down
162 changes: 162 additions & 0 deletions tests/test_localdoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,165 @@ def test_create_nothing(self):

assert self.exists('.couchapprc')
assert not self.exists('.couchappignore')


def test_check_ignore():
f = check_check_ignore

ignores = ['.*\.bak']
yield f, ignores, 'magic.bak', True
yield f, ignores, 'magicbak', False
yield f, ignores, 'bar/magic.bak', True

ignores = ['bar']
yield f, ignores, 'bar', True
yield f, ignores, 'bar/', True
yield f, ignores, 'bar.txt', False
yield f, ignores, 'magic_bar', False

yield f, ignores, 'foo/bar', True
yield f, ignores, 'foo/qaz/bar', True
yield f, ignores, 'foo/bar/app.js', True

yield f, ignores, 'bar/app.js', True
yield f, ignores, 'bar/foo.txt', True

yield f, ignores, 'magic_bar/app.js', False
yield f, ignores, 'bar_magic/app.js', False

# the result should be same as ``['bar']``,
# the ``$`` is include by default
ignores = ['bar$']
yield f, ignores, 'bar', True
yield f, ignores, 'bar/', True
yield f, ignores, 'bar.txt', False
yield f, ignores, 'magic_bar', False

yield f, ignores, 'foo/bar', True
yield f, ignores, 'foo/qaz/bar', True
yield f, ignores, 'foo/bar/app.js', True

yield f, ignores, 'bar/app.js', True
yield f, ignores, 'bar/foo.txt', True

yield f, ignores, 'magic_bar/app.js', False
yield f, ignores, 'bar_magic/app.js', False

ignores = ['foo/bar']
yield f, ignores, 'foo/bar', True
yield f, ignores, 'qaz/foo/bar', True

yield f, ignores, 'foo/bar/', True
yield f, ignores, 'qaz/foo/bar/', True

yield f, ignores, 'foo/bar/app.js', True
yield f, ignores, 'qaz/foo/bar/app.js', True

ignores = ['foo/.*bar']
yield f, ignores, 'foo/magic_bar', True
yield f, ignores, 'foo/magic_bar/', True
yield f, ignores, 'foo/magic_bar/app.js', True

yield f, ignores, 'foo/magic/bar/', True
yield f, ignores, 'foo/magic/bar/app.js', True

yield f, ignores, 'foo/magic/long/long/bar', True
yield f, ignores, 'foo/magic/long/long/bar/app.js', True

yield f, ignores, 'foobar', False

yield f, ignores, 'qaz/foo/magic_bar', True
yield f, ignores, 'qaz/foo/magic_bar/', True
yield f, ignores, 'qaz/foo/magic_bar/app.js', True

yield f, ignores, 'qaz/foo/magic/bar/', True
yield f, ignores, 'qaz/foo/magic/bar/app.js', True

yield f, ignores, 'qaz/foo/magic/long/long/bar', True
yield f, ignores, 'qaz/foo/magic/long/long/bar/app.js', True

yield f, ignores, 'qaz_foo/magic_bar', False
yield f, ignores, 'qaz_foo/magic_bar/', False
yield f, ignores, 'qaz_foo/magic_bar/app.js', False

yield f, ignores, 'qaz_foo/magic/bar/', False
yield f, ignores, 'qaz_foo/magic/bar/app.js', False

yield f, ignores, 'qaz_foo/magic/long/long/bar', False
yield f, ignores, 'qaz_foo/magic/long/long/bar/app.js', False

yield f, ignores, 'foo/magic_bar_', False
yield f, ignores, 'foo/magic_bar_/', False
yield f, ignores, 'foo/magic_bar_/app.js', False

yield f, ignores, 'foo/magic/bar_/', False
yield f, ignores, 'foo/magic/bar_/app.js', False

yield f, ignores, 'foo/magic/long/long/bar_', False
yield f, ignores, 'foo/magic/long/long/bar_/app.js', False

ignores = ['foo/.*/bar']
yield f, ignores, 'foo/magic_bar', False
yield f, ignores, 'foo/magic_bar/', False
yield f, ignores, 'foo/magic_bar/app.js', False

yield f, ignores, 'foo/magic/bar/', True
yield f, ignores, 'foo/magic/bar/app.js', True

yield f, ignores, 'foo/magic/long/long/bar', True
yield f, ignores, 'foo/magic/long/long/bar/app.js', True

yield f, ignores, 'foobar', False

yield f, ignores, 'qaz/foo/magic_bar', False
yield f, ignores, 'qaz/foo/magic_bar/', False
yield f, ignores, 'qaz/foo/magic_bar/app.js', False

yield f, ignores, 'qaz/foo/magic/bar/', True
yield f, ignores, 'qaz/foo/magic/bar/app.js', True

yield f, ignores, 'qaz/foo/magic/long/long/bar', True
yield f, ignores, 'qaz/foo/magic/long/long/bar/app.js', True

yield f, ignores, 'qaz_foo/magic_bar', False
yield f, ignores, 'qaz_foo/magic_bar/', False
yield f, ignores, 'qaz_foo/magic_bar/app.js', False

yield f, ignores, 'qaz_foo/magic/bar/', False
yield f, ignores, 'qaz_foo/magic/bar/app.js', False

yield f, ignores, 'qaz_foo/magic/long/long/bar', False
yield f, ignores, 'qaz_foo/magic/long/long/bar/app.js', False

yield f, ignores, 'foo/magic/bar_', False
yield f, ignores, 'foo/magic/bar_/', False
yield f, ignores, 'foo/magic/bar_/app.js', False

yield f, ignores, 'foo/magic/long/long/bar_', False
yield f, ignores, 'foo/magic/long/long/bar_/app.js', False

ignores = ['/foo/bar']
yield f, ignores, 'foo/bar', True
yield f, ignores, 'foo/bar/app.js', True

yield f, ignores, 'qaz/foo/bar', False
yield f, ignores, 'qaz/foo/bar/app.js', False

ignores = [u'測試'] # unicode testing
yield f, ignores, u'測試', True
yield f, ignores, u'測 試', False
yield f, ignores, u'測試/app.js', True
yield f, ignores, u'測試資料夾', False
yield f, ignores, u'測試.txt', False

yield f, ignores, u'foo/測試', True
yield f, ignores, u'foo/測 試', False
yield f, ignores, u'foo/測試/app.js', True
yield f, ignores, u'foo/測試資料夾', False
yield f, ignores, u'foo/測試.txt', False


def check_check_ignore(ignores, path, ans):
doc = LocalDoc('/mock/app', create=False)
doc.ignores = ignores
assert doc.check_ignore(path) is ans

0 comments on commit c757000

Please sign in to comment.