diff options
Diffstat (limited to 'subcmds/status.py')
-rw-r--r-- | subcmds/status.py | 96 |
1 files changed, 39 insertions, 57 deletions
diff --git a/subcmds/status.py b/subcmds/status.py index 63972d72..5b669547 100644 --- a/subcmds/status.py +++ b/subcmds/status.py | |||
@@ -1,5 +1,3 @@ | |||
1 | # -*- coding:utf-8 -*- | ||
2 | # | ||
3 | # Copyright (C) 2008 The Android Open Source Project | 1 | # Copyright (C) 2008 The Android Open Source Project |
4 | # | 2 | # |
5 | # Licensed under the Apache License, Version 2.0 (the "License"); | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
@@ -14,25 +12,19 @@ | |||
14 | # See the License for the specific language governing permissions and | 12 | # See the License for the specific language governing permissions and |
15 | # limitations under the License. | 13 | # limitations under the License. |
16 | 14 | ||
17 | from __future__ import print_function | 15 | import functools |
18 | |||
19 | from command import PagedCommand | ||
20 | |||
21 | try: | ||
22 | import threading as _threading | ||
23 | except ImportError: | ||
24 | import dummy_threading as _threading | ||
25 | |||
26 | import glob | 16 | import glob |
27 | 17 | import io | |
28 | import itertools | ||
29 | import os | 18 | import os |
30 | 19 | ||
20 | from command import DEFAULT_LOCAL_JOBS, PagedCommand | ||
21 | |||
31 | from color import Coloring | 22 | from color import Coloring |
32 | import platform_utils | 23 | import platform_utils |
33 | 24 | ||
25 | |||
34 | class Status(PagedCommand): | 26 | class Status(PagedCommand): |
35 | common = True | 27 | COMMON = True |
36 | helpSummary = "Show the working tree status" | 28 | helpSummary = "Show the working tree status" |
37 | helpUsage = """ | 29 | helpUsage = """ |
38 | %prog [<project>...] | 30 | %prog [<project>...] |
@@ -84,36 +76,29 @@ the following meanings: | |||
84 | d: deleted ( in index, not in work tree ) | 76 | d: deleted ( in index, not in work tree ) |
85 | 77 | ||
86 | """ | 78 | """ |
79 | PARALLEL_JOBS = DEFAULT_LOCAL_JOBS | ||
87 | 80 | ||
88 | def _Options(self, p): | 81 | def _Options(self, p): |
89 | p.add_option('-j', '--jobs', | ||
90 | dest='jobs', action='store', type='int', default=2, | ||
91 | help="number of projects to check simultaneously") | ||
92 | p.add_option('-o', '--orphans', | 82 | p.add_option('-o', '--orphans', |
93 | dest='orphans', action='store_true', | 83 | dest='orphans', action='store_true', |
94 | help="include objects in working directory outside of repo projects") | 84 | help="include objects in working directory outside of repo projects") |
95 | p.add_option('-q', '--quiet', action='store_true', | ||
96 | help="only print the name of modified projects") | ||
97 | 85 | ||
98 | def _StatusHelper(self, project, clean_counter, sem, quiet): | 86 | def _StatusHelper(self, quiet, project): |
99 | """Obtains the status for a specific project. | 87 | """Obtains the status for a specific project. |
100 | 88 | ||
101 | Obtains the status for a project, redirecting the output to | 89 | Obtains the status for a project, redirecting the output to |
102 | the specified object. It will release the semaphore | 90 | the specified object. |
103 | when done. | ||
104 | 91 | ||
105 | Args: | 92 | Args: |
93 | quiet: Where to output the status. | ||
106 | project: Project to get status of. | 94 | project: Project to get status of. |
107 | clean_counter: Counter for clean projects. | 95 | |
108 | sem: Semaphore, will call release() when complete. | 96 | Returns: |
109 | output: Where to output the status. | 97 | The status of the project. |
110 | """ | 98 | """ |
111 | try: | 99 | buf = io.StringIO() |
112 | state = project.PrintWorkTreeStatus(quiet=quiet) | 100 | ret = project.PrintWorkTreeStatus(quiet=quiet, output_redir=buf) |
113 | if state == 'CLEAN': | 101 | return (ret, buf.getvalue()) |
114 | next(clean_counter) | ||
115 | finally: | ||
116 | sem.release() | ||
117 | 102 | ||
118 | def _FindOrphans(self, dirs, proj_dirs, proj_dirs_parents, outstring): | 103 | def _FindOrphans(self, dirs, proj_dirs, proj_dirs_parents, outstring): |
119 | """find 'dirs' that are present in 'proj_dirs_parents' but not in 'proj_dirs'""" | 104 | """find 'dirs' that are present in 'proj_dirs_parents' but not in 'proj_dirs'""" |
@@ -126,34 +111,31 @@ the following meanings: | |||
126 | continue | 111 | continue |
127 | if item in proj_dirs_parents: | 112 | if item in proj_dirs_parents: |
128 | self._FindOrphans(glob.glob('%s/.*' % item) + | 113 | self._FindOrphans(glob.glob('%s/.*' % item) + |
129 | glob.glob('%s/*' % item), | 114 | glob.glob('%s/*' % item), |
130 | proj_dirs, proj_dirs_parents, outstring) | 115 | proj_dirs, proj_dirs_parents, outstring) |
131 | continue | 116 | continue |
132 | outstring.append(''.join([status_header, item, '/'])) | 117 | outstring.append(''.join([status_header, item, '/'])) |
133 | 118 | ||
134 | def Execute(self, opt, args): | 119 | def Execute(self, opt, args): |
135 | all_projects = self.GetProjects(args) | 120 | all_projects = self.GetProjects(args) |
136 | counter = itertools.count() | ||
137 | 121 | ||
138 | if opt.jobs == 1: | 122 | def _ProcessResults(_pool, _output, results): |
139 | for project in all_projects: | 123 | ret = 0 |
140 | state = project.PrintWorkTreeStatus(quiet=opt.quiet) | 124 | for (state, output) in results: |
125 | if output: | ||
126 | print(output, end='') | ||
141 | if state == 'CLEAN': | 127 | if state == 'CLEAN': |
142 | next(counter) | 128 | ret += 1 |
143 | else: | 129 | return ret |
144 | sem = _threading.Semaphore(opt.jobs) | 130 | |
145 | threads = [] | 131 | counter = self.ExecuteInParallel( |
146 | for project in all_projects: | 132 | opt.jobs, |
147 | sem.acquire() | 133 | functools.partial(self._StatusHelper, opt.quiet), |
148 | 134 | all_projects, | |
149 | t = _threading.Thread(target=self._StatusHelper, | 135 | callback=_ProcessResults, |
150 | args=(project, counter, sem, opt.quiet)) | 136 | ordered=True) |
151 | threads.append(t) | 137 | |
152 | t.daemon = True | 138 | if not opt.quiet and len(all_projects) == counter: |
153 | t.start() | ||
154 | for t in threads: | ||
155 | t.join() | ||
156 | if not opt.quiet and len(all_projects) == next(counter): | ||
157 | print('nothing to commit (working directory clean)') | 139 | print('nothing to commit (working directory clean)') |
158 | 140 | ||
159 | if opt.orphans: | 141 | if opt.orphans: |
@@ -170,8 +152,8 @@ the following meanings: | |||
170 | class StatusColoring(Coloring): | 152 | class StatusColoring(Coloring): |
171 | def __init__(self, config): | 153 | def __init__(self, config): |
172 | Coloring.__init__(self, config, 'status') | 154 | Coloring.__init__(self, config, 'status') |
173 | self.project = self.printer('header', attr = 'bold') | 155 | self.project = self.printer('header', attr='bold') |
174 | self.untracked = self.printer('untracked', fg = 'red') | 156 | self.untracked = self.printer('untracked', fg='red') |
175 | 157 | ||
176 | orig_path = os.getcwd() | 158 | orig_path = os.getcwd() |
177 | try: | 159 | try: |
@@ -179,11 +161,11 @@ the following meanings: | |||
179 | 161 | ||
180 | outstring = [] | 162 | outstring = [] |
181 | self._FindOrphans(glob.glob('.*') + | 163 | self._FindOrphans(glob.glob('.*') + |
182 | glob.glob('*'), | 164 | glob.glob('*'), |
183 | proj_dirs, proj_dirs_parents, outstring) | 165 | proj_dirs, proj_dirs_parents, outstring) |
184 | 166 | ||
185 | if outstring: | 167 | if outstring: |
186 | output = StatusColoring(self.manifest.globalConfig) | 168 | output = StatusColoring(self.client.globalConfig) |
187 | output.project('Objects not within a project (orphans)') | 169 | output.project('Objects not within a project (orphans)') |
188 | output.nl() | 170 | output.nl() |
189 | for entry in outstring: | 171 | for entry in outstring: |