globsyntax = ' This program allows specifying filenames with "mglob" mechanism.\n Supported syntax in globs (wilcard matching patterns)::\n \n *.cpp ?ellowo* \n - obvious. Differs from normal glob in that dirs are not included.\n Unix users might want to write this as: "*.cpp" "?ellowo*"\n rec:/usr/share=*.txt,*.doc \n - get all *.txt and *.doc under /usr/share, \n recursively\n rec:/usr/share\n - All files under /usr/share, recursively\n rec:*.py\n - All .py files under current working dir, recursively\n foo \n - File or dir foo\n !*.bak readme* \n - readme*, exclude files ending with .bak\n !.svn/ !.hg/ !*_Data/ rec:.\n - Skip .svn, .hg, foo_Data dirs (and their subdirs) in recurse.\n Trailing / is the key, \\ does not work! Use !.*/ for all hidden.\n dir:foo \n - the directory foo if it exists (not files in foo)\n dir:* \n - all directories in current folder\n foo.py bar.* !h* rec:*.py\n - Obvious. !h* exclusion only applies for rec:*.py.\n foo.py is *not* included twice.\n @filelist.txt\n - All files listed in \'filelist.txt\' file, on separate lines.\n "cont:class \\wak:" rec:*.py\n - Match files containing regexp. Applies to subsequent files.\n note quotes because of whitespace.\n '
__version__ = '0.2'
import os
import glob
import fnmatch
import sys
import re
def expand(flist, exp_dirs = False):
if isinstance(flist, basestring):
import shlex
flist = shlex.split(flist)
done_set = set()
denied_set = set()
cont_set = set()
cur_rejected_dirs = set()
def recfind(p, pats = (None, [
'*'])):
denied_dirs = _[1]
for dp, dnames, fnames in os.walk(p):
dp_norm = dp.replace('\\', '/') + '/'
deny = False
for d in cur_rejected_dirs:
if dp.startswith(d):
deny = True
break
continue
[]
if deny:
continue
bname = os.path.basename(dp)
for deny_pat in denied_dirs:
if fnmatch.fnmatch(bname, deny_pat):
deny = True
cur_rejected_dirs.add(dp)
break
continue
if deny:
continue
for f in fnames:
matched = False
for p in pats:
if fnmatch.fnmatch(f, p):
matched = True
break
continue
if matched:
yield os.path.join(dp, f)
continue
def once_filter(seq):
for it in seq:
p = os.path.abspath(it)
if p in done_set:
continue
done_set.add(p)
deny = False
for deny_pat in denied_set:
if fnmatch.fnmatch(os.path.basename(p), deny_pat):
deny = True
break
continue
if cont_set:
try:
cont = open(p).read()
except IOError:
continue
for pat in cont_set:
if not re.search(pat, cont, re.IGNORECASE):
deny = True
break
continue
if not deny:
yield it
continue
res = []
for ent in flist:
ent = os.path.expanduser(os.path.expandvars(ent))
if ent.lower().startswith('rec:'):
fields = ent[4:].split('=')
if len(fields) == 2:
(pth, patlist) = fields
elif len(fields) == 1:
if os.path.isdir(fields[0]):
pth = fields[0]
patlist = '*'
else:
pth = '.'
patlist = fields[0]
elif len(fields) == 0:
(pth, pathlist) = ('.', '*')
pats = patlist.split(',')
res.extend(once_filter(recfind(pth, pats)))
continue
if ent.startswith('@') and os.path.isfile(ent[1:]):