xref: /aosp_15_r20/external/skia/tools/rewrite_includes.py (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker#!/usr/bin/python
2*c8dee2aaSAndroid Build Coastguard Worker#
3*c8dee2aaSAndroid Build Coastguard Worker# Copyright 2019 Google Inc.
4*c8dee2aaSAndroid Build Coastguard Worker#
5*c8dee2aaSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
6*c8dee2aaSAndroid Build Coastguard Worker# found in the LICENSE file.
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker
9*c8dee2aaSAndroid Build Coastguard Workerimport argparse
10*c8dee2aaSAndroid Build Coastguard Workerimport os
11*c8dee2aaSAndroid Build Coastguard Workerimport sys
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard Workerfrom io import StringIO
14*c8dee2aaSAndroid Build Coastguard Worker
15*c8dee2aaSAndroid Build Coastguard Worker
16*c8dee2aaSAndroid Build Coastguard Workerparser = argparse.ArgumentParser()
17*c8dee2aaSAndroid Build Coastguard Workerparser.add_argument('-n', '--dry-run', action='store_true',
18*c8dee2aaSAndroid Build Coastguard Worker                    help='Just check there is nothing to rewrite.')
19*c8dee2aaSAndroid Build Coastguard Workerparser.add_argument('sources', nargs='*',
20*c8dee2aaSAndroid Build Coastguard Worker                    help='Source files to rewrite, or all if empty.')
21*c8dee2aaSAndroid Build Coastguard Workerargs = parser.parse_args()
22*c8dee2aaSAndroid Build Coastguard Worker
23*c8dee2aaSAndroid Build Coastguard Workerroots = [
24*c8dee2aaSAndroid Build Coastguard Worker  'bench',
25*c8dee2aaSAndroid Build Coastguard Worker  'dm',
26*c8dee2aaSAndroid Build Coastguard Worker  'docs',
27*c8dee2aaSAndroid Build Coastguard Worker  'experimental',
28*c8dee2aaSAndroid Build Coastguard Worker  'fuzz',
29*c8dee2aaSAndroid Build Coastguard Worker  'gm',
30*c8dee2aaSAndroid Build Coastguard Worker  'include',
31*c8dee2aaSAndroid Build Coastguard Worker  'modules',
32*c8dee2aaSAndroid Build Coastguard Worker  'platform_tools/android/apps',
33*c8dee2aaSAndroid Build Coastguard Worker  'samplecode',
34*c8dee2aaSAndroid Build Coastguard Worker  'src',
35*c8dee2aaSAndroid Build Coastguard Worker  'tests',
36*c8dee2aaSAndroid Build Coastguard Worker  'third_party/etc1',
37*c8dee2aaSAndroid Build Coastguard Worker  'third_party/gif',
38*c8dee2aaSAndroid Build Coastguard Worker  'tools'
39*c8dee2aaSAndroid Build Coastguard Worker]
40*c8dee2aaSAndroid Build Coastguard Worker
41*c8dee2aaSAndroid Build Coastguard Workerignorelist = [
42*c8dee2aaSAndroid Build Coastguard Worker  # Don't count our local Vulkan headers as Skia headers;
43*c8dee2aaSAndroid Build Coastguard Worker  # we don't want #include <vulkan/vulkan_foo.h> rewritten to point to them.
44*c8dee2aaSAndroid Build Coastguard Worker  'include/third_party/vulkan',
45*c8dee2aaSAndroid Build Coastguard Worker  # Some node_modules/ files (used by CanvasKit et al) have c++ code which we should ignore.
46*c8dee2aaSAndroid Build Coastguard Worker  'node_modules',
47*c8dee2aaSAndroid Build Coastguard Worker  'include/third_party/skcms',
48*c8dee2aaSAndroid Build Coastguard Worker  'src/gpu/vk/vulkanmemoryallocator',
49*c8dee2aaSAndroid Build Coastguard Worker  # Used by Jetski and Graphite
50*c8dee2aaSAndroid Build Coastguard Worker  'Surface.h',
51*c8dee2aaSAndroid Build Coastguard Worker  # Used by Ganesh and Graphite
52*c8dee2aaSAndroid Build Coastguard Worker  'Device.h',
53*c8dee2aaSAndroid Build Coastguard Worker
54*c8dee2aaSAndroid Build Coastguard Worker  # Transitional
55*c8dee2aaSAndroid Build Coastguard Worker  'tools/window',
56*c8dee2aaSAndroid Build Coastguard Worker]
57*c8dee2aaSAndroid Build Coastguard Worker
58*c8dee2aaSAndroid Build Coastguard Workerassert '/' in [os.sep, os.altsep]
59*c8dee2aaSAndroid Build Coastguard Workerdef fix_path(p):
60*c8dee2aaSAndroid Build Coastguard Worker  return p.replace(os.sep, os.altsep) if os.altsep else p
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker# Map short name -> absolute path for all Skia headers.
63*c8dee2aaSAndroid Build Coastguard Workerheaders = {}
64*c8dee2aaSAndroid Build Coastguard Workerfor root in roots:
65*c8dee2aaSAndroid Build Coastguard Worker  for path, _, files in os.walk(root):
66*c8dee2aaSAndroid Build Coastguard Worker    if not any(snippet in fix_path(path) for snippet in ignorelist):
67*c8dee2aaSAndroid Build Coastguard Worker      for file_name in files:
68*c8dee2aaSAndroid Build Coastguard Worker        if file_name.endswith('.h') and not file_name in ignorelist:
69*c8dee2aaSAndroid Build Coastguard Worker          if file_name in headers:
70*c8dee2aaSAndroid Build Coastguard Worker            message = ('Header filename is used more than once!\n- ' + path + '/' + file_name +
71*c8dee2aaSAndroid Build Coastguard Worker                       '\n- ' + headers[file_name])
72*c8dee2aaSAndroid Build Coastguard Worker            assert file_name not in headers, message
73*c8dee2aaSAndroid Build Coastguard Worker          headers[file_name] = os.path.abspath(os.path.join(path, file_name))
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard Workerdef to_rewrite():
76*c8dee2aaSAndroid Build Coastguard Worker  if args.sources:
77*c8dee2aaSAndroid Build Coastguard Worker    for path in args.sources:
78*c8dee2aaSAndroid Build Coastguard Worker      yield path
79*c8dee2aaSAndroid Build Coastguard Worker  else:
80*c8dee2aaSAndroid Build Coastguard Worker    for root in roots:
81*c8dee2aaSAndroid Build Coastguard Worker      for path, _, files in os.walk(root):
82*c8dee2aaSAndroid Build Coastguard Worker        for file_name in files:
83*c8dee2aaSAndroid Build Coastguard Worker          yield os.path.join(path, file_name)
84*c8dee2aaSAndroid Build Coastguard Worker
85*c8dee2aaSAndroid Build Coastguard Worker# Rewrite any #includes relative to Skia's top-level directory.
86*c8dee2aaSAndroid Build Coastguard Workerneed_rewriting = []
87*c8dee2aaSAndroid Build Coastguard Workerfor file_path in to_rewrite():
88*c8dee2aaSAndroid Build Coastguard Worker  if ('/generated/' in file_path or
89*c8dee2aaSAndroid Build Coastguard Worker      'tests/sksl/' in file_path or
90*c8dee2aaSAndroid Build Coastguard Worker      'third_party/skcms' in file_path or
91*c8dee2aaSAndroid Build Coastguard Worker      'modules/skcms' in file_path or
92*c8dee2aaSAndroid Build Coastguard Worker      # transitional
93*c8dee2aaSAndroid Build Coastguard Worker      'jetski' in file_path or
94*c8dee2aaSAndroid Build Coastguard Worker      'tools/window' in file_path or
95*c8dee2aaSAndroid Build Coastguard Worker      file_path.startswith('bazel/rbe') or
96*c8dee2aaSAndroid Build Coastguard Worker      'example/external_client/' in file_path or
97*c8dee2aaSAndroid Build Coastguard Worker      # We intentionally list SkUserConfig.h not from the root in this file.
98*c8dee2aaSAndroid Build Coastguard Worker      file_path == 'include/private/base/SkLoadUserConfig.h'):
99*c8dee2aaSAndroid Build Coastguard Worker    continue
100*c8dee2aaSAndroid Build Coastguard Worker  if (file_path.endswith('.h') or
101*c8dee2aaSAndroid Build Coastguard Worker      file_path.endswith('.c') or
102*c8dee2aaSAndroid Build Coastguard Worker      file_path.endswith('.m') or
103*c8dee2aaSAndroid Build Coastguard Worker      file_path.endswith('.mm') or
104*c8dee2aaSAndroid Build Coastguard Worker      file_path.endswith('.inc') or
105*c8dee2aaSAndroid Build Coastguard Worker      file_path.endswith('.cc') or
106*c8dee2aaSAndroid Build Coastguard Worker      file_path.endswith('.cpp')):
107*c8dee2aaSAndroid Build Coastguard Worker    # Read the whole file into memory.
108*c8dee2aaSAndroid Build Coastguard Worker    lines = open(file_path).readlines()
109*c8dee2aaSAndroid Build Coastguard Worker
110*c8dee2aaSAndroid Build Coastguard Worker    # Write it back out again line by line with substitutions for #includes.
111*c8dee2aaSAndroid Build Coastguard Worker    output = StringIO() if args.dry_run else open(file_path, 'w')
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker    includes = []
114*c8dee2aaSAndroid Build Coastguard Worker    for line in lines:
115*c8dee2aaSAndroid Build Coastguard Worker      parts = line.replace('<', '"').replace('>', '"').split('"')
116*c8dee2aaSAndroid Build Coastguard Worker      if (len(parts) == 3
117*c8dee2aaSAndroid Build Coastguard Worker          and '#' in parts[0]
118*c8dee2aaSAndroid Build Coastguard Worker          and 'include' in parts[0]
119*c8dee2aaSAndroid Build Coastguard Worker          and os.path.basename(parts[1]) in headers):
120*c8dee2aaSAndroid Build Coastguard Worker        header = fix_path(os.path.relpath(headers[os.path.basename(parts[1])], '.'))
121*c8dee2aaSAndroid Build Coastguard Worker        includes.append(parts[0] + '"%s"' % header + parts[2])
122*c8dee2aaSAndroid Build Coastguard Worker      else:
123*c8dee2aaSAndroid Build Coastguard Worker        # deduplicate includes in this block. If a file needs to be included
124*c8dee2aaSAndroid Build Coastguard Worker        # multiple times, the separate includes should go in different blocks.
125*c8dee2aaSAndroid Build Coastguard Worker        includes = sorted(list(set(includes)))
126*c8dee2aaSAndroid Build Coastguard Worker        for inc in includes:
127*c8dee2aaSAndroid Build Coastguard Worker          output.write(inc.strip('\n') + '\n')
128*c8dee2aaSAndroid Build Coastguard Worker        includes = []
129*c8dee2aaSAndroid Build Coastguard Worker        output.write(line.strip('\n') + '\n')
130*c8dee2aaSAndroid Build Coastguard Worker    # Fix any straggling includes, e.g. in a file that only includes something else.
131*c8dee2aaSAndroid Build Coastguard Worker    for inc in sorted(includes):
132*c8dee2aaSAndroid Build Coastguard Worker      output.write(inc.strip('\n') + '\n')
133*c8dee2aaSAndroid Build Coastguard Worker    if args.dry_run and output.getvalue() != open(file_path).read():
134*c8dee2aaSAndroid Build Coastguard Worker      need_rewriting.append(file_path)
135*c8dee2aaSAndroid Build Coastguard Worker      rc = 1
136*c8dee2aaSAndroid Build Coastguard Worker    output.close()
137*c8dee2aaSAndroid Build Coastguard Worker
138*c8dee2aaSAndroid Build Coastguard Workerif need_rewriting:
139*c8dee2aaSAndroid Build Coastguard Worker  print('Some files need rewritten #includes:')
140*c8dee2aaSAndroid Build Coastguard Worker  for path in need_rewriting:
141*c8dee2aaSAndroid Build Coastguard Worker    print('\t' + path)
142*c8dee2aaSAndroid Build Coastguard Worker  print('To do this automatically, run')
143*c8dee2aaSAndroid Build Coastguard Worker  print('python3 tools/rewrite_includes.py ' + ' '.join(need_rewriting))
144*c8dee2aaSAndroid Build Coastguard Worker  sys.exit(1)
145