summaryrefslogtreecommitdiffstats
path: root/subcmds/status.py
diff options
context:
space:
mode:
Diffstat (limited to 'subcmds/status.py')
-rw-r--r--subcmds/status.py239
1 files changed, 129 insertions, 110 deletions
diff --git a/subcmds/status.py b/subcmds/status.py
index 572c72f7..6e0026f9 100644
--- a/subcmds/status.py
+++ b/subcmds/status.py
@@ -24,12 +24,12 @@ import platform_utils
24 24
25 25
26class Status(PagedCommand): 26class Status(PagedCommand):
27 COMMON = True 27 COMMON = True
28 helpSummary = "Show the working tree status" 28 helpSummary = "Show the working tree status"
29 helpUsage = """ 29 helpUsage = """
30%prog [<project>...] 30%prog [<project>...]
31""" 31"""
32 helpDescription = """ 32 helpDescription = """
33'%prog' compares the working tree to the staging area (aka index), 33'%prog' compares the working tree to the staging area (aka index),
34and the most recent commit on this branch (HEAD), in each project 34and the most recent commit on this branch (HEAD), in each project
35specified. A summary is displayed, one line per file where there 35specified. A summary is displayed, one line per file where there
@@ -76,109 +76,128 @@ the following meanings:
76 d: deleted ( in index, not in work tree ) 76 d: deleted ( in index, not in work tree )
77 77
78""" 78"""
79 PARALLEL_JOBS = DEFAULT_LOCAL_JOBS 79 PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
80 80
81 def _Options(self, p): 81 def _Options(self, p):
82 p.add_option('-o', '--orphans', 82 p.add_option(
83 dest='orphans', action='store_true', 83 "-o",
84 help="include objects in working directory outside of repo projects") 84 "--orphans",
85 85 dest="orphans",
86 def _StatusHelper(self, quiet, local, project): 86 action="store_true",
87 """Obtains the status for a specific project. 87 help="include objects in working directory outside of repo "
88 88 "projects",
89 Obtains the status for a project, redirecting the output to 89 )
90 the specified object. 90
91 91 def _StatusHelper(self, quiet, local, project):
92 Args: 92 """Obtains the status for a specific project.
93 quiet: Where to output the status. 93
94 local: a boolean, if True, the path is relative to the local 94 Obtains the status for a project, redirecting the output to
95 (sub)manifest. If false, the path is relative to the 95 the specified object.
96 outermost manifest. 96
97 project: Project to get status of. 97 Args:
98 98 quiet: Where to output the status.
99 Returns: 99 local: a boolean, if True, the path is relative to the local
100 The status of the project. 100 (sub)manifest. If false, the path is relative to the outermost
101 """ 101 manifest.
102 buf = io.StringIO() 102 project: Project to get status of.
103 ret = project.PrintWorkTreeStatus(quiet=quiet, output_redir=buf, 103
104 local=local) 104 Returns:
105 return (ret, buf.getvalue()) 105 The status of the project.
106 106 """
107 def _FindOrphans(self, dirs, proj_dirs, proj_dirs_parents, outstring): 107 buf = io.StringIO()
108 """find 'dirs' that are present in 'proj_dirs_parents' but not in 'proj_dirs'""" 108 ret = project.PrintWorkTreeStatus(
109 status_header = ' --\t' 109 quiet=quiet, output_redir=buf, local=local
110 for item in dirs: 110 )
111 if not platform_utils.isdir(item): 111 return (ret, buf.getvalue())
112 outstring.append(''.join([status_header, item])) 112
113 continue 113 def _FindOrphans(self, dirs, proj_dirs, proj_dirs_parents, outstring):
114 if item in proj_dirs: 114 """find 'dirs' that are present in 'proj_dirs_parents' but not in 'proj_dirs'""" # noqa: E501
115 continue 115 status_header = " --\t"
116 if item in proj_dirs_parents: 116 for item in dirs:
117 self._FindOrphans(glob.glob('%s/.*' % item) + 117 if not platform_utils.isdir(item):
118 glob.glob('%s/*' % item), 118 outstring.append("".join([status_header, item]))
119 proj_dirs, proj_dirs_parents, outstring) 119 continue
120 continue 120 if item in proj_dirs:
121 outstring.append(''.join([status_header, item, '/'])) 121 continue
122 122 if item in proj_dirs_parents:
123 def Execute(self, opt, args): 123 self._FindOrphans(
124 all_projects = self.GetProjects(args, all_manifests=not opt.this_manifest_only) 124 glob.glob("%s/.*" % item) + glob.glob("%s/*" % item),
125 125 proj_dirs,
126 def _ProcessResults(_pool, _output, results): 126 proj_dirs_parents,
127 ret = 0 127 outstring,
128 for (state, output) in results: 128 )
129 if output: 129 continue
130 print(output, end='') 130 outstring.append("".join([status_header, item, "/"]))
131 if state == 'CLEAN': 131
132 ret += 1 132 def Execute(self, opt, args):
133 return ret 133 all_projects = self.GetProjects(
134 134 args, all_manifests=not opt.this_manifest_only
135 counter = self.ExecuteInParallel( 135 )
136 opt.jobs, 136
137 functools.partial(self._StatusHelper, opt.quiet, opt.this_manifest_only), 137 def _ProcessResults(_pool, _output, results):
138 all_projects, 138 ret = 0
139 callback=_ProcessResults, 139 for state, output in results:
140 ordered=True) 140 if output:
141 141 print(output, end="")
142 if not opt.quiet and len(all_projects) == counter: 142 if state == "CLEAN":
143 print('nothing to commit (working directory clean)') 143 ret += 1
144 144 return ret
145 if opt.orphans: 145
146 proj_dirs = set() 146 counter = self.ExecuteInParallel(
147 proj_dirs_parents = set() 147 opt.jobs,
148 for project in self.GetProjects(None, missing_ok=True, all_manifests=not opt.this_manifest_only): 148 functools.partial(
149 relpath = project.RelPath(local=opt.this_manifest_only) 149 self._StatusHelper, opt.quiet, opt.this_manifest_only
150 proj_dirs.add(relpath) 150 ),
151 (head, _tail) = os.path.split(relpath) 151 all_projects,
152 while head != "": 152 callback=_ProcessResults,
153 proj_dirs_parents.add(head) 153 ordered=True,
154 (head, _tail) = os.path.split(head) 154 )
155 proj_dirs.add('.repo') 155
156 156 if not opt.quiet and len(all_projects) == counter:
157 class StatusColoring(Coloring): 157 print("nothing to commit (working directory clean)")
158 def __init__(self, config): 158
159 Coloring.__init__(self, config, 'status') 159 if opt.orphans:
160 self.project = self.printer('header', attr='bold') 160 proj_dirs = set()
161 self.untracked = self.printer('untracked', fg='red') 161 proj_dirs_parents = set()
162 162 for project in self.GetProjects(
163 orig_path = os.getcwd() 163 None, missing_ok=True, all_manifests=not opt.this_manifest_only
164 try: 164 ):
165 os.chdir(self.manifest.topdir) 165 relpath = project.RelPath(local=opt.this_manifest_only)
166 166 proj_dirs.add(relpath)
167 outstring = [] 167 (head, _tail) = os.path.split(relpath)
168 self._FindOrphans(glob.glob('.*') + 168 while head != "":
169 glob.glob('*'), 169 proj_dirs_parents.add(head)
170 proj_dirs, proj_dirs_parents, outstring) 170 (head, _tail) = os.path.split(head)
171 171 proj_dirs.add(".repo")
172 if outstring: 172
173 output = StatusColoring(self.client.globalConfig) 173 class StatusColoring(Coloring):
174 output.project('Objects not within a project (orphans)') 174 def __init__(self, config):
175 output.nl() 175 Coloring.__init__(self, config, "status")
176 for entry in outstring: 176 self.project = self.printer("header", attr="bold")
177 output.untracked(entry) 177 self.untracked = self.printer("untracked", fg="red")
178 output.nl() 178
179 else: 179 orig_path = os.getcwd()
180 print('No orphan files or directories') 180 try:
181 181 os.chdir(self.manifest.topdir)
182 finally: 182
183 # Restore CWD. 183 outstring = []
184 os.chdir(orig_path) 184 self._FindOrphans(
185 glob.glob(".*") + glob.glob("*"),
186 proj_dirs,
187 proj_dirs_parents,
188 outstring,
189 )
190
191 if outstring:
192 output = StatusColoring(self.client.globalConfig)
193 output.project("Objects not within a project (orphans)")
194 output.nl()
195 for entry in outstring:
196 output.untracked(entry)
197 output.nl()
198 else:
199 print("No orphan files or directories")
200
201 finally:
202 # Restore CWD.
203 os.chdir(orig_path)