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 | |
Anton Staaf | 1037c44 | 2011-02-08 14:39:53 -0800 | [diff] [blame^] | 46 | def GetBranches(full_name, relative_name, color): |
| 47 | """Return a list of branch descriptions.""" |
Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame] | 48 | |
Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame] | 49 | command = ['git', 'branch', '-vv'] |
| 50 | |
| 51 | if color: |
| 52 | command.append('--color') |
| 53 | |
Anton Staaf | 1037c44 | 2011-02-08 14:39:53 -0800 | [diff] [blame^] | 54 | branches = RunCommand(full_name, command).splitlines() |
Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame] | 55 | |
Anton Staaf | 1037c44 | 2011-02-08 14:39:53 -0800 | [diff] [blame^] | 56 | if re.search(r"\(no branch\)", branches[0]): |
| 57 | return [] |
Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame] | 58 | |
Anton Staaf | 1037c44 | 2011-02-08 14:39:53 -0800 | [diff] [blame^] | 59 | return branches |
Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame] | 60 | |
Anton Staaf | 1037c44 | 2011-02-08 14:39:53 -0800 | [diff] [blame^] | 61 | def GetStatus(full_name, relative_name, color): |
| 62 | """Return a list of files that have modifications.""" |
Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame] | 63 | |
Anton Staaf | 1037c44 | 2011-02-08 14:39:53 -0800 | [diff] [blame^] | 64 | command = ['git', 'status', '-s'] |
| 65 | |
| 66 | return RunCommand(full_name, command).splitlines() |
| 67 | |
| 68 | |
| 69 | def ShowDir(full_name, relative_name, color): |
| 70 | """Display active work in a single git repository.""" |
| 71 | |
| 72 | branches = GetBranches(full_name, relative_name, color) |
| 73 | status = GetStatus(full_name, relative_name, color) |
| 74 | |
| 75 | if branches or status: |
| 76 | ShowName(relative_name, color) |
| 77 | |
| 78 | if branches: print '\n'.join(branches) |
| 79 | if status: print '\n'.join(status) |
| 80 | |
| 81 | if branches or status: |
Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame] | 82 | print "" |
| 83 | |
| 84 | |
| 85 | def FindRoot(): |
| 86 | """Returns the repo root.""" |
| 87 | |
| 88 | repo_file = '.repo' |
| 89 | repo_path = FindFileUpwards(repo_file, os.getcwd()) |
| 90 | |
| 91 | if repo_path is None: |
| 92 | raise Exception('Failed to find %s.' % repo_file) |
| 93 | |
| 94 | return os.path.dirname(repo_path) |
| 95 | |
| 96 | |
| 97 | def main(): |
| 98 | """Take no arguments.""" |
| 99 | |
| 100 | color = os.isatty(1) |
Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame] | 101 | root = FindRoot() |
| 102 | repos = RunCommand(root, ['repo', 'forall', '-c', 'pwd']).splitlines() |
| 103 | |
| 104 | # We want to use the full path for testing, but we want to use the relative |
| 105 | # path for display. |
Anton Staaf | 82340d7 | 2011-02-08 14:39:19 -0800 | [diff] [blame] | 106 | reldirs = [re.sub('^' + re.escape(root) + '/', '', p) for p in repos] |
Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame] | 107 | |
Anton Staaf | 82340d7 | 2011-02-08 14:39:19 -0800 | [diff] [blame] | 108 | for full, relative in zip(repos, reldirs): |
| 109 | ShowDir(full, relative, color) |
Anton Staaf | 60f4fd7 | 2011-02-01 13:20:54 -0800 | [diff] [blame] | 110 | |
| 111 | |
| 112 | if __name__ == '__main__': |
| 113 | main() |