def aggregate_components_from_owners(all_owners_data, root):
  """Converts the team/component/os tags parsed from OWNERS into mappings.

  Args:
    all_owners_data (dict): A mapping from relative path to a dir to a dict
        mapping the tag names to their values. See docstring for scrape_owners.
    root (str): the path to the src directory.

  Returns:
    A tuple (data, warnings, stats) where data is a dict of the form
      {'component-to-team': {'Component1': 'team1@chr...', ...},
       'teams-per-component': {'Component1': ['team1@chr...', 'team2@chr...]},
       'dir-to-component': {'/path/to/1': 'Component1', ...}}
       'dir-to-team': {'/path/to/1': 'team1@', ...}}
      , warnings is a list of strings, stats is a dict of form
      {'OWNERS-count': total number of OWNERS files,
       'OWNERS-with-component-only-count': number of OWNERS have # COMPONENT,
       'OWNERS-with-team-and-component-count': number of
                          OWNERS have TEAM and COMPONENT,
       'OWNERS-count-by-depth': {directory depth: number of OWNERS},
       'OWNERS-with-component-only-count-by-depth': {directory depth: number
                          of OWNERS have COMPONENT at this depth},
       'OWNERS-with-team-and-component-count-by-depth':{directory depth: ...}}
  """
  stats = {}
  num_total = 0
  num_with_component = 0
  num_with_team_component = 0
  num_total_by_depth = defaultdict(int)
  num_with_component_by_depth = defaultdict(int)
  num_with_team_component_by_depth = defaultdict(int)
  warnings = []
  teams_per_component = defaultdict(set)
  topmost_team = {}
  dir_to_component = {}
  dir_missing_info_by_depth = defaultdict(list)
  dir_to_team = {}
  for rel_dirname, owners_data in all_owners_data.iteritems():
    # Normalize this relative path to posix-style to make counting separators
    # work correctly as a means of obtaining the file_depth.
    rel_path = uniform_path_format(os.path.relpath(rel_dirname, root))
    file_depth = 0 if rel_path == '.' else rel_path.count(posixpath.sep) + 1
    num_total += 1
    num_total_by_depth[file_depth] += 1
    component = owners_data.get('component')
    team = owners_data.get('team')
    os_tag = owners_data.get('os')
    if os_tag and component:
      component = '%s(%s)' % (component, os_tag)
    if team:
      dir_to_team[rel_dirname] = team
    if component:
      num_with_component += 1
      num_with_component_by_depth[file_depth] += 1
      dir_to_component[rel_dirname] = component
      if team:
        num_with_team_component += 1
        num_with_team_component_by_depth[file_depth] += 1
        teams_per_component[component].add(team)
        if component not in topmost_team or file_depth < topmost_team[
            component]['depth']:
          topmost_team[component] = {'depth': file_depth, 'team': team}
    else:
      rel_owners_path = uniform_path_format(os.path.join(rel_dirname, 'OWNERS'))
      warnings.append('%s has no COMPONENT tag' % rel_owners_path)
      if not team and not os_tag:
        dir_missing_info_by_depth[file_depth].append(rel_owners_path)

  mappings = {
      'component-to-team': {
          k: v['team'] for k, v in topmost_team.iteritems()
      },
      'teams-per-component': {
          k: sorted(list(v)) for k, v in teams_per_component.iteritems()
      },
      'dir-to-component': dir_to_component,
      'dir-to-team': dir_to_team,
  }
  warnings += validate_one_team_per_component(mappings)
  stats = {'OWNERS-count': num_total,
           'OWNERS-with-component-only-count': num_with_component,
           'OWNERS-with-team-and-component-count': num_with_team_component,
           'OWNERS-count-by-depth': num_total_by_depth,
           'OWNERS-with-component-only-count-by-depth':
           num_with_component_by_depth,
           'OWNERS-with-team-and-component-count-by-depth':
           num_with_team_component_by_depth,
           'OWNERS-missing-info-by-depth':
           dir_missing_info_by_depth}
  return mappings, warnings, stats