diff --git a/git_cl.py b/git_cl.py index 51577048d0..b0f169fad2 100755 --- a/git_cl.py +++ b/git_cl.py @@ -16,6 +16,7 @@ import collections import contextlib import fnmatch import httplib +import itertools import json import logging import multiprocessing @@ -3446,6 +3447,13 @@ def GetRietveldCodereviewSettingsInteractively(): class _GitCookiesChecker(object): """Provides facilties for validating and suggesting fixes to .gitcookies.""" + _GOOGLESOURCE = 'googlesource.com' + + def __init__(self): + # Cached list of [host, identity, source], where source is either + # .gitcookies or .netrc. + self._all_hosts = None + def ensure_configured_gitcookies(self): """Runs checks and suggests fixes to make git use .gitcookies from default path.""" @@ -3505,6 +3513,34 @@ class _GitCookiesChecker(object): RunGit(['config', '--global', 'http.cookiefile', default_path]) print('Configured git to use .gitcookies from %s' % default_path) + def get_hosts_with_creds(self, include_netrc=False): + if self._all_hosts is None: + a = gerrit_util.CookiesAuthenticator() + self._all_hosts = [ + (h, u, s) + for h, u, s in itertools.chain( + ((h, u, '.netrc') for h, (u, _, _) in a.netrc.hosts.iteritems()), + ((h, u, '.gitcookies') for h, (u, _) in a.gitcookies.iteritems()) + ) + if h.endswith(self._GOOGLESOURCE) + ] + + if include_netrc: + return self._all_hosts + return [(h, u, s) for h, u, s in self._all_hosts if s != '.netrc'] + + def print_current_creds(self, include_netrc=False): + hosts = sorted(self.get_hosts_with_creds(include_netrc=include_netrc)) + if not hosts: + print('No Git/Gerrit credentials found') + return + lengths = [max(map(len, (row[i] for row in hosts))) for i in xrange(3)] + header = [('Host', 'User', 'Which file'), + ['=' * l for l in lengths]] + for row in (header + hosts): + print('\t'.join((('%%+%ds' % l) % s) + for l, s in zip(lengths, row))) + def CMDcreds_check(parser, args): """Checks credentials and suggests changes.""" @@ -3515,6 +3551,10 @@ def CMDcreds_check(parser, args): checker = _GitCookiesChecker() checker.ensure_configured_gitcookies() + + print('Your .netrc and .gitcookies have credentails for these hosts:') + checker.print_current_creds(include_netrc=True) + # TODO(tandrii): finish this. return 0 diff --git a/tests/git_cl_test.py b/tests/git_cl_test.py index d112f0bd42..588c016ac7 100755 --- a/tests/git_cl_test.py +++ b/tests/git_cl_test.py @@ -2933,6 +2933,38 @@ class TestGitCl(TestCase): self.assertEqual(cl.GetDescription(), 'desc1') # cache hit. self.assertEqual(cl.GetDescription(force=True), 'desc2') + def test_print_current_creds(self): + class CookiesAuthenticatorMock(object): + def __init__(self): + self.gitcookies = { + 'host.googlesource.com': ('user', 'pass'), + 'host-review.googlesource.com': ('user', 'pass'), + } + self.netrc = self + self.netrc.hosts = { + 'github.com': ('user2', None, 'pass2'), + 'host2.googlesource.com': ('user3', None, 'pass'), + } + self.mock(git_cl.gerrit_util, 'CookiesAuthenticator', + CookiesAuthenticatorMock) + self.mock(sys, 'stdout', StringIO.StringIO()) + git_cl._GitCookiesChecker().print_current_creds(include_netrc=True) + self.assertEqual(list(sys.stdout.getvalue().splitlines()), [ + ' Host\t User\t Which file', + '============================\t=====\t===========', + 'host-review.googlesource.com\t user\t.gitcookies', + ' host.googlesource.com\t user\t.gitcookies', + ' host2.googlesource.com\tuser3\t .netrc', + ]) + sys.stdout.buf = '' + git_cl._GitCookiesChecker().print_current_creds(include_netrc=False) + self.assertEqual(list(sys.stdout.getvalue().splitlines()), [ + ' Host\tUser\t Which file', + '============================\t====\t===========', + 'host-review.googlesource.com\tuser\t.gitcookies', + ' host.googlesource.com\tuser\t.gitcookies', + ]) + def _common_creds_check_mocks(self): def exists_mock(path): dirname = os.path.dirname(path) @@ -2948,6 +2980,8 @@ class TestGitCl(TestCase): def test_creds_check_gitcookies_not_configured(self): self._common_creds_check_mocks() + self.mock(git_cl._GitCookiesChecker, 'get_hosts_with_creds', + lambda _, include_netrc: []) self.calls = [ ((['git', 'config', '--global', 'http.cookiefile'],), CERR1), (('os.path.exists', '~/.netrc'), True), @@ -2966,6 +3000,8 @@ class TestGitCl(TestCase): def test_creds_check_gitcookies_configured_custom_broken(self): self._common_creds_check_mocks() + self.mock(git_cl._GitCookiesChecker, 'get_hosts_with_creds', + lambda _, include_netrc: []) self.calls = [ ((['git', 'config', '--global', 'http.cookiefile'],), '/custom/.gitcookies'), @@ -2983,6 +3019,7 @@ class TestGitCl(TestCase): sys.stdout.getvalue(), 'However, your configured .gitcookies file is missing.') + if __name__ == '__main__': logging.basicConfig( level=logging.DEBUG if '-v' in sys.argv else logging.ERROR)