66 res += re.escape(c) |
67 res += re.escape(c) |
67 return head + res + tail |
68 return head + res + tail |
68 |
69 |
69 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1} |
70 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1} |
70 |
71 |
71 def matcher(cwd, names, inc, exc, head = ''): |
72 def pathto(n1, n2): |
|
73 '''return the relative path from one place to another. |
|
74 this returns a path in the form used by the local filesystem, not hg.''' |
|
75 if not n1: return localpath(n2) |
|
76 a, b = n1.split('/'), n2.split('/') |
|
77 a.reverse(), b.reverse() |
|
78 while a and b and a[-1] == b[-1]: |
|
79 a.pop(), b.pop() |
|
80 b.reverse() |
|
81 return os.sep.join((['..'] * len(a)) + b) |
|
82 |
|
83 def canonpath(repo, cwd, myname): |
|
84 rootsep = repo.root + os.sep |
|
85 name = myname |
|
86 if not name.startswith(os.sep): |
|
87 name = os.path.join(repo.root, cwd, name) |
|
88 name = os.path.normpath(name) |
|
89 if name.startswith(rootsep): |
|
90 return pconvert(name[len(rootsep):]) |
|
91 elif name == repo.root: |
|
92 return '' |
|
93 else: |
|
94 raise Abort('%s not under repository root' % myname) |
|
95 |
|
96 def matcher(repo, cwd, names, inc, exc, head = ''): |
72 def patkind(name): |
97 def patkind(name): |
73 for prefix in 're:', 'glob:', 'path:': |
98 for prefix in 're:', 'glob:', 'path:', 'relpath:': |
74 if name.startswith(prefix): return name.split(':', 1) |
99 if name.startswith(prefix): return name.split(':', 1) |
75 for c in name: |
100 for c in name: |
76 if c in _globchars: return 'glob', name |
101 if c in _globchars: return 'glob', name |
77 return 'relpath', name |
102 return 'relpath', name |
78 |
103 |
79 cwdsep = cwd + os.sep |
104 def regex(kind, name, tail): |
80 |
|
81 def regex(name, tail): |
|
82 '''convert a pattern into a regular expression''' |
105 '''convert a pattern into a regular expression''' |
83 kind, name = patkind(name) |
|
84 if kind == 're': |
106 if kind == 're': |
85 return name |
107 return name |
86 elif kind == 'path': |
108 elif kind == 'path': |
87 return '^' + re.escape(name) + '$' |
109 return '^' + re.escape(name) + '(?:/|$)' |
88 if cwd: name = os.path.join(cwdsep, name) |
110 elif kind == 'relpath': |
89 name = os.path.normpath(name) |
111 return head + re.escape(name) + tail |
90 if name == '.': name = '**' |
|
91 return head + globre(name, '', tail) |
112 return head + globre(name, '', tail) |
92 |
|
93 def under(fn): |
|
94 """check if fn is under our cwd""" |
|
95 return not cwd or fn.startswith(cwdsep) |
|
96 |
113 |
97 def matchfn(pats, tail): |
114 def matchfn(pats, tail): |
98 """build a matching function from a set of patterns""" |
115 """build a matching function from a set of patterns""" |
99 if pats: |
116 if pats: |
100 pat = '(?:%s)' % '|'.join([regex(p, tail) for p in pats]) |
117 pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats]) |
101 return re.compile(pat).match |
118 return re.compile(pat).match |
102 |
119 |
103 def globprefix(pat): |
120 def globprefix(pat): |
104 '''return the non-glob prefix of a path, e.g. foo/* -> foo''' |
121 '''return the non-glob prefix of a path, e.g. foo/* -> foo''' |
105 root = [] |
122 root = [] |
106 for p in pat.split(os.sep): |
123 for p in pat.split(os.sep): |
107 if patkind(p)[0] == 'glob': break |
124 if patkind(p)[0] == 'glob': break |
108 root.append(p) |
125 root.append(p) |
109 return os.sep.join(root) |
126 return '/'.join(root) |
110 |
127 |
111 patkinds = map(patkind, names) |
128 pats = [] |
112 pats = [name for (kind, name) in patkinds if kind != 'relpath'] |
129 files = [] |
113 files = [name for (kind, name) in patkinds if kind == 'relpath'] |
130 roots = [] |
114 roots = filter(None, map(globprefix, pats)) + files |
131 for kind, name in map(patkind, names): |
115 if cwd: roots = [cwdsep + r for r in roots] |
132 if kind in ('glob', 'relpath'): |
|
133 name = canonpath(repo, cwd, name) |
|
134 if name == '': |
|
135 kind, name = 'glob', '**' |
|
136 if kind in ('glob', 'path', 're'): |
|
137 pats.append((kind, name)) |
|
138 if kind == 'glob': |
|
139 root = globprefix(name) |
|
140 if root: roots.append(root) |
|
141 elif kind == 'relpath': |
|
142 files.append((kind, name)) |
|
143 roots.append(name) |
116 |
144 |
117 patmatch = matchfn(pats, '$') or always |
145 patmatch = matchfn(pats, '$') or always |
118 filematch = matchfn(files, '(?:/|$)') or always |
146 filematch = matchfn(files, '(?:/|$)') or always |
119 incmatch = matchfn(inc, '(?:/|$)') or always |
147 incmatch = matchfn(map(patkind, inc), '(?:/|$)') or always |
120 excmatch = matchfn(exc, '(?:/|$)') or (lambda fn: False) |
148 excmatch = matchfn(map(patkind, exc), '(?:/|$)') or (lambda fn: False) |
121 |
149 |
122 return roots, lambda fn: (incmatch(fn) and not excmatch(fn) and |
150 return roots, lambda fn: (incmatch(fn) and not excmatch(fn) and |
123 (fn.endswith('/') or |
151 (fn.endswith('/') or |
124 (not pats and not files) or |
152 (not pats and not files) or |
125 (pats and patmatch(fn)) or |
153 (pats and patmatch(fn)) or |