• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Copyright 2022 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""check_cronet_dependencies.py - Keep track of Cronet's dependencies."""
6
7import argparse
8import os
9import subprocess
10import sys
11
12REPOSITORY_ROOT = os.path.abspath(
13    os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))
14
15sys.path.insert(0, os.path.join(REPOSITORY_ROOT, 'build/android/gyp'))
16from util import build_utils  # pylint: disable=wrong-import-position
17
18
19def normalize_third_party_dep(dependency):
20  third_party_str = 'third_party/'
21  if third_party_str not in dependency:
22    raise ValueError('Dependency is not third_party dependency')
23  root_end_index = dependency.rfind(third_party_str) + len(third_party_str)
24  dependency_name_end_index = dependency.find("/", root_end_index)
25  if dependency_name_end_index == -1:
26    return dependency
27  return dependency[:dependency_name_end_index]
28
29
30def dedup_third_party_deps_internal(dependencies, root_deps=None):
31  if root_deps is None:
32    root_deps = set()
33  deduped_deps = []
34  for dependency in dependencies:
35    # crbug.com(1406537): `gn desc deps` can spit out non-deps stuff if it finds unknown
36    # GN args
37    if not dependency or not dependency.startswith('//'):
38      continue
39    if dependency[-1] == '/':
40      raise ValueError('Dependencies must not have a trailing forward slash')
41
42    if 'third_party/' not in dependency:
43      # We don't apply any filtering to non third_party deps.
44      deduped_deps.append(dependency)
45      continue
46
47    # Take the last occurrence to consider //third_party/foo and
48    # //third_party/foo/third_party/bar as two distinct dependencies.
49    third_party_dep_segments = dependency.split('third_party/')
50    third_party_dep = third_party_dep_segments[-1]
51    if '/' not in third_party_dep:
52      # Root dependencies are always unique.
53      # Note: We append the amount of splits to differentiate between
54      # //third_party/foo and //third_party/bar/third_party/foo.
55      root_dep = str(len(third_party_dep_segments)) + third_party_dep
56      root_deps.add(root_dep)
57      deduped_deps.append(normalize_third_party_dep(dependency))
58    else:
59      third_party_dep_root = (str(len(third_party_dep_segments)) +
60                              third_party_dep.split('/')[0])
61      if third_party_dep_root not in root_deps:
62        root_deps.add(third_party_dep_root)
63        deduped_deps.append(normalize_third_party_dep(dependency))
64  return (deduped_deps, root_deps)
65
66
67def dedup_third_party_deps(old_dependencies, new_dependencies):
68  """Maintains only a single target for each third_party dependency."""
69  (_, root_deps) = dedup_third_party_deps_internal(old_dependencies)
70  (deduped_deps, _) = dedup_third_party_deps_internal(new_dependencies,
71                                                      root_deps=root_deps)
72  return '\n'.join(deduped_deps)
73
74
75def main():
76  parser = argparse.ArgumentParser(
77      prog='Check cronet dependencies',
78      description=
79      "Checks whether Cronet's current dependencies match the known ones.")
80  parser.add_argument(
81      '--new_dependencies_script',
82      type=str,
83      help='Relative path to the script that outputs new dependencies',
84      required=True,
85  )
86  parser.add_argument(
87      '--old_dependencies',
88      type=str,
89      help='Relative path to file that contains the old dependencies',
90      required=True,
91  )
92  parser.add_argument(
93      '--stamp',
94      type=str,
95      help='Path to touch on success',
96  )
97  args = parser.parse_args()
98
99  new_dependencies = subprocess.check_output(
100      [args.new_dependencies_script, args.old_dependencies]).decode('utf-8')
101  with open(args.old_dependencies, 'r') as f:
102    new_dependencies = dedup_third_party_deps(f.read().splitlines(),
103                                              new_dependencies.splitlines())
104  if new_dependencies != '':
105    print('New dependencies detected:')
106    print(new_dependencies)
107    print('Please update: ' + args.old_dependencies)
108    sys.exit(-1)
109  else:
110    build_utils.Touch(args.stamp)
111
112
113if __name__ == '__main__':
114  main()
115