diff options
Diffstat (limited to 'subcmds/forall.py')
-rw-r--r-- | subcmds/forall.py | 106 |
1 files changed, 40 insertions, 66 deletions
diff --git a/subcmds/forall.py b/subcmds/forall.py index b874b6d2..4ea7db66 100644 --- a/subcmds/forall.py +++ b/subcmds/forall.py | |||
@@ -13,6 +13,7 @@ | |||
13 | # limitations under the License. | 13 | # limitations under the License. |
14 | 14 | ||
15 | import errno | 15 | import errno |
16 | import io | ||
16 | import multiprocessing | 17 | import multiprocessing |
17 | import re | 18 | import re |
18 | import os | 19 | import os |
@@ -22,7 +23,6 @@ import subprocess | |||
22 | 23 | ||
23 | from color import Coloring | 24 | from color import Coloring |
24 | from command import DEFAULT_LOCAL_JOBS, Command, MirrorSafeCommand, WORKER_BATCH_SIZE | 25 | from command import DEFAULT_LOCAL_JOBS, Command, MirrorSafeCommand, WORKER_BATCH_SIZE |
25 | import platform_utils | ||
26 | 26 | ||
27 | _CAN_COLOR = [ | 27 | _CAN_COLOR = [ |
28 | 'branch', | 28 | 'branch', |
@@ -241,7 +241,18 @@ without iterating through the remaining projects. | |||
241 | DoWorkWrapper, | 241 | DoWorkWrapper, |
242 | self.ProjectArgs(projects, mirror, opt, cmd, shell, config), | 242 | self.ProjectArgs(projects, mirror, opt, cmd, shell, config), |
243 | chunksize=WORKER_BATCH_SIZE) | 243 | chunksize=WORKER_BATCH_SIZE) |
244 | for r in results_it: | 244 | first = True |
245 | for (r, output) in results_it: | ||
246 | if output: | ||
247 | if first: | ||
248 | first = False | ||
249 | elif opt.project_header: | ||
250 | print() | ||
251 | # To simplify the DoWorkWrapper, take care of automatic newlines. | ||
252 | end = '\n' | ||
253 | if output[-1] == '\n': | ||
254 | end = '' | ||
255 | print(output, end=end) | ||
245 | rc = rc or r | 256 | rc = rc or r |
246 | if r != 0 and opt.abort_on_errors: | 257 | if r != 0 and opt.abort_on_errors: |
247 | raise Exception('Aborting due to previous error') | 258 | raise Exception('Aborting due to previous error') |
@@ -326,73 +337,36 @@ def DoWork(project, mirror, opt, cmd, shell, cnt, config): | |||
326 | # Allow the user to silently ignore missing checkouts so they can run on | 337 | # Allow the user to silently ignore missing checkouts so they can run on |
327 | # partial checkouts (good for infra recovery tools). | 338 | # partial checkouts (good for infra recovery tools). |
328 | if opt.ignore_missing: | 339 | if opt.ignore_missing: |
329 | return 0 | 340 | return (0, '') |
341 | |||
342 | output = '' | ||
330 | if ((opt.project_header and opt.verbose) | 343 | if ((opt.project_header and opt.verbose) |
331 | or not opt.project_header): | 344 | or not opt.project_header): |
332 | print('skipping %s/' % project['relpath'], file=sys.stderr) | 345 | output = 'skipping %s/' % project['relpath'] |
333 | return 1 | 346 | return (1, output) |
334 | 347 | ||
335 | if opt.project_header: | 348 | if opt.verbose: |
336 | stdin = subprocess.PIPE | 349 | stderr = subprocess.STDOUT |
337 | stdout = subprocess.PIPE | ||
338 | stderr = subprocess.PIPE | ||
339 | else: | 350 | else: |
340 | stdin = None | 351 | stderr = subprocess.DEVNULL |
341 | stdout = None | ||
342 | stderr = None | ||
343 | |||
344 | p = subprocess.Popen(cmd, | ||
345 | cwd=cwd, | ||
346 | shell=shell, | ||
347 | env=env, | ||
348 | stdin=stdin, | ||
349 | stdout=stdout, | ||
350 | stderr=stderr) | ||
351 | 352 | ||
353 | result = subprocess.run( | ||
354 | cmd, cwd=cwd, shell=shell, env=env, check=False, | ||
355 | encoding='utf-8', errors='replace', | ||
356 | stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=stderr) | ||
357 | |||
358 | output = result.stdout | ||
352 | if opt.project_header: | 359 | if opt.project_header: |
353 | out = ForallColoring(config) | 360 | if output: |
354 | out.redirect(sys.stdout) | 361 | buf = io.StringIO() |
355 | empty = True | 362 | out = ForallColoring(config) |
356 | errbuf = '' | 363 | out.redirect(buf) |
357 | 364 | if mirror: | |
358 | p.stdin.close() | 365 | project_header_path = project['name'] |
359 | s_in = platform_utils.FileDescriptorStreams.create() | 366 | else: |
360 | s_in.add(p.stdout, sys.stdout, 'stdout') | 367 | project_header_path = project['relpath'] |
361 | s_in.add(p.stderr, sys.stderr, 'stderr') | 368 | out.project('project %s/' % project_header_path) |
362 | 369 | out.nl() | |
363 | while not s_in.is_done: | 370 | buf.write(output) |
364 | in_ready = s_in.select() | 371 | output = buf.getvalue() |
365 | for s in in_ready: | 372 | return (result.returncode, output) |
366 | buf = s.read().decode() | ||
367 | if not buf: | ||
368 | s_in.remove(s) | ||
369 | s.close() | ||
370 | continue | ||
371 | |||
372 | if not opt.verbose: | ||
373 | if s.std_name == 'stderr': | ||
374 | errbuf += buf | ||
375 | continue | ||
376 | |||
377 | if empty and out: | ||
378 | if not cnt == 0: | ||
379 | out.nl() | ||
380 | |||
381 | if mirror: | ||
382 | project_header_path = project['name'] | ||
383 | else: | ||
384 | project_header_path = project['relpath'] | ||
385 | out.project('project %s/', project_header_path) | ||
386 | out.nl() | ||
387 | out.flush() | ||
388 | if errbuf: | ||
389 | sys.stderr.write(errbuf) | ||
390 | sys.stderr.flush() | ||
391 | errbuf = '' | ||
392 | empty = False | ||
393 | |||
394 | s.dest.write(buf) | ||
395 | s.dest.flush() | ||
396 | |||
397 | r = p.wait() | ||
398 | return r | ||