##// END OF EJS Templates
fileset: insert hints where status should be computed...
Yuya Nishihara -
r38915:e79a69af default
parent child Browse files
Show More
@@ -43,6 +43,9 b' def getmatch(mctx, x):'
43 raise error.ParseError(_("missing argument"))
43 raise error.ParseError(_("missing argument"))
44 return methods[x[0]](mctx, *x[1:])
44 return methods[x[0]](mctx, *x[1:])
45
45
46 def getmatchwithstatus(mctx, x, hint):
47 return getmatch(mctx, x)
48
46 def stringmatch(mctx, x):
49 def stringmatch(mctx, x):
47 return mctx.matcher([x])
50 return mctx.matcher([x])
48
51
@@ -443,6 +446,7 b' def subrepo(mctx, x):'
443 return mctx.predicate(sstate.__contains__, predrepr='subrepo')
446 return mctx.predicate(sstate.__contains__, predrepr='subrepo')
444
447
445 methods = {
448 methods = {
449 'withstatus': getmatchwithstatus,
446 'string': stringmatch,
450 'string': stringmatch,
447 'symbol': stringmatch,
451 'symbol': stringmatch,
448 'kindpat': kindpatmatch,
452 'kindpat': kindpatmatch,
@@ -171,6 +171,82 b' def _analyze(x):'
171 return (op, x[1], ta)
171 return (op, x[1], ta)
172 raise error.ProgrammingError('invalid operator %r' % op)
172 raise error.ProgrammingError('invalid operator %r' % op)
173
173
174 def _insertstatushints(x):
175 """Insert hint nodes where status should be calculated (first path)
176
177 This works in bottom-up way, summing up status names and inserting hint
178 nodes at 'and' and 'or' as needed. Thus redundant hint nodes may be left.
179
180 Returns (status-names, new-tree) at the given subtree, where status-names
181 is a sum of status names referenced in the given subtree.
182 """
183 if x is None:
184 return (), x
185
186 op = x[0]
187 if op in {'string', 'symbol', 'kindpat'}:
188 return (), x
189 if op == 'not':
190 h, t = _insertstatushints(x[1])
191 return h, (op, t)
192 if op == 'and':
193 ha, ta = _insertstatushints(x[1])
194 hb, tb = _insertstatushints(x[2])
195 hr = ha + hb
196 if ha and hb:
197 return hr, ('withstatus', (op, ta, tb), ('string', ' '.join(hr)))
198 return hr, (op, ta, tb)
199 if op == 'or':
200 hs, ts = zip(*(_insertstatushints(y) for y in x[1:]))
201 hr = sum(hs, ())
202 if sum(bool(h) for h in hs) > 1:
203 return hr, ('withstatus', (op,) + ts, ('string', ' '.join(hr)))
204 return hr, (op,) + ts
205 if op == 'list':
206 hs, ts = zip(*(_insertstatushints(y) for y in x[1:]))
207 return sum(hs, ()), (op,) + ts
208 if op == 'func':
209 f = getsymbol(x[1])
210 # don't propagate 'ha' crossing a function boundary
211 ha, ta = _insertstatushints(x[2])
212 if getattr(symbols.get(f), '_callstatus', False):
213 return (f,), ('withstatus', (op, x[1], ta), ('string', f))
214 return (), (op, x[1], ta)
215 raise error.ProgrammingError('invalid operator %r' % op)
216
217 def _mergestatushints(x, instatus):
218 """Remove redundant status hint nodes (second path)
219
220 This is the top-down path to eliminate inner hint nodes.
221 """
222 if x is None:
223 return x
224
225 op = x[0]
226 if op == 'withstatus':
227 if instatus:
228 # drop redundant hint node
229 return _mergestatushints(x[1], instatus)
230 t = _mergestatushints(x[1], instatus=True)
231 return (op, t, x[2])
232 if op in {'string', 'symbol', 'kindpat'}:
233 return x
234 if op == 'not':
235 t = _mergestatushints(x[1], instatus)
236 return (op, t)
237 if op == 'and':
238 ta = _mergestatushints(x[1], instatus)
239 tb = _mergestatushints(x[2], instatus)
240 return (op, ta, tb)
241 if op in {'list', 'or'}:
242 ts = tuple(_mergestatushints(y, instatus) for y in x[1:])
243 return (op,) + ts
244 if op == 'func':
245 # don't propagate 'instatus' crossing a function boundary
246 ta = _mergestatushints(x[2], instatus=False)
247 return (op, x[1], ta)
248 raise error.ProgrammingError('invalid operator %r' % op)
249
174 def analyze(x):
250 def analyze(x):
175 """Transform raw parsed tree to evaluatable tree which can be fed to
251 """Transform raw parsed tree to evaluatable tree which can be fed to
176 optimize() or getmatch()
252 optimize() or getmatch()
@@ -178,7 +254,9 b' def analyze(x):'
178 All pseudo operations should be mapped to real operations or functions
254 All pseudo operations should be mapped to real operations or functions
179 defined in methods or symbols table respectively.
255 defined in methods or symbols table respectively.
180 """
256 """
181 return _analyze(x)
257 t = _analyze(x)
258 _h, t = _insertstatushints(t)
259 return _mergestatushints(t, instatus=False)
182
260
183 def _optimizeandops(op, ta, tb):
261 def _optimizeandops(op, ta, tb):
184 if tb is not None and tb[0] == 'not':
262 if tb is not None and tb[0] == 'not':
@@ -205,6 +283,9 b' def _optimize(x):'
205 return 0, x
283 return 0, x
206
284
207 op = x[0]
285 op = x[0]
286 if op == 'withstatus':
287 w, t = _optimize(x[1])
288 return w, (op, t, x[2])
208 if op in {'string', 'symbol'}:
289 if op in {'string', 'symbol'}:
209 return WEIGHT_CHECK_FILENAME, x
290 return WEIGHT_CHECK_FILENAME, x
210 if op == 'kindpat':
291 if op == 'kindpat':
@@ -24,7 +24,9 b' def _compile(tree):'
24 if not tree:
24 if not tree:
25 raise error.ParseError(_("missing argument"))
25 raise error.ParseError(_("missing argument"))
26 op = tree[0]
26 op = tree[0]
27 if op in {'symbol', 'string', 'kindpat'}:
27 if op == 'withstatus':
28 return _compile(tree[1])
29 elif op in {'symbol', 'string', 'kindpat'}:
28 name = filesetlang.getpattern(tree, {'path'}, _('invalid file pattern'))
30 name = filesetlang.getpattern(tree, {'path'}, _('invalid file pattern'))
29 if name.startswith('**'): # file extension test, ex. "**.tar.gz"
31 if name.startswith('**'): # file extension test, ex. "**.tar.gz"
30 ext = name[2:]
32 ext = name[2:]
@@ -175,18 +175,22 b' Show parsed tree at stages:'
175 (func
175 (func
176 (symbol 'grep')
176 (symbol 'grep')
177 (string 'b'))
177 (string 'b'))
178 (func
178 (withstatus
179 (symbol 'clean')
179 (func
180 None)))
180 (symbol 'clean')
181 None)
182 (string 'clean'))))
181 * optimized:
183 * optimized:
182 (or
184 (or
183 (patterns
185 (patterns
184 (symbol 'a1')
186 (symbol 'a1')
185 (symbol 'a2'))
187 (symbol 'a2'))
186 (and
188 (and
187 (func
189 (withstatus
188 (symbol 'clean')
190 (func
189 None)
191 (symbol 'clean')
192 None)
193 (string 'clean'))
190 (func
194 (func
191 (symbol 'grep')
195 (symbol 'grep')
192 (string 'b'))))
196 (string 'b'))))
@@ -374,6 +378,156 b' Test files status in different revisions'
374 b2
378 b2
375 c1
379 c1
376
380
381 Test insertion of status hints
382
383 $ fileset -p optimized 'added()'
384 * optimized:
385 (withstatus
386 (func
387 (symbol 'added')
388 None)
389 (string 'added'))
390 c1
391
392 $ fileset -p optimized 'a* & removed()'
393 * optimized:
394 (and
395 (symbol 'a*')
396 (withstatus
397 (func
398 (symbol 'removed')
399 None)
400 (string 'removed')))
401 a2
402
403 $ fileset -p optimized 'a* - removed()'
404 * optimized:
405 (minus
406 (symbol 'a*')
407 (withstatus
408 (func
409 (symbol 'removed')
410 None)
411 (string 'removed')))
412 a1
413
414 $ fileset -p analyzed -p optimized '(added() + removed()) - a*'
415 * analyzed:
416 (and
417 (withstatus
418 (or
419 (func
420 (symbol 'added')
421 None)
422 (func
423 (symbol 'removed')
424 None))
425 (string 'added removed'))
426 (not
427 (symbol 'a*')))
428 * optimized:
429 (and
430 (not
431 (symbol 'a*'))
432 (withstatus
433 (or
434 (func
435 (symbol 'added')
436 None)
437 (func
438 (symbol 'removed')
439 None))
440 (string 'added removed')))
441 c1
442
443 $ fileset -p optimized 'a* + b* + added() + unknown()'
444 * optimized:
445 (withstatus
446 (or
447 (patterns
448 (symbol 'a*')
449 (symbol 'b*'))
450 (func
451 (symbol 'added')
452 None)
453 (func
454 (symbol 'unknown')
455 None))
456 (string 'added unknown'))
457 a1
458 a2
459 b1
460 b2
461 c1
462 c3
463
464 $ fileset -p analyzed -p optimized 'removed() & missing() & a*'
465 * analyzed:
466 (and
467 (withstatus
468 (and
469 (func
470 (symbol 'removed')
471 None)
472 (func
473 (symbol 'missing')
474 None))
475 (string 'removed missing'))
476 (symbol 'a*'))
477 * optimized:
478 (and
479 (symbol 'a*')
480 (withstatus
481 (and
482 (func
483 (symbol 'removed')
484 None)
485 (func
486 (symbol 'missing')
487 None))
488 (string 'removed missing')))
489
490 $ fileset -p optimized 'clean() & revs(0, added())'
491 * optimized:
492 (and
493 (withstatus
494 (func
495 (symbol 'clean')
496 None)
497 (string 'clean'))
498 (func
499 (symbol 'revs')
500 (list
501 (symbol '0')
502 (withstatus
503 (func
504 (symbol 'added')
505 None)
506 (string 'added')))))
507 b1
508
509 $ fileset -p optimized 'clean() & status(null, 0, b* & added())'
510 * optimized:
511 (and
512 (withstatus
513 (func
514 (symbol 'clean')
515 None)
516 (string 'clean'))
517 (func
518 (symbol 'status')
519 (list
520 (symbol 'null')
521 (symbol '0')
522 (and
523 (symbol 'b*')
524 (withstatus
525 (func
526 (symbol 'added')
527 None)
528 (string 'added'))))))
529 b1
530
377 Test files properties
531 Test files properties
378
532
379 >>> open('bin', 'wb').write(b'\0a') and None
533 >>> open('bin', 'wb').write(b'\0a') and None
General Comments 0
You need to be logged in to leave comments. Login now