Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame^] | 1 | #!/usr/bin/env python |
| 2 | # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | """Display active git branches and code changes in a ChromiumOS workspace.""" |
| 7 | |
| 8 | import os |
| 9 | import re |
| 10 | import subprocess |
| 11 | |
| 12 | def RunCommand(path, command): |
| 13 | """Run a command in a given directory, return stdout.""" |
| 14 | |
| 15 | return subprocess.Popen(command, |
| 16 | cwd=path, |
| 17 | stdout=subprocess.PIPE).communicate()[0].rstrip() |
| 18 | |
| 19 | # |
| 20 | # Taken with slight modification from gclient_utils.py in the depot_tools |
| 21 | # project. |
| 22 | # |
| 23 | def FindFileUpwards(filename, path): |
| 24 | """Search upwards from the a directory to find a file.""" |
| 25 | |
| 26 | path = os.path.realpath(path) |
| 27 | while True: |
| 28 | file_path = os.path.join(path, filename) |
| 29 | if os.path.exists(file_path): |
| 30 | return file_path |
| 31 | (new_path, _) = os.path.split(path) |
| 32 | if new_path == path: |
| 33 | return None |
| 34 | path = new_path |
| 35 | |
| 36 | |
| 37 | def ShowName(relative_name, color): |
| 38 | """Display the directory name.""" |
| 39 | |
| 40 | if color: |
| 41 | print('\033[44m\033[37m%s\033[0m' % relative_name) |
| 42 | else: |
| 43 | print relative_name |
| 44 | |
| 45 | |
| 46 | def ShowDir(full_name, relative_name, color): |
| 47 | """Display active work in a single git repo.""" |
| 48 | |
| 49 | lines_printed = 0 |
| 50 | command = ['git', 'branch', '-vv'] |
| 51 | |
| 52 | if color: |
| 53 | command.append('--color') |
| 54 | |
| 55 | branch = RunCommand(full_name, command) |
| 56 | lines = branch.splitlines() |
| 57 | |
| 58 | if (len(lines) > 1 or |
| 59 | (len(lines) == 1 and not re.search(r"\(no branch\)", lines[0]))): |
| 60 | if lines_printed == 0: |
| 61 | ShowName(relative_name, color) |
| 62 | lines_printed += 1 |
| 63 | print branch |
| 64 | |
| 65 | status = RunCommand(full_name, ['git', 'status', '-s']) |
| 66 | |
| 67 | if status.splitlines(): |
| 68 | if lines_printed == 0: |
| 69 | ShowName(relative_name, color) |
| 70 | if lines_printed == 1: |
| 71 | print '---------------' |
| 72 | lines_printed += 1 |
| 73 | print status |
| 74 | |
| 75 | if lines_printed > 0: |
| 76 | print "" |
| 77 | |
| 78 | |
| 79 | def FindRoot(): |
| 80 | """Returns the repo root.""" |
| 81 | |
| 82 | repo_file = '.repo' |
| 83 | repo_path = FindFileUpwards(repo_file, os.getcwd()) |
| 84 | |
| 85 | if repo_path is None: |
| 86 | raise Exception('Failed to find %s.' % repo_file) |
| 87 | |
| 88 | return os.path.dirname(repo_path) |
| 89 | |
| 90 | |
| 91 | def main(): |
| 92 | """Take no arguments.""" |
| 93 | |
| 94 | color = os.isatty(1) |
| 95 | base = os.path.basename(os.getcwd()) |
| 96 | root = FindRoot() |
| 97 | repos = RunCommand(root, ['repo', 'forall', '-c', 'pwd']).splitlines() |
| 98 | |
| 99 | # We want to use the full path for testing, but we want to use the relative |
| 100 | # path for display. |
| 101 | fulldirs = [os.path.normpath(os.path.join(root, p)) for p in repos] |
| 102 | reldirs = [re.sub('^' + re.escape(base), '.', p) for p in repos] |
| 103 | |
| 104 | for full_path, relative_path in zip(fulldirs, reldirs): |
| 105 | ShowDir(full_path, relative_path, color) |
| 106 | |
| 107 | |
| 108 | if __name__ == '__main__': |
| 109 | main() |