blob: b8a8258c8a4bf8387781a5959d036e652146f009 [file] [log] [blame]
John Stiles4498aa82021-08-16 18:14:52 -04001#!/usr/bin/python
Mike Kleinc0bd9f92019-04-23 12:05:21 -05002#
3# Copyright 2019 Google Inc.
4#
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
Eric Borena1db7992021-03-25 09:04:43 -04008
Mike Kleinbb413432019-07-26 11:55:40 -05009import argparse
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010import os
Mike Kleinbb413432019-07-26 11:55:40 -050011import sys
12
Kevin Lubick2f576262022-05-06 08:30:28 -040013from io import StringIO
John Stiles4498aa82021-08-16 18:14:52 -040014
Eric Borena1db7992021-03-25 09:04:43 -040015
Mike Kleinbb413432019-07-26 11:55:40 -050016parser = argparse.ArgumentParser()
17parser.add_argument('-n', '--dry-run', action='store_true',
18 help='Just check there is nothing to rewrite.')
19parser.add_argument('sources', nargs='*',
20 help='Source files to rewrite, or all if empty.')
21args = parser.parse_args()
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022
23roots = [
Kevin Lubickfed97e82022-03-25 14:59:33 -040024 'bench',
25 'dm',
26 'docs',
Kevin Lubickfed97e82022-03-25 14:59:33 -040027 'experimental',
28 'fuzz',
29 'gm',
30 'include',
31 'modules',
32 'platform_tools/android/apps',
33 'samplecode',
34 'src',
35 'tests',
36 'third_party/etc1',
37 'third_party/gif',
38 'tools'
39]
Mike Kleinc0bd9f92019-04-23 12:05:21 -050040
Kevin Lubickfed97e82022-03-25 14:59:33 -040041ignorelist = [
42 # Don't count our local Vulkan headers as Skia headers;
43 # we don't want #include <vulkan/vulkan_foo.h> rewritten to point to them.
44 'include/third_party/vulkan',
45 # Some node_modules/ files (used by CanvasKit et al) have c++ code which we should ignore.
46 'node_modules',
Kevin Lubick52904d32022-06-29 15:34:49 -040047 'include/third_party/skcms',
Kevin Lubick26d70e62023-10-09 12:50:57 -040048 'src/gpu/vk/vulkanmemoryallocator',
Kevin Lubick5c93acf2023-05-09 12:11:43 -040049 # Used by Jetski and Graphite
50 'Surface.h',
Kevin Lubickacdc1082023-06-09 11:05:24 -040051 # Used by Ganesh and Graphite
52 'Device.h',
Kevin Lubick3b233922023-03-23 09:26:34 -040053 # Temporary shims
K Lubicka8e4db12024-02-15 13:32:24 -050054 'GrBackendDrawableInfo.h',
Kevin Lubick68de6e32023-10-13 11:19:03 -040055 'SkMultiPictureDocument.h',
Florin Malita28f5db52023-05-02 10:34:11 -040056 # Transitional
57 'tools/window',
Kevin Lubickfed97e82022-03-25 14:59:33 -040058]
Mike Klein52337de2019-07-25 09:00:52 -050059
Hal Canary4df3d532019-07-30 13:49:45 -040060assert '/' in [os.sep, os.altsep]
61def fix_path(p):
62 return p.replace(os.sep, os.altsep) if os.altsep else p
63
Mike Kleinc0bd9f92019-04-23 12:05:21 -050064# Map short name -> absolute path for all Skia headers.
65headers = {}
66for root in roots:
67 for path, _, files in os.walk(root):
Kevin Lubick87fe9b02019-10-17 15:03:00 -040068 if not any(snippet in fix_path(path) for snippet in ignorelist):
Mike Klein66ed6a02019-07-25 11:18:06 -050069 for file_name in files:
Kevin Lubick10fdc3d2023-01-05 15:40:24 -050070 if file_name.endswith('.h') and not file_name in ignorelist:
Mike Klein66ed6a02019-07-25 11:18:06 -050071 if file_name in headers:
John Stilesf35853a2021-04-15 14:45:59 -040072 message = ('Header filename is used more than once!\n- ' + path + '/' + file_name +
73 '\n- ' + headers[file_name])
74 assert file_name not in headers, message
Mike Klein66ed6a02019-07-25 11:18:06 -050075 headers[file_name] = os.path.abspath(os.path.join(path, file_name))
Mike Kleinc0bd9f92019-04-23 12:05:21 -050076
Mike Kleinbb413432019-07-26 11:55:40 -050077def to_rewrite():
78 if args.sources:
79 for path in args.sources:
80 yield path
81 else:
82 for root in roots:
83 for path, _, files in os.walk(root):
84 for file_name in files:
85 yield os.path.join(path, file_name)
86
Mike Kleinc0bd9f92019-04-23 12:05:21 -050087# Rewrite any #includes relative to Skia's top-level directory.
Mike Klein140a4762019-08-01 14:24:08 -050088need_rewriting = []
Mike Kleinbb413432019-07-26 11:55:40 -050089for file_path in to_rewrite():
John Stilesd836f842020-09-14 10:21:44 -040090 if ('/generated/' in file_path or
91 'tests/sksl/' in file_path or
Kevin Lubickfed97e82022-03-25 14:59:33 -040092 'third_party/skcms' in file_path or
Kevin Lubick52904d32022-06-29 15:34:49 -040093 'modules/skcms' in file_path or
Florin Malita28f5db52023-05-02 10:34:11 -040094 # transitional
95 'jetski' in file_path or
96 'tools/window' in file_path or
Kevin Lubick23f1dcb2023-03-23 10:34:20 -040097 file_path.startswith('bazel/rbe') or
Kevin Lubick6f4fd972023-08-29 10:44:24 -040098 'example/external_client/' in file_path or
Kevin Lubick23f1dcb2023-03-23 10:34:20 -040099 # We intentionally list SkUserConfig.h not from the root in this file.
100 file_path == 'include/private/base/SkLoadUserConfig.h'):
Mike Kleinbb413432019-07-26 11:55:40 -0500101 continue
102 if (file_path.endswith('.h') or
103 file_path.endswith('.c') or
104 file_path.endswith('.m') or
105 file_path.endswith('.mm') or
106 file_path.endswith('.inc') or
Mike Kleinbb413432019-07-26 11:55:40 -0500107 file_path.endswith('.cc') or
108 file_path.endswith('.cpp')):
109 # Read the whole file into memory.
110 lines = open(file_path).readlines()
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500111
Mike Kleinbb413432019-07-26 11:55:40 -0500112 # Write it back out again line by line with substitutions for #includes.
John Stiles4498aa82021-08-16 18:14:52 -0400113 output = StringIO() if args.dry_run else open(file_path, 'w')
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500114
Mike Kleinbb413432019-07-26 11:55:40 -0500115 includes = []
116 for line in lines:
117 parts = line.replace('<', '"').replace('>', '"').split('"')
118 if (len(parts) == 3
119 and '#' in parts[0]
120 and 'include' in parts[0]
121 and os.path.basename(parts[1]) in headers):
Hal Canary4df3d532019-07-30 13:49:45 -0400122 header = fix_path(os.path.relpath(headers[os.path.basename(parts[1])], '.'))
123 includes.append(parts[0] + '"%s"' % header + parts[2])
Mike Kleinbb413432019-07-26 11:55:40 -0500124 else:
Kevin Lubick18ac33a2023-01-12 10:15:07 -0500125 # deduplicate includes in this block. If a file needs to be included
126 # multiple times, the separate includes should go in different blocks.
127 includes = sorted(list(set(includes)))
128 for inc in includes:
Hal Canary4df3d532019-07-30 13:49:45 -0400129 output.write(inc.strip('\n') + '\n')
Mike Kleinbb413432019-07-26 11:55:40 -0500130 includes = []
Hal Canary4df3d532019-07-30 13:49:45 -0400131 output.write(line.strip('\n') + '\n')
Kevin Lubickdc6cc022023-01-13 11:24:27 -0500132 # Fix any straggling includes, e.g. in a file that only includes something else.
133 for inc in sorted(includes):
134 output.write(inc.strip('\n') + '\n')
Mike Kleinbb413432019-07-26 11:55:40 -0500135 if args.dry_run and output.getvalue() != open(file_path).read():
Mike Klein140a4762019-08-01 14:24:08 -0500136 need_rewriting.append(file_path)
Mike Kleinbb413432019-07-26 11:55:40 -0500137 rc = 1
138 output.close()
Mike Klein140a4762019-08-01 14:24:08 -0500139
140if need_rewriting:
Eric Borena1db7992021-03-25 09:04:43 -0400141 print('Some files need rewritten #includes:')
Mike Klein140a4762019-08-01 14:24:08 -0500142 for path in need_rewriting:
Eric Borena1db7992021-03-25 09:04:43 -0400143 print('\t' + path)
144 print('To do this automatically, run')
John Stiles9c34b542023-03-22 17:20:16 -0400145 print('python3 tools/rewrite_includes.py ' + ' '.join(need_rewriting))
Mike Klein140a4762019-08-01 14:24:08 -0500146 sys.exit(1)