Mercurial > hg
comparison mercurial/cmdutil.py @ 33548:4cd4344a53c4
status: add a flag to terse the output (issue4119)
This adds an experimental flag -t/--terse which will terse the output. The terse flag
will respect other flags which filters the output. The flag takes a string
whose value can be a subsequence of "marduic" (the order does not matter here.)
Ignored files are not considered while tersing unless -i flag is passed or 'i'
is there is the terse flag value.
The flag is experimental for testing as there may be cases which will produce
strange results with the flag. We can set the terse on by default by simply
passing 'u' to the cmdutil.tersestatus().
This patch also adds a test file with tests covering the new feature.
author | Pulkit Goyal <7895pulkit@gmail.com> |
---|---|
date | Sat, 17 Jun 2017 20:10:22 +0530 |
parents | a3acacbd0ff3 |
children | 5ac845ca059a 6f4bc9688ca9 |
comparison
equal
deleted
inserted
replaced
33547:a6af8560494e | 33548:4cd4344a53c4 |
---|---|
397 def recordinwlock(ui, repo, message, match, opts): | 397 def recordinwlock(ui, repo, message, match, opts): |
398 with repo.wlock(): | 398 with repo.wlock(): |
399 return recordfunc(ui, repo, message, match, opts) | 399 return recordfunc(ui, repo, message, match, opts) |
400 | 400 |
401 return commit(ui, repo, recordinwlock, pats, opts) | 401 return commit(ui, repo, recordinwlock, pats, opts) |
402 | |
403 def tersestatus(root, statlist, status, ignorefn, ignore): | |
404 """ | |
405 Returns a list of statuses with directory collapsed if all the files in the | |
406 directory has the same status. | |
407 """ | |
408 | |
409 def numfiles(dirname): | |
410 """ | |
411 Calculates the number of tracked files in a given directory which also | |
412 includes files which were removed or deleted. Considers ignored files | |
413 if ignore argument is True or 'i' is present in status argument. | |
414 """ | |
415 if lencache.get(dirname): | |
416 return lencache[dirname] | |
417 if 'i' in status or ignore: | |
418 def match(localpath): | |
419 absolutepath = os.path.join(root, localpath) | |
420 if os.path.isdir(absolutepath) and isemptydir(absolutepath): | |
421 return True | |
422 return False | |
423 else: | |
424 def match(localpath): | |
425 # there can be directory whose all the files are ignored and | |
426 # hence the drectory should also be ignored while counting | |
427 # number of files or subdirs in it's parent directory. This | |
428 # checks the same. | |
429 # XXX: We need a better logic here. | |
430 if os.path.isdir(os.path.join(root, localpath)): | |
431 return isignoreddir(localpath) | |
432 else: | |
433 # XXX: there can be files which have the ignored pattern but | |
434 # are not ignored. That leads to bug in counting number of | |
435 # tracked files in the directory. | |
436 return ignorefn(localpath) | |
437 lendir = 0 | |
438 abspath = os.path.join(root, dirname) | |
439 # There might be cases when a directory does not exists as the whole | |
440 # directory can be removed and/or deleted. | |
441 try: | |
442 for f in os.listdir(abspath): | |
443 localpath = os.path.join(dirname, f) | |
444 if not match(localpath): | |
445 lendir += 1 | |
446 except OSError: | |
447 pass | |
448 lendir += len(absentdir.get(dirname, [])) | |
449 lencache[dirname] = lendir | |
450 return lendir | |
451 | |
452 def isemptydir(abspath): | |
453 """ | |
454 Check whether a directory is empty or not, i.e. there is no files in the | |
455 directory and all its subdirectories. | |
456 """ | |
457 for f in os.listdir(abspath): | |
458 fullpath = os.path.join(abspath, f) | |
459 if os.path.isdir(fullpath): | |
460 # recursion here | |
461 ret = isemptydir(fullpath) | |
462 if not ret: | |
463 return False | |
464 else: | |
465 return False | |
466 return True | |
467 | |
468 def isignoreddir(localpath): | |
469 """ | |
470 This function checks whether the directory contains only ignored files | |
471 and hence should the directory be considered ignored. Returns True, if | |
472 that should be ignored otherwise False. | |
473 """ | |
474 dirpath = os.path.join(root, localpath) | |
475 for f in os.listdir(dirpath): | |
476 filepath = os.path.join(dirpath, f) | |
477 if os.path.isdir(filepath): | |
478 # recursion here | |
479 ret = isignoreddir(os.path.join(localpath, f)) | |
480 if not ret: | |
481 return False | |
482 else: | |
483 if not ignorefn(os.path.join(localpath, f)): | |
484 return False | |
485 return True | |
486 | |
487 def absentones(removedfiles, missingfiles): | |
488 """ | |
489 Returns a dictionary of directories with files in it which are either | |
490 removed or missing (deleted) in them. | |
491 """ | |
492 absentdir = {} | |
493 absentfiles = removedfiles + missingfiles | |
494 while absentfiles: | |
495 f = absentfiles.pop() | |
496 par = os.path.dirname(f) | |
497 if par == '': | |
498 continue | |
499 # we need to store files rather than number of files as some files | |
500 # or subdirectories in a directory can be counted twice. This is | |
501 # also we have used sets here. | |
502 try: | |
503 absentdir[par].add(f) | |
504 except KeyError: | |
505 absentdir[par] = set([f]) | |
506 absentfiles.append(par) | |
507 return absentdir | |
508 | |
509 indexes = {'m': 0, 'a': 1, 'r': 2, 'd': 3, 'u': 4, 'i': 5, 'c': 6} | |
510 # get a dictonary of directories and files which are missing as os.listdir() | |
511 # won't be able to list them. | |
512 absentdir = absentones(statlist[2], statlist[3]) | |
513 finalrs = [[]] * len(indexes) | |
514 didsomethingchanged = False | |
515 # dictionary to store number of files and subdir in a directory so that we | |
516 # don't compute that again. | |
517 lencache = {} | |
518 | |
519 for st in pycompat.bytestr(status): | |
520 | |
521 try: | |
522 ind = indexes[st] | |
523 except KeyError: | |
524 # TODO: Need a better error message here | |
525 raise error.Abort("'%s' not recognized" % st) | |
526 | |
527 sfiles = statlist[ind] | |
528 if not sfiles: | |
529 continue | |
530 pardict = {} | |
531 for a in sfiles: | |
532 par = os.path.dirname(a) | |
533 pardict.setdefault(par, []).append(a) | |
534 | |
535 rs = [] | |
536 newls = [] | |
537 for par, files in pardict.iteritems(): | |
538 lenpar = numfiles(par) | |
539 if lenpar == len(files): | |
540 newls.append(par) | |
541 | |
542 if not newls: | |
543 continue | |
544 | |
545 while newls: | |
546 newel = newls.pop() | |
547 if newel == '': | |
548 continue | |
549 parn = os.path.dirname(newel) | |
550 pardict[newel] = [] | |
551 # Adding pycompat.ossep as newel is a directory. | |
552 pardict.setdefault(parn, []).append(newel + pycompat.ossep) | |
553 lenpar = numfiles(parn) | |
554 if lenpar == len(pardict[parn]): | |
555 newls.append(parn) | |
556 | |
557 # dict.values() for Py3 compatibility | |
558 for files in pardict.values(): | |
559 rs.extend(files) | |
560 | |
561 rs.sort() | |
562 finalrs[ind] = rs | |
563 didsomethingchanged = True | |
564 | |
565 # If nothing is changed, make sure the order of files is preserved. | |
566 if not didsomethingchanged: | |
567 return statlist | |
568 | |
569 for x in xrange(len(indexes)): | |
570 if not finalrs[x]: | |
571 finalrs[x] = statlist[x] | |
572 | |
573 return finalrs | |
402 | 574 |
403 def findpossible(cmd, table, strict=False): | 575 def findpossible(cmd, table, strict=False): |
404 """ | 576 """ |
405 Return cmd -> (aliases, command table entry) | 577 Return cmd -> (aliases, command table entry) |
406 for each matching command. | 578 for each matching command. |