git cl creds-check: add methods analysing .gitcookies.

These methods are used to produce report in the next CL.

BUG=689543

Change-Id: I71b2705ac8b046103b4982d47f7ec97f8ef7818b
Reviewed-on: https://chromium-review.googlesource.com/455838
Commit-Queue: Andrii Shyshkalov <tandrii@chromium.org>
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
diff --git a/git_cl.py b/git_cl.py
index 8dea2d2..aa2238a 100755
--- a/git_cl.py
+++ b/git_cl.py
@@ -3541,6 +3541,89 @@
       print('\t'.join((('%%+%ds' % l) % s)
                        for l, s in zip(lengths, row)))
 
+  @staticmethod
+  def _parse_identity(identity):
+    """Parses identity "git-<ldap>.example.com" into <ldap> and domain."""
+    username, domain = identity.split('.', 1)
+    if username.startswith('git-'):
+      username = username[len('git-'):]
+    return username, domain
+
+  def _get_usernames_of_domain(self, domain):
+    """Returns list of usernames referenced by .gitcookies in a given domain."""
+    identities_by_domain = {}
+    for _, identity, _ in self.get_hosts_with_creds():
+      username, domain = self._parse_identity(identity)
+      identities_by_domain.setdefault(domain, []).append(username)
+    return identities_by_domain.get(domain)
+
+  def _canonical_git_googlesource_host(self, host):
+    """Normalizes Gerrit hosts (with '-review') to Git host."""
+    assert host.endswith(self._GOOGLESOURCE)
+    # Prefix doesn't include '.' at the end.
+    prefix = host[:-(1 + len(self._GOOGLESOURCE))]
+    if prefix.endswith('-review'):
+      prefix = prefix[:-len('-review')]
+    return prefix + '.' + self._GOOGLESOURCE
+
+  def has_generic_host(self):
+    """Returns whether generic .googlesource.com has been configured.
+
+    Chrome Infra recommends to use explicit ${host}.googlesource.com instead.
+    """
+    for host, _, _ in self.get_hosts_with_creds(include_netrc=False):
+      if host == '.' + self._GOOGLESOURCE:
+        return True
+    return False
+
+  def _get_git_gerrit_identity_pairs(self):
+    """Returns map from canonic host to pair of identities (Git, Gerrit).
+
+    One of identities might be None, meaning not configured.
+    """
+    host_to_identity_pairs = {}
+    for host, identity, _ in self.get_hosts_with_creds():
+      canonical = self._canonical_git_googlesource_host(host)
+      pair = host_to_identity_pairs.setdefault(canonical, [None, None])
+      idx = 0 if canonical == host else 1
+      pair[idx] = identity
+    return host_to_identity_pairs
+
+  def get_partially_configured_hosts(self):
+    return set(
+        host for host, identities_pair in
+        self._get_git_gerrit_identity_pairs().iteritems()
+        if None in identities_pair and host != '.' + self._GOOGLESOURCE)
+
+  def get_conflicting_hosts(self):
+    return set(
+        host for host, (i1, i2) in
+        self._get_git_gerrit_identity_pairs().iteritems()
+        if None not in (i1, i2) and i1 != i2)
+
+  def get_duplicated_hosts(self):
+    counters = collections.Counter(h for h, _, _ in self.get_hosts_with_creds())
+    return set(host for host, count in counters.iteritems() if count > 1)
+
+  _EXPECTED_HOST_IDENTITY_DOMAINS = {
+    'chromium.googlesource.com': 'chromium.org',
+    'chrome-internal.googlesource.com': 'google.com',
+  }
+
+  def get_hosts_with_wrong_identities(self):
+    """Finds hosts which **likely** reference wrong identities.
+
+    Note: skips hosts which have conflicting identities for Git and Gerrit.
+    """
+    hosts = set()
+    for host, expected in self._EXPECTED_HOST_IDENTITY_DOMAINS.iteritems():
+      pair = self._get_git_gerrit_identity_pairs().get(host)
+      if pair and pair[0] == pair[1]:
+        _, domain = self._parse_identity(pair[0])
+        if domain != expected:
+          hosts.add(host)
+    return hosts
+
 
 def CMDcreds_check(parser, args):
   """Checks credentials and suggests changes."""
@@ -3555,7 +3638,7 @@
   print('Your .netrc and .gitcookies have credentails for these hosts:')
   checker.print_current_creds(include_netrc=True)
 
-  # TODO(tandrii): finish this.
+  # TODO(tandrii): add report && autofixes.
   return 0