|
@@ -20,10 +20,14 @@ try:
|
|
|
except ImportError:
|
|
except ImportError:
|
|
|
import dummy_threading as _threading
|
|
import dummy_threading as _threading
|
|
|
|
|
|
|
|
|
|
+import glob
|
|
|
import itertools
|
|
import itertools
|
|
|
|
|
+import os
|
|
|
import sys
|
|
import sys
|
|
|
import StringIO
|
|
import StringIO
|
|
|
|
|
|
|
|
|
|
+from color import Coloring
|
|
|
|
|
+
|
|
|
class Status(PagedCommand):
|
|
class Status(PagedCommand):
|
|
|
common = True
|
|
common = True
|
|
|
helpSummary = "Show the working tree status"
|
|
helpSummary = "Show the working tree status"
|
|
@@ -39,6 +43,13 @@ is a difference between these three states.
|
|
|
The -j/--jobs option can be used to run multiple status queries
|
|
The -j/--jobs option can be used to run multiple status queries
|
|
|
in parallel.
|
|
in parallel.
|
|
|
|
|
|
|
|
|
|
+The -o/--orphans option can be used to show objects that are in
|
|
|
|
|
+the working directory, but not associated with a repo project.
|
|
|
|
|
+This includes unmanaged top-level files and directories, but also
|
|
|
|
|
+includes deeper items. For example, if dir/subdir/proj1 and
|
|
|
|
|
+dir/subdir/proj2 are repo projects, dir/subdir/proj3 will be shown
|
|
|
|
|
+if it is not known to repo.
|
|
|
|
|
+
|
|
|
Status Display
|
|
Status Display
|
|
|
--------------
|
|
--------------
|
|
|
|
|
|
|
@@ -76,6 +87,9 @@ the following meanings:
|
|
|
p.add_option('-j', '--jobs',
|
|
p.add_option('-j', '--jobs',
|
|
|
dest='jobs', action='store', type='int', default=2,
|
|
dest='jobs', action='store', type='int', default=2,
|
|
|
help="number of projects to check simultaneously")
|
|
help="number of projects to check simultaneously")
|
|
|
|
|
+ p.add_option('-o', '--orphans',
|
|
|
|
|
+ dest='orphans', action='store_true',
|
|
|
|
|
+ help="include objects in working directory outside of repo projects")
|
|
|
|
|
|
|
|
def _StatusHelper(self, project, clean_counter, sem, output):
|
|
def _StatusHelper(self, project, clean_counter, sem, output):
|
|
|
"""Obtains the status for a specific project.
|
|
"""Obtains the status for a specific project.
|
|
@@ -97,6 +111,22 @@ the following meanings:
|
|
|
finally:
|
|
finally:
|
|
|
sem.release()
|
|
sem.release()
|
|
|
|
|
|
|
|
|
|
+ def _FindOrphans(self, dirs, proj_dirs, proj_dirs_parents, outstring):
|
|
|
|
|
+ """find 'dirs' that are present in 'proj_dirs_parents' but not in 'proj_dirs'"""
|
|
|
|
|
+ status_header = ' --\t'
|
|
|
|
|
+ for item in dirs:
|
|
|
|
|
+ if not os.path.isdir(item):
|
|
|
|
|
+ outstring.write(''.join([status_header, item]))
|
|
|
|
|
+ continue
|
|
|
|
|
+ if item in proj_dirs:
|
|
|
|
|
+ continue
|
|
|
|
|
+ if item in proj_dirs_parents:
|
|
|
|
|
+ self._FindOrphans(glob.glob('%s/.*' % item) + \
|
|
|
|
|
+ glob.glob('%s/*' % item), \
|
|
|
|
|
+ proj_dirs, proj_dirs_parents, outstring)
|
|
|
|
|
+ continue
|
|
|
|
|
+ outstring.write(''.join([status_header, item, '/']))
|
|
|
|
|
+
|
|
|
def Execute(self, opt, args):
|
|
def Execute(self, opt, args):
|
|
|
all_projects = self.GetProjects(args)
|
|
all_projects = self.GetProjects(args)
|
|
|
counter = itertools.count()
|
|
counter = itertools.count()
|
|
@@ -130,3 +160,45 @@ the following meanings:
|
|
|
output.close()
|
|
output.close()
|
|
|
if len(all_projects) == counter.next():
|
|
if len(all_projects) == counter.next():
|
|
|
print('nothing to commit (working directory clean)')
|
|
print('nothing to commit (working directory clean)')
|
|
|
|
|
+
|
|
|
|
|
+ if opt.orphans:
|
|
|
|
|
+ proj_dirs = set()
|
|
|
|
|
+ proj_dirs_parents = set()
|
|
|
|
|
+ for project in self.GetProjects(None, missing_ok=True):
|
|
|
|
|
+ proj_dirs.add(project.relpath)
|
|
|
|
|
+ (head, _tail) = os.path.split(project.relpath)
|
|
|
|
|
+ while head != "":
|
|
|
|
|
+ proj_dirs_parents.add(head)
|
|
|
|
|
+ (head, _tail) = os.path.split(head)
|
|
|
|
|
+ proj_dirs.add('.repo')
|
|
|
|
|
+
|
|
|
|
|
+ class StatusColoring(Coloring):
|
|
|
|
|
+ def __init__(self, config):
|
|
|
|
|
+ Coloring.__init__(self, config, 'status')
|
|
|
|
|
+ self.project = self.printer('header', attr = 'bold')
|
|
|
|
|
+ self.untracked = self.printer('untracked', fg = 'red')
|
|
|
|
|
+
|
|
|
|
|
+ orig_path = os.getcwd()
|
|
|
|
|
+ try:
|
|
|
|
|
+ os.chdir(self.manifest.topdir)
|
|
|
|
|
+
|
|
|
|
|
+ outstring = StringIO.StringIO()
|
|
|
|
|
+ self._FindOrphans(glob.glob('.*') + \
|
|
|
|
|
+ glob.glob('*'), \
|
|
|
|
|
+ proj_dirs, proj_dirs_parents, outstring)
|
|
|
|
|
+
|
|
|
|
|
+ if outstring.buflist:
|
|
|
|
|
+ output = StatusColoring(self.manifest.globalConfig)
|
|
|
|
|
+ output.project('Objects not within a project (orphans)')
|
|
|
|
|
+ output.nl()
|
|
|
|
|
+ for entry in outstring.buflist:
|
|
|
|
|
+ output.untracked(entry)
|
|
|
|
|
+ output.nl()
|
|
|
|
|
+ else:
|
|
|
|
|
+ print('No orphan files or directories')
|
|
|
|
|
+
|
|
|
|
|
+ outstring.close()
|
|
|
|
|
+
|
|
|
|
|
+ finally:
|
|
|
|
|
+ # Restore CWD.
|
|
|
|
|
+ os.chdir(orig_path)
|