blob: 6ee7f774fb1912df4a206f51bca09f21fdccf5c1 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Display active git branches and code changes in a ChromiumOS workspace."""
import optparse
import os
import re
import subprocess
def RunCommand(path, command):
"""Run a command in a given directory, return stdout."""
return subprocess.Popen(command,
cwd=path,
stdout=subprocess.PIPE).communicate()[0].rstrip()
#
# Taken with slight modification from gclient_utils.py in the depot_tools
# project.
#
def FindFileUpwards(filename, path):
"""Search upwards from the a directory to find a file."""
path = os.path.realpath(path)
while True:
file_path = os.path.join(path, filename)
if os.path.exists(file_path):
return file_path
(new_path, _) = os.path.split(path)
if new_path == path:
return None
path = new_path
def ShowName(relative_name, color):
"""Display the directory name."""
if color:
print('\033[44m\033[37m%s\033[0m' % relative_name)
else:
print relative_name
def GetBranches(full_name, color):
"""Return a list of branch descriptions."""
command = ['git', 'branch', '-vv']
if color:
command.append('--color')
branches = RunCommand(full_name, command).splitlines()
if re.search(r"\(no branch\)", branches[0]):
return []
return branches
def GetStatus(full_name, color):
"""Return a list of files that have modifications."""
command = ['git', 'status', '-s']
return RunCommand(full_name, command).splitlines()
def GetHistory(full_name, color, author, days):
"""Return a list of oneline log messages.
The messages are for the author going back a specified number of days.
"""
command = ['git', 'log',
'--author=' + author,
'--after=' + '-' + str(days) + 'days',
'--pretty=oneline',
'm/master']
return RunCommand(full_name, command).splitlines()
def ShowDir(full_name, color, logs, author, days):
"""Display active work in a single git repository."""
branches = GetBranches(full_name, color)
status = GetStatus(full_name, color)
if logs:
history = GetHistory(full_name, color, author, days)
else:
history = []
if branches or status or history:
# We want to use the full path for testing, but we want to use the
# relative path for display.
ShowName(os.path.relpath(full_name), color)
if branches: print '\n'.join(branches)
if status: print '\n'.join(status)
if history: print '\n'.join(history)
if branches or status or history:
print ""
def FindRoot():
"""Returns the repo root."""
repo_file = '.repo'
repo_path = FindFileUpwards(repo_file, os.getcwd())
if repo_path is None:
raise Exception('Failed to find %s.' % repo_file)
return os.path.dirname(repo_path)
def main():
parser = optparse.OptionParser(usage = 'usage: %prog [options]\n')
parser.add_option('-l', '--logs', default=False,
help='Show the last few days of your commits in short '
'form.',
action='store_true',
dest='logs')
parser.add_option('-d', '--days', default=8,
help='Set the number of days of history to show.',
type='int',
dest='days')
parser.add_option('-a', '--author', default=os.environ['USER'],
help='Set the author to filter for.',
type='string',
dest='author')
options, arguments = parser.parse_args()
if arguments:
parser.print_usage()
return 1
color = os.isatty(1)
root = FindRoot()
repos = RunCommand(root, ['repo', 'forall', '-c', 'pwd']).splitlines()
for full in repos:
ShowDir(full, color, options.logs, options.author, options.days)
if __name__ == '__main__':
main()