@@ -604,6 +604,8 @@ def do_add_parser(self, parser_adder):
604604 exiting with an error if there are issues''' )
605605 group .add_argument ('--path' , action = 'store_true' ,
606606 help = "print the top level manifest file's path" )
607+ group .add_argument ('--status' , action = 'store_true' ,
608+ help = "print the local workspace status" )
607609
608610 group = parser .add_argument_group ('options for --resolve and --freeze' )
609611 group .add_argument ('-o' , '--out' ,
@@ -624,6 +626,8 @@ def do_run(self, args, user_args):
624626 elif args .freeze :
625627 self ._die_if_manifest_project_filter ('freeze' )
626628 self ._dump (args , manifest .as_frozen_yaml (** dump_kwargs ))
629+ elif args .status :
630+ self ._status ()
627631 elif args .path :
628632 self .inf (manifest .path )
629633 else :
@@ -640,6 +644,48 @@ def _die_if_manifest_project_filter(self, action):
640644 'the manifest while projects are made inactive by the '
641645 'project filter.' )
642646
647+ def _status (self ):
648+ topdir = Path (self .topdir )
649+ ppaths = []
650+ untracked = []
651+ for project in self ._projects (None ):
652+ # Skip inactive projects unless the user said
653+ # --all or named some projects explicitly.
654+ if not self .manifest .is_active (project ):
655+ self .dbg (f'{ project .name } : skipping inactive project' )
656+ continue
657+ ppaths .append (Path (project .abspath ).resolve ())
658+
659+ def _folder_status (folder ):
660+ self .dbg (f'folder status in: { folder } ' )
661+ for e in [e .resolve () for e in folder .iterdir ()]:
662+ if e .is_dir ():
663+ self .dbg (f'processing folder: { e } ' )
664+ recurse = False
665+ for ppath in ppaths :
666+ if e .samefile (ppath ):
667+ # We hit a project root folder, skip it
668+ break
669+ elif e in ppath .parents :
670+ self .dbg (f'recursing into: { e } ' )
671+ _folder_status (e )
672+ break
673+ else :
674+ # No match, untracked folder
675+ untracked .append (e )
676+ continue
677+ else :
678+ # Untracked file
679+ untracked .append (e )
680+
681+ # Avoid using Path.walk() since that returns all files and folders under
682+ # a particular folder, which is overkill in our case. Instead, recurse
683+ # only when required.
684+ _folder_status (Path .cwd ())
685+ self .inf ('Untracked files and folders:' )
686+ for u in untracked :
687+ self .inf (u )
688+
643689 def _dump (self , args , to_dump ):
644690 if args .out :
645691 with open (args .out , 'w' ) as f :
0 commit comments